From f630a11a6fbd43954ebd17d2b7930836f035a6f4 Mon Sep 17 00:00:00 2001 From: andriyDev Date: Tue, 15 Jul 2025 17:02:52 -0700 Subject: [PATCH] Despawn scenes before hot reloading them. --- crates/bevy_scene/src/scene_spawner.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/crates/bevy_scene/src/scene_spawner.rs b/crates/bevy_scene/src/scene_spawner.rs index 56db96f4f5..a319470af7 100644 --- a/crates/bevy_scene/src/scene_spawner.rs +++ b/crates/bevy_scene/src/scene_spawner.rs @@ -236,15 +236,21 @@ impl SceneSpawner { /// Immediately despawns a scene instance, removing all its entities from the world. pub fn despawn_instance_sync(&mut self, world: &mut World, instance_id: &InstanceId) { - if let Some(instance) = self.spawned_instances.remove(instance_id) { - for &entity in instance.entity_map.values() { - if let Ok(entity_mut) = world.get_entity_mut(entity) { - entity_mut.despawn(); - }; - } + if let Some(mut instance) = self.spawned_instances.remove(instance_id) { + Self::despawn_instance_internal(world, &mut instance); } } + fn despawn_instance_internal(world: &mut World, instance: &mut InstanceInfo) { + for &entity in instance.entity_map.values() { + if let Ok(entity_mut) = world.get_entity_mut(entity) { + entity_mut.despawn(); + }; + } + // Just make sure if we reuse `InstanceInfo` for something, we don't reuse the despawned entities. + instance.entity_map.clear(); + } + /// Immediately spawns a new instance of the provided dynamic scene. pub fn spawn_dynamic_sync( &mut self, @@ -324,6 +330,10 @@ impl SceneSpawner { if let Some(spawned_instances) = self.spawned_scenes.get(id) { for instance_id in spawned_instances { if let Some(instance_info) = self.spawned_instances.get_mut(instance_id) { + // Despawn the scene before respawning it. This is a very heavy operation, + // but otherwise, entities may be left behind, or be left in an otherwise + // invalid state (e.g., invalid relationships). + Self::despawn_instance_internal(world, instance_info); Self::spawn_sync_internal(world, *id, &mut instance_info.entity_map)?; } } @@ -345,6 +355,10 @@ impl SceneSpawner { if let Some(spawned_instances) = self.spawned_dynamic_scenes.get(id) { for instance_id in spawned_instances { if let Some(instance_info) = self.spawned_instances.get_mut(instance_id) { + // Despawn the scene before respawning it. This is a very heavy operation, + // but otherwise, entities may be left behind, or be left in an otherwise + // invalid state (e.g., invalid relationships). + Self::despawn_instance_internal(world, instance_info); Self::spawn_dynamic_internal(world, *id, &mut instance_info.entity_map)?; } }