mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 15:14:50 +00:00
Cleanup dynamic scene before building (#6254)
# Objective - Dynamic scene builder can build scenes without components, if they didn't have any matching the type registry - Those entities are not really useful in the final `DynamicScene` ## Solution - Add a method `remove_empty_entities` that will remove empty entities. It's not called by default when calling `build`, I'm not sure if that's a good idea or not.
This commit is contained in:
parent
5b8b7dc08f
commit
e8b28547bf
1 changed files with 46 additions and 12 deletions
|
@ -31,9 +31,9 @@ use std::collections::BTreeMap;
|
||||||
/// let dynamic_scene = builder.build();
|
/// let dynamic_scene = builder.build();
|
||||||
/// ```
|
/// ```
|
||||||
pub struct DynamicSceneBuilder<'w> {
|
pub struct DynamicSceneBuilder<'w> {
|
||||||
entities: BTreeMap<u32, DynamicEntity>,
|
extracted_scene: BTreeMap<u32, DynamicEntity>,
|
||||||
type_registry: AppTypeRegistry,
|
type_registry: AppTypeRegistry,
|
||||||
world: &'w World,
|
original_world: &'w World,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w> DynamicSceneBuilder<'w> {
|
impl<'w> DynamicSceneBuilder<'w> {
|
||||||
|
@ -41,9 +41,9 @@ impl<'w> DynamicSceneBuilder<'w> {
|
||||||
/// All components registered in that world's [`AppTypeRegistry`] resource will be extracted.
|
/// All components registered in that world's [`AppTypeRegistry`] resource will be extracted.
|
||||||
pub fn from_world(world: &'w World) -> Self {
|
pub fn from_world(world: &'w World) -> Self {
|
||||||
Self {
|
Self {
|
||||||
entities: default(),
|
extracted_scene: default(),
|
||||||
type_registry: world.resource::<AppTypeRegistry>().clone(),
|
type_registry: world.resource::<AppTypeRegistry>().clone(),
|
||||||
world,
|
original_world: world,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,16 +51,19 @@ impl<'w> DynamicSceneBuilder<'w> {
|
||||||
/// Only components registered in the given [`AppTypeRegistry`] will be extracted.
|
/// Only components registered in the given [`AppTypeRegistry`] will be extracted.
|
||||||
pub fn from_world_with_type_registry(world: &'w World, type_registry: AppTypeRegistry) -> Self {
|
pub fn from_world_with_type_registry(world: &'w World, type_registry: AppTypeRegistry) -> Self {
|
||||||
Self {
|
Self {
|
||||||
entities: default(),
|
extracted_scene: default(),
|
||||||
type_registry,
|
type_registry,
|
||||||
world,
|
original_world: world,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consume the builder, producing a [`DynamicScene`].
|
/// 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 {
|
pub fn build(self) -> DynamicScene {
|
||||||
DynamicScene {
|
DynamicScene {
|
||||||
entities: self.entities.into_values().collect(),
|
entities: self.extracted_scene.into_values().collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +74,16 @@ impl<'w> DynamicSceneBuilder<'w> {
|
||||||
self.extract_entities(std::iter::once(entity))
|
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
|
||||||
|
.retain(|_, entity| !entity.components.is_empty());
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Extract entities from the builder's [`World`].
|
/// Extract entities from the builder's [`World`].
|
||||||
///
|
///
|
||||||
/// Re-extracting an entity that was already extracted will have no effect.
|
/// Re-extracting an entity that was already extracted will have no effect.
|
||||||
|
@ -102,7 +115,7 @@ impl<'w> DynamicSceneBuilder<'w> {
|
||||||
for entity in entities {
|
for entity in entities {
|
||||||
let index = entity.index();
|
let index = entity.index();
|
||||||
|
|
||||||
if self.entities.contains_key(&index) {
|
if self.extracted_scene.contains_key(&index) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,21 +124,22 @@ impl<'w> DynamicSceneBuilder<'w> {
|
||||||
components: Vec::new(),
|
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
|
let reflect_component = self
|
||||||
.world
|
.original_world
|
||||||
.components()
|
.components()
|
||||||
.get_info(component_id)
|
.get_info(component_id)
|
||||||
.and_then(|info| type_registry.get(info.type_id().unwrap()))
|
.and_then(|info| type_registry.get(info.type_id().unwrap()))
|
||||||
.and_then(|registration| registration.data::<ReflectComponent>());
|
.and_then(|registration| registration.data::<ReflectComponent>());
|
||||||
|
|
||||||
if let Some(reflect_component) = reflect_component {
|
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());
|
entry.components.push(component.clone_value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.entities.insert(index, entry);
|
self.extracted_scene.insert(index, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(type_registry);
|
drop(type_registry);
|
||||||
|
@ -270,4 +284,24 @@ mod tests {
|
||||||
scene_entities.sort();
|
scene_entities.sort();
|
||||||
assert_eq!(scene_entities, [entity_a_b.index(), entity_a.index()]);
|
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::<ComponentA>();
|
||||||
|
world.insert_resource(atr);
|
||||||
|
|
||||||
|
let entity_a = world.spawn(ComponentA).id();
|
||||||
|
let entity_b = world.spawn(ComponentB).id();
|
||||||
|
|
||||||
|
let mut builder = DynamicSceneBuilder::from_world(&world);
|
||||||
|
builder.extract_entities([entity_a, entity_b].into_iter());
|
||||||
|
builder.remove_empty_entities();
|
||||||
|
let scene = builder.build();
|
||||||
|
|
||||||
|
assert_eq!(scene.entities.len(), 1);
|
||||||
|
assert_eq!(scene.entities[0].entity, entity_a.index());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue