mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 06:00:20 +00:00
Send SceneInstanceReady
when spawning any kind of scene (#11741)
# Objective - Emit an event regardless of scene type (`Scene` and `DynamicScene`). - Also send the `InstanceId` along. Follow-up to #11002. Fixes #2218. ## Solution - Send `SceneInstanceReady` regardless of scene type. - Make `SceneInstanceReady::parent` `Option`al. - Add `SceneInstanceReady::id`. --- ## Changelog ### Changed - `SceneInstanceReady` is now sent for `Scene` as well. `SceneInstanceReady::parent` is an `Option` and `SceneInstanceReady::id`, an `InstanceId`, is added to identify the corresponding `Scene`. ## Migration Guide - `SceneInstanceReady { parent: Entity }` is now `SceneInstanceReady { id: InstanceId, parent: Option<Entity> }`.
This commit is contained in:
parent
1ceb45540b
commit
ea2a7e5552
1 changed files with 185 additions and 30 deletions
|
@ -18,8 +18,10 @@ use uuid::Uuid;
|
||||||
/// See also [`SceneSpawner::instance_is_ready`].
|
/// See also [`SceneSpawner::instance_is_ready`].
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Event)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Event)]
|
||||||
pub struct SceneInstanceReady {
|
pub struct SceneInstanceReady {
|
||||||
|
/// ID of the spawned instance.
|
||||||
|
pub id: InstanceId,
|
||||||
/// Entity to which the scene was spawned as a child.
|
/// Entity to which the scene was spawned as a child.
|
||||||
pub parent: Entity,
|
pub parent: Option<Entity>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information about a scene instance.
|
/// Information about a scene instance.
|
||||||
|
@ -63,8 +65,8 @@ pub struct SceneSpawner {
|
||||||
pub(crate) spawned_dynamic_scenes: HashMap<AssetId<DynamicScene>, HashSet<InstanceId>>,
|
pub(crate) spawned_dynamic_scenes: HashMap<AssetId<DynamicScene>, HashSet<InstanceId>>,
|
||||||
pub(crate) spawned_instances: HashMap<InstanceId, InstanceInfo>,
|
pub(crate) spawned_instances: HashMap<InstanceId, InstanceInfo>,
|
||||||
scene_asset_event_reader: ManualEventReader<AssetEvent<DynamicScene>>,
|
scene_asset_event_reader: ManualEventReader<AssetEvent<DynamicScene>>,
|
||||||
dynamic_scenes_to_spawn: Vec<(Handle<DynamicScene>, InstanceId)>,
|
dynamic_scenes_to_spawn: Vec<(Handle<DynamicScene>, InstanceId, Option<Entity>)>,
|
||||||
scenes_to_spawn: Vec<(Handle<Scene>, InstanceId)>,
|
scenes_to_spawn: Vec<(Handle<Scene>, InstanceId, Option<Entity>)>,
|
||||||
scenes_to_despawn: Vec<AssetId<DynamicScene>>,
|
scenes_to_despawn: Vec<AssetId<DynamicScene>>,
|
||||||
instances_to_despawn: Vec<InstanceId>,
|
instances_to_despawn: Vec<InstanceId>,
|
||||||
scenes_with_parent: Vec<(InstanceId, Entity)>,
|
scenes_with_parent: Vec<(InstanceId, Entity)>,
|
||||||
|
@ -128,7 +130,8 @@ impl SceneSpawner {
|
||||||
/// Schedule the spawn of a new instance of the provided dynamic scene.
|
/// Schedule the spawn of a new instance of the provided dynamic scene.
|
||||||
pub fn spawn_dynamic(&mut self, id: impl Into<Handle<DynamicScene>>) -> InstanceId {
|
pub fn spawn_dynamic(&mut self, id: impl Into<Handle<DynamicScene>>) -> InstanceId {
|
||||||
let instance_id = InstanceId::new();
|
let instance_id = InstanceId::new();
|
||||||
self.dynamic_scenes_to_spawn.push((id.into(), instance_id));
|
self.dynamic_scenes_to_spawn
|
||||||
|
.push((id.into(), instance_id, None));
|
||||||
instance_id
|
instance_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +142,8 @@ impl SceneSpawner {
|
||||||
parent: Entity,
|
parent: Entity,
|
||||||
) -> InstanceId {
|
) -> InstanceId {
|
||||||
let instance_id = InstanceId::new();
|
let instance_id = InstanceId::new();
|
||||||
self.dynamic_scenes_to_spawn.push((id.into(), instance_id));
|
self.dynamic_scenes_to_spawn
|
||||||
|
.push((id.into(), instance_id, Some(parent)));
|
||||||
self.scenes_with_parent.push((instance_id, parent));
|
self.scenes_with_parent.push((instance_id, parent));
|
||||||
instance_id
|
instance_id
|
||||||
}
|
}
|
||||||
|
@ -147,14 +151,15 @@ impl SceneSpawner {
|
||||||
/// Schedule the spawn of a new instance of the provided scene.
|
/// Schedule the spawn of a new instance of the provided scene.
|
||||||
pub fn spawn(&mut self, id: impl Into<Handle<Scene>>) -> InstanceId {
|
pub fn spawn(&mut self, id: impl Into<Handle<Scene>>) -> InstanceId {
|
||||||
let instance_id = InstanceId::new();
|
let instance_id = InstanceId::new();
|
||||||
self.scenes_to_spawn.push((id.into(), instance_id));
|
self.scenes_to_spawn.push((id.into(), instance_id, None));
|
||||||
instance_id
|
instance_id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Schedule the spawn of a new instance of the provided scene as a child of `parent`.
|
/// Schedule the spawn of a new instance of the provided scene as a child of `parent`.
|
||||||
pub fn spawn_as_child(&mut self, id: impl Into<Handle<Scene>>, parent: Entity) -> InstanceId {
|
pub fn spawn_as_child(&mut self, id: impl Into<Handle<Scene>>, parent: Entity) -> InstanceId {
|
||||||
let instance_id = InstanceId::new();
|
let instance_id = InstanceId::new();
|
||||||
self.scenes_to_spawn.push((id.into(), instance_id));
|
self.scenes_to_spawn
|
||||||
|
.push((id.into(), instance_id, Some(parent)));
|
||||||
self.scenes_with_parent.push((instance_id, parent));
|
self.scenes_with_parent.push((instance_id, parent));
|
||||||
instance_id
|
instance_id
|
||||||
}
|
}
|
||||||
|
@ -296,7 +301,7 @@ impl SceneSpawner {
|
||||||
pub fn spawn_queued_scenes(&mut self, world: &mut World) -> Result<(), SceneSpawnError> {
|
pub fn spawn_queued_scenes(&mut self, world: &mut World) -> Result<(), SceneSpawnError> {
|
||||||
let scenes_to_spawn = std::mem::take(&mut self.dynamic_scenes_to_spawn);
|
let scenes_to_spawn = std::mem::take(&mut self.dynamic_scenes_to_spawn);
|
||||||
|
|
||||||
for (handle, instance_id) in scenes_to_spawn {
|
for (handle, instance_id, parent) in scenes_to_spawn {
|
||||||
let mut entity_map = EntityHashMap::default();
|
let mut entity_map = EntityHashMap::default();
|
||||||
|
|
||||||
match Self::spawn_dynamic_internal(world, handle.id(), &mut entity_map) {
|
match Self::spawn_dynamic_internal(world, handle.id(), &mut entity_map) {
|
||||||
|
@ -308,9 +313,19 @@ impl SceneSpawner {
|
||||||
.entry(handle.id())
|
.entry(handle.id())
|
||||||
.or_insert_with(HashSet::new);
|
.or_insert_with(HashSet::new);
|
||||||
spawned.insert(instance_id);
|
spawned.insert(instance_id);
|
||||||
|
|
||||||
|
// Scenes with parents need more setup before they are ready.
|
||||||
|
// See `set_scene_instance_parent_sync()`.
|
||||||
|
if parent.is_none() {
|
||||||
|
world.send_event(SceneInstanceReady {
|
||||||
|
id: instance_id,
|
||||||
|
parent: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(SceneSpawnError::NonExistentScene { .. }) => {
|
Err(SceneSpawnError::NonExistentScene { .. }) => {
|
||||||
self.dynamic_scenes_to_spawn.push((handle, instance_id));
|
self.dynamic_scenes_to_spawn
|
||||||
|
.push((handle, instance_id, parent));
|
||||||
}
|
}
|
||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err),
|
||||||
}
|
}
|
||||||
|
@ -318,11 +333,21 @@ impl SceneSpawner {
|
||||||
|
|
||||||
let scenes_to_spawn = std::mem::take(&mut self.scenes_to_spawn);
|
let scenes_to_spawn = std::mem::take(&mut self.scenes_to_spawn);
|
||||||
|
|
||||||
for (scene_handle, instance_id) in scenes_to_spawn {
|
for (scene_handle, instance_id, parent) in scenes_to_spawn {
|
||||||
match self.spawn_sync_internal(world, scene_handle.id(), instance_id) {
|
match self.spawn_sync_internal(world, scene_handle.id(), instance_id) {
|
||||||
Ok(_) => {}
|
Ok(_) => {
|
||||||
|
// Scenes with parents need more setup before they are ready.
|
||||||
|
// See `set_scene_instance_parent_sync()`.
|
||||||
|
if parent.is_none() {
|
||||||
|
world.send_event(SceneInstanceReady {
|
||||||
|
id: instance_id,
|
||||||
|
parent: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Err(SceneSpawnError::NonExistentRealScene { .. }) => {
|
Err(SceneSpawnError::NonExistentRealScene { .. }) => {
|
||||||
self.scenes_to_spawn.push((scene_handle, instance_id));
|
self.scenes_to_spawn
|
||||||
|
.push((scene_handle, instance_id, parent));
|
||||||
}
|
}
|
||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err),
|
||||||
}
|
}
|
||||||
|
@ -356,7 +381,10 @@ impl SceneSpawner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
world.send_event(SceneInstanceReady { parent });
|
world.send_event(SceneInstanceReady {
|
||||||
|
id: instance_id,
|
||||||
|
parent: Some(parent),
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
self.scenes_with_parent.push((instance_id, parent));
|
self.scenes_with_parent.push((instance_id, parent));
|
||||||
}
|
}
|
||||||
|
@ -403,10 +431,10 @@ pub fn scene_spawner_system(world: &mut World) {
|
||||||
});
|
});
|
||||||
scene_spawner
|
scene_spawner
|
||||||
.dynamic_scenes_to_spawn
|
.dynamic_scenes_to_spawn
|
||||||
.retain(|(_, instance)| !dead_instances.contains(instance));
|
.retain(|(_, instance, _)| !dead_instances.contains(instance));
|
||||||
scene_spawner
|
scene_spawner
|
||||||
.scenes_to_spawn
|
.scenes_to_spawn
|
||||||
.retain(|(_, instance)| !dead_instances.contains(instance));
|
.retain(|(_, instance, _)| !dead_instances.contains(instance));
|
||||||
|
|
||||||
let scene_asset_events = world.resource::<Events<AssetEvent<DynamicScene>>>();
|
let scene_asset_events = world.resource::<Events<AssetEvent<DynamicScene>>>();
|
||||||
|
|
||||||
|
@ -438,6 +466,7 @@ pub fn scene_spawner_system(world: &mut World) {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use bevy_app::App;
|
use bevy_app::App;
|
||||||
|
use bevy_asset::Handle;
|
||||||
use bevy_asset::{AssetPlugin, AssetServer};
|
use bevy_asset::{AssetPlugin, AssetServer};
|
||||||
use bevy_ecs::event::EventReader;
|
use bevy_ecs::event::EventReader;
|
||||||
use bevy_ecs::prelude::ReflectComponent;
|
use bevy_ecs::prelude::ReflectComponent;
|
||||||
|
@ -505,8 +534,7 @@ mod tests {
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
struct ComponentA;
|
struct ComponentA;
|
||||||
|
|
||||||
#[test]
|
fn setup() -> App {
|
||||||
fn event() {
|
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
app.add_plugins((AssetPlugin::default(), ScenePlugin));
|
app.add_plugins((AssetPlugin::default(), ScenePlugin));
|
||||||
|
|
||||||
|
@ -514,19 +542,66 @@ mod tests {
|
||||||
app.world_mut().spawn(ComponentA);
|
app.world_mut().spawn(ComponentA);
|
||||||
app.world_mut().spawn(ComponentA);
|
app.world_mut().spawn(ComponentA);
|
||||||
|
|
||||||
|
app
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_scene(app: &mut App) -> Handle<Scene> {
|
||||||
|
app.world_mut().run_system_once(
|
||||||
|
|world: &World,
|
||||||
|
type_registry: Res<'_, AppTypeRegistry>,
|
||||||
|
asset_server: Res<'_, AssetServer>| {
|
||||||
|
asset_server.add(
|
||||||
|
Scene::from_dynamic_scene(&DynamicScene::from_world(world), &type_registry)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn event_scene() {
|
||||||
|
let mut app = setup();
|
||||||
|
|
||||||
// Build scene.
|
// Build scene.
|
||||||
let scene =
|
let scene = build_scene(&mut app);
|
||||||
app.world_mut()
|
|
||||||
.run_system_once(|world: &World, asset_server: Res<'_, AssetServer>| {
|
|
||||||
asset_server.add(DynamicScene::from_world(world))
|
|
||||||
});
|
|
||||||
|
|
||||||
// Spawn scene.
|
// Spawn scene.
|
||||||
let scene_entity = app.world_mut().run_system_once(
|
let scene_id =
|
||||||
|
app.world_mut()
|
||||||
|
.run_system_once(move |mut scene_spawner: ResMut<'_, SceneSpawner>| {
|
||||||
|
scene_spawner.spawn(scene.clone())
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check for event arrival.
|
||||||
|
app.update();
|
||||||
|
app.world_mut().run_system_once(
|
||||||
|
move |mut ev_scene: EventReader<'_, '_, SceneInstanceReady>| {
|
||||||
|
let mut events = ev_scene.read();
|
||||||
|
|
||||||
|
let event = events.next().expect("found no `SceneInstanceReady` event");
|
||||||
|
assert_eq!(
|
||||||
|
event.id, scene_id,
|
||||||
|
"`SceneInstanceReady` contains the wrong `InstanceId`"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(events.next().is_none(), "found more than one event");
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn event_scene_as_child() {
|
||||||
|
let mut app = setup();
|
||||||
|
|
||||||
|
// Build scene.
|
||||||
|
let scene = build_scene(&mut app);
|
||||||
|
|
||||||
|
// Spawn scene as child.
|
||||||
|
let (scene_id, scene_entity) = app.world_mut().run_system_once(
|
||||||
move |mut commands: Commands<'_, '_>, mut scene_spawner: ResMut<'_, SceneSpawner>| {
|
move |mut commands: Commands<'_, '_>, mut scene_spawner: ResMut<'_, SceneSpawner>| {
|
||||||
let scene_entity = commands.spawn_empty().id();
|
let entity = commands.spawn_empty().id();
|
||||||
scene_spawner.spawn_dynamic_as_child(scene.clone(), scene_entity);
|
let id = scene_spawner.spawn_as_child(scene.clone(), entity);
|
||||||
scene_entity
|
(id, entity)
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -536,13 +611,93 @@ mod tests {
|
||||||
move |mut ev_scene: EventReader<'_, '_, SceneInstanceReady>| {
|
move |mut ev_scene: EventReader<'_, '_, SceneInstanceReady>| {
|
||||||
let mut events = ev_scene.read();
|
let mut events = ev_scene.read();
|
||||||
|
|
||||||
|
let event = events.next().expect("found no `SceneInstanceReady` event");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
events.next().expect("found no `SceneInstanceReady` event"),
|
event.id, scene_id,
|
||||||
&SceneInstanceReady {
|
"`SceneInstanceReady` contains the wrong `InstanceId`"
|
||||||
parent: scene_entity
|
);
|
||||||
},
|
assert_eq!(
|
||||||
|
event.parent,
|
||||||
|
Some(scene_entity),
|
||||||
"`SceneInstanceReady` contains the wrong parent entity"
|
"`SceneInstanceReady` contains the wrong parent entity"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assert!(events.next().is_none(), "found more than one event");
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_dynamic_scene(app: &mut App) -> Handle<DynamicScene> {
|
||||||
|
app.world_mut()
|
||||||
|
.run_system_once(|world: &World, asset_server: Res<'_, AssetServer>| {
|
||||||
|
asset_server.add(DynamicScene::from_world(world))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn event_dynamic_scene() {
|
||||||
|
let mut app = setup();
|
||||||
|
|
||||||
|
// Build scene.
|
||||||
|
let scene = build_dynamic_scene(&mut app);
|
||||||
|
|
||||||
|
// Spawn scene.
|
||||||
|
let scene_id =
|
||||||
|
app.world_mut()
|
||||||
|
.run_system_once(move |mut scene_spawner: ResMut<'_, SceneSpawner>| {
|
||||||
|
scene_spawner.spawn_dynamic(scene.clone())
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check for event arrival.
|
||||||
|
app.update();
|
||||||
|
app.world_mut().run_system_once(
|
||||||
|
move |mut ev_scene: EventReader<'_, '_, SceneInstanceReady>| {
|
||||||
|
let mut events = ev_scene.read();
|
||||||
|
|
||||||
|
let event = events.next().expect("found no `SceneInstanceReady` event");
|
||||||
|
assert_eq!(
|
||||||
|
event.id, scene_id,
|
||||||
|
"`SceneInstanceReady` contains the wrong `InstanceId`"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(events.next().is_none(), "found more than one event");
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn event_dynamic_scene_as_child() {
|
||||||
|
let mut app = setup();
|
||||||
|
|
||||||
|
// Build scene.
|
||||||
|
let scene = build_dynamic_scene(&mut app);
|
||||||
|
|
||||||
|
// Spawn scene as child.
|
||||||
|
let (scene_id, scene_entity) = app.world_mut().run_system_once(
|
||||||
|
move |mut commands: Commands<'_, '_>, mut scene_spawner: ResMut<'_, SceneSpawner>| {
|
||||||
|
let entity = commands.spawn_empty().id();
|
||||||
|
let id = scene_spawner.spawn_dynamic_as_child(scene.clone(), entity);
|
||||||
|
(id, entity)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check for event arrival.
|
||||||
|
app.update();
|
||||||
|
app.world_mut().run_system_once(
|
||||||
|
move |mut ev_scene: EventReader<'_, '_, SceneInstanceReady>| {
|
||||||
|
let mut events = ev_scene.read();
|
||||||
|
|
||||||
|
let event = events.next().expect("found no `SceneInstanceReady` event");
|
||||||
|
assert_eq!(
|
||||||
|
event.id, scene_id,
|
||||||
|
"`SceneInstanceReady` contains the wrong `InstanceId`"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
event.parent,
|
||||||
|
Some(scene_entity),
|
||||||
|
"`SceneInstanceReady` contains the wrong parent entity"
|
||||||
|
);
|
||||||
|
|
||||||
assert!(events.next().is_none(), "found more than one event");
|
assert!(events.next().is_none(), "found more than one event");
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue