# Objective Fixes #19219 ## Solution Instead of calling `world.commands().trigger` and `world.commands().trigger_targets` whenever each scene is spawned, save the `instance_id` and optional parent entity to perform all such calls at the end. This prevents the potential flush of the world command queue that can happen if `add_child` is called from causing the crash. ## Testing - Did you test these changes? If so, how? - Verified that I can no longer reproduce the bug with the instructions at #19219. - Ran `bevy_scene` tests - Visually verified that the following examples still run as expected `many_foxes`, `scene` . (should I test any more?) - Are there any parts that need more testing? - Pending to run `cargo test` at the root to test that all examples still build; I will update the PR when that's done - How can other people (reviewers) test your changes? Is there anything specific they need to know? - Run bevy as usual - If relevant, what platforms did you test these changes on, and are there any important ones you can't test? - N/a (tested on Linux/wayland but it shouldn't be relevant) ---
This commit is contained in:
parent
bc00178b59
commit
56bdd5c3c1
@ -79,6 +79,7 @@ pub struct SceneSpawner {
|
|||||||
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)>,
|
||||||
|
instances_ready: Vec<(InstanceId, Option<Entity>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Errors that can occur when spawning a scene.
|
/// Errors that can occur when spawning a scene.
|
||||||
@ -337,8 +338,9 @@ impl SceneSpawner {
|
|||||||
// Scenes with parents need more setup before they are ready.
|
// Scenes with parents need more setup before they are ready.
|
||||||
// See `set_scene_instance_parent_sync()`.
|
// See `set_scene_instance_parent_sync()`.
|
||||||
if parent.is_none() {
|
if parent.is_none() {
|
||||||
// Defer via commands otherwise SceneSpawner is not available in the observer.
|
// We trigger `SceneInstanceReady` events after processing all scenes
|
||||||
world.commands().trigger(SceneInstanceReady { instance_id });
|
// SceneSpawner may not be available in the observer.
|
||||||
|
self.instances_ready.push((instance_id, None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(SceneSpawnError::NonExistentScene { .. }) => {
|
Err(SceneSpawnError::NonExistentScene { .. }) => {
|
||||||
@ -362,8 +364,9 @@ impl SceneSpawner {
|
|||||||
// Scenes with parents need more setup before they are ready.
|
// Scenes with parents need more setup before they are ready.
|
||||||
// See `set_scene_instance_parent_sync()`.
|
// See `set_scene_instance_parent_sync()`.
|
||||||
if parent.is_none() {
|
if parent.is_none() {
|
||||||
// Defer via commands otherwise SceneSpawner is not available in the observer.
|
// We trigger `SceneInstanceReady` events after processing all scenes
|
||||||
world.commands().trigger(SceneInstanceReady { instance_id });
|
// SceneSpawner may not be available in the observer.
|
||||||
|
self.instances_ready.push((instance_id, None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(SceneSpawnError::NonExistentRealScene { .. }) => {
|
Err(SceneSpawnError::NonExistentRealScene { .. }) => {
|
||||||
@ -398,12 +401,25 @@ impl SceneSpawner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trigger_scene_ready_events(&mut self, world: &mut World) {
|
||||||
|
for (instance_id, parent) in self.instances_ready.drain(..) {
|
||||||
|
if let Some(parent) = parent {
|
||||||
// Defer via commands otherwise SceneSpawner is not available in the observer.
|
// Defer via commands otherwise SceneSpawner is not available in the observer.
|
||||||
world
|
world
|
||||||
.commands()
|
.commands()
|
||||||
.trigger_targets(SceneInstanceReady { instance_id }, parent);
|
.trigger_targets(SceneInstanceReady { instance_id }, parent);
|
||||||
} else {
|
} else {
|
||||||
self.scenes_with_parent.push((instance_id, parent));
|
// Defer via commands otherwise SceneSpawner is not available in the observer.
|
||||||
|
world.commands().trigger(SceneInstanceReady { instance_id });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -477,6 +493,7 @@ pub fn scene_spawner_system(world: &mut World) {
|
|||||||
.update_spawned_scenes(world, &updated_spawned_scenes)
|
.update_spawned_scenes(world, &updated_spawned_scenes)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
scene_spawner.set_scene_instance_parent_sync(world);
|
scene_spawner.set_scene_instance_parent_sync(world);
|
||||||
|
scene_spawner.trigger_scene_ready_events(world);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user