Skip to content

Commit 4b1b70d

Browse files
Trashtalk217alice-i-cecileCarter0
authored
Deprecate iter_entities and iter_entities_mut (#20260)
# Objective Both `iter_entities()` and `iter_entities_mut` are awkward functions as they both return _all_ entities, which is something you (should) rarely want. ## Solution Deprecate both functions and substitute them where they are used. ## Testing Not necessary. --------- Co-authored-by: Alice Cecile <[email protected]> Co-authored-by: Carter Weinberg <[email protected]>
1 parent 7b866ee commit 4b1b70d

File tree

6 files changed

+68
-10
lines changed

6 files changed

+68
-10
lines changed

benches/benches/bevy_ecs/world/despawn.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@ pub fn world_despawn(criterion: &mut Criterion) {
1717
bencher.iter_batched_ref(
1818
|| {
1919
let mut world = World::default();
20-
for _ in 0..entity_count {
21-
world.spawn((A(Mat4::default()), B(Vec4::default())));
22-
}
23-
let ents = world.iter_entities().map(|e| e.id()).collect::<Vec<_>>();
24-
(world, ents)
20+
let entities: Vec<Entity> = world
21+
.spawn_batch(
22+
(0..entity_count).map(|_| (A(Mat4::default()), B(Vec4::default()))),
23+
)
24+
.collect();
25+
(world, entities)
2526
},
26-
|(world, ents)| {
27-
ents.iter().for_each(|e| {
27+
|(world, entities)| {
28+
entities.iter().for_each(|e| {
2829
world.despawn(*e);
2930
});
3031
},

crates/bevy_ecs/src/entity_disabling.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
//!
3737
//! ## Default query filters
3838
//!
39-
//! In Bevy, entity disabling is implemented through the construction of a global "default query filter".
39+
//! In Bevy, entity disabling is implemented through the construction of a global "default query filter" resource.
4040
//! Queries which do not explicitly mention the disabled component will not include entities with that component.
4141
//! If an entity has multiple disabling components, it will only be included in queries that mention all of them.
4242
//!
@@ -50,6 +50,32 @@
5050
//! Entities with disabling components are still present in the [`World`] and can be accessed directly,
5151
//! using methods on [`World`] or [`Commands`](crate::prelude::Commands).
5252
//!
53+
//! As default query filters are implemented through a resource,
54+
//! it's possible to temporarily ignore any default filters by using [`World::resource_scope`](crate::prelude::World).
55+
//!
56+
//! ```
57+
//! use bevy_ecs::prelude::*;
58+
//! use bevy_ecs::entity_disabling::{DefaultQueryFilters, Disabled};
59+
//!
60+
//! let mut world = World::default();
61+
//!
62+
//! #[derive(Component)]
63+
//! struct CustomDisabled;
64+
//!
65+
//! world.register_disabling_component::<CustomDisabled>();
66+
//!
67+
//! world.spawn(Disabled);
68+
//! world.spawn(CustomDisabled);
69+
//!
70+
//! // resource_scope removes DefaultQueryFilters temporarily before re-inserting into the world.
71+
//! world.resource_scope(|world: &mut World, _: Mut<DefaultQueryFilters>| {
72+
//! // within this scope, we can query like no components are disabled.
73+
//! assert_eq!(world.query::<&Disabled>().query(&world).count(), 1);
74+
//! assert_eq!(world.query::<&CustomDisabled>().query(&world).count(), 1);
75+
//! assert_eq!(world.query::<()>().query(&world).count(), world.entities().len() as usize);
76+
//! })
77+
//! ```
78+
//!
5379
//! ### Warnings
5480
//!
5581
//! Currently, only queries for which the cache is built after enabling a default query filter will have entities

crates/bevy_ecs/src/world/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -969,6 +969,7 @@ impl World {
969969
/// Returns an [`Entity`] iterator of current entities.
970970
///
971971
/// This is useful in contexts where you only have read-only access to the [`World`].
972+
#[deprecated(since = "0.17.0", note = "use world.query::<EntityRef>()` instead")]
972973
#[inline]
973974
pub fn iter_entities(&self) -> impl Iterator<Item = EntityRef<'_>> + '_ {
974975
self.archetypes.iter().flat_map(|archetype| {
@@ -990,6 +991,7 @@ impl World {
990991
}
991992

992993
/// Returns a mutable iterator over all entities in the `World`.
994+
#[deprecated(since = "0.17.0", note = "use world.query::<EntityMut>()` instead")]
993995
pub fn iter_entities_mut(&mut self) -> impl Iterator<Item = EntityMut<'_>> + '_ {
994996
let last_change_tick = self.last_change_tick;
995997
let change_tick = self.change_tick();
@@ -4099,6 +4101,7 @@ mod tests {
40994101

41004102
let iterate_and_count_entities = |world: &World, entity_counters: &mut HashMap<_, _>| {
41014103
entity_counters.clear();
4104+
#[expect(deprecated, reason = "remove this test in in 0.17.0")]
41024105
for entity in world.iter_entities() {
41034106
let counter = entity_counters.entry(entity.id()).or_insert(0);
41044107
*counter += 1;
@@ -4176,6 +4179,7 @@ mod tests {
41764179
let b1 = world.spawn(B(1)).id();
41774180
let b2 = world.spawn(B(2)).id();
41784181

4182+
#[expect(deprecated, reason = "remove this test in 0.17.0")]
41794183
for mut entity in world.iter_entities_mut() {
41804184
if let Some(mut a) = entity.get_mut::<A>() {
41814185
a.0 -= 1;
@@ -4186,6 +4190,7 @@ mod tests {
41864190
assert_eq!(world.entity(b1).get(), Some(&B(1)));
41874191
assert_eq!(world.entity(b2).get(), Some(&B(2)));
41884192

4193+
#[expect(deprecated, reason = "remove this test in in 0.17.0")]
41894194
for mut entity in world.iter_entities_mut() {
41904195
if let Some(mut b) = entity.get_mut::<B>() {
41914196
b.0 *= 2;
@@ -4196,6 +4201,7 @@ mod tests {
41964201
assert_eq!(world.entity(b1).get(), Some(&B(2)));
41974202
assert_eq!(world.entity(b2).get(), Some(&B(4)));
41984203

4204+
#[expect(deprecated, reason = "remove this test in in 0.17.0")]
41994205
let mut entities = world.iter_entities_mut().collect::<Vec<_>>();
42004206
entities.sort_by_key(|e| e.get::<A>().map(|a| a.0).or(e.get::<B>().map(|b| b.0)));
42014207
let (a, b) = entities.split_at_mut(2);

crates/bevy_scene/src/dynamic_scene.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,15 @@ impl DynamicScene {
5454
/// Create a new dynamic scene from a given world.
5555
pub fn from_world(world: &World) -> Self {
5656
DynamicSceneBuilder::from_world(world)
57-
.extract_entities(world.iter_entities().map(|entity| entity.id()))
57+
.extract_entities(
58+
// we do this instead of a query, in order to completely sidestep default query filters.
59+
// while we could use `Allows<_>`, this wouldn't account for custom disabled components
60+
world
61+
.archetypes()
62+
.iter()
63+
.flat_map(bevy_ecs::archetype::Archetype::entities)
64+
.map(bevy_ecs::archetype::ArchetypeEntity::id),
65+
)
5866
.extract_resources()
5967
.build()
6068
}

crates/bevy_scene/src/lib.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,10 @@ mod tests {
121121
use bevy_asset::{AssetPlugin, Assets};
122122
use bevy_ecs::{
123123
component::Component,
124+
entity::Entity,
125+
entity_disabling::Internal,
124126
hierarchy::{ChildOf, Children},
127+
query::Allows,
125128
reflect::{AppTypeRegistry, ReflectComponent},
126129
world::World,
127130
};
@@ -302,8 +305,13 @@ mod tests {
302305
scene
303306
.world
304307
.insert_resource(world.resource::<AppTypeRegistry>().clone());
308+
let entities: Vec<Entity> = scene
309+
.world
310+
.query_filtered::<Entity, Allows<Internal>>()
311+
.iter(&scene.world)
312+
.collect();
305313
DynamicSceneBuilder::from_world(&scene.world)
306-
.extract_entities(scene.world.iter_entities().map(|entity| entity.id()))
314+
.extract_entities(entities.into_iter())
307315
.build()
308316
};
309317

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
title: Deprecate `iter_entities` and `iter_entities_mut`.
3+
pull_requests: [20260]
4+
---
5+
6+
In Bevy 0.17.0 we deprecate `world.iter_entities()` and `world.iter_entities_mut()`.
7+
Use `world.query::<EntityMut>().iter(&world)` and `world.query::<EntityRef>().iter(&mut world)` instead.
8+
9+
This may not return every single entity, because of [default filter queries](https://docs.rs/bevy/latest/bevy/ecs/entity_disabling/index.html). If you really intend to query disabled entities too, consider removing the `DefaultQueryFilters` resource from the world before querying the elements. You can also add an `Allows<Component>` filter to allow a specific disabled `Component`, to show up in the query.

0 commit comments

Comments
 (0)