Skip to content

Commit

Permalink
Update EntityMut's location in push_children() and insert_children() (#…
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
Davier committed Aug 10, 2021
1 parent 90586a4 commit 336583a
Showing 1 changed file with 13 additions and 2 deletions.
15 changes: 13 additions & 2 deletions crates/bevy_transform/src/hierarchy/child_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,14 +219,16 @@ 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
.entity_mut(*child)
// 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>() {
children_component.0.extend(children.iter().cloned());
Expand All @@ -239,14 +241,16 @@ 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
.entity_mut(*child)
// 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>() {
Expand Down Expand Up @@ -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]);
}
}

0 comments on commit 336583a

Please sign in to comment.