Allow despawning of hierarchies in threadlocal systems (#908)

* Rename test components for easier understanding of failures

* Make recursive despawn public

This way, threadlocal systems can despawn hierarchies.

* Swap children before despawning
This commit is contained in:
SvenTS 2020-11-26 02:13:11 +01:00 committed by GitHub
parent dd1b08ef8b
commit 69603904ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -7,7 +7,7 @@ pub struct DespawnRecursive {
entity: Entity,
}
fn despawn_with_children_recursive(world: &mut World, entity: Entity) {
pub fn despawn_with_children_recursive(world: &mut World, entity: Entity) {
// first, make the entity's own parent forget about it
if let Ok(parent) = world.get::<Parent>(entity).map(|parent| parent.0) {
if let Ok(mut children) = world.get_mut::<Children>(parent) {
@ -21,12 +21,8 @@ fn despawn_with_children_recursive(world: &mut World, entity: Entity) {
// Should only be called by `despawn_with_children_recursive`!
fn despawn_with_children_recursive_inner(world: &mut World, entity: Entity) {
if let Some(children) = world
.get::<Children>(entity)
.ok()
.map(|children| children.0.iter().cloned().collect::<Vec<Entity>>())
{
for e in children {
if let Ok(mut children) = world.get_mut::<Children>(entity) {
for e in std::mem::take(&mut children.0) {
despawn_with_children_recursive(world, e);
}
}
@ -67,28 +63,32 @@ mod tests {
let mut command_buffer = Commands::default();
command_buffer.set_entity_reserver(world.get_entity_reserver());
command_buffer.spawn((0u32, 0u64)).with_children(|parent| {
parent.spawn((0u32, 0u64));
});
command_buffer
.spawn(("Another parent".to_owned(), 0u32))
.with_children(|parent| {
parent.spawn(("Another child".to_owned(), 1u32));
});
// Create a grandparent entity which will _not_ be deleted
command_buffer.spawn((1u32, 1u64));
command_buffer.spawn(("Grandparent".to_owned(), 2u32));
let grandparent_entity = command_buffer.current_entity().unwrap();
command_buffer.with_children(|parent| {
// Add a child to the grandparent (the "parent"), which will get deleted
parent.spawn((2u32, 2u64));
parent.spawn(("Parent, to be deleted".to_owned(), 3u32));
// All descendents of the "parent" should also be deleted.
parent.with_children(|parent| {
parent.spawn((3u32, 3u64)).with_children(|parent| {
// child
parent.spawn((4u32, 4u64));
});
parent.spawn((5u32, 5u64));
parent
.spawn(("First Child, to be deleted".to_owned(), 4u32))
.with_children(|parent| {
// child
parent.spawn(("First grand child, to be deleted".to_owned(), 5u32));
});
parent.spawn(("Second child, to be deleted".to_owned(), 6u32));
});
});
command_buffer.spawn((0u32, 0u64));
command_buffer.spawn(("An innocent bystander".to_owned(), 7u32));
command_buffer.apply(&mut world, &mut resources);
let parent_entity = world.get::<Children>(grandparent_entity).unwrap()[0];
@ -97,10 +97,11 @@ mod tests {
command_buffer.despawn_recursive(parent_entity); // despawning the same entity twice should not panic
command_buffer.apply(&mut world, &mut resources);
let results = world
.query::<(&u32, &u64)>()
.map(|(a, b)| (*a, *b))
let mut results = world
.query::<(&String, &u32)>()
.map(|(a, b)| (a.clone(), *b))
.collect::<Vec<_>>();
results.sort_unstable_by_key(|(_, index)| *index);
{
let children = world.get::<Children>(grandparent_entity).unwrap();
@ -111,11 +112,14 @@ mod tests {
);
}
// parent_entity and its children should be deleted,
// the grandparent tuple (1, 1) and (0, 0) tuples remaining.
assert_eq!(
results,
vec![(0u32, 0u64), (0u32, 0u64), (0u32, 0u64), (1u32, 1u64)]
vec![
("Another parent".to_owned(), 0u32),
("Another child".to_owned(), 1u32),
("Grandparent".to_owned(), 2u32),
("An innocent bystander".to_owned(), 7u32)
]
);
}
}