Add iter_entities to World #6228 (#6242)

# Objective

- Add a way to iterate over all entities from &World

## Solution

- Added a function `iter_entities` on World which returns an iterator of `Entity` derived from the entities in the `World`'s `archetypes`

---

## Changelog

- Added a function `iter_entities` on World, allowing iterating over all entities in contexts where you only have read-only access to the World.
This commit is contained in:
mike 2022-10-17 13:47:00 +00:00
parent 05c7babba2
commit a0f1468108
2 changed files with 81 additions and 7 deletions

View file

@ -320,6 +320,16 @@ impl World {
Some(EntityRef::new(self, entity, location)) Some(EntityRef::new(self, entity, location))
} }
/// Returns an [`Entity`] iterator of current entities.
///
/// This is useful in contexts where you only have read-only access to the [`World`].
#[inline]
pub fn iter_entities(&self) -> impl Iterator<Item = Entity> + '_ {
self.archetypes
.iter()
.flat_map(|archetype| archetype.entities().iter().copied())
}
/// Retrieves an [`EntityMut`] that exposes read and write operations for the given `entity`. /// Retrieves an [`EntityMut`] that exposes read and write operations for the given `entity`.
/// Returns [`None`] if the `entity` does not exist. Use [`World::entity_mut`] if you don't want /// Returns [`None`] if the `entity` does not exist. Use [`World::entity_mut`] if you don't want
/// to unwrap the [`EntityMut`] yourself. /// to unwrap the [`EntityMut`] yourself.
@ -1634,7 +1644,7 @@ mod tests {
system::Resource, system::Resource,
}; };
use bevy_ecs_macros::Component; use bevy_ecs_macros::Component;
use bevy_utils::HashSet; use bevy_utils::{HashMap, HashSet};
use std::{ use std::{
any::TypeId, any::TypeId,
panic, panic,
@ -1907,4 +1917,73 @@ mod tests {
[Some(baz_id)].into() [Some(baz_id)].into()
); );
} }
#[test]
fn iterate_entities() {
let mut world = World::new();
let mut entity_counters = HashMap::new();
let iterate_and_count_entities = |world: &World, entity_counters: &mut HashMap<_, _>| {
entity_counters.clear();
for entity in world.iter_entities() {
let counter = entity_counters.entry(entity).or_insert(0);
*counter += 1;
}
};
// Adding one entity and validating iteration
let ent0 = world.spawn((Foo, Bar, Baz)).id();
iterate_and_count_entities(&world, &mut entity_counters);
assert_eq!(entity_counters[&ent0], 1);
assert_eq!(entity_counters.len(), 1);
// Spawning three more entities and then validating iteration
let ent1 = world.spawn((Foo, Bar)).id();
let ent2 = world.spawn((Bar, Baz)).id();
let ent3 = world.spawn((Foo, Baz)).id();
iterate_and_count_entities(&world, &mut entity_counters);
assert_eq!(entity_counters[&ent0], 1);
assert_eq!(entity_counters[&ent1], 1);
assert_eq!(entity_counters[&ent2], 1);
assert_eq!(entity_counters[&ent3], 1);
assert_eq!(entity_counters.len(), 4);
// Despawning first entity and then validating the iteration
assert!(world.despawn(ent0));
iterate_and_count_entities(&world, &mut entity_counters);
assert_eq!(entity_counters[&ent1], 1);
assert_eq!(entity_counters[&ent2], 1);
assert_eq!(entity_counters[&ent3], 1);
assert_eq!(entity_counters.len(), 3);
// Spawning three more entities, despawning three and then validating the iteration
let ent4 = world.spawn(Foo).id();
let ent5 = world.spawn(Bar).id();
let ent6 = world.spawn(Baz).id();
assert!(world.despawn(ent2));
assert!(world.despawn(ent3));
assert!(world.despawn(ent4));
iterate_and_count_entities(&world, &mut entity_counters);
assert_eq!(entity_counters[&ent1], 1);
assert_eq!(entity_counters[&ent5], 1);
assert_eq!(entity_counters[&ent6], 1);
assert_eq!(entity_counters.len(), 3);
// Despawning remaining entities and then validating the iteration
assert!(world.despawn(ent1));
assert!(world.despawn(ent5));
assert!(world.despawn(ent6));
iterate_and_count_entities(&world, &mut entity_counters);
assert_eq!(entity_counters.len(), 0);
}
} }

View file

@ -42,12 +42,7 @@ impl DynamicScene {
let mut builder = let mut builder =
DynamicSceneBuilder::from_world_with_type_registry(world, type_registry.clone()); DynamicSceneBuilder::from_world_with_type_registry(world, type_registry.clone());
builder.extract_entities( builder.extract_entities(world.iter_entities());
world
.archetypes()
.iter()
.flat_map(|archetype| archetype.entities().iter().copied()),
);
builder.build() builder.build()
} }