gravitron_ecs/
commands.rs

1use std::marker::PhantomData;
2
3#[cfg(feature = "debug")]
4use log::trace;
5
6use crate::{
7  components::Component,
8  entity::IntoEntity,
9  storage::{ComponentBox, Storage},
10  systems::{metadata::SystemMeta, SystemParam},
11  tick::Tick,
12  world::UnsafeWorldCell,
13  EntityId, SystemId,
14};
15
16pub struct Commands {
17  commands: Vec<Box<dyn Command>>,
18  world: UnsafeWorldCell<'static>,
19}
20
21impl Commands {
22  pub(crate) fn create(world: UnsafeWorldCell<'static>) -> Self {
23    Commands {
24      world,
25      commands: Vec::new(),
26    }
27  }
28
29  pub(crate) fn execute(&mut self, storage: &mut Storage, tick: Tick) {
30    for mut cmd in std::mem::take(&mut self.commands) {
31      cmd.execute(storage, tick)
32    }
33  }
34
35  pub fn create_entity(&mut self, entity: impl IntoEntity) -> EntityId {
36    #[cfg(feature = "debug")]
37    trace!("Registering Create Entity Command");
38
39    let id = unsafe { self.world.world_mut() }.reserve_entity_id();
40
41    self.commands.push(Box::new(CreateEntityCommand {
42      comps: Some(entity.into_entity()),
43      id,
44    }));
45
46    id
47  }
48
49  pub fn remove_entity(&mut self, entity: EntityId) {
50    #[cfg(feature = "debug")]
51    trace!("Registering Remove Entity Command for Entity {}", entity);
52
53    self
54      .commands
55      .push(Box::new(RemoveEntityCommand { id: entity }));
56  }
57
58  pub fn add_comp(&mut self, entity: EntityId, comp: impl Component) {
59    #[cfg(feature = "debug")]
60    trace!(
61      "Registering Add Component Command for Entity {} with Component {:?}",
62      entity,
63      comp.id()
64    );
65
66    self.commands.push(Box::new(AddComponentCommand {
67      id: entity,
68      comp: Some(Box::new(comp)),
69    }));
70  }
71
72  pub fn remove_comp<C: Component>(&mut self, entity: EntityId) {
73    #[cfg(feature = "debug")]
74    trace!(
75      "Registering Remove Component Command for Entity {} with Component {:?}",
76      entity,
77      C::sid()
78    );
79
80    self.commands.push(Box::new(RemoveComponentCommand {
81      id: entity,
82      phantom: PhantomData::<C>,
83    }));
84  }
85
86  pub fn custom_fn_command<F>(&mut self, func: F)
87  where
88    F: Fn(&mut Storage, Tick) + 'static,
89  {
90    #[cfg(feature = "debug")]
91    trace!("Registering Custom Fn Command",);
92
93    self.commands.push(Box::new(CustomFnCommand { func }));
94  }
95}
96
97impl SystemParam for &mut Commands {
98  type Item<'new> = &'new mut Commands;
99
100  #[inline]
101  fn get_param(world: crate::world::UnsafeWorldCell<'_>, id: SystemId) -> Self::Item<'_> {
102    unsafe { world.world_mut() }.get_commands_mut(id)
103  }
104
105  #[inline]
106  fn check_metadata(meta: &mut SystemMeta) {
107    meta.add_cmds();
108  }
109}
110
111trait Command {
112  fn execute(&mut self, storage: &mut Storage, tick: Tick);
113}
114
115struct CreateEntityCommand {
116  comps: Option<Vec<Box<dyn Component>>>,
117  id: EntityId,
118}
119
120impl Command for CreateEntityCommand {
121  fn execute(&mut self, storage: &mut Storage, tick: Tick) {
122    #[cfg(feature = "debug")]
123    trace!("Executing Create Entity Command");
124
125    storage.create_entity_with_id(std::mem::take(&mut self.comps).unwrap(), self.id, tick);
126  }
127}
128
129struct RemoveEntityCommand {
130  id: EntityId,
131}
132
133impl Command for RemoveEntityCommand {
134  fn execute(&mut self, storage: &mut Storage, _: Tick) {
135    #[cfg(feature = "debug")]
136    trace!("Executing Remove Entity Command for Entity {}", self.id);
137
138    storage.remove_entity(self.id);
139  }
140}
141
142struct AddComponentCommand {
143  id: EntityId,
144  comp: Option<Box<dyn Component>>,
145}
146
147impl Command for AddComponentCommand {
148  fn execute(&mut self, storage: &mut Storage, tick: Tick) {
149    #[cfg(feature = "debug")]
150    trace!(
151      "Executing Add Component Command for Entity {} with Component {:?}",
152      self.id,
153      self.comp.as_ref().unwrap().id()
154    );
155
156    storage.add_comp(
157      self.id,
158      ComponentBox {
159        comp: std::mem::take(&mut self.comp).unwrap(),
160        added: tick,
161        changed: (Tick::INVALID, Tick::INVALID),
162      },
163    );
164  }
165}
166
167struct RemoveComponentCommand<C: Component> {
168  id: EntityId,
169  phantom: PhantomData<C>,
170}
171
172impl<C: Component> Command for RemoveComponentCommand<C> {
173  fn execute(&mut self, storage: &mut Storage, tick: Tick) {
174    #[cfg(feature = "debug")]
175    trace!(
176      "Executing Remove Component Command for Entity {} with Component {:?}",
177      self.id,
178      C::sid()
179    );
180
181    storage.remove_comp::<C>(self.id, tick);
182  }
183}
184
185struct CustomFnCommand<F>
186where
187  F: Fn(&mut Storage, Tick),
188{
189  func: F,
190}
191
192impl<F> Command for CustomFnCommand<F>
193where
194  F: Fn(&mut Storage, Tick),
195{
196  fn execute(&mut self, storage: &mut Storage, tick: Tick) {
197    (self.func)(storage, tick)
198  }
199}
200
201#[cfg(test)]
202mod test {
203  use super::Commands;
204  use crate::{
205    self as gravitron_ecs,
206    world::{UnsafeWorldCell, World},
207    Id,
208  };
209  use gravitron_ecs_macros::Component;
210
211  #[derive(Component)]
212  struct A {}
213
214  #[test]
215  fn create_entity() {
216    let mut world = World::default();
217    let mut commands = Commands::create(UnsafeWorldCell::new(&mut world));
218
219    commands.create_entity(A {});
220  }
221
222  #[test]
223  fn remove_entity() {
224    let mut world = World::default();
225    let mut commands = Commands::create(UnsafeWorldCell::new(&mut world));
226
227    commands.remove_entity(Id(0));
228  }
229
230  #[test]
231  fn add_comp() {
232    let mut world = World::default();
233    let mut commands = Commands::create(UnsafeWorldCell::new(&mut world));
234
235    commands.add_comp(Id(0), A {});
236  }
237
238  #[test]
239  fn remove_comp() {
240    let mut world = World::default();
241    let mut commands = Commands::create(UnsafeWorldCell::new(&mut world));
242
243    commands.remove_comp::<A>(Id(0));
244  }
245}