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.
			
			
This commit is contained in:
		
							parent
							
								
									90586a4c46
								
							
						
					
					
						commit
						336583a86b
					
				@ -219,7 +219,7 @@ impl<'w> BuildWorldChildren for EntityMut<'w> {
 | 
				
			|||||||
    fn push_children(&mut self, children: &[Entity]) -> &mut Self {
 | 
					    fn push_children(&mut self, children: &[Entity]) -> &mut Self {
 | 
				
			||||||
        let parent = self.id();
 | 
					        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() };
 | 
					            let world = unsafe { self.world_mut() };
 | 
				
			||||||
            for child in children.iter() {
 | 
					            for child in children.iter() {
 | 
				
			||||||
                world
 | 
					                world
 | 
				
			||||||
@ -227,6 +227,8 @@ impl<'w> BuildWorldChildren for EntityMut<'w> {
 | 
				
			|||||||
                    // FIXME: don't erase the previous parent (see #1545)
 | 
					                    // FIXME: don't erase the previous parent (see #1545)
 | 
				
			||||||
                    .insert_bundle((Parent(parent), PreviousParent(parent)));
 | 
					                    .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>() {
 | 
					        if let Some(mut children_component) = self.get_mut::<Children>() {
 | 
				
			||||||
            children_component.0.extend(children.iter().cloned());
 | 
					            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 {
 | 
					    fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self {
 | 
				
			||||||
        let parent = self.id();
 | 
					        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() };
 | 
					            let world = unsafe { self.world_mut() };
 | 
				
			||||||
            for child in children.iter() {
 | 
					            for child in children.iter() {
 | 
				
			||||||
                world
 | 
					                world
 | 
				
			||||||
@ -247,6 +249,8 @@ impl<'w> BuildWorldChildren for EntityMut<'w> {
 | 
				
			|||||||
                    // FIXME: don't erase the previous parent (see #1545)
 | 
					                    // FIXME: don't erase the previous parent (see #1545)
 | 
				
			||||||
                    .insert_bundle((Parent(parent), PreviousParent(parent)));
 | 
					                    .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>() {
 | 
					        if let Some(mut children_component) = self.get_mut::<Children>() {
 | 
				
			||||||
@ -471,4 +475,11 @@ mod tests {
 | 
				
			|||||||
            PreviousParent(parent)
 | 
					            PreviousParent(parent)
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn regression_push_children_same_archetype() {
 | 
				
			||||||
 | 
					        let mut world = World::new();
 | 
				
			||||||
 | 
					        let child = world.spawn().id();
 | 
				
			||||||
 | 
					        world.spawn().push_children(&[child]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user