Skip to main content

mittens_engine/engine/ecs/
command_queue.rs

1//! Per-frame context + legacy name: used to be a command queue.
2//!
3//! This is a transitional facade that stages signals locally and drains them into `RxWorld`
4//! at explicit drain points.
5//!
6//! Important safety note:
7//! - This type must not store raw pointers into `SystemWorld`/`RxWorld` owned alongside it
8//!   (e.g. in `Universe`), because moving that owner would invalidate the pointer.
9//! - Instead, we queue signals locally and drain them into `SystemWorld.rx` at explicit
10//!   drain points.
11
12use crate::engine::ecs::{ComponentId, EventSignal, IntentSignal, RxWorld, Signal, SignalEmitter};
13
14pub struct CommandQueue {
15    queued: Vec<Signal>,
16}
17
18impl CommandQueue {
19    pub fn new() -> Self {
20        Self { queued: Vec::new() }
21    }
22
23    /// Drain locally-queued signals into the target `RxWorld`.
24    ///
25    /// Returns the number of signals moved.
26    pub fn drain_into_rx(&mut self, rx: &mut RxWorld) -> usize {
27        if self.queued.is_empty() {
28            return 0;
29        }
30
31        let drained = std::mem::take(&mut self.queued);
32        let moved = drained.len();
33        for env in drained {
34            if let Some(event) = env.event {
35                rx.push_event(env.scope, event);
36                continue;
37            }
38            if let Some(intent) = env.intent {
39                rx.push_intent(env.scope, intent);
40                continue;
41            }
42        }
43        moved
44    }
45
46    // Note: this type is intentionally minimal; emit `Signal` values directly via the
47    // `SignalEmitter` impl instead of using command-style convenience methods.
48
49    /// Flush used to apply queued commands; now it executes pending signals.
50    pub fn flush(
51        &mut self,
52        world: &mut crate::engine::ecs::World,
53        systems: &mut crate::engine::ecs::system::SystemWorld,
54        visuals: &mut crate::engine::graphics::VisualWorld,
55        render_assets: &mut crate::engine::graphics::RenderAssets,
56    ) {
57        // Execute + dispatch any newly-pushed signals.
58        let _ = systems.process_signals(world, visuals, render_assets, self, 100_000);
59    }
60}
61
62impl SignalEmitter for CommandQueue {
63    fn push_event(&mut self, scope: ComponentId, event: EventSignal) {
64        self.queued.push(Signal::event(scope, event));
65    }
66
67    fn push_intent(&mut self, scope: ComponentId, intent: IntentSignal) {
68        self.queued.push(Signal::intent(scope, intent));
69    }
70}