From 8683eb2cef0e42370889f1f3c0c13c9032be4faa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Thu, 1 Sep 2022 22:35:10 +0200 Subject: [PATCH 1/7] can clone a scene --- crates/bevy_scene/src/scene.rs | 74 +++++++++++++++++++++++++- crates/bevy_scene/src/scene_spawner.rs | 51 +++--------------- 2 files changed, 79 insertions(+), 46 deletions(-) diff --git a/crates/bevy_scene/src/scene.rs b/crates/bevy_scene/src/scene.rs index 4cd871fa7283a..e55caa1232a09 100644 --- a/crates/bevy_scene/src/scene.rs +++ b/crates/bevy_scene/src/scene.rs @@ -1,6 +1,13 @@ -use bevy_ecs::world::World; +use bevy_app::AppTypeRegistry; +use bevy_ecs::{ + entity::EntityMap, + reflect::{ReflectComponent, ReflectMapEntities}, + world::World, +}; use bevy_reflect::TypeUuid; +use crate::{InstanceInfo, SceneSpawnError}; + /// To spawn a scene, you can use either: /// * [`SceneSpawner::spawn`](crate::SceneSpawner::spawn) /// * adding the [`SceneBundle`](crate::SceneBundle) to an entity @@ -18,3 +25,68 @@ impl Scene { Self { world } } } + +impl Scene { + /// Clone the scene. + /// + /// This method will return a `SceneSpawnError` if either a type is not registered in the + /// provided `AppTypeRegistry` or doesn't reflect the `Component` trait. + pub fn clone(&self, type_registry: &AppTypeRegistry) -> Result { + let mut new_world = World::new(); + new_world.insert_resource(type_registry.clone()); + self.write_to_world(&mut new_world)?; + new_world.remove_resource::(); + Ok(Self { world: new_world }) + } + + /// Write the entities and their corresponding components to the given world. + /// + /// This method will return a `SceneSpawnError` if either a type is not registered + /// or doesn't reflect the `Component` trait. + pub fn write_to_world(&self, world: &mut World) -> Result { + let mut instance_info = InstanceInfo { + entity_map: EntityMap::default(), + }; + + let type_registry = world.resource::().clone(); + let type_registry = type_registry.read(); + for archetype in self.world.archetypes().iter() { + for scene_entity in archetype.entities() { + let entity = *instance_info + .entity_map + .entry(*scene_entity) + .or_insert_with(|| world.spawn().id()); + for component_id in archetype.components() { + let component_info = self + .world + .components() + .get_info(component_id) + .expect("component_ids in archetypes should have ComponentInfo"); + + let reflect_component = type_registry + .get(component_info.type_id().unwrap()) + .ok_or_else(|| SceneSpawnError::UnregisteredType { + type_name: component_info.name().to_string(), + }) + .and_then(|registration| { + registration.data::().ok_or_else(|| { + SceneSpawnError::UnregisteredComponent { + type_name: component_info.name().to_string(), + } + }) + })?; + reflect_component.copy(&self.world, world, *scene_entity, entity); + } + } + } + for registration in type_registry.iter() { + if let Some(map_entities_reflect) = registration.data::() { + map_entities_reflect + .map_entities(world, &instance_info.entity_map) + .unwrap(); + } + } + + Ok(instance_info) + } +} diff --git a/crates/bevy_scene/src/scene_spawner.rs b/crates/bevy_scene/src/scene_spawner.rs index d9bfcb213687e..4b384246602e7 100644 --- a/crates/bevy_scene/src/scene_spawner.rs +++ b/crates/bevy_scene/src/scene_spawner.rs @@ -1,10 +1,8 @@ use crate::{DynamicScene, Scene}; -use bevy_app::AppTypeRegistry; use bevy_asset::{AssetEvent, Assets, Handle}; use bevy_ecs::{ entity::{Entity, EntityMap}, event::{Events, ManualEventReader}, - reflect::{ReflectComponent, ReflectMapEntities}, system::{Command, Resource}, world::{Mut, World}, }; @@ -13,9 +11,11 @@ use bevy_utils::{tracing::error, HashMap}; use thiserror::Error; use uuid::Uuid; +/// Informations about a scene instance. #[derive(Debug)] -struct InstanceInfo { - entity_map: EntityMap, +pub struct InstanceInfo { + /// Mapping of entities between the scene world and the instance world. + pub entity_map: EntityMap, } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] @@ -161,11 +161,6 @@ impl SceneSpawner { scene_handle: Handle, instance_id: InstanceId, ) -> Result { - let mut instance_info = InstanceInfo { - entity_map: EntityMap::default(), - }; - let type_registry = world.resource::().clone(); - let type_registry = type_registry.read(); world.resource_scope(|world, scenes: Mut>| { let scene = scenes @@ -174,42 +169,8 @@ impl SceneSpawner { handle: scene_handle.clone(), })?; - for archetype in scene.world.archetypes().iter() { - for scene_entity in archetype.entities() { - let entity = *instance_info - .entity_map - .entry(*scene_entity) - .or_insert_with(|| world.spawn().id()); - for component_id in archetype.components() { - let component_info = scene - .world - .components() - .get_info(component_id) - .expect("component_ids in archetypes should have ComponentInfo"); - - let reflect_component = type_registry - .get(component_info.type_id().unwrap()) - .ok_or_else(|| SceneSpawnError::UnregisteredType { - type_name: component_info.name().to_string(), - }) - .and_then(|registration| { - registration.data::().ok_or_else(|| { - SceneSpawnError::UnregisteredComponent { - type_name: component_info.name().to_string(), - } - }) - })?; - reflect_component.copy(&scene.world, world, *scene_entity, entity); - } - } - } - for registration in type_registry.iter() { - if let Some(map_entities_reflect) = registration.data::() { - map_entities_reflect - .map_entities(world, &instance_info.entity_map) - .unwrap(); - } - } + let instance_info = scene.write_to_world(world)?; + self.spawned_instances.insert(instance_id, instance_info); let spawned = self .spawned_scenes From ca3185bd9174a38280537e69c6996f42197aec5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Fri, 2 Sep 2022 00:34:36 +0200 Subject: [PATCH 2/7] no duplicate impl --- crates/bevy_scene/src/scene.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/bevy_scene/src/scene.rs b/crates/bevy_scene/src/scene.rs index e55caa1232a09..069ddb18fec46 100644 --- a/crates/bevy_scene/src/scene.rs +++ b/crates/bevy_scene/src/scene.rs @@ -24,9 +24,7 @@ impl Scene { pub fn new(world: World) -> Self { Self { world } } -} -impl Scene { /// Clone the scene. /// /// This method will return a `SceneSpawnError` if either a type is not registered in the From 673d36d8f645ae5205ccddecfdfd02b16f8255d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Fri, 2 Sep 2022 00:35:37 +0200 Subject: [PATCH 3/7] rename method --- crates/bevy_scene/src/scene.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_scene/src/scene.rs b/crates/bevy_scene/src/scene.rs index 069ddb18fec46..cd5ced4de53c9 100644 --- a/crates/bevy_scene/src/scene.rs +++ b/crates/bevy_scene/src/scene.rs @@ -29,7 +29,7 @@ impl Scene { /// /// This method will return a `SceneSpawnError` if either a type is not registered in the /// provided `AppTypeRegistry` or doesn't reflect the `Component` trait. - pub fn clone(&self, type_registry: &AppTypeRegistry) -> Result { + pub fn clone_with(&self, type_registry: &AppTypeRegistry) -> Result { let mut new_world = World::new(); new_world.insert_resource(type_registry.clone()); self.write_to_world(&mut new_world)?; From 676ef66a29d1000de0b96ec68ad26ba8a2315c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Fri, 2 Sep 2022 00:37:10 +0200 Subject: [PATCH 4/7] links --- crates/bevy_scene/src/dynamic_scene.rs | 4 ++-- crates/bevy_scene/src/scene.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/bevy_scene/src/dynamic_scene.rs b/crates/bevy_scene/src/dynamic_scene.rs index 1de7202bfab4e..d4ed50dfe47e5 100644 --- a/crates/bevy_scene/src/dynamic_scene.rs +++ b/crates/bevy_scene/src/dynamic_scene.rs @@ -78,8 +78,8 @@ impl DynamicScene { /// Write the dynamic entities and their corresponding components to the given world. /// - /// This method will return a `SceneSpawnError` if either a type is not registered - /// or doesn't reflect the `Component` trait. + /// This method will return a [`SceneSpawnError`] if either a type is not registered + /// or doesn't reflect the [`Component`](bevy_ecs::component::Component) trait. pub fn write_to_world( &self, world: &mut World, diff --git a/crates/bevy_scene/src/scene.rs b/crates/bevy_scene/src/scene.rs index cd5ced4de53c9..4c0e051fb9bfa 100644 --- a/crates/bevy_scene/src/scene.rs +++ b/crates/bevy_scene/src/scene.rs @@ -27,8 +27,8 @@ impl Scene { /// Clone the scene. /// - /// This method will return a `SceneSpawnError` if either a type is not registered in the - /// provided `AppTypeRegistry` or doesn't reflect the `Component` trait. + /// This method will return a [`SceneSpawnError`] if either a type is not registered in the + /// provided [`AppTypeRegistry`] or doesn't reflect the [`Component`](bevy_ecs::component::Component) trait. pub fn clone_with(&self, type_registry: &AppTypeRegistry) -> Result { let mut new_world = World::new(); new_world.insert_resource(type_registry.clone()); @@ -39,8 +39,8 @@ impl Scene { /// Write the entities and their corresponding components to the given world. /// - /// This method will return a `SceneSpawnError` if either a type is not registered - /// or doesn't reflect the `Component` trait. + /// This method will return a [`SceneSpawnError`] if either a type is not registered + /// or doesn't reflect the [`Component`](bevy_ecs::component::Component) trait. pub fn write_to_world(&self, world: &mut World) -> Result { let mut instance_info = InstanceInfo { entity_map: EntityMap::default(), From 9d833f92cef77b908a7e9e83658c27abdaab11f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Fri, 2 Sep 2022 00:39:41 +0200 Subject: [PATCH 5/7] reorder words --- crates/bevy_scene/src/dynamic_scene.rs | 2 +- crates/bevy_scene/src/scene.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_scene/src/dynamic_scene.rs b/crates/bevy_scene/src/dynamic_scene.rs index d4ed50dfe47e5..7a292aaf69666 100644 --- a/crates/bevy_scene/src/dynamic_scene.rs +++ b/crates/bevy_scene/src/dynamic_scene.rs @@ -78,7 +78,7 @@ impl DynamicScene { /// Write the dynamic entities and their corresponding components to the given world. /// - /// This method will return a [`SceneSpawnError`] if either a type is not registered + /// This method will return a [`SceneSpawnError`] if a type either is not registered /// or doesn't reflect the [`Component`](bevy_ecs::component::Component) trait. pub fn write_to_world( &self, diff --git a/crates/bevy_scene/src/scene.rs b/crates/bevy_scene/src/scene.rs index 4c0e051fb9bfa..50cbe2aed33e2 100644 --- a/crates/bevy_scene/src/scene.rs +++ b/crates/bevy_scene/src/scene.rs @@ -27,7 +27,7 @@ impl Scene { /// Clone the scene. /// - /// This method will return a [`SceneSpawnError`] if either a type is not registered in the + /// This method will return a [`SceneSpawnError`] if a type either is not registered in the /// provided [`AppTypeRegistry`] or doesn't reflect the [`Component`](bevy_ecs::component::Component) trait. pub fn clone_with(&self, type_registry: &AppTypeRegistry) -> Result { let mut new_world = World::new(); @@ -39,7 +39,7 @@ impl Scene { /// Write the entities and their corresponding components to the given world. /// - /// This method will return a [`SceneSpawnError`] if either a type is not registered + /// This method will return a [`SceneSpawnError`] if a type either is not registered /// or doesn't reflect the [`Component`](bevy_ecs::component::Component) trait. pub fn write_to_world(&self, world: &mut World) -> Result { let mut instance_info = InstanceInfo { From 65cdf39696a3fce9e8a761d6fccb9c3312fec60b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Fri, 2 Sep 2022 00:43:46 +0200 Subject: [PATCH 6/7] no funny AppTypeRegistry business --- crates/bevy_scene/src/scene.rs | 15 ++++++++------- crates/bevy_scene/src/scene_spawner.rs | 4 +++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/crates/bevy_scene/src/scene.rs b/crates/bevy_scene/src/scene.rs index 50cbe2aed33e2..1e67402a11ad9 100644 --- a/crates/bevy_scene/src/scene.rs +++ b/crates/bevy_scene/src/scene.rs @@ -31,22 +31,23 @@ impl Scene { /// provided [`AppTypeRegistry`] or doesn't reflect the [`Component`](bevy_ecs::component::Component) trait. pub fn clone_with(&self, type_registry: &AppTypeRegistry) -> Result { let mut new_world = World::new(); - new_world.insert_resource(type_registry.clone()); - self.write_to_world(&mut new_world)?; - new_world.remove_resource::(); + self.write_to_world_with(&mut new_world, type_registry)?; Ok(Self { world: new_world }) } /// Write the entities and their corresponding components to the given world. /// - /// This method will return a [`SceneSpawnError`] if a type either is not registered - /// or doesn't reflect the [`Component`](bevy_ecs::component::Component) trait. - pub fn write_to_world(&self, world: &mut World) -> Result { + /// This method will return a [`SceneSpawnError`] if a type either is not registered in the + /// provided [`AppTypeRegistry`] or doesn't reflect the [`Component`](bevy_ecs::component::Component) trait. + pub fn write_to_world_with( + &self, + world: &mut World, + type_registry: &AppTypeRegistry, + ) -> Result { let mut instance_info = InstanceInfo { entity_map: EntityMap::default(), }; - let type_registry = world.resource::().clone(); let type_registry = type_registry.read(); for archetype in self.world.archetypes().iter() { for scene_entity in archetype.entities() { diff --git a/crates/bevy_scene/src/scene_spawner.rs b/crates/bevy_scene/src/scene_spawner.rs index 4b384246602e7..8ab2d0973ad27 100644 --- a/crates/bevy_scene/src/scene_spawner.rs +++ b/crates/bevy_scene/src/scene_spawner.rs @@ -1,4 +1,5 @@ use crate::{DynamicScene, Scene}; +use bevy_app::AppTypeRegistry; use bevy_asset::{AssetEvent, Assets, Handle}; use bevy_ecs::{ entity::{Entity, EntityMap}, @@ -169,7 +170,8 @@ impl SceneSpawner { handle: scene_handle.clone(), })?; - let instance_info = scene.write_to_world(world)?; + let instance_info = + scene.write_to_world_with(world, &world.resource::().clone())?; self.spawned_instances.insert(instance_id, instance_info); let spawned = self From f6069a8d24ffe16fd2695991bc0d88cb58e6da28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Fri, 2 Sep 2022 00:45:34 +0200 Subject: [PATCH 7/7] clarify direction of entity map --- crates/bevy_scene/src/scene_spawner.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_scene/src/scene_spawner.rs b/crates/bevy_scene/src/scene_spawner.rs index 8ab2d0973ad27..73eaa93e4cd18 100644 --- a/crates/bevy_scene/src/scene_spawner.rs +++ b/crates/bevy_scene/src/scene_spawner.rs @@ -15,7 +15,7 @@ use uuid::Uuid; /// Informations about a scene instance. #[derive(Debug)] pub struct InstanceInfo { - /// Mapping of entities between the scene world and the instance world. + /// Mapping of entities from the scene world to the instance world. pub entity_map: EntityMap, }