Skip to main content

pebble/ecs/
commands.rs

1use crate::ecs::{
2    observers::Observers,
3    resources::{Resources, Write},
4    system_param::SystemParam,
5};
6
7#[derive(Default)]
8pub struct ResourceCommandQueue(pub(crate) Vec<Box<dyn FnOnce(&mut Resources)>>);
9
10#[derive(Default)]
11pub(crate) struct TriggerQueue(pub(crate) Vec<Box<dyn FnOnce(&hecs::World, &Resources)>>);
12
13/// Deferred entity spawns and resource/observer mutations — applied at the
14/// end of the current stage, not immediately. `Deref`s to `hecs::CommandBuffer`
15/// for spawning/despawning entities and adding/removing components.
16pub struct Commands<'a> {
17    buffer: Write<'a, hecs::CommandBuffer>,
18    resource_commands: Write<'a, ResourceCommandQueue>,
19    triggers: Write<'a, TriggerQueue>,
20}
21
22impl<'a> std::ops::Deref for Commands<'a> {
23    type Target = hecs::CommandBuffer;
24    fn deref(&self) -> &hecs::CommandBuffer {
25        &self.buffer
26    }
27}
28
29impl<'a> std::ops::DerefMut for Commands<'a> {
30    fn deref_mut(&mut self) -> &mut hecs::CommandBuffer {
31        &mut self.buffer
32    }
33}
34
35impl<'a> Commands<'a> {
36    /// Queues a resource insert, applied once commands are synced.
37    pub fn insert_resource<T: 'static>(&mut self, value: T) {
38        self.resource_commands
39            .0
40            .push(Box::new(move |resources| resources.insert(value)));
41    }
42
43    /// Queues a resource removal, applied once commands are synced.
44    pub fn remove_resource<T: 'static>(&mut self) {
45        self.resource_commands.0.push(Box::new(|resources| {
46            resources.remove::<T>();
47        }));
48    }
49
50    /// Queues `event` to be dispatched to every observer registered for
51    /// `E` via [`App::add_observer`](crate::app::App::add_observer), once
52    /// commands are synced (right after the system that called this
53    /// returns — same tick, not necessarily end of stage).
54    pub fn trigger<E: 'static + Send + Sync>(&mut self, event: E) {
55        self.triggers.0.push(Box::new(move |world, resources| {
56            if !resources.contains::<Observers<E>>() {
57                return;
58            }
59            let mut observers = std::mem::take(&mut resources.get_mut::<Observers<E>>().0);
60            for observer in observers.iter_mut() {
61                observer.run(&event, world, resources);
62            }
63            resources.get_mut::<Observers<E>>().0 = observers;
64        }));
65    }
66}
67
68impl SystemParam for Commands<'_> {
69    type Item<'w> = Commands<'w>;
70    type State = ((), (), ());
71
72    fn fetch<'w>(
73        world: &'w hecs::World,
74        resources: &'w Resources,
75        state: &'w mut Self::State,
76    ) -> Self::Item<'w> {
77        Commands {
78            buffer: Write::fetch(world, resources, &mut state.0),
79            resource_commands: Write::fetch(world, resources, &mut state.1),
80            triggers: Write::fetch(world, resources, &mut state.2),
81        }
82    }
83}