-
Hello, I am building an application where a set of processors can execute commands received from the network. Since command execution can be arbitrarily long, processor components have an internal queue where pending commands are stored. Commands themselves are implemented and registered as one shot systems: processors offer a registering API so developers can register systems to handle specific commands. #[derive(Component)]
pub struct Processor {
id: Id,
registry: HashMap<CommandKey, RegistryEntry>,
queue: Vec<Command>,
/* Other fields */
}
impl Processor {
pub fn register_cmd<M>(
&mut self,
world: &mut World,
key: CommandKey,
system: impl IntoSystem<In<Command>, CommandStatus, M> + 'static,
) -> Result<(), RegistryError>;
} I am trying to optimize how commands are routed from the network layer to each target processor internal queue. Currently, the network layer emits "Command" events. I want a routing system to process those events and pushes the associated commands into the target processor queue. To prevent excessive looping/filtering, I created a "Registry" resource which contains a mapping from a Processor Id to its corresponding entity. #[derive(Resource, Default)]
pub struct ProcessorRegistry(pub(crate) HashMap<Id, Entity>); But I am having troubles implementing a "routing" system that leverages that registry. Conceptually, I would like to implement this system: /// Forward inbound commands to their processor
pub fn forward_messages(
world: &mut World,
mut ev_in: EventReader<Command>,
registry: Res<ApplicationRegistry>,
) {
// Iterate over all inbound commands
for command in ev_in.read() {
// Use registry to find which entity will process that command
let target_entity_id = registry.0.get(&command.dst_id()).unwrap();
let mut processor_entity = world.entity_mut(*target_entity_id);
let mut processor = processor_entity.get_mut::<Processor>().unwrap();
// Add command to that processor queue
processor.queue.push(command.clone());
}
} However, this system signature is a not compliant exclusive system APIs. According to the documentation, I have two alternatives: I did not manage to read events from an Events resource, so I tried to use I found some workarounds but it seems to me I will run into these kind of issues every time I try to use |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
I believe you're right that accessing an /// Forward inbound commands to their processor
pub fn forward_messages(
world: &mut World,
system_state: &mut SystemState<
EventReader<Command>,
Res<ApplicationRegistry>,
Query<&mut Processor>,
>,
) {
let (mut evr, registry, mut q_processor) = system_state.get_mut(world);
// Iterate over all inbound commands
for command in evr.read() {
// Use registry to find which entity will process that command
let target_entity_id = registry.0.get(&command.dst_id()).unwrap();
let mut processor = q_processor.get_mut(target_entity_id).unwrap();
// Add command to that processor queue
processor.queue.push(command.clone());
}
} But at this point you might as well remove the |
Beta Was this translation helpful? Give feedback.
I believe you're right that accessing an
EventReader
from an exclusive system requires the use ofSystemState
. However if all you need is mutable access to theProcessor
component you can add aQuery
to theSystemState
.