From 336583a86bdaef6339c60fc00c52d469727e262e Mon Sep 17 00:00:00 2001 From: davier Date: Tue, 10 Aug 2021 01:12:42 +0000 Subject: [PATCH] Update EntityMut's location in push_children() and insert_children() (#2604) ## Objective This code would result in a crash: ```rust use bevy::prelude::*; fn main() { let mut world = World::new(); let child = world.spawn().id(); world.spawn().push_children(&[child]); } ``` ## Solution Update the `EntityMut`'s location after inserting a component on the children entities, as it may have changed. --- .../bevy_transform/src/hierarchy/child_builder.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/crates/bevy_transform/src/hierarchy/child_builder.rs b/crates/bevy_transform/src/hierarchy/child_builder.rs index 9731c8c02b0e5..71fc54aeb24ce 100644 --- a/crates/bevy_transform/src/hierarchy/child_builder.rs +++ b/crates/bevy_transform/src/hierarchy/child_builder.rs @@ -219,7 +219,7 @@ impl<'w> BuildWorldChildren for EntityMut<'w> { fn push_children(&mut self, children: &[Entity]) -> &mut Self { let parent = self.id(); { - // SAFE: parent entity is not modified + // SAFE: parent entity is not modified and its location is updated manually let world = unsafe { self.world_mut() }; for child in children.iter() { world @@ -227,6 +227,8 @@ impl<'w> BuildWorldChildren for EntityMut<'w> { // FIXME: don't erase the previous parent (see #1545) .insert_bundle((Parent(parent), PreviousParent(parent))); } + // 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.extend(children.iter().cloned()); @@ -239,7 +241,7 @@ impl<'w> BuildWorldChildren for EntityMut<'w> { fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self { let parent = self.id(); { - // SAFE: parent entity is not modified + // SAFE: parent entity is not modified and its location is updated manually let world = unsafe { self.world_mut() }; for child in children.iter() { world @@ -247,6 +249,8 @@ impl<'w> BuildWorldChildren for EntityMut<'w> { // FIXME: don't erase the previous parent (see #1545) .insert_bundle((Parent(parent), PreviousParent(parent))); } + // 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::() { @@ -471,4 +475,11 @@ mod tests { PreviousParent(parent) ); } + + #[test] + fn regression_push_children_same_archetype() { + let mut world = World::new(); + let child = world.spawn().id(); + world.spawn().push_children(&[child]); + } }