Skip to content

Commit 5d5d783

Browse files
committed
fix parenting of scenes (#2410)
# Objective Fix #2406 Scene parenting was not done completely, leaving the hierarchy maintenance to the standard system. As scene spawning happens in stage `PreUpdate` and hierarchy maintenance in stage `PostUpdate`, this left the scene in an invalid state parent wise for part of a frame ## Solution Also add/update the `Children` component when spawning the scene. I kept the `Children` component as a `SmallVec`, it could be moved to an `HashSet` to guarantee uniqueness Co-authored-by: François <[email protected]>
1 parent 08b5234 commit 5d5d783

File tree

3 files changed

+50
-9
lines changed

3 files changed

+50
-9
lines changed

crates/bevy_scene/src/scene_spawner.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ use bevy_asset::{AssetEvent, Assets, Handle};
44
use bevy_ecs::{
55
entity::{Entity, EntityMap},
66
reflect::{ReflectComponent, ReflectMapEntities},
7+
system::Command,
78
world::{Mut, World},
89
};
910
use bevy_reflect::TypeRegistryArc;
10-
use bevy_transform::prelude::Parent;
11+
use bevy_transform::{hierarchy::AddChild, prelude::Parent};
1112
use bevy_utils::{tracing::error, HashMap};
1213
use thiserror::Error;
1314
use uuid::Uuid;
@@ -268,10 +269,22 @@ impl SceneSpawner {
268269
for (instance_id, parent) in scenes_with_parent {
269270
if let Some(instance) = self.spawned_instances.get(&instance_id) {
270271
for entity in instance.entity_map.values() {
271-
if let Some(mut entity_mut) = world.get_entity_mut(entity) {
272-
if !entity_mut.contains::<Parent>() {
273-
entity_mut.insert(Parent(parent));
272+
// Add the `Parent` component to the scene root, and update the `Children` component of
273+
// the scene parent
274+
if !world
275+
.get_entity(entity)
276+
// This will filter only the scene root entity, as all other from the
277+
// scene have a parent
278+
.map(|entity| entity.contains::<Parent>())
279+
// Default is true so that it won't run on an entity that wouldn't exist anymore
280+
// this case shouldn't happen anyway
281+
.unwrap_or(true)
282+
{
283+
AddChild {
284+
parent,
285+
child: entity,
274286
}
287+
.write(world);
275288
}
276289
}
277290
} else {

crates/bevy_transform/src/hierarchy/child_builder.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,28 @@ use bevy_ecs::{
77
};
88
use smallvec::SmallVec;
99

10+
#[derive(Debug)]
11+
pub struct AddChild {
12+
pub parent: Entity,
13+
pub child: Entity,
14+
}
15+
16+
impl Command for AddChild {
17+
fn write(self, world: &mut World) {
18+
world
19+
.entity_mut(self.child)
20+
// FIXME: don't erase the previous parent (see #1545)
21+
.insert_bundle((Parent(self.parent), PreviousParent(self.parent)));
22+
if let Some(mut children) = world.get_mut::<Children>(self.parent) {
23+
children.0.push(self.child);
24+
} else {
25+
world
26+
.entity_mut(self.parent)
27+
.insert(Children(smallvec::smallvec![self.child]));
28+
}
29+
}
30+
}
31+
1032
#[derive(Debug)]
1133
pub struct InsertChildren {
1234
parent: Entity,
@@ -134,6 +156,7 @@ pub trait BuildChildren {
134156
fn push_children(&mut self, children: &[Entity]) -> &mut Self;
135157
fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self;
136158
fn remove_children(&mut self, children: &[Entity]) -> &mut Self;
159+
fn add_child(&mut self, child: Entity) -> &mut Self;
137160
}
138161

139162
impl<'w, 's, 'a> BuildChildren for EntityCommands<'w, 's, 'a> {
@@ -182,6 +205,12 @@ impl<'w, 's, 'a> BuildChildren for EntityCommands<'w, 's, 'a> {
182205
});
183206
self
184207
}
208+
209+
fn add_child(&mut self, child: Entity) -> &mut Self {
210+
let parent = self.id();
211+
self.commands().add(AddChild { child, parent });
212+
self
213+
}
185214
}
186215

187216
#[derive(Debug)]

crates/bevy_transform/src/hierarchy/hierarchy_maintenance_system.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,10 @@ pub fn parent_update_system(
4949
// `children_additions`).
5050
if let Ok(mut new_parent_children) = children_query.get_mut(parent.0) {
5151
// This is the parent
52-
debug_assert!(
53-
!(*new_parent_children).0.contains(&entity),
54-
"children already added"
55-
);
56-
(*new_parent_children).0.push(entity);
52+
// PERF: Ideally we shouldn't need to check for duplicates
53+
if !(*new_parent_children).0.contains(&entity) {
54+
(*new_parent_children).0.push(entity);
55+
}
5756
} else {
5857
// The parent doesn't have a children entity, lets add it
5958
children_additions

0 commit comments

Comments
 (0)