From 0d6b8a927ddea8e9de6a76381c35b2455c8e81d1 Mon Sep 17 00:00:00 2001 From: ld000 Date: Wed, 21 Sep 2022 01:17:45 +0800 Subject: [PATCH 1/4] add ClearChildren and ReplaceChildren EntityCommand --- crates/bevy_hierarchy/src/child_builder.rs | 156 +++++++++++++++++++-- 1 file changed, 147 insertions(+), 9 deletions(-) diff --git a/crates/bevy_hierarchy/src/child_builder.rs b/crates/bevy_hierarchy/src/child_builder.rs index c7334a3d9bac0..16197a5183fb0 100644 --- a/crates/bevy_hierarchy/src/child_builder.rs +++ b/crates/bevy_hierarchy/src/child_builder.rs @@ -84,6 +84,23 @@ fn remove_children(parent: Entity, children: &[Entity], world: &mut World) { } } +fn clear_children(parent: Entity, world: &mut World) { + if let Some(children) = world.entity(parent).get::() { + remove_children(parent, &children.0.clone(), world); + } +} + +fn push_children(parent: Entity, mut children: SmallVec<[Entity; 8]>, world: &mut World) { + update_old_parents(world, parent, &children); + let mut parent = world.entity_mut(parent); + if let Some(mut parent_children) = parent.get_mut::() { + parent_children.0.retain(|child| !children.contains(child)); + parent_children.0.append(&mut children); + } else { + parent.insert(Children(children)); + } +} + /// Command that adds a child to an entity #[derive(Debug)] pub struct AddChild { @@ -154,15 +171,8 @@ pub struct PushChildren { } impl Command for PushChildren { - fn write(mut self, world: &mut World) { - 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.append(&mut self.children); - } else { - parent.insert(Children(self.children)); - } + fn write(self, world: &mut World) { + push_children(self.parent, self.children, world); } } @@ -178,6 +188,30 @@ impl Command for RemoveChildren { } } +/// Command that clear all children from an entity. +pub struct ClearChildren { + parent: Entity, +} + +impl Command for ClearChildren { + fn write(self, world: &mut World) { + clear_children(self.parent, world); + } +} + +/// Command that clear all children from an entity. And replace with the given children. +pub struct ReplaceChildren { + parent: Entity, + children: SmallVec<[Entity; 8]>, +} + +impl Command for ReplaceChildren { + fn write(self, world: &mut World) { + clear_children(self.parent, world); + push_children(self.parent, self.children, world); + } +} + /// Struct for building children onto an entity pub struct ChildBuilder<'w, 's, 'a> { commands: &'a mut Commands<'w, 's>, @@ -256,6 +290,10 @@ pub trait BuildChildren { fn remove_children(&mut self, children: &[Entity]) -> &mut Self; /// Adds a single child fn add_child(&mut self, child: Entity) -> &mut Self; + /// Clear children + fn clear_children(&mut self) -> &mut Self; + /// Replace children + fn replace_children(&mut self, children: &[Entity]) -> &mut Self; } impl<'w, 's, 'a> BuildChildren for EntityCommands<'w, 's, 'a> { @@ -314,6 +352,21 @@ impl<'w, 's, 'a> BuildChildren for EntityCommands<'w, 's, 'a> { self.commands().add(AddChild { child, parent }); self } + + fn clear_children(&mut self) -> &mut Self { + let parent = self.id(); + self.commands().add(ClearChildren { parent }); + self + } + + fn replace_children(&mut self, children: &[Entity]) -> &mut Self { + let parent = self.id(); + self.commands().add(ReplaceChildren { + children: SmallVec::from(children), + parent, + }); + self + } } /// Struct for adding children to an entity directly through the [`World`] for use in exclusive systems @@ -616,6 +669,91 @@ mod tests { assert!(world.get::(child4).is_none()); } + #[test] + fn push_and_clear_children_commands() { + let mut world = World::default(); + let entities = world + .spawn_batch(vec![(C(1),), (C(2),), (C(3),), (C(4),), (C(5),)]) + .collect::>(); + + let mut queue = CommandQueue::default(); + { + let mut commands = Commands::new(&mut queue, &world); + commands.entity(entities[0]).push_children(&entities[1..3]); + } + queue.apply(&mut world); + + let parent = entities[0]; + let child1 = entities[1]; + let child2 = entities[2]; + + 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)); + + { + let mut commands = Commands::new(&mut queue, &world); + commands.entity(parent).clear_children(); + } + queue.apply(&mut world); + + let expected_children: SmallVec<[Entity; 8]> = smallvec![]; + assert_eq!( + world.get::(parent).unwrap().0.clone(), + expected_children + ); + assert!(world.get::(child1).is_none()); + assert!(world.get::(child2).is_none()); + } + + #[test] + fn push_and_replace_children_commands() { + let mut world = World::default(); + let entities = world + .spawn_batch(vec![(C(1),), (C(2),), (C(3),), (C(4),), (C(5),)]) + .collect::>(); + + let mut queue = CommandQueue::default(); + { + let mut commands = Commands::new(&mut queue, &world); + commands.entity(entities[0]).push_children(&entities[1..3]); + } + queue.apply(&mut world); + + let parent = entities[0]; + let child1 = entities[1]; + let child2 = entities[2]; + 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)); + + let replace_children = [child1, child4]; + { + let mut commands = Commands::new(&mut queue, &world); + commands.entity(parent).replace_children(&replace_children); + } + queue.apply(&mut world); + + let expected_children: SmallVec<[Entity; 8]> = smallvec![child1, child4]; + assert_eq!( + world.get::(parent).unwrap().0.clone(), + expected_children + ); + assert_eq!(*world.get::(child1).unwrap(), Parent(parent)); + assert_eq!(*world.get::(child4).unwrap(), Parent(parent)); + assert!(world.get::(child2).is_none()); + } + #[test] fn push_and_insert_and_remove_children_world() { let mut world = World::default(); From 81c3e9ef058774b0c15afb53120c63c416191821 Mon Sep 17 00:00:00 2001 From: lidong63 Date: Tue, 1 Nov 2022 17:47:05 +0800 Subject: [PATCH 2/4] clear_children not clone children, use remove instead --- crates/bevy_hierarchy/src/child_builder.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/crates/bevy_hierarchy/src/child_builder.rs b/crates/bevy_hierarchy/src/child_builder.rs index 16197a5183fb0..c00dacec8e7d0 100644 --- a/crates/bevy_hierarchy/src/child_builder.rs +++ b/crates/bevy_hierarchy/src/child_builder.rs @@ -85,8 +85,17 @@ fn remove_children(parent: Entity, children: &[Entity], world: &mut World) { } fn clear_children(parent: Entity, world: &mut World) { - if let Some(children) = world.entity(parent).get::() { - remove_children(parent, &children.0.clone(), world); + let mut events: SmallVec<[HierarchyEvent; 8]> = SmallVec::new(); + if let Some(children) = world.entity_mut(parent).remove::() { + for child in &children.0 { + world.entity_mut(*child).remove::(); + events.push(HierarchyEvent::ChildRemoved { + child: *child, + parent, + }); + } + + push_events(world, events); } } @@ -700,12 +709,9 @@ mod tests { commands.entity(parent).clear_children(); } queue.apply(&mut world); + + assert!(world.get::(parent).is_none()); - let expected_children: SmallVec<[Entity; 8]> = smallvec![]; - assert_eq!( - world.get::(parent).unwrap().0.clone(), - expected_children - ); assert!(world.get::(child1).is_none()); assert!(world.get::(child2).is_none()); } From 3bfe1c4f789e491641a5adbf14e7aeb7263a2cfe Mon Sep 17 00:00:00 2001 From: lidong63 Date: Tue, 1 Nov 2022 19:36:22 +0800 Subject: [PATCH 3/4] format code --- crates/bevy_hierarchy/src/child_builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_hierarchy/src/child_builder.rs b/crates/bevy_hierarchy/src/child_builder.rs index c00dacec8e7d0..cacd7673d4cb7 100644 --- a/crates/bevy_hierarchy/src/child_builder.rs +++ b/crates/bevy_hierarchy/src/child_builder.rs @@ -709,7 +709,7 @@ mod tests { commands.entity(parent).clear_children(); } queue.apply(&mut world); - + assert!(world.get::(parent).is_none()); assert!(world.get::(child1).is_none()); From df5ebf7e7abfb2fa41a7b59d3414e92ffb11b6dd Mon Sep 17 00:00:00 2001 From: ld000 Date: Wed, 11 Jan 2023 16:46:41 +0800 Subject: [PATCH 4/4] resolve conversation --- crates/bevy_hierarchy/src/child_builder.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/bevy_hierarchy/src/child_builder.rs b/crates/bevy_hierarchy/src/child_builder.rs index 49eb296b3bcc7..0323031986bb0 100644 --- a/crates/bevy_hierarchy/src/child_builder.rs +++ b/crates/bevy_hierarchy/src/child_builder.rs @@ -96,10 +96,10 @@ fn remove_children(parent: Entity, children: &[Entity], world: &mut World) { fn clear_children(parent: Entity, world: &mut World) { let mut events: SmallVec<[HierarchyEvent; 8]> = SmallVec::new(); if let Some(children) = world.entity_mut(parent).remove::() { - for child in &children.0 { - world.entity_mut(*child).remove::(); + for &child in &children.0 { + world.entity_mut(child).remove::(); events.push(HierarchyEvent::ChildRemoved { - child: *child, + child, parent, }); } @@ -352,9 +352,9 @@ pub trait BuildChildren { /// will have those children removed from its list. Removing all children from a parent causes its /// [`Children`] component to be removed from the entity. fn add_child(&mut self, child: Entity) -> &mut Self; - /// Clear children + /// Removes all children from this entity. The [`Children`] component will be removed if it exists, otherwise this does nothing. fn clear_children(&mut self) -> &mut Self; - /// Replace children + /// Removes all current children from this entity, replacing them with the specified list of entities. fn replace_children(&mut self, children: &[Entity]) -> &mut Self; /// Sets the parent of this entity. fn set_parent(&mut self, parent: Entity) -> &mut Self;