Store the parent of a scene in its InstanceInfo
.
This commit is contained in:
parent
065043d687
commit
0c687143e3
@ -39,6 +39,8 @@ pub struct SceneInstanceReady {
|
|||||||
struct InstanceInfo {
|
struct InstanceInfo {
|
||||||
/// Mapping of entities from the scene world to the instance world.
|
/// Mapping of entities from the scene world to the instance world.
|
||||||
entity_map: EntityHashMap<Entity>,
|
entity_map: EntityHashMap<Entity>,
|
||||||
|
/// The parent to attach this instance to.
|
||||||
|
parent: Option<Entity>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unique id identifying a scene instance.
|
/// Unique id identifying a scene instance.
|
||||||
@ -86,7 +88,6 @@ pub struct SceneSpawner {
|
|||||||
scenes_to_despawn: Vec<AssetId<Scene>>,
|
scenes_to_despawn: Vec<AssetId<Scene>>,
|
||||||
dynamic_scenes_to_despawn: Vec<AssetId<DynamicScene>>,
|
dynamic_scenes_to_despawn: Vec<AssetId<DynamicScene>>,
|
||||||
instances_to_despawn: Vec<InstanceId>,
|
instances_to_despawn: Vec<InstanceId>,
|
||||||
scenes_with_parent: Vec<(InstanceId, Entity)>,
|
|
||||||
instances_ready: Vec<(InstanceId, Option<Entity>)>,
|
instances_ready: Vec<(InstanceId, Option<Entity>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,7 +163,6 @@ impl SceneSpawner {
|
|||||||
let instance_id = InstanceId::new();
|
let instance_id = InstanceId::new();
|
||||||
self.dynamic_scenes_to_spawn
|
self.dynamic_scenes_to_spawn
|
||||||
.push((id.into(), instance_id, Some(parent)));
|
.push((id.into(), instance_id, Some(parent)));
|
||||||
self.scenes_with_parent.push((instance_id, parent));
|
|
||||||
instance_id
|
instance_id
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +178,6 @@ impl SceneSpawner {
|
|||||||
let instance_id = InstanceId::new();
|
let instance_id = InstanceId::new();
|
||||||
self.scenes_to_spawn
|
self.scenes_to_spawn
|
||||||
.push((id.into(), instance_id, Some(parent)));
|
.push((id.into(), instance_id, Some(parent)));
|
||||||
self.scenes_with_parent.push((instance_id, parent));
|
|
||||||
instance_id
|
instance_id
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,10 +260,18 @@ impl SceneSpawner {
|
|||||||
let id = id.into();
|
let id = id.into();
|
||||||
Self::spawn_dynamic_internal(world, id, &mut entity_map)?;
|
Self::spawn_dynamic_internal(world, id, &mut entity_map)?;
|
||||||
let instance_id = InstanceId::new();
|
let instance_id = InstanceId::new();
|
||||||
self.spawned_instances
|
self.spawned_instances.insert(
|
||||||
.insert(instance_id, InstanceInfo { entity_map });
|
instance_id,
|
||||||
|
InstanceInfo {
|
||||||
|
entity_map,
|
||||||
|
parent: None,
|
||||||
|
},
|
||||||
|
);
|
||||||
let spawned = self.spawned_dynamic_scenes.entry(id).or_default();
|
let spawned = self.spawned_dynamic_scenes.entry(id).or_default();
|
||||||
spawned.insert(instance_id);
|
spawned.insert(instance_id);
|
||||||
|
// We trigger `SceneInstanceReady` events after processing all scenes
|
||||||
|
// SceneSpawner may not be available in the observer.
|
||||||
|
self.instances_ready.push((instance_id, None));
|
||||||
Ok(instance_id)
|
Ok(instance_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,10 +299,18 @@ impl SceneSpawner {
|
|||||||
let id = id.into();
|
let id = id.into();
|
||||||
Self::spawn_sync_internal(world, id, &mut entity_map)?;
|
Self::spawn_sync_internal(world, id, &mut entity_map)?;
|
||||||
let instance_id = InstanceId::new();
|
let instance_id = InstanceId::new();
|
||||||
self.spawned_instances
|
self.spawned_instances.insert(
|
||||||
.insert(instance_id, InstanceInfo { entity_map });
|
instance_id,
|
||||||
|
InstanceInfo {
|
||||||
|
entity_map,
|
||||||
|
parent: None,
|
||||||
|
},
|
||||||
|
);
|
||||||
let spawned = self.spawned_scenes.entry(id).or_default();
|
let spawned = self.spawned_scenes.entry(id).or_default();
|
||||||
spawned.insert(instance_id);
|
spawned.insert(instance_id);
|
||||||
|
// We trigger `SceneInstanceReady` events after processing all scenes
|
||||||
|
// SceneSpawner may not be available in the observer.
|
||||||
|
self.instances_ready.push((instance_id, None));
|
||||||
Ok(instance_id)
|
Ok(instance_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,6 +350,7 @@ impl SceneSpawner {
|
|||||||
// invalid state (e.g., invalid relationships).
|
// invalid state (e.g., invalid relationships).
|
||||||
Self::despawn_instance_internal(world, instance_info);
|
Self::despawn_instance_internal(world, instance_info);
|
||||||
Self::spawn_sync_internal(world, *id, &mut instance_info.entity_map)?;
|
Self::spawn_sync_internal(world, *id, &mut instance_info.entity_map)?;
|
||||||
|
Self::set_scene_instance_parent_sync(world, instance_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -360,6 +376,7 @@ impl SceneSpawner {
|
|||||||
// invalid state (e.g., invalid relationships).
|
// invalid state (e.g., invalid relationships).
|
||||||
Self::despawn_instance_internal(world, instance_info);
|
Self::despawn_instance_internal(world, instance_info);
|
||||||
Self::spawn_dynamic_internal(world, *id, &mut instance_info.entity_map)?;
|
Self::spawn_dynamic_internal(world, *id, &mut instance_info.entity_map)?;
|
||||||
|
Self::set_scene_instance_parent_sync(world, instance_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -398,18 +415,15 @@ impl SceneSpawner {
|
|||||||
|
|
||||||
match Self::spawn_dynamic_internal(world, handle.id(), &mut entity_map) {
|
match Self::spawn_dynamic_internal(world, handle.id(), &mut entity_map) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
self.spawned_instances
|
let instance_info = InstanceInfo { entity_map, parent };
|
||||||
.insert(instance_id, InstanceInfo { entity_map });
|
Self::set_scene_instance_parent_sync(world, &instance_info);
|
||||||
|
|
||||||
|
self.spawned_instances.insert(instance_id, instance_info);
|
||||||
let spawned = self.spawned_dynamic_scenes.entry(handle.id()).or_default();
|
let spawned = self.spawned_dynamic_scenes.entry(handle.id()).or_default();
|
||||||
spawned.insert(instance_id);
|
spawned.insert(instance_id);
|
||||||
|
// We trigger `SceneInstanceReady` events after processing all scenes
|
||||||
// Scenes with parents need more setup before they are ready.
|
// SceneSpawner may not be available in the observer.
|
||||||
// See `set_scene_instance_parent_sync()`.
|
self.instances_ready.push((instance_id, parent));
|
||||||
if parent.is_none() {
|
|
||||||
// We trigger `SceneInstanceReady` events after processing all scenes
|
|
||||||
// SceneSpawner may not be available in the observer.
|
|
||||||
self.instances_ready.push((instance_id, None));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(SceneSpawnError::NonExistentScene { .. }) => {
|
Err(SceneSpawnError::NonExistentScene { .. }) => {
|
||||||
self.dynamic_scenes_to_spawn
|
self.dynamic_scenes_to_spawn
|
||||||
@ -426,18 +440,16 @@ impl SceneSpawner {
|
|||||||
|
|
||||||
match Self::spawn_sync_internal(world, scene_handle.id(), &mut entity_map) {
|
match Self::spawn_sync_internal(world, scene_handle.id(), &mut entity_map) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
self.spawned_instances
|
let instance_info = InstanceInfo { entity_map, parent };
|
||||||
.insert(instance_id, InstanceInfo { entity_map });
|
Self::set_scene_instance_parent_sync(world, &instance_info);
|
||||||
|
|
||||||
|
self.spawned_instances.insert(instance_id, instance_info);
|
||||||
let spawned = self.spawned_scenes.entry(scene_handle.id()).or_default();
|
let spawned = self.spawned_scenes.entry(scene_handle.id()).or_default();
|
||||||
spawned.insert(instance_id);
|
spawned.insert(instance_id);
|
||||||
|
|
||||||
// Scenes with parents need more setup before they are ready.
|
// We trigger `SceneInstanceReady` events after processing all scenes
|
||||||
// See `set_scene_instance_parent_sync()`.
|
// SceneSpawner may not be available in the observer.
|
||||||
if parent.is_none() {
|
self.instances_ready.push((instance_id, parent));
|
||||||
// We trigger `SceneInstanceReady` events after processing all scenes
|
|
||||||
// SceneSpawner may not be available in the observer.
|
|
||||||
self.instances_ready.push((instance_id, None));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(SceneSpawnError::NonExistentRealScene { .. }) => {
|
Err(SceneSpawnError::NonExistentRealScene { .. }) => {
|
||||||
self.scenes_to_spawn
|
self.scenes_to_spawn
|
||||||
@ -450,32 +462,23 @@ impl SceneSpawner {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_scene_instance_parent_sync(&mut self, world: &mut World) {
|
fn set_scene_instance_parent_sync(world: &mut World, instance: &InstanceInfo) {
|
||||||
let scenes_with_parent = core::mem::take(&mut self.scenes_with_parent);
|
let Some(parent) = instance.parent else {
|
||||||
|
return;
|
||||||
for (instance_id, parent) in scenes_with_parent {
|
};
|
||||||
if let Some(instance) = self.spawned_instances.get(&instance_id) {
|
for &entity in instance.entity_map.values() {
|
||||||
for &entity in instance.entity_map.values() {
|
// Add the `ChildOf` component to the scene root, and update the `Children` component of
|
||||||
// Add the `ChildOf` component to the scene root, and update the `Children` component of
|
// the scene parent
|
||||||
// the scene parent
|
if !world
|
||||||
if !world
|
.get_entity(entity)
|
||||||
.get_entity(entity)
|
.ok()
|
||||||
.ok()
|
// This will filter only the scene root entity, as all other from the
|
||||||
// This will filter only the scene root entity, as all other from the
|
// scene have a parent
|
||||||
// scene have a parent
|
// Entities that wouldn't exist anymore are also skipped
|
||||||
// Entities that wouldn't exist anymore are also skipped
|
// this case shouldn't happen anyway
|
||||||
// this case shouldn't happen anyway
|
.is_none_or(|entity| entity.contains::<ChildOf>())
|
||||||
.is_none_or(|entity| entity.contains::<ChildOf>())
|
{
|
||||||
{
|
world.entity_mut(parent).add_child(entity);
|
||||||
world.entity_mut(parent).add_child(entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We trigger `SceneInstanceReady` events after processing all scenes
|
|
||||||
// SceneSpawner may not be available in the observer.
|
|
||||||
self.instances_ready.push((instance_id, Some(parent)));
|
|
||||||
} else {
|
|
||||||
self.scenes_with_parent.push((instance_id, parent));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -520,24 +523,17 @@ impl SceneSpawner {
|
|||||||
pub fn scene_spawner_system(world: &mut World) {
|
pub fn scene_spawner_system(world: &mut World) {
|
||||||
world.resource_scope(|world, mut scene_spawner: Mut<SceneSpawner>| {
|
world.resource_scope(|world, mut scene_spawner: Mut<SceneSpawner>| {
|
||||||
// remove any loading instances where parent is deleted
|
// remove any loading instances where parent is deleted
|
||||||
let mut dead_instances = <HashSet<_>>::default();
|
let is_parent_alive = |parent: &Option<Entity>| {
|
||||||
scene_spawner
|
parent
|
||||||
.scenes_with_parent
|
.map(|parent| world.get_entity(parent).is_ok())
|
||||||
.retain(|(instance, parent)| {
|
.unwrap_or(true) // If we don't have a parent, then consider the parent alive.
|
||||||
let retain = world.get_entity(*parent).is_ok();
|
};
|
||||||
|
|
||||||
if !retain {
|
|
||||||
dead_instances.insert(*instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
retain
|
|
||||||
});
|
|
||||||
scene_spawner
|
scene_spawner
|
||||||
.dynamic_scenes_to_spawn
|
.dynamic_scenes_to_spawn
|
||||||
.retain(|(_, instance, _)| !dead_instances.contains(instance));
|
.retain(|(_, _, parent)| is_parent_alive(parent));
|
||||||
scene_spawner
|
scene_spawner
|
||||||
.scenes_to_spawn
|
.scenes_to_spawn
|
||||||
.retain(|(_, instance, _)| !dead_instances.contains(instance));
|
.retain(|(_, _, parent)| is_parent_alive(parent));
|
||||||
|
|
||||||
let scene_asset_events = world.resource::<Events<AssetEvent<Scene>>>();
|
let scene_asset_events = world.resource::<Events<AssetEvent<Scene>>>();
|
||||||
let dynamic_scene_asset_events = world.resource::<Events<AssetEvent<DynamicScene>>>();
|
let dynamic_scene_asset_events = world.resource::<Events<AssetEvent<DynamicScene>>>();
|
||||||
@ -577,7 +573,6 @@ pub fn scene_spawner_system(world: &mut World) {
|
|||||||
scene_spawner
|
scene_spawner
|
||||||
.update_spawned_dynamic_scenes(world, &updated_spawned_dynamic_scenes)
|
.update_spawned_dynamic_scenes(world, &updated_spawned_dynamic_scenes)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
scene_spawner.set_scene_instance_parent_sync(world);
|
|
||||||
scene_spawner.trigger_scene_ready_events(world);
|
scene_spawner.trigger_scene_ready_events(world);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user