bevy_hierarchy/
hierarchy.rs1use crate::components::{Children, Parent};
2use bevy_ecs::{
3 entity::Entity,
4 system::EntityCommands,
5 world::{Command, EntityWorldMut, World},
6};
7use bevy_utils::tracing::debug;
8
9#[derive(Debug)]
11pub struct DespawnRecursive {
12 pub entity: Entity,
14}
15
16#[derive(Debug)]
18pub struct DespawnChildrenRecursive {
19 pub entity: Entity,
21}
22
23pub fn despawn_with_children_recursive(world: &mut World, entity: Entity) {
25 if let Some(parent) = world.get::<Parent>(entity).map(|parent| parent.0) {
27 if let Some(mut children) = world.get_mut::<Children>(parent) {
28 children.0.retain(|c| *c != entity);
29 }
30 }
31
32 despawn_with_children_recursive_inner(world, entity);
34}
35
36fn despawn_with_children_recursive_inner(world: &mut World, entity: Entity) {
38 if let Some(mut children) = world.get_mut::<Children>(entity) {
39 for e in std::mem::take(&mut children.0) {
40 despawn_with_children_recursive_inner(world, e);
41 }
42 }
43
44 if !world.despawn(entity) {
45 debug!("Failed to despawn entity {:?}", entity);
46 }
47}
48
49fn despawn_children_recursive(world: &mut World, entity: Entity) {
50 if let Some(children) = world.entity_mut(entity).take::<Children>() {
51 for e in children.0 {
52 despawn_with_children_recursive_inner(world, e);
53 }
54 }
55}
56
57impl Command for DespawnRecursive {
58 fn apply(self, world: &mut World) {
59 #[cfg(feature = "trace")]
60 let _span = bevy_utils::tracing::info_span!(
61 "command",
62 name = "DespawnRecursive",
63 entity = bevy_utils::tracing::field::debug(self.entity)
64 )
65 .entered();
66 despawn_with_children_recursive(world, self.entity);
67 }
68}
69
70impl Command for DespawnChildrenRecursive {
71 fn apply(self, world: &mut World) {
72 #[cfg(feature = "trace")]
73 let _span = bevy_utils::tracing::info_span!(
74 "command",
75 name = "DespawnChildrenRecursive",
76 entity = bevy_utils::tracing::field::debug(self.entity)
77 )
78 .entered();
79 despawn_children_recursive(world, self.entity);
80 }
81}
82
83pub trait DespawnRecursiveExt {
85 fn despawn_recursive(self);
87
88 fn despawn_descendants(&mut self) -> &mut Self;
90}
91
92impl DespawnRecursiveExt for EntityCommands<'_> {
93 fn despawn_recursive(mut self) {
96 let entity = self.id();
97 self.commands().add(DespawnRecursive { entity });
98 }
99
100 fn despawn_descendants(&mut self) -> &mut Self {
101 let entity = self.id();
102 self.commands().add(DespawnChildrenRecursive { entity });
103 self
104 }
105}
106
107impl<'w> DespawnRecursiveExt for EntityWorldMut<'w> {
108 fn despawn_recursive(self) {
111 let entity = self.id();
112
113 #[cfg(feature = "trace")]
114 let _span = bevy_utils::tracing::info_span!(
115 "despawn_recursive",
116 entity = bevy_utils::tracing::field::debug(entity)
117 )
118 .entered();
119
120 despawn_with_children_recursive(self.into_world_mut(), entity);
121 }
122
123 fn despawn_descendants(&mut self) -> &mut Self {
124 let entity = self.id();
125
126 #[cfg(feature = "trace")]
127 let _span = bevy_utils::tracing::info_span!(
128 "despawn_descendants",
129 entity = bevy_utils::tracing::field::debug(entity)
130 )
131 .entered();
132
133 self.world_scope(|world| {
134 despawn_children_recursive(world, entity);
135 });
136 self
137 }
138}
139
140#[cfg(test)]
141mod tests {
142 use bevy_ecs::{
143 component::Component,
144 system::Commands,
145 world::{CommandQueue, World},
146 };
147
148 use super::DespawnRecursiveExt;
149 use crate::{child_builder::BuildChildren, components::Children};
150
151 #[derive(Component, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Debug)]
152 struct Idx(u32);
153
154 #[derive(Component, Clone, PartialEq, Eq, Ord, PartialOrd, Debug)]
155 struct N(String);
156
157 #[test]
158 fn despawn_recursive() {
159 let mut world = World::default();
160 let mut queue = CommandQueue::default();
161 let grandparent_entity;
162 {
163 let mut commands = Commands::new(&mut queue, &world);
164
165 commands
166 .spawn((N("Another parent".to_owned()), Idx(0)))
167 .with_children(|parent| {
168 parent.spawn((N("Another child".to_owned()), Idx(1)));
169 });
170
171 grandparent_entity = commands.spawn((N("Grandparent".to_owned()), Idx(2))).id();
173 commands.entity(grandparent_entity).with_children(|parent| {
174 parent
176 .spawn((N("Parent, to be deleted".to_owned()), Idx(3)))
177 .with_children(|parent| {
179 parent
180 .spawn((N("First Child, to be deleted".to_owned()), Idx(4)))
181 .with_children(|parent| {
182 parent.spawn((
184 N("First grand child, to be deleted".to_owned()),
185 Idx(5),
186 ));
187 });
188 parent.spawn((N("Second child, to be deleted".to_owned()), Idx(6)));
189 });
190 });
191
192 commands.spawn((N("An innocent bystander".to_owned()), Idx(7)));
193 }
194 queue.apply(&mut world);
195
196 let parent_entity = world.get::<Children>(grandparent_entity).unwrap()[0];
197
198 {
199 let mut commands = Commands::new(&mut queue, &world);
200 commands.entity(parent_entity).despawn_recursive();
201 commands.entity(parent_entity).despawn_recursive();
203 }
204 queue.apply(&mut world);
205
206 let mut results = world
207 .query::<(&N, &Idx)>()
208 .iter(&world)
209 .map(|(a, b)| (a.clone(), *b))
210 .collect::<Vec<_>>();
211 results.sort_unstable_by_key(|(_, index)| *index);
212
213 {
214 let children = world.get::<Children>(grandparent_entity).unwrap();
215 assert!(
216 !children.iter().any(|&i| i == parent_entity),
217 "grandparent should no longer know about its child which has been removed"
218 );
219 }
220
221 assert_eq!(
222 results,
223 vec![
224 (N("Another parent".to_owned()), Idx(0)),
225 (N("Another child".to_owned()), Idx(1)),
226 (N("Grandparent".to_owned()), Idx(2)),
227 (N("An innocent bystander".to_owned()), Idx(7))
228 ]
229 );
230 }
231
232 #[test]
233 fn despawn_descendants() {
234 let mut world = World::default();
235 let mut queue = CommandQueue::default();
236 let mut commands = Commands::new(&mut queue, &world);
237
238 let parent = commands.spawn_empty().id();
239 let child = commands.spawn_empty().id();
240
241 commands
242 .entity(parent)
243 .add_child(child)
244 .despawn_descendants();
245
246 queue.apply(&mut world);
247
248 assert!(world.entity(parent).get::<Children>().is_none());
250 assert!(world.get_entity(child).is_none());
252 }
253
254 #[test]
255 fn spawn_children_after_despawn_descendants() {
256 let mut world = World::default();
257 let mut queue = CommandQueue::default();
258 let mut commands = Commands::new(&mut queue, &world);
259
260 let parent = commands.spawn_empty().id();
261 let child = commands.spawn_empty().id();
262
263 commands
264 .entity(parent)
265 .add_child(child)
266 .despawn_descendants()
267 .with_children(|parent| {
268 parent.spawn_empty();
269 parent.spawn_empty();
270 });
271
272 queue.apply(&mut world);
273
274 let children = world.entity(parent).get::<Children>();
276 assert!(children.is_some());
277 assert_eq!(children.unwrap().len(), 2_usize);
278 assert!(world.get_entity(child).is_none());
280 }
281}