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 crate::system::sealed::Sealed for Commands<'static> {}
48impl SystemParam for Commands<'static> {
49 type Item<'w> = Commands<'w>;
50
51 fn fetch<'w>(
52 world: &'w World,
53 dt: f32,
54 ) -> Result<Self::Item<'w>, crate::system::SystemParamFetchError> {
55 let queue = <Res<'static, CommandQueue> as SystemParam>::fetch(world, dt)?;
56 let entities =
57 <Res<'static, crate::entity::allocator::Entities> as SystemParam>::fetch(world, dt)?;
58 Ok(Commands { queue, entities })
59 }
60
61 fn get_access_info(info: &mut crate::system::AccessInfo) {
62 <Res<'static, CommandQueue> as SystemParam>::get_access_info(info);
63 <Res<'static, crate::entity::allocator::Entities> as SystemParam>::get_access_info(info);
64 }
65}
66
67impl<'w> Commands<'w> {
68 pub fn spawn(&mut self) -> EntityCommands<'_, 'w> {
70 let entity = self.entities.reserve_entity();
71
72 self.queue.push(move |world| {
73 world.flush_spawn(entity);
74 });
75
76 EntityCommands {
77 entity,
78 commands: self,
79 }
80 }
81
82 pub fn entity(&mut self, entity: Entity) -> EntityCommands<'_, 'w> {
84 EntityCommands {
85 entity,
86 commands: self,
87 }
88 }
89}
90
91pub struct EntityCommands<'a, 'w> {
92 entity: Entity,
93 commands: &'a mut Commands<'w>,
94}
95
96impl<'a, 'w> EntityCommands<'a, 'w> {
97 pub fn id(&self) -> Entity {
99 self.entity
100 }
101
102 pub fn insert<T: Component>(&mut self, component: T) -> &mut Self {
104 let e = self.entity;
105 self.commands.queue.push(move |world| {
106 world.add_component(e, component);
107 });
108 self
109 }
110
111 pub fn remove<T: Component>(&mut self) -> &mut Self {
113 let e = self.entity;
114 self.commands.queue.push(move |world| {
115 world.remove_component::<T>(e);
116 });
117 self
118 }
119
120 pub fn despawn(&mut self) {
122 let e = self.entity;
123 self.commands.queue.push(move |world| {
124 world.despawn(e);
125 });
126 }
127
128 pub fn despawn_recursive(&mut self) {
130 use crate::hierarchy::HierarchyExt;
131 let e = self.entity;
132 self.commands.queue.push(move |world| {
133 world.despawn_recursive(e);
134 });
135 }
136
137 pub fn add_child(&mut self, child: Entity) -> &mut Self {
139 use crate::hierarchy::HierarchyExt;
140 let p = self.entity;
141 self.commands.queue.push(move |world| {
142 world.add_child(p, child);
143 });
144 self
145 }
146
147 pub fn remove_child(&mut self, child: Entity) -> &mut Self {
149 use crate::hierarchy::HierarchyExt;
150 let p = self.entity;
151 self.commands.queue.push(move |world| {
152 world.remove_child(p, child);
153 });
154 self
155 }
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161 use crate::system::Schedule;
162
163 use crate::world::World;
164
165 #[derive(Clone, PartialEq, Debug)]
166 struct ComponentA(i32);
167 impl Component for ComponentA {}
168
169 #[derive(Clone, PartialEq, Debug)]
170 struct ComponentB(f32);
171 impl Component for ComponentB {}
172
173 #[test]
174 fn test_command_queue_push_and_apply() {
175 let mut world = World::new();
176 let queue = CommandQueue::new();
177
178 queue.push(|w| {
179 let e = w.spawn();
180 w.add_component(e, ComponentA(42));
181 });
182
183 assert_eq!(world.entity_count(), 0);
185
186 queue.apply(&mut world);
187
188 assert_eq!(world.entity_count(), 1);
190
191 let mut count = 0;
192 if let Some(q) = world.query::<&ComponentA>() {
193 for (_, c) in q.iter() {
194 assert_eq!(c.0, 42);
195 count += 1;
196 }
197 }
198 assert_eq!(count, 1);
199 }
200
201 #[test]
202 fn test_commands_system_spawn_and_insert() {
203 let mut world = World::new();
204 let mut schedule = Schedule::new();
205
206 schedule.add_di_system::<(Commands<'static>,), _>(|mut commands: Commands| {
207 commands
208 .spawn()
209 .insert(ComponentA(100))
210 .insert(ComponentB(2.5));
211 });
212
213 schedule.run(&mut world, 0.1);
214
215 let mut count = 0;
216 if let Some(q) = world.query::<(&ComponentA, &ComponentB)>() {
217 for (_, (ca, cb)) in q.iter() {
218 assert_eq!(ca.0, 100);
219 assert_eq!(cb.0, 2.5);
220 count += 1;
221 }
222 }
223 assert_eq!(count, 1);
224 }
225
226 #[test]
227 fn test_commands_system_despawn() {
228 let mut world = World::new();
229
230 let e1 = world.spawn();
231 world.add_component(e1, ComponentA(10));
232
233 let e2 = world.spawn();
234 world.add_component(e2, ComponentA(20));
235
236 let mut schedule = Schedule::new();
237
238 schedule.add_system(|world: &World, dt: f32| {
240 let mut commands = Commands::fetch(world, dt).unwrap();
241 if let Some(q) = world.query::<&ComponentA>() {
242 for (id, c) in q.iter() {
243 if c.0 == 10 {
244 commands.entity(Entity::new(id, 0)).despawn();
245 }
246 }
247 }
248 });
249
250 schedule.run(&mut world, 0.1);
251
252 assert_eq!(world.entity_count(), 1);
253 if let Some(q) = world.query::<&ComponentA>() {
254 for (_, c) in q.iter() {
255 assert_eq!(c.0, 20);
256 }
257 }
258 }
259
260 #[test]
261 fn test_commands_system_remove_component() {
262 let mut world = World::new();
263
264 let e = world.spawn();
265 world.add_component(e, ComponentA(1));
266 world.add_component(e, ComponentB(2.0));
267
268 let mut schedule = Schedule::new();
269
270 schedule.add_system(|world: &World, dt: f32| {
271 let mut commands = Commands::fetch(world, dt).unwrap();
272 if let Some(q) = world.query::<&ComponentA>() {
273 for (id, _) in q.iter() {
274 commands.entity(Entity::new(id, 0)).remove::<ComponentA>();
275 }
276 }
277 });
278
279 schedule.run(&mut world, 0.1);
280
281 assert_eq!(world.entity_count(), 1);
282
283 let mut has_a = false;
284 if let Some(q) = world.query::<&ComponentA>() {
285 has_a = q.iter().count() > 0;
286 }
287 assert!(!has_a, "ComponentA still exists!");
288
289 let mut has_b = false;
290 if let Some(q) = world.query::<&ComponentB>() {
291 has_b = q.iter().count() > 0;
292 }
293 assert!(has_b, "ComponentB was unexpectedly removed!");
294 }
295}