gravitron_ecs/
commands.rs1use 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}