diff --git a/crates/bevy_transform/src/hierarchy/child_builder.rs b/crates/bevy_transform/src/hierarchy/child_builder.rs index b2321e4af5bab..0a97c4a850382 100644 --- a/crates/bevy_transform/src/hierarchy/child_builder.rs +++ b/crates/bevy_transform/src/hierarchy/child_builder.rs @@ -19,6 +19,7 @@ impl Command for InsertChildren { 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))); } { @@ -55,6 +56,7 @@ impl Command for PushChildren { 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))); } { @@ -198,6 +200,8 @@ impl<'w> WorldChildBuilder<'w> { pub trait BuildWorldChildren { fn with_children(&mut self, spawn_children: impl FnOnce(&mut WorldChildBuilder)) -> &mut Self; + fn push_children(&mut self, children: &[Entity]) -> &mut Self; + fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self; } impl<'w> BuildWorldChildren for EntityMut<'w> { @@ -217,6 +221,47 @@ impl<'w> BuildWorldChildren for EntityMut<'w> { self.update_location(); self } + + fn push_children(&mut self, children: &[Entity]) -> &mut Self { + let parent = self.id(); + { + // SAFE: parent entity is not modified + 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))); + } + } + if let Some(mut children_component) = self.get_mut::() { + children_component.0.extend(children.iter().cloned()); + } else { + self.insert(Children::with(children)); + } + self + } + + fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self { + let parent = self.id(); + { + // SAFE: parent entity is not modified + 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))); + } + } + + if let Some(mut children_component) = self.get_mut::() { + children_component.0.insert_from_slice(index, children); + } else { + self.insert(Children::with(children)); + } + self + } } impl<'w> BuildWorldChildren for WorldChildBuilder<'w> { @@ -235,11 +280,52 @@ impl<'w> BuildWorldChildren for WorldChildBuilder<'w> { self.current_entity = self.parent_entities.pop(); self } + + fn push_children(&mut self, children: &[Entity]) -> &mut Self { + 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))); + } + if let Some(mut children_component) = self.world.get_mut::(parent) { + children_component.0.extend(children.iter().cloned()); + } else { + self.world + .entity_mut(parent) + .insert(Children::with(children)); + } + self + } + + fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self { + 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))); + } + if let Some(mut children_component) = self.world.get_mut::(parent) { + children_component.0.insert_from_slice(index, children); + } else { + self.world + .entity_mut(parent) + .insert(Children::with(children)); + } + self + } } #[cfg(test)] mod tests { - use super::BuildChildren; + use super::{BuildChildren, BuildWorldChildren}; use crate::prelude::{Children, Parent, PreviousParent}; use bevy_ecs::{ entity::Entity, @@ -281,7 +367,7 @@ mod tests { } #[test] - fn push_and_insert_children() { + fn push_and_insert_children_commands() { let mut world = World::default(); let entities = world @@ -340,4 +426,55 @@ mod tests { PreviousParent(parent) ); } + + #[test] + fn push_and_insert_children_world() { + let mut world = World::default(); + + let entities = world + .spawn_batch(vec![(1,), (2,), (3,), (4,), (5,)]) + .collect::>(); + + world.entity_mut(entities[0]).push_children(&entities[1..3]); + + let parent = entities[0]; + let child1 = entities[1]; + let child2 = entities[2]; + let child3 = entities[3]; + let child4 = entities[4]; + + let expected_children: SmallVec<[Entity; 8]> = smallvec![child1, child2]; + assert_eq!( + world.get::(parent).unwrap().0.clone(), + expected_children + ); + assert_eq!(*world.get::(child1).unwrap(), Parent(parent)); + assert_eq!(*world.get::(child2).unwrap(), Parent(parent)); + + assert_eq!( + *world.get::(child1).unwrap(), + PreviousParent(parent) + ); + assert_eq!( + *world.get::(child2).unwrap(), + PreviousParent(parent) + ); + + world.entity_mut(parent).insert_children(1, &entities[3..]); + let expected_children: SmallVec<[Entity; 8]> = smallvec![child1, child3, child4, child2]; + assert_eq!( + world.get::(parent).unwrap().0.clone(), + expected_children + ); + assert_eq!(*world.get::(child3).unwrap(), Parent(parent)); + assert_eq!(*world.get::(child4).unwrap(), Parent(parent)); + assert_eq!( + *world.get::(child3).unwrap(), + PreviousParent(parent) + ); + assert_eq!( + *world.get::(child4).unwrap(), + PreviousParent(parent) + ); + } }