From a509f0a8da4690958fb972e089754b2d863052bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Thu, 13 Oct 2022 22:18:39 +0200 Subject: [PATCH 1/7] rename fields --- .../bevy_scene/src/dynamic_scene_builder.rs | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/crates/bevy_scene/src/dynamic_scene_builder.rs b/crates/bevy_scene/src/dynamic_scene_builder.rs index 841af6756f3ba..dad830756840f 100644 --- a/crates/bevy_scene/src/dynamic_scene_builder.rs +++ b/crates/bevy_scene/src/dynamic_scene_builder.rs @@ -31,9 +31,9 @@ use std::collections::BTreeMap; /// let dynamic_scene = builder.build(); /// ``` pub struct DynamicSceneBuilder<'w> { - entities: BTreeMap, + extracted_scene: BTreeMap, type_registry: AppTypeRegistry, - world: &'w World, + original_world: &'w World, } impl<'w> DynamicSceneBuilder<'w> { @@ -41,9 +41,9 @@ impl<'w> DynamicSceneBuilder<'w> { /// All components registered in that world's [`AppTypeRegistry`] resource will be extracted. pub fn from_world(world: &'w World) -> Self { Self { - entities: default(), + extracted_scene: default(), type_registry: world.resource::().clone(), - world, + original_world: world, } } @@ -51,16 +51,16 @@ impl<'w> DynamicSceneBuilder<'w> { /// Only components registered in the given [`AppTypeRegistry`] will be extracted. pub fn from_world_with_type_registry(world: &'w World, type_registry: AppTypeRegistry) -> Self { Self { - entities: default(), + extracted_scene: default(), type_registry, - world, + original_world: world, } } /// Consume the builder, producing a [`DynamicScene`]. pub fn build(self) -> DynamicScene { DynamicScene { - entities: self.entities.into_values().collect(), + entities: self.extracted_scene.into_values().collect(), } } @@ -102,7 +102,7 @@ impl<'w> DynamicSceneBuilder<'w> { for entity in entities { let index = entity.index(); - if self.entities.contains_key(&index) { + if self.extracted_scene.contains_key(&index) { continue; } @@ -111,21 +111,22 @@ impl<'w> DynamicSceneBuilder<'w> { components: Vec::new(), }; - for component_id in self.world.entity(entity).archetype().components() { + for component_id in self.original_world.entity(entity).archetype().components() { let reflect_component = self - .world + .original_world .components() .get_info(component_id) .and_then(|info| type_registry.get(info.type_id().unwrap())) .and_then(|registration| registration.data::()); if let Some(reflect_component) = reflect_component { - if let Some(component) = reflect_component.reflect(self.world, entity) { + if let Some(component) = reflect_component.reflect(self.original_world, entity) + { entry.components.push(component.clone_value()); } } } - self.entities.insert(index, entry); + self.extracted_scene.insert(index, entry); } drop(type_registry); From a172a0351e707502f1b2a82309f20ff1f2ce75f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Thu, 13 Oct 2022 23:29:57 +0200 Subject: [PATCH 2/7] can remove empty entities from a dynamic scene builder --- .../bevy_scene/src/dynamic_scene_builder.rs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/crates/bevy_scene/src/dynamic_scene_builder.rs b/crates/bevy_scene/src/dynamic_scene_builder.rs index dad830756840f..b90531f21fdb9 100644 --- a/crates/bevy_scene/src/dynamic_scene_builder.rs +++ b/crates/bevy_scene/src/dynamic_scene_builder.rs @@ -71,6 +71,15 @@ impl<'w> DynamicSceneBuilder<'w> { self.extract_entities(std::iter::once(entity)) } + pub fn remove_empty_entities(&mut self) -> &mut Self { + self.extracted_scene = self + .extracted_scene + .drain_filter(|_, entity| !entity.components.is_empty()) + .collect(); + + self + } + /// Extract entities from the builder's [`World`]. /// /// Re-extracting an entity that was already extracted will have no effect. @@ -271,4 +280,22 @@ mod tests { scene_entities.sort(); assert_eq!(scene_entities, [entity_a_b.index(), entity_a.index()]); } + + #[test] + fn remove_componentless_entity() { + let mut world = World::default(); + + let atr = AppTypeRegistry::default(); + atr.write().register::(); + world.insert_resource(atr); + + let entity = world.spawn(ComponentB).id(); + + let mut builder = DynamicSceneBuilder::from_world(&world); + builder.extract_entity(entity); + builder.remove_empty_entities(); + let scene = builder.build(); + + assert_eq!(scene.entities.len(), 0); + } } From b3ec897ec9c4f512b8c2f1208299cfe25b3f8809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sat, 15 Oct 2022 23:06:29 +0200 Subject: [PATCH 3/7] doc! Co-authored-by: Alice Cecile --- crates/bevy_scene/src/dynamic_scene_builder.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/bevy_scene/src/dynamic_scene_builder.rs b/crates/bevy_scene/src/dynamic_scene_builder.rs index b90531f21fdb9..d9bd5c5783479 100644 --- a/crates/bevy_scene/src/dynamic_scene_builder.rs +++ b/crates/bevy_scene/src/dynamic_scene_builder.rs @@ -71,6 +71,9 @@ impl<'w> DynamicSceneBuilder<'w> { self.extract_entities(std::iter::once(entity)) } + /// Despawns all enitities with no components. + /// + /// These were likely created because none of their components were present in the provided type registry upon extraction. pub fn remove_empty_entities(&mut self) -> &mut Self { self.extracted_scene = self .extracted_scene From 1372f942d4fc6aa4310cc55b37e378d0aaabce31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sat, 15 Oct 2022 23:43:36 +0200 Subject: [PATCH 4/7] test that entity not empty is kept --- crates/bevy_scene/src/dynamic_scene_builder.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/bevy_scene/src/dynamic_scene_builder.rs b/crates/bevy_scene/src/dynamic_scene_builder.rs index d9bd5c5783479..5616cfc1077eb 100644 --- a/crates/bevy_scene/src/dynamic_scene_builder.rs +++ b/crates/bevy_scene/src/dynamic_scene_builder.rs @@ -292,13 +292,15 @@ mod tests { atr.write().register::(); world.insert_resource(atr); - let entity = world.spawn(ComponentB).id(); + let entity_a = world.spawn(ComponentA).id(); + let entity_b = world.spawn(ComponentB).id(); let mut builder = DynamicSceneBuilder::from_world(&world); - builder.extract_entity(entity); + builder.extract_entities([entity_a, entity_b].into_iter()); builder.remove_empty_entities(); let scene = builder.build(); - assert_eq!(scene.entities.len(), 0); + assert_eq!(scene.entities.len(), 1); + assert_eq!(scene.entities[0].entity, entity_a.id()); } } From 333b754cd9afa3eec9236d51616fd66be733b1b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sat, 15 Oct 2022 23:47:38 +0200 Subject: [PATCH 5/7] build doc links to remove_empty_entities --- crates/bevy_scene/src/dynamic_scene_builder.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/bevy_scene/src/dynamic_scene_builder.rs b/crates/bevy_scene/src/dynamic_scene_builder.rs index 5616cfc1077eb..4592569afa8aa 100644 --- a/crates/bevy_scene/src/dynamic_scene_builder.rs +++ b/crates/bevy_scene/src/dynamic_scene_builder.rs @@ -58,6 +58,9 @@ impl<'w> DynamicSceneBuilder<'w> { } /// Consume the builder, producing a [`DynamicScene`]. + /// + /// To make sure the dynamic scene doesn't contain entities without any components, call + /// [`Self::remove_empty_entities`] before building the scene. pub fn build(self) -> DynamicScene { DynamicScene { entities: self.extracted_scene.into_values().collect(), From 774154a46ab745989cbd6a7f1d63892ecf272a6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sat, 17 Dec 2022 09:14:23 +0100 Subject: [PATCH 6/7] use HashMap::retain --- crates/bevy_scene/src/dynamic_scene_builder.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/bevy_scene/src/dynamic_scene_builder.rs b/crates/bevy_scene/src/dynamic_scene_builder.rs index 4592569afa8aa..f850b328b410a 100644 --- a/crates/bevy_scene/src/dynamic_scene_builder.rs +++ b/crates/bevy_scene/src/dynamic_scene_builder.rs @@ -78,10 +78,8 @@ impl<'w> DynamicSceneBuilder<'w> { /// /// These were likely created because none of their components were present in the provided type registry upon extraction. pub fn remove_empty_entities(&mut self) -> &mut Self { - self.extracted_scene = self - .extracted_scene - .drain_filter(|_, entity| !entity.components.is_empty()) - .collect(); + self.extracted_scene + .retain(|_, entity| !entity.components.is_empty()); self } From 9fd7db7860644979a40a0564e2a2166c99db2aac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sat, 17 Dec 2022 09:18:50 +0100 Subject: [PATCH 7/7] update method name --- crates/bevy_scene/src/dynamic_scene_builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_scene/src/dynamic_scene_builder.rs b/crates/bevy_scene/src/dynamic_scene_builder.rs index f850b328b410a..5ea65a8714eab 100644 --- a/crates/bevy_scene/src/dynamic_scene_builder.rs +++ b/crates/bevy_scene/src/dynamic_scene_builder.rs @@ -302,6 +302,6 @@ mod tests { let scene = builder.build(); assert_eq!(scene.entities.len(), 1); - assert_eq!(scene.entities[0].entity, entity_a.id()); + assert_eq!(scene.entities[0].entity, entity_a.index()); } }