diff --git a/crates/bevy_hierarchy/src/child_builder.rs b/crates/bevy_hierarchy/src/child_builder.rs index 54d65646cf357..f4425d60df83f 100644 --- a/crates/bevy_hierarchy/src/child_builder.rs +++ b/crates/bevy_hierarchy/src/child_builder.rs @@ -9,6 +9,69 @@ use bevy_ecs::{ use crate::prelude::{Children, Parent, PreviousParent}; +fn push_child_unchecked(world: &mut World, parent: Entity, child: Entity) { + let mut parent = world.entity_mut(parent); + if let Some(mut children) = parent.get_mut::() { + children.0.push(child); + } else { + parent.insert(Children(smallvec::smallvec![child])); + } +} + +fn update_parent(world: &mut World, child: Entity, new_parent: Entity) -> Option { + let mut child = world.entity_mut(child); + if let Some(mut parent) = child.get_mut::() { + let previous = parent.0; + *parent = Parent(new_parent); + child.insert(PreviousParent(new_parent)); + Some(previous) + } else { + child.insert_bundle((Parent(new_parent), PreviousParent(new_parent))); + None + } +} + +fn remove_from_children(world: &mut World, parent: Entity, child: Entity) { + let mut parent = world.entity_mut(parent); + if let Some(mut children) = parent.get_mut::() { + if let Some(idx) = children.iter().position(|x| *x == child) { + children.0.remove(idx); + if children.is_empty() { + parent.remove::(); + } + } + } +} + +fn update_old_parents(world: &mut World, parent: Entity, children: &[Entity]) { + for child in children { + if let Some(previous) = update_parent(world, *child, parent) { + remove_from_children(world, previous, *child); + } + } +} + +fn remove_children(parent: Entity, children: &[Entity], world: &mut World) { + for child in children.iter() { + let mut child = world.entity_mut(*child); + if let Some(child_parent) = child.get::() { + if child_parent.0 == parent { + child.remove_bundle::<(Parent, PreviousParent)>(); + } + } + } + + let mut parent = world.entity_mut(parent); + if let Some(mut parent_children) = parent.get_mut::() { + parent_children + .0 + .retain(|parent_child| !children.contains(parent_child)); + if children.is_empty() { + parent.remove::(); + } + } +} + /// Command that adds a child to an entity #[derive(Debug)] pub struct AddChild { @@ -20,16 +83,22 @@ pub struct AddChild { impl Command for AddChild { fn write(self, world: &mut World) { - world - .entity_mut(self.child) - // FIXME: don't erase the previous parent (see #1545) - .insert_bundle((Parent(self.parent), PreviousParent(self.parent))); - if let Some(mut children) = world.get_mut::(self.parent) { - children.0.push(self.child); + let previous = update_parent(world, self.child, self.parent); + if let Some(previous) = previous { + if previous == self.parent { + return; + } + + remove_from_children(world, previous, self.child); + } + + let mut parent = world.entity_mut(self.parent); + if let Some(mut children) = parent.get_mut::() { + if !children.contains(&self.child) { + children.0.push(self.child); + } } else { - world - .entity_mut(self.parent) - .insert(Children(smallvec::smallvec![self.child])); + parent.insert(Children(smallvec::smallvec![self.child])); } } } @@ -44,20 +113,13 @@ pub struct InsertChildren { impl Command for InsertChildren { fn write(self, world: &mut World) { - for child in self.children.iter() { - world - .entity_mut(*child) - // FIXME: don't erase the previous parent (see #1545) - .insert_bundle((Parent(self.parent), PreviousParent(self.parent))); - } - { - if let Some(mut children) = world.get_mut::(self.parent) { - children.0.insert_from_slice(self.index, &self.children); - } else { - world - .entity_mut(self.parent) - .insert(Children(self.children)); - } + update_old_parents(world, self.parent, &self.children); + let mut parent = world.entity_mut(self.parent); + if let Some(mut children) = parent.get_mut::() { + children.0.retain(|value| !self.children.contains(value)); + children.0.insert_from_slice(self.index, &self.children); + } else { + parent.insert(Children(self.children)); } } } @@ -71,26 +133,13 @@ pub struct PushChildren { impl Command for PushChildren { fn write(self, world: &mut World) { - for child in self.children.iter() { - world - .entity_mut(*child) - // FIXME: don't erase the previous parent (see #1545) - .insert_bundle((Parent(self.parent), PreviousParent(self.parent))); - } - { - let mut added = false; - if let Some(mut children) = world.get_mut::(self.parent) { - children.0.extend(self.children.iter().cloned()); - added = true; - } - - // NOTE: ideally this is just an else statement, but currently that _incorrectly_ fails - // borrow-checking - if !added { - world - .entity_mut(self.parent) - .insert(Children(self.children)); - } + update_old_parents(world, self.parent, &self.children); + let mut parent = world.entity_mut(self.parent); + if let Some(mut children) = parent.get_mut::() { + children.0.retain(|child| !self.children.contains(child)); + children.0.extend(self.children); + } else { + parent.insert(Children(self.children)); } } } @@ -101,32 +150,8 @@ pub struct RemoveChildren { children: SmallVec<[Entity; 8]>, } -fn remove_children(parent: Entity, children: &[Entity], world: &mut World) { - for child in children.iter() { - let mut child = world.entity_mut(*child); - let mut remove_parent = false; - if let Some(child_parent) = child.get_mut::() { - if child_parent.0 == parent { - remove_parent = true; - } - } - if remove_parent { - if let Some(parent) = child.remove::() { - child.insert(PreviousParent(parent.0)); - } - } - } - // Remove the children from the parents. - if let Some(mut parent_children) = world.get_mut::(parent) { - parent_children - .0 - .retain(|parent_child| !children.contains(parent_child)); - } -} - impl Command for RemoveChildren { fn write(self, world: &mut World) { - // Remove any matching Parent components from the children remove_children(self.parent, &self.children, world); } } @@ -288,13 +313,7 @@ impl<'w> WorldChildBuilder<'w> { .insert_bundle((Parent(parent_entity), PreviousParent(parent_entity))) .id(); self.current_entity = Some(entity); - if let Some(mut parent) = self.world.get_entity_mut(parent_entity) { - if let Some(mut children) = parent.get_mut::() { - children.0.push(entity); - } else { - parent.insert(Children(smallvec::smallvec![entity])); - } - } + push_child_unchecked(self.world, parent_entity, entity); self.world.entity_mut(entity) } @@ -307,13 +326,7 @@ impl<'w> WorldChildBuilder<'w> { .insert_bundle((Parent(parent_entity), PreviousParent(parent_entity))) .id(); self.current_entity = Some(entity); - if let Some(mut parent) = self.world.get_entity_mut(parent_entity) { - if let Some(mut children) = parent.get_mut::() { - children.0.push(entity); - } else { - parent.insert(Children(smallvec::smallvec![entity])); - } - } + push_child_unchecked(self.world, parent_entity, entity); self.world.entity_mut(entity) } @@ -361,16 +374,14 @@ impl<'w> BuildWorldChildren for EntityMut<'w> { { // SAFE: parent entity is not modified and its location is updated manually let world = unsafe { self.world_mut() }; - for child in children.iter() { - world - .entity_mut(*child) - // FIXME: don't erase the previous parent (see #1545) - .insert_bundle((Parent(parent), PreviousParent(parent))); - } + update_old_parents(world, parent, children); // Inserting a bundle in the children entities may change the parent entity's location if they were of the same archetype self.update_location(); } if let Some(mut children_component) = self.get_mut::() { + children_component + .0 + .retain(|value| !children.contains(value)); children_component.0.extend(children.iter().cloned()); } else { self.insert(Children::with(children)); @@ -383,17 +394,15 @@ impl<'w> BuildWorldChildren for EntityMut<'w> { { // SAFE: parent entity is not modified and its location is updated manually let world = unsafe { self.world_mut() }; - for child in children.iter() { - world - .entity_mut(*child) - // FIXME: don't erase the previous parent (see #1545) - .insert_bundle((Parent(parent), PreviousParent(parent))); - } + update_old_parents(world, parent, children); // Inserting a bundle in the children entities may change the parent entity's location if they were of the same archetype self.update_location(); } if let Some(mut children_component) = self.get_mut::() { + children_component + .0 + .retain(|value| !children.contains(value)); children_component.0.insert_from_slice(index, children); } else { self.insert(Children::with(children)); @@ -405,26 +414,7 @@ impl<'w> BuildWorldChildren for EntityMut<'w> { let parent = self.id(); // SAFE: This doesn't change the parent's location let world = unsafe { self.world_mut() }; - for child in children.iter() { - let mut child = world.entity_mut(*child); - let mut remove_parent = false; - if let Some(child_parent) = child.get_mut::() { - if child_parent.0 == parent { - remove_parent = true; - } - } - if remove_parent { - if let Some(parent) = child.remove::() { - child.insert(PreviousParent(parent.0)); - } - } - } - // Remove the children from the parents. - if let Some(mut parent_children) = world.get_mut::(parent) { - parent_children - .0 - .retain(|parent_child| !children.contains(parent_child)); - } + remove_children(parent, children, world); self } } @@ -450,13 +440,11 @@ impl<'w> BuildWorldChildren for WorldChildBuilder<'w> { let parent = self .current_entity .expect("Cannot add children without a parent. Try creating an entity first."); - for child in children.iter() { - self.world - .entity_mut(*child) - // FIXME: don't erase the previous parent (see #1545) - .insert_bundle((Parent(parent), PreviousParent(parent))); - } + update_old_parents(self.world, parent, children); if let Some(mut children_component) = self.world.get_mut::(parent) { + children_component + .0 + .retain(|value| !children.contains(value)); children_component.0.extend(children.iter().cloned()); } else { self.world @@ -470,14 +458,11 @@ impl<'w> BuildWorldChildren for WorldChildBuilder<'w> { let parent = self .current_entity .expect("Cannot add children without a parent. Try creating an entity first."); - - for child in children.iter() { - self.world - .entity_mut(*child) - // FIXME: don't erase the previous parent (see #1545) - .insert_bundle((Parent(parent), PreviousParent(parent))); - } + update_old_parents(self.world, parent, children); if let Some(mut children_component) = self.world.get_mut::(parent) { + children_component + .0 + .retain(|value| !children.contains(value)); children_component.0.insert_from_slice(index, children); } else { self.world @@ -622,14 +607,8 @@ mod tests { ); assert!(world.get::(child1).is_none()); assert!(world.get::(child4).is_none()); - assert_eq!( - *world.get::(child1).unwrap(), - PreviousParent(parent) - ); - assert_eq!( - *world.get::(child4).unwrap(), - PreviousParent(parent) - ); + assert!(world.get::(child1).is_none()); + assert!(world.get::(child4).is_none()); } #[test] @@ -691,14 +670,8 @@ mod tests { ); assert!(world.get::(child1).is_none()); assert!(world.get::(child4).is_none()); - assert_eq!( - *world.get::(child1).unwrap(), - PreviousParent(parent) - ); - assert_eq!( - *world.get::(child4).unwrap(), - PreviousParent(parent) - ); + assert!(world.get::(child1).is_none()); + assert!(world.get::(child4).is_none()); } #[test]