1use crate::component::Component;
2use crate::entity::Entity;
3use crate::system::{Res, SystemParam};
4use crate::world::World;
5use std::sync::Arc;
6
7use crossbeam_queue::SegQueue;
8
9type BoxedCommand = Box<dyn FnOnce(&mut World) + Send + Sync>;
10
11#[derive(Default, Clone)]
14pub struct CommandQueue {
15 queue: Arc<SegQueue<BoxedCommand>>,
16}
17
18impl CommandQueue {
19 pub fn new() -> Self {
20 Self::default()
21 }
22
23 pub fn push<F>(&self, command: F)
24 where
25 F: FnOnce(&mut World) + Send + Sync + 'static,
26 {
27 self.queue.push(Box::new(command));
28 }
29
30 pub fn is_empty(&self) -> bool {
31 self.queue.is_empty()
32 }
33
34 pub fn apply(&self, world: &mut World) {
35 while let Some(command) = self.queue.pop() {
36 command(world);
37 }
38 }
39}
40
41pub struct Commands<'w> {
43 pub queue: Res<'w, CommandQueue>,
44 pub entities: Res<'w, crate::entity::allocator::Entities>,
45}
46
47impl SystemParam for Commands<'static> {
48 type Item<'w> = Commands<'w>;
49
50 fn fetch<'w>(
51 world: &'w World,
52 dt: f32,
53 ) -> Result<Self::Item<'w>, crate::system::SystemParamFetchError> {
54 let queue = <Res<'static, CommandQueue> as SystemParam>::fetch(world, dt)?;
55 let entities =
56 <Res<'static, crate::entity::allocator::Entities> as SystemParam>::fetch(world, dt)?;
57 Ok(Commands { queue, entities })
58 }
59
60 fn get_access_info(info: &mut crate::system::AccessInfo) {
61 <Res<'static, CommandQueue> as SystemParam>::get_access_info(info);
62 <Res<'static, crate::entity::allocator::Entities> as SystemParam>::get_access_info(info);
63 }
64}
65
66impl<'w> Commands<'w> {
67 pub fn spawn(&mut self) -> EntityCommands<'_, 'w> {
69 let entity = self.entities.reserve_entity();
70
71 self.queue.push(move |world| {
72 world.flush_spawn(entity);
73 });
74
75 EntityCommands {
76 entity,
77 commands: self,
78 }
79 }
80
81 pub fn entity(&mut self, entity: Entity) -> EntityCommands<'_, 'w> {
83 EntityCommands {
84 entity,
85 commands: self,
86 }
87 }
88}
89
90pub struct EntityCommands<'a, 'w> {
91 entity: Entity,
92 commands: &'a mut Commands<'w>,
93}
94
95impl<'a, 'w> EntityCommands<'a, 'w> {
96 pub fn id(&self) -> Entity {
98 self.entity
99 }
100
101 pub fn insert<T: Component>(&mut self, component: T) -> &mut Self {
103 let e = self.entity;
104 self.commands.queue.push(move |world| {
105 world.add_component(e, component);
106 });
107 self
108 }
109
110 pub fn remove<T: Component>(&mut self) -> &mut Self {
112 let e = self.entity;
113 self.commands.queue.push(move |world| {
114 world.remove_component::<T>(e);
115 });
116 self
117 }
118
119 pub fn despawn(&mut self) {
121 let e = self.entity;
122 self.commands.queue.push(move |world| {
123 world.despawn(e);
124 });
125 }
126
127 pub fn despawn_recursive(&mut self) {
129 use crate::hierarchy::HierarchyExt;
130 let e = self.entity;
131 self.commands.queue.push(move |world| {
132 world.despawn_recursive(e);
133 });
134 }
135
136 pub fn add_child(&mut self, child: Entity) -> &mut Self {
138 use crate::hierarchy::HierarchyExt;
139 let p = self.entity;
140 self.commands.queue.push(move |world| {
141 world.add_child(p, child);
142 });
143 self
144 }
145
146 pub fn remove_child(&mut self, child: Entity) -> &mut Self {
148 use crate::hierarchy::HierarchyExt;
149 let p = self.entity;
150 self.commands.queue.push(move |world| {
151 world.remove_child(p, child);
152 });
153 self
154 }
155}
156
157#[cfg(test)]
158mod tests {
159 use super::*;
160 use crate::system::Schedule;
161
162 use crate::world::World;
163
164 #[derive(Clone, PartialEq, Debug)]
165 struct ComponentA(i32);
166 impl Component for ComponentA {}
167
168 #[derive(Clone, PartialEq, Debug)]
169 struct ComponentB(f32);
170 impl Component for ComponentB {}
171
172 #[test]
173 fn test_command_queue_push_and_apply() {
174 let mut world = World::new();
175 let queue = CommandQueue::new();
176
177 queue.push(|w| {
178 let e = w.spawn();
179 w.add_component(e, ComponentA(42));
180 });
181
182 assert_eq!(world.entity_count(), 0);
184
185 queue.apply(&mut world);
186
187 assert_eq!(world.entity_count(), 1);
189
190 let mut count = 0;
191 if let Some(q) = world.query::<&ComponentA>() {
192 for (_, c) in q.iter() {
193 assert_eq!(c.0, 42);
194 count += 1;
195 }
196 }
197 assert_eq!(count, 1);
198 }
199
200 #[test]
201 fn test_commands_system_spawn_and_insert() {
202 let mut world = World::new();
203 let mut schedule = Schedule::new();
204
205 schedule.add_di_system::<(Commands<'static>,), _>(|mut commands: Commands| {
206 commands
207 .spawn()
208 .insert(ComponentA(100))
209 .insert(ComponentB(3.14));
210 });
211
212 schedule.run(&mut world, 0.1);
213
214 let mut count = 0;
215 if let Some(q) = world.query::<(&ComponentA, &ComponentB)>() {
216 for (_, (ca, cb)) in q.iter() {
217 assert_eq!(ca.0, 100);
218 assert_eq!(cb.0, 3.14);
219 count += 1;
220 }
221 }
222 assert_eq!(count, 1);
223 }
224
225 #[test]
226 fn test_commands_system_despawn() {
227 let mut world = World::new();
228
229 let e1 = world.spawn();
230 world.add_component(e1, ComponentA(10));
231
232 let e2 = world.spawn();
233 world.add_component(e2, ComponentA(20));
234
235 let mut schedule = Schedule::new();
236
237 schedule.add_system(|world: &World, dt: f32| {
239 let mut commands = Commands::fetch(world, dt).unwrap();
240 if let Some(q) = world.query::<&ComponentA>() {
241 for (id, c) in q.iter() {
242 if c.0 == 10 {
243 commands.entity(Entity::new(id, 0)).despawn();
244 }
245 }
246 }
247 });
248
249 schedule.run(&mut world, 0.1);
250
251 assert_eq!(world.entity_count(), 1);
252 if let Some(q) = world.query::<&ComponentA>() {
253 for (_, c) in q.iter() {
254 assert_eq!(c.0, 20);
255 }
256 }
257 }
258
259 #[test]
260 fn test_commands_system_remove_component() {
261 let mut world = World::new();
262
263 let e = world.spawn();
264 world.add_component(e, ComponentA(1));
265 world.add_component(e, ComponentB(2.0));
266
267 let mut schedule = Schedule::new();
268
269 schedule.add_system(|world: &World, dt: f32| {
270 let mut commands = Commands::fetch(world, dt).unwrap();
271 if let Some(q) = world.query::<&ComponentA>() {
272 for (id, _) in q.iter() {
273 commands.entity(Entity::new(id, 0)).remove::<ComponentA>();
274 }
275 }
276 });
277
278 schedule.run(&mut world, 0.1);
279
280 assert_eq!(world.entity_count(), 1);
281
282 let mut has_a = false;
283 if let Some(q) = world.query::<&ComponentA>() {
284 has_a = q.iter().count() > 0;
285 }
286 assert!(!has_a, "ComponentA still exists!");
287
288 let mut has_b = false;
289 if let Some(q) = world.query::<&ComponentB>() {
290 has_b = q.iter().count() > 0;
291 }
292 assert!(has_b, "ComponentB was unexpectedly removed!");
293 }
294}