From 96a9c98996e19c601aeb5bb33678b445c6e6e614 Mon Sep 17 00:00:00 2001 From: Trashtalk Date: Wed, 23 Jul 2025 09:34:49 +0000 Subject: [PATCH 01/11] deprecate iter_entities and iter_entities_mut --- crates/bevy_ecs/src/world/mod.rs | 6 ++++++ crates/bevy_scene/src/dynamic_scene.rs | 10 +++++++++- crates/bevy_scene/src/lib.rs | 10 +++++++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index f6e3a197efc82..cffde88d4b268 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -977,6 +977,7 @@ impl World { /// Returns an [`Entity`] iterator of current entities. /// /// This is useful in contexts where you only have read-only access to the [`World`]. + #[deprecated(since = "0.17.0", note = "use world.query::()` instead")] #[inline] pub fn iter_entities(&self) -> impl Iterator> + '_ { self.archetypes.iter().flat_map(|archetype| { @@ -998,6 +999,7 @@ impl World { } /// Returns a mutable iterator over all entities in the `World`. + #[deprecated(since = "0.17.0", note = "use world.query::()` instead")] pub fn iter_entities_mut(&mut self) -> impl Iterator> + '_ { let last_change_tick = self.last_change_tick; let change_tick = self.change_tick(); @@ -4107,6 +4109,7 @@ mod tests { let iterate_and_count_entities = |world: &World, entity_counters: &mut HashMap<_, _>| { entity_counters.clear(); + #[allow(deprecated)] // TODO: remove this test in 0.17.0 for entity in world.iter_entities() { let counter = entity_counters.entry(entity.id()).or_insert(0); *counter += 1; @@ -4184,6 +4187,7 @@ mod tests { let b1 = world.spawn(B(1)).id(); let b2 = world.spawn(B(2)).id(); + #[allow(deprecated)] // TODO: remove this test in 0.17.0 for mut entity in world.iter_entities_mut() { if let Some(mut a) = entity.get_mut::() { a.0 -= 1; @@ -4194,6 +4198,7 @@ mod tests { assert_eq!(world.entity(b1).get(), Some(&B(1))); assert_eq!(world.entity(b2).get(), Some(&B(2))); + #[allow(deprecated)] for mut entity in world.iter_entities_mut() { if let Some(mut b) = entity.get_mut::() { b.0 *= 2; @@ -4204,6 +4209,7 @@ mod tests { assert_eq!(world.entity(b1).get(), Some(&B(2))); assert_eq!(world.entity(b2).get(), Some(&B(4))); + #[allow(deprecated)] let mut entities = world.iter_entities_mut().collect::>(); entities.sort_by_key(|e| e.get::().map(|a| a.0).or(e.get::().map(|b| b.0))); let (a, b) = entities.split_at_mut(2); diff --git a/crates/bevy_scene/src/dynamic_scene.rs b/crates/bevy_scene/src/dynamic_scene.rs index f0cf3960d60ea..f8880b168fff5 100644 --- a/crates/bevy_scene/src/dynamic_scene.rs +++ b/crates/bevy_scene/src/dynamic_scene.rs @@ -54,7 +54,15 @@ impl DynamicScene { /// Create a new dynamic scene from a given world. pub fn from_world(world: &World) -> Self { DynamicSceneBuilder::from_world(world) - .extract_entities(world.iter_entities().map(|entity| entity.id())) + .extract_entities( + // we do this instead of a query, in order to completely sidestep default query filters. + // while we could use `Allows<_>`, this wouldn't account for custom disabled components + world + .archetypes() + .iter() + .flat_map(|archetype| archetype.entities()) + .map(|archetype_entity| archetype_entity.id()), + ) .extract_resources() .build() } diff --git a/crates/bevy_scene/src/lib.rs b/crates/bevy_scene/src/lib.rs index 9e6fe16d1a0a6..b088fb9871055 100644 --- a/crates/bevy_scene/src/lib.rs +++ b/crates/bevy_scene/src/lib.rs @@ -121,7 +121,10 @@ mod tests { use bevy_asset::{AssetPlugin, Assets}; use bevy_ecs::{ component::Component, + entity::Entity, + entity_disabling::Internal, hierarchy::{ChildOf, Children}, + query::Allows, reflect::{AppTypeRegistry, ReflectComponent}, world::World, }; @@ -302,8 +305,13 @@ mod tests { scene .world .insert_resource(world.resource::().clone()); + let entities: Vec = scene + .world + .query_filtered::>() + .iter(&scene.world) + .collect(); DynamicSceneBuilder::from_world(&scene.world) - .extract_entities(scene.world.iter_entities().map(|entity| entity.id())) + .extract_entities(entities.into_iter()) .build() }; From 694e3cb77a68819d5dfc3449d519c99667b6f8fa Mon Sep 17 00:00:00 2001 From: Trashtalk Date: Wed, 23 Jul 2025 18:02:55 +0000 Subject: [PATCH 02/11] cargo clippy --- crates/bevy_scene/src/dynamic_scene.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_scene/src/dynamic_scene.rs b/crates/bevy_scene/src/dynamic_scene.rs index f8880b168fff5..fc3b223ce2b60 100644 --- a/crates/bevy_scene/src/dynamic_scene.rs +++ b/crates/bevy_scene/src/dynamic_scene.rs @@ -60,8 +60,8 @@ impl DynamicScene { world .archetypes() .iter() - .flat_map(|archetype| archetype.entities()) - .map(|archetype_entity| archetype_entity.id()), + .flat_map(bevy_ecs::archetype::Archetype::entities) + .map(bevy_ecs::archetype::ArchetypeEntity::id), ) .extract_resources() .build() From aad2c69fe1eccb8b325131bc69ccf465a264a649 Mon Sep 17 00:00:00 2001 From: Trashtalk Date: Wed, 23 Jul 2025 18:13:26 +0000 Subject: [PATCH 03/11] add migration guide --- .../migration-guides/deprecate_iter_entities.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 release-content/migration-guides/deprecate_iter_entities.md diff --git a/release-content/migration-guides/deprecate_iter_entities.md b/release-content/migration-guides/deprecate_iter_entities.md new file mode 100644 index 0000000000000..b20371673d4eb --- /dev/null +++ b/release-content/migration-guides/deprecate_iter_entities.md @@ -0,0 +1,9 @@ +--- +title: Deprecate `iter_entities` and `iter_entities_mut`. +pull_requests: [20260] +--- + +In Bevy 0.17.0 we depcrecate `world.iter_entities()` and `world.iter_entities_mut()`. +Use `world.query::().iter(&world)` and `world.query::().iter(&mut world)` instead. + +This may not return every single entity, because of [default filter queries](). If you really intend to query disabled entities too, consider removing the `DefaultQueryFilter` resource from the world before querying the elements. You can also add an `Allows` filter to allow a specific disabled `Component`, to show up in the query. From 06361b10e9f81f9ebf6d23f72bbc488bb97030de Mon Sep 17 00:00:00 2001 From: Trashtalk Date: Wed, 23 Jul 2025 18:17:05 +0000 Subject: [PATCH 04/11] appease CI --- crates/bevy_ecs/src/world/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index cffde88d4b268..ed662499267d8 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -4109,7 +4109,7 @@ mod tests { let iterate_and_count_entities = |world: &World, entity_counters: &mut HashMap<_, _>| { entity_counters.clear(); - #[allow(deprecated)] // TODO: remove this test in 0.17.0 + #[expect(deprecated, reason = "remove this test in in 0.17.0")] for entity in world.iter_entities() { let counter = entity_counters.entry(entity.id()).or_insert(0); *counter += 1; @@ -4187,7 +4187,7 @@ mod tests { let b1 = world.spawn(B(1)).id(); let b2 = world.spawn(B(2)).id(); - #[allow(deprecated)] // TODO: remove this test in 0.17.0 + #[expect(deprecated, reason = "remove this test in in 0.17.0")] for mut entity in world.iter_entities_mut() { if let Some(mut a) = entity.get_mut::() { a.0 -= 1; @@ -4198,7 +4198,7 @@ mod tests { assert_eq!(world.entity(b1).get(), Some(&B(1))); assert_eq!(world.entity(b2).get(), Some(&B(2))); - #[allow(deprecated)] + #[expect(deprecated, reason = "remove this test in in 0.17.0")] for mut entity in world.iter_entities_mut() { if let Some(mut b) = entity.get_mut::() { b.0 *= 2; @@ -4209,7 +4209,7 @@ mod tests { assert_eq!(world.entity(b1).get(), Some(&B(2))); assert_eq!(world.entity(b2).get(), Some(&B(4))); - #[allow(deprecated)] + #[expect(deprecated, reason = "remove this test in in 0.17.0")] let mut entities = world.iter_entities_mut().collect::>(); entities.sort_by_key(|e| e.get::().map(|a| a.0).or(e.get::().map(|b| b.0))); let (a, b) = entities.split_at_mut(2); From 9d5807680a9118f80de04d658b46603a4fbc0697 Mon Sep 17 00:00:00 2001 From: Trashtalk Date: Wed, 23 Jul 2025 18:19:31 +0000 Subject: [PATCH 05/11] forgot to add a link --- release-content/migration-guides/deprecate_iter_entities.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-content/migration-guides/deprecate_iter_entities.md b/release-content/migration-guides/deprecate_iter_entities.md index b20371673d4eb..01720b4b61dde 100644 --- a/release-content/migration-guides/deprecate_iter_entities.md +++ b/release-content/migration-guides/deprecate_iter_entities.md @@ -6,4 +6,4 @@ pull_requests: [20260] In Bevy 0.17.0 we depcrecate `world.iter_entities()` and `world.iter_entities_mut()`. Use `world.query::().iter(&world)` and `world.query::().iter(&mut world)` instead. -This may not return every single entity, because of [default filter queries](). If you really intend to query disabled entities too, consider removing the `DefaultQueryFilter` resource from the world before querying the elements. You can also add an `Allows` filter to allow a specific disabled `Component`, to show up in the query. +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 `DefaultQueryFilter` resource from the world before querying the elements. You can also add an `Allows` filter to allow a specific disabled `Component`, to show up in the query. From f3e2970bb48c34c5aa2aed16b6367bda33eae098 Mon Sep 17 00:00:00 2001 From: Trashtalk Date: Wed, 23 Jul 2025 18:32:21 +0000 Subject: [PATCH 06/11] fixed bench --- benches/benches/bevy_ecs/world/despawn.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/benches/benches/bevy_ecs/world/despawn.rs b/benches/benches/bevy_ecs/world/despawn.rs index 7b79ed95d9af5..892b791314d4f 100644 --- a/benches/benches/bevy_ecs/world/despawn.rs +++ b/benches/benches/bevy_ecs/world/despawn.rs @@ -17,14 +17,15 @@ pub fn world_despawn(criterion: &mut Criterion) { bencher.iter_batched_ref( || { let mut world = World::default(); - for _ in 0..entity_count { - world.spawn((A(Mat4::default()), B(Vec4::default()))); - } - let ents = world.iter_entities().map(|e| e.id()).collect::>(); - (world, ents) + let entities: Vec = world + .spawn_batch( + (0..entity_count).map(|_| (A(Mat4::default()), B(Vec4::default()))), + ) + .collect(); + (world, entities) }, - |(world, ents)| { - ents.iter().for_each(|e| { + |(world, entities)| { + entities.iter().for_each(|e| { world.despawn(*e); }); }, From 82d54563606cac7ae4bdacdaa61137d7328d2511 Mon Sep 17 00:00:00 2001 From: Trashtalk217 Date: Wed, 23 Jul 2025 18:37:42 +0000 Subject: [PATCH 07/11] Update release-content/migration-guides/deprecate_iter_entities.md Co-authored-by: Alice Cecile --- release-content/migration-guides/deprecate_iter_entities.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-content/migration-guides/deprecate_iter_entities.md b/release-content/migration-guides/deprecate_iter_entities.md index 01720b4b61dde..ec03f98c0e330 100644 --- a/release-content/migration-guides/deprecate_iter_entities.md +++ b/release-content/migration-guides/deprecate_iter_entities.md @@ -6,4 +6,4 @@ pull_requests: [20260] In Bevy 0.17.0 we depcrecate `world.iter_entities()` and `world.iter_entities_mut()`. Use `world.query::().iter(&world)` and `world.query::().iter(&mut world)` instead. -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 `DefaultQueryFilter` resource from the world before querying the elements. You can also add an `Allows` filter to allow a specific disabled `Component`, to show up in the query. +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` filter to allow a specific disabled `Component`, to show up in the query. From a37cbbb2c4d46ab4346b2948e7130dc92608565e Mon Sep 17 00:00:00 2001 From: Trashtalk217 Date: Wed, 23 Jul 2025 18:43:31 +0000 Subject: [PATCH 08/11] Update crates/bevy_ecs/src/world/mod.rs Co-authored-by: Carter Weinberg --- crates/bevy_ecs/src/world/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index ed662499267d8..44ef11aa4567b 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -4187,7 +4187,7 @@ mod tests { let b1 = world.spawn(B(1)).id(); let b2 = world.spawn(B(2)).id(); - #[expect(deprecated, reason = "remove this test in in 0.17.0")] + #[expect(deprecated, reason = "remove this test in 0.17.0")] for mut entity in world.iter_entities_mut() { if let Some(mut a) = entity.get_mut::() { a.0 -= 1; From 8dd913a1d42e0216dacc7f399b278844be8e7b59 Mon Sep 17 00:00:00 2001 From: Trashtalk217 Date: Wed, 23 Jul 2025 18:44:27 +0000 Subject: [PATCH 09/11] Update release-content/migration-guides/deprecate_iter_entities.md Co-authored-by: Carter Weinberg --- release-content/migration-guides/deprecate_iter_entities.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-content/migration-guides/deprecate_iter_entities.md b/release-content/migration-guides/deprecate_iter_entities.md index ec03f98c0e330..0b4a167a65c38 100644 --- a/release-content/migration-guides/deprecate_iter_entities.md +++ b/release-content/migration-guides/deprecate_iter_entities.md @@ -3,7 +3,7 @@ title: Deprecate `iter_entities` and `iter_entities_mut`. pull_requests: [20260] --- -In Bevy 0.17.0 we depcrecate `world.iter_entities()` and `world.iter_entities_mut()`. +In Bevy 0.17.0 we deprecate `world.iter_entities()` and `world.iter_entities_mut()`. Use `world.query::().iter(&world)` and `world.query::().iter(&mut world)` instead. 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` filter to allow a specific disabled `Component`, to show up in the query. From f82bf619ec2944cb7c7e12a645531482178bc9f0 Mon Sep 17 00:00:00 2001 From: Trashtalk Date: Wed, 23 Jul 2025 19:23:51 +0000 Subject: [PATCH 10/11] added doctest --- crates/bevy_ecs/src/entity_disabling.rs | 26 ++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index a27eb54c8f8ea..fbc183fac7403 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -36,7 +36,7 @@ //! //! ## Default query filters //! -//! In Bevy, entity disabling is implemented through the construction of a global "default query filter". +//! In Bevy, entity disabling is implemented through the construction of a global "default query filter" resource. //! Queries which do not explicitly mention the disabled component will not include entities with that component. //! If an entity has multiple disabling components, it will only be included in queries that mention all of them. //! @@ -50,6 +50,30 @@ //! Entities with disabling components are still present in the [`World`] and can be accessed directly, //! using methods on [`World`] or [`Commands`](crate::prelude::Commands). //! +//! As default query filters are implemented through a resource, it's possible to temporarily ignore any default filters by using [`World::resource_scope`](crate::prelude::World). +//! +//! ``` +//! use bevy_ecs::prelude::*; +//! +//! let mut world = World::default(); +//! +//! #[derive(Component)] +//! struct CustomDisabled; +//! +//! world.register_default_query_filter::(); +//! +//! world.spawn(Disabled); +//! world.spawn(CustomDisabled); +//! +//! // resource_scope removes DefaultQueryFilters temporarily before re-inserting into the world. +//! world.resource_scope(|world: &mut World, _: Mut| { +//! // within this scope, we can query like no components are disabled. +//! assert_eq!(world.query::().query(&world).count(), 1); +//! assert_eq!(world.query::().query(&world).count(), 1); +//! assert_eq!(world.query::<()>.query(&world).count(), world.entities().len() as usize); +//! }) +//! ``` +//! //! ### Warnings //! //! Currently, only queries for which the cache is built after enabling a default query filter will have entities From b645d82bb7e9cd3adfe51ad25a3fc035ca7219ee Mon Sep 17 00:00:00 2001 From: Trashtalk Date: Wed, 23 Jul 2025 19:47:04 +0000 Subject: [PATCH 11/11] fixed doctest --- crates/bevy_ecs/src/entity_disabling.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index fbc183fac7403..d87373f48149c 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -50,17 +50,19 @@ //! Entities with disabling components are still present in the [`World`] and can be accessed directly, //! using methods on [`World`] or [`Commands`](crate::prelude::Commands). //! -//! As default query filters are implemented through a resource, it's possible to temporarily ignore any default filters by using [`World::resource_scope`](crate::prelude::World). +//! As default query filters are implemented through a resource, +//! it's possible to temporarily ignore any default filters by using [`World::resource_scope`](crate::prelude::World). //! //! ``` //! use bevy_ecs::prelude::*; +//! use bevy_ecs::entity_disabling::{DefaultQueryFilters, Disabled}; //! //! let mut world = World::default(); //! //! #[derive(Component)] //! struct CustomDisabled; //! -//! world.register_default_query_filter::(); +//! world.register_disabling_component::(); //! //! world.spawn(Disabled); //! world.spawn(CustomDisabled); @@ -68,9 +70,9 @@ //! // resource_scope removes DefaultQueryFilters temporarily before re-inserting into the world. //! world.resource_scope(|world: &mut World, _: Mut| { //! // within this scope, we can query like no components are disabled. -//! assert_eq!(world.query::().query(&world).count(), 1); -//! assert_eq!(world.query::().query(&world).count(), 1); -//! assert_eq!(world.query::<()>.query(&world).count(), world.entities().len() as usize); +//! assert_eq!(world.query::<&Disabled>().query(&world).count(), 1); +//! assert_eq!(world.query::<&CustomDisabled>().query(&world).count(), 1); +//! assert_eq!(world.query::<()>().query(&world).count(), world.entities().len() as usize); //! }) //! ``` //!