diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index 2b6314536c6ef..422d35811e560 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -508,6 +508,19 @@ impl<'w> EntityMut<'w> { self.world } + /// Access the inner `&mut World` within `use_world` and run [`Self::update_location`]. + /// + /// This is a safe alternative to [`EntityMut::world_mut`]. + /// + /// If you _know_ that `use_world` doesn't change the current entity's location, + /// then `self.update_location` is extaneous and it might be more efficient to use + /// the unsafe `world_mut` method instead. + #[inline] + pub fn with_world_mut(&mut self, use_world: impl FnOnce(&mut World)) { + use_world(self.world); + self.update_location(); + } + /// Return this `EntityMut`'s [`World`], consuming itself. #[inline] pub fn into_world_mut(self) -> &'w mut World { diff --git a/crates/bevy_hierarchy/src/child_builder.rs b/crates/bevy_hierarchy/src/child_builder.rs index c7334a3d9bac0..921bb3011c5f0 100644 --- a/crates/bevy_hierarchy/src/child_builder.rs +++ b/crates/bevy_hierarchy/src/child_builder.rs @@ -166,7 +166,8 @@ impl Command for PushChildren { } } -/// Command that removes children from an entity, and removes that child's parent and inserts it into the previous parent component +/// Command that removes children from an entity, +/// and removes that child's parent and inserts it into the previous parent component pub struct RemoveChildren { parent: Entity, children: SmallVec<[Entity; 8]>, @@ -192,7 +193,9 @@ impl<'w, 's, 'a> ChildBuilder<'w, 's, 'a> { e } - /// Spawns an [`Entity`] with no components and inserts it into the children defined by the [`ChildBuilder`] which adds the [`Parent`] component to it. + /// Spawns an [`Entity`] with no components + /// and inserts it into the children defined by the [`ChildBuilder`] + /// which adds the [`Parent`] component to it. pub fn spawn(&mut self) -> EntityCommands<'w, 's, '_> { let e = self.commands.spawn(); self.push_children.children.push(e.id()); @@ -256,6 +259,11 @@ 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; + + /// Set the parent. + /// + /// This overwrites the existing parent. + fn set_parent(&mut self, parent: Entity) -> &mut Self; } impl<'w, 's, 'a> BuildChildren for EntityCommands<'w, 's, 'a> { @@ -314,6 +322,12 @@ impl<'w, 's, 'a> BuildChildren for EntityCommands<'w, 's, 'a> { self.commands().add(AddChild { child, parent }); self } + + fn set_parent(&mut self, parent: Entity) -> &mut Self { + let child = self.id(); + self.commands().add(AddChild { child, parent }); + self + } } /// Struct for adding children to an entity directly through the [`World`] for use in exclusive systems @@ -345,7 +359,9 @@ impl<'w> WorldChildBuilder<'w> { self.world.entity_mut(entity) } - /// Spawns an [`Entity`] with no components and inserts it into the children defined by the [`WorldChildBuilder`] which adds the [`Parent`] component to it. + /// Spawns an [`Entity`] with no components and inserts it + /// into the children defined by the [`WorldChildBuilder`] + /// which adds the [`Parent`] component to it. pub fn spawn(&mut self) -> EntityMut<'_> { let parent_entity = self.parent_entity(); let entity = self.world.spawn().insert(Parent(parent_entity)).id(); @@ -383,31 +399,22 @@ pub trait BuildWorldChildren { impl<'w> BuildWorldChildren for EntityMut<'w> { fn with_children(&mut self, spawn_children: impl FnOnce(&mut WorldChildBuilder)) -> &mut Self { - { - let entity = self.id(); + let entity = self.id(); + self.with_world_mut(|world| { let mut builder = WorldChildBuilder { current_entity: None, parent_entities: vec![entity], - // SAFETY: self.update_location() is called below. It is impossible to make EntityMut - // function calls on `self` within the scope defined here - world: unsafe { self.world_mut() }, + world, }; spawn_children(&mut builder); - } - self.update_location(); + }); self } fn push_children(&mut self, children: &[Entity]) -> &mut Self { let parent = self.id(); - { - // SAFETY: parent entity is not modified and its location is updated manually - let world = unsafe { self.world_mut() }; - 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(); - } + self.with_world_mut(|world| update_old_parents(world, parent, children)); if let Some(mut children_component) = self.get_mut::() { children_component .0 @@ -421,13 +428,7 @@ impl<'w> BuildWorldChildren for EntityMut<'w> { fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self { let parent = self.id(); - { - // SAFETY: parent entity is not modified and its location is updated manually - let world = unsafe { self.world_mut() }; - 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(); - } + self.with_world_mut(|world| update_old_parents(world, parent, children)); if let Some(mut children_component) = self.get_mut::() { children_component @@ -442,9 +443,7 @@ impl<'w> BuildWorldChildren for EntityMut<'w> { fn remove_children(&mut self, children: &[Entity]) -> &mut Self { let parent = self.id(); - // SAFETY: This doesn't change the parent's location - let world = unsafe { self.world_mut() }; - remove_children(parent, children, world); + self.with_world_mut(|world| remove_children(parent, children, world)); self } } @@ -542,6 +541,8 @@ mod tests { parent.spawn().insert(C(4)).id(), ] }); + let mut children = children.to_vec(); + children.push(commands.spawn().insert(C(5)).set_parent(parent).id()); queue.apply(&mut world); assert_eq!( @@ -583,6 +584,7 @@ mod tests { assert_eq!(*world.get::(child1).unwrap(), Parent(parent)); assert_eq!(*world.get::(child2).unwrap(), Parent(parent)); + // Why are those assertions repeated? assert_eq!(*world.get::(child1).unwrap(), Parent(parent)); assert_eq!(*world.get::(child2).unwrap(), Parent(parent));