From 58a62cec6141b07405209e045fa34ded9467c6a7 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Sun, 9 Feb 2025 15:38:07 -0800 Subject: [PATCH 01/21] Rewrite entity disabling module docs --- crates/bevy_ecs/src/entity_disabling.rs | 26 ++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index 77326cea3f8af..773486a464a57 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -1,14 +1,26 @@ -//! Types for entity disabling. -//! //! Disabled entities do not show up in queries unless the query explicitly mentions them. //! -//! If for example we have `Disabled` as an entity disabling component, when you add `Disabled` -//! to an entity, the entity will only be visible to queries with a filter like -//! [`With`]`` or query data like [`Has`]``. +//! While Bevy ships with a built-in [`Disabled`] component, you can also create your own +//! disabling components, which will operate in the same way but can have distinct semantics. +//! +//! ## Defining your own disabling components +//! +//! ## Default query filters +//! +//! In Bevy, entity disabling is implemented through the construction of a global "default query filter". +//! 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. +//! +//! For example, `Query<&Position>` will not include entities with the [`Disabled`] component, +//! even if they have a `Position` component, +//! but `Query<&Position, With>` or `Query<(&Position, Has)>` will see them. +//! +//! Entities with disabling components are still present in the [`World`] and can be accessed directly, +//! using methods on [`World`] or [`Commands`](crate::prelude::Commands). //! -//! ### Note +//! ### Warning //! -//! Currently only queries for which the cache is built after enabling a filter will have entities +//! Currently, only queries for which the cache is built after enabling a default query filter will have entities //! with those components filtered. As a result, they should generally only be modified before the //! app starts. //! From f3029ee42d84bf4db0d3fa77f6c5936c37474cbc Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Sun, 9 Feb 2025 15:41:34 -0800 Subject: [PATCH 02/21] Derive Clone and Debug for Disabled --- crates/bevy_ecs/src/entity_disabling.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index 773486a464a57..5bf50a3d1e172 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -45,8 +45,13 @@ use {crate::reflect::ReflectComponent, bevy_reflect::Reflect}; /// A marker component for disabled entities. See [the module docs] for more info. /// /// [the module docs]: crate::entity_disabling -#[derive(Component)] -#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Component))] +#[derive(Component, Clone, Debug)] +#[cfg_attr( + feature = "bevy_reflect", + derive(Reflect), + reflect(Component), + reflect(Debug) +)] pub struct Disabled; /// The default filters for all queries, these are used to globally exclude entities from queries. From 37fd3637c58beaf6f7d465237da10cc353db2696 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Sun, 9 Feb 2025 15:54:23 -0800 Subject: [PATCH 03/21] Rename set_disabled --- crates/bevy_ecs/src/entity_disabling.rs | 27 +++++++++++++++---------- crates/bevy_ecs/src/query/state.rs | 6 +++--- crates/bevy_ecs/src/world/mod.rs | 2 +- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index 5bf50a3d1e172..b090a4671487d 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -63,8 +63,9 @@ pub struct DefaultQueryFilters { } impl DefaultQueryFilters { - /// Set the [`ComponentId`] for the entity disabling marker - pub(crate) fn set_disabled(&mut self, component_id: ComponentId) -> Option<()> { + /// Adds this [`ComponentId`] to the set of [`DefaultQueryFilters`], + /// causing entities with this component to be excluded from queries. + pub(crate) fn register_disabling_component(&mut self, component_id: ComponentId) -> Option<()> { if self.disabled.is_some() { return None; } @@ -73,12 +74,12 @@ impl DefaultQueryFilters { } /// Get an iterator over all currently enabled filter components - pub fn ids(&self) -> impl Iterator { + pub fn disabling_ids(&self) -> impl Iterator { [self.disabled].into_iter().flatten() } pub(super) fn apply(&self, component_access: &mut FilteredAccess) { - for component_id in self.ids() { + for component_id in self.disabling_ids() { if !component_access.contains(component_id) { component_access.and_without(component_id); } @@ -86,7 +87,7 @@ impl DefaultQueryFilters { } pub(super) fn is_dense(&self, components: &Components) -> bool { - self.ids().all(|component_id| { + self.disabling_ids().all(|component_id| { components .get_info(component_id) .is_some_and(|info| info.storage_type() == StorageType::Table) @@ -103,19 +104,23 @@ mod tests { #[test] fn test_set_filters() { let mut filters = DefaultQueryFilters::default(); - assert_eq!(0, filters.ids().count()); + assert_eq!(0, filters.disabling_ids().count()); - assert!(filters.set_disabled(ComponentId::new(1)).is_some()); - assert!(filters.set_disabled(ComponentId::new(3)).is_none()); + assert!(filters + .register_disabling_component(ComponentId::new(1)) + .is_some()); + assert!(filters + .register_disabling_component(ComponentId::new(3)) + .is_none()); - assert_eq!(1, filters.ids().count()); - assert_eq!(Some(ComponentId::new(1)), filters.ids().next()); + assert_eq!(1, filters.disabling_ids().count()); + assert_eq!(Some(ComponentId::new(1)), filters.disabling_ids().next()); } #[test] fn test_apply_filters() { let mut filters = DefaultQueryFilters::default(); - filters.set_disabled(ComponentId::new(1)); + filters.register_disabling_component(ComponentId::new(1)); // A component access with an unrelated component let mut component_access = FilteredAccess::::default(); diff --git a/crates/bevy_ecs/src/query/state.rs b/crates/bevy_ecs/src/query/state.rs index 0019fe378376b..d6e8f776b1525 100644 --- a/crates/bevy_ecs/src/query/state.rs +++ b/crates/bevy_ecs/src/query/state.rs @@ -2455,7 +2455,7 @@ mod tests { world.spawn(C(0)); let mut df = DefaultQueryFilters::default(); - df.set_disabled(world.register_component::()); + df.register_disabling_component(world.register_component::()); world.insert_resource(df); // Without only matches the first entity @@ -2495,7 +2495,7 @@ mod tests { assert_eq!(3, query.iter(&world).count()); let mut df = DefaultQueryFilters::default(); - df.set_disabled(world.register_component::()); + df.register_disabling_component(world.register_component::()); world.insert_resource(df); let mut query = QueryState::<()>::new(&mut world); @@ -2505,7 +2505,7 @@ mod tests { assert_eq!(1, query.iter(&world).count()); let mut df = DefaultQueryFilters::default(); - df.set_disabled(world.register_component::()); + df.register_disabling_component(world.register_component::
()); world.insert_resource(df); let mut query = QueryState::<()>::new(&mut world); diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 28ef6a6e5a6ca..3aafa597c30eb 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -161,7 +161,7 @@ impl World { let disabled = self.register_component::(); let mut filters = DefaultQueryFilters::default(); - filters.set_disabled(disabled); + filters.register_disabling_component(disabled); self.insert_resource(filters); } /// Creates a new empty [`World`]. From 0bb31658d7000392cec1e5cf30635c46b20bdc2f Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Sun, 9 Feb 2025 16:00:56 -0800 Subject: [PATCH 04/21] Use a hashset rather than a single Option to store DQF --- crates/bevy_ecs/src/entity_disabling.rs | 35 ++++++------------------- 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index b090a4671487d..e265e01af05e7 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -38,6 +38,7 @@ use crate::{ query::FilteredAccess, }; use bevy_ecs_macros::{Component, Resource}; +use bevy_platform_support::collections::HashSet; #[cfg(feature = "bevy_reflect")] use {crate::reflect::ReflectComponent, bevy_reflect::Reflect}; @@ -59,27 +60,23 @@ pub struct Disabled; #[derive(Resource, Default, Debug)] #[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))] pub struct DefaultQueryFilters { - disabled: Option, + disabling: HashSet, } impl DefaultQueryFilters { /// Adds this [`ComponentId`] to the set of [`DefaultQueryFilters`], /// causing entities with this component to be excluded from queries. - pub(crate) fn register_disabling_component(&mut self, component_id: ComponentId) -> Option<()> { - if self.disabled.is_some() { - return None; - } - self.disabled = Some(component_id); - Some(()) + pub(crate) fn register_disabling_component(&mut self, component_id: ComponentId) { + self.disabling.insert(component_id); } /// Get an iterator over all currently enabled filter components - pub fn disabling_ids(&self) -> impl Iterator { - [self.disabled].into_iter().flatten() + pub fn disabling_ids(&self) -> impl Iterator { + self.disabling.iter() } pub(super) fn apply(&self, component_access: &mut FilteredAccess) { - for component_id in self.disabling_ids() { + for &component_id in self.disabling_ids() { if !component_access.contains(component_id) { component_access.and_without(component_id); } @@ -89,7 +86,7 @@ impl DefaultQueryFilters { pub(super) fn is_dense(&self, components: &Components) -> bool { self.disabling_ids().all(|component_id| { components - .get_info(component_id) + .get_info(*component_id) .is_some_and(|info| info.storage_type() == StorageType::Table) }) } @@ -101,22 +98,6 @@ mod tests { use super::*; use alloc::{vec, vec::Vec}; - #[test] - fn test_set_filters() { - let mut filters = DefaultQueryFilters::default(); - assert_eq!(0, filters.disabling_ids().count()); - - assert!(filters - .register_disabling_component(ComponentId::new(1)) - .is_some()); - assert!(filters - .register_disabling_component(ComponentId::new(3)) - .is_none()); - - assert_eq!(1, filters.disabling_ids().count()); - assert_eq!(Some(ComponentId::new(1)), filters.disabling_ids().next()); - } - #[test] fn test_apply_filters() { let mut filters = DefaultQueryFilters::default(); From 9904e4c3d9222b09b1ce9d295d390087d767490a Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Sun, 9 Feb 2025 16:02:31 -0800 Subject: [PATCH 05/21] Rename DefaultQueryFilters::apply --- crates/bevy_ecs/src/entity_disabling.rs | 12 ++++++------ crates/bevy_ecs/src/query/state.rs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index e265e01af05e7..a7aeb998a5b2d 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -75,7 +75,7 @@ impl DefaultQueryFilters { self.disabling.iter() } - pub(super) fn apply(&self, component_access: &mut FilteredAccess) { + pub(super) fn modify_access(&self, component_access: &mut FilteredAccess) { for &component_id in self.disabling_ids() { if !component_access.contains(component_id) { component_access.and_without(component_id); @@ -99,7 +99,7 @@ mod tests { use alloc::{vec, vec::Vec}; #[test] - fn test_apply_filters() { + fn filters_modify_access() { let mut filters = DefaultQueryFilters::default(); filters.register_disabling_component(ComponentId::new(1)); @@ -110,7 +110,7 @@ mod tests { .add_component_read(ComponentId::new(2)); let mut applied_access = component_access.clone(); - filters.apply(&mut applied_access); + filters.modify_access(&mut applied_access); assert_eq!(0, applied_access.with_filters().count()); assert_eq!( vec![ComponentId::new(1)], @@ -121,7 +121,7 @@ mod tests { component_access.and_with(ComponentId::new(4)); let mut applied_access = component_access.clone(); - filters.apply(&mut applied_access); + filters.modify_access(&mut applied_access); assert_eq!( vec![ComponentId::new(4)], applied_access.with_filters().collect::>() @@ -136,7 +136,7 @@ mod tests { component_access.and_with(ComponentId::new(1)); let mut applied_access = component_access.clone(); - filters.apply(&mut applied_access); + filters.modify_access(&mut applied_access); assert_eq!( vec![ComponentId::new(1), ComponentId::new(4)], applied_access.with_filters().collect::>() @@ -150,7 +150,7 @@ mod tests { .add_archetypal(ComponentId::new(1)); let mut applied_access = component_access.clone(); - filters.apply(&mut applied_access); + filters.modify_access(&mut applied_access); assert_eq!( vec![ComponentId::new(4)], applied_access.with_filters().collect::>() diff --git a/crates/bevy_ecs/src/query/state.rs b/crates/bevy_ecs/src/query/state.rs index d6e8f776b1525..c9ef0d6cfa6dd 100644 --- a/crates/bevy_ecs/src/query/state.rs +++ b/crates/bevy_ecs/src/query/state.rs @@ -258,7 +258,7 @@ impl QueryState { let mut is_dense = D::IS_DENSE && F::IS_DENSE; if let Some(default_filters) = world.get_resource::() { - default_filters.apply(&mut component_access); + default_filters.modify_access(&mut component_access); is_dense &= default_filters.is_dense(world.components()); } @@ -293,7 +293,7 @@ impl QueryState { let mut is_dense = builder.is_dense(); if let Some(default_filters) = builder.world().get_resource::() { - default_filters.apply(&mut component_access); + default_filters.modify_access(&mut component_access); is_dense &= default_filters.is_dense(builder.world().components()); } From 3dc884d1d30d5e26f10279218ffbee3ca93f5953 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Sun, 9 Feb 2025 16:11:42 -0800 Subject: [PATCH 06/21] Improve docs for DefaultQueryFilters --- crates/bevy_ecs/src/entity_disabling.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index a7aeb998a5b2d..22be41ca2cd0f 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -55,7 +55,12 @@ use {crate::reflect::ReflectComponent, bevy_reflect::Reflect}; )] pub struct Disabled; -/// The default filters for all queries, these are used to globally exclude entities from queries. +/// Default query filters work by excluding entities with certain components from most queries. +/// +/// If a query does not explicitly mention a given disabling component, it will not include entities with that component. +/// To be more precise, this checks if the query's [`FilteredAccess`] contains the component, +/// and if it does not, adds a [`Without`](crate::prelude::Without) filter for that component to the query. +/// /// See the [module docs](crate::entity_disabling) for more info. #[derive(Resource, Default, Debug)] #[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))] @@ -66,15 +71,21 @@ pub struct DefaultQueryFilters { impl DefaultQueryFilters { /// Adds this [`ComponentId`] to the set of [`DefaultQueryFilters`], /// causing entities with this component to be excluded from queries. - pub(crate) fn register_disabling_component(&mut self, component_id: ComponentId) { + /// + /// # Warning + /// + /// This method should only be called before the app starts, as it will not affect queries + /// initialized before it is called. + pub fn register_disabling_component(&mut self, component_id: ComponentId) { self.disabling.insert(component_id); } - /// Get an iterator over all currently enabled filter components + /// Get an iterator over all currently enabled filter components. pub fn disabling_ids(&self) -> impl Iterator { self.disabling.iter() } + /// Modifies the provided [`FilteredAccess`] to include the filters from this [`DefaultQueryFilters`]. pub(super) fn modify_access(&self, component_access: &mut FilteredAccess) { for &component_id in self.disabling_ids() { if !component_access.contains(component_id) { From b6f93b10d191b0574a4980b3b510ee949a5770fd Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Sun, 9 Feb 2025 16:16:16 -0800 Subject: [PATCH 07/21] More docs for Disabled --- crates/bevy_ecs/src/entity_disabling.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index 22be41ca2cd0f..63aac9bf21932 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -43,7 +43,11 @@ use bevy_platform_support::collections::HashSet; #[cfg(feature = "bevy_reflect")] use {crate::reflect::ReflectComponent, bevy_reflect::Reflect}; -/// A marker component for disabled entities. See [the module docs] for more info. +/// A marker component for disabled entities. +/// +/// Every [`World`](crate::prelude::World) has a default query filter that excludes entities with this component, +/// registered in the [`DefaultQueryFilters`] resource. +/// See [the module docs] for more info. /// /// [the module docs]: crate::entity_disabling #[derive(Component, Clone, Debug)] @@ -53,6 +57,7 @@ use {crate::reflect::ReflectComponent, bevy_reflect::Reflect}; reflect(Component), reflect(Debug) )] +// This component is registered as a disabling component during World::bootstrap pub struct Disabled; /// Default query filters work by excluding entities with certain components from most queries. From 997e5480809df5f0329712537ef2920b04e25bfc Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Sun, 9 Feb 2025 16:30:42 -0800 Subject: [PATCH 08/21] Add public API for registering disabling components --- crates/bevy_app/src/app.rs | 6 ++++++ crates/bevy_ecs/src/entity_disabling.rs | 26 ++++++++++++++++++++++++- crates/bevy_ecs/src/world/mod.rs | 8 ++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index 081e3e7ac0352..8ee515c843003 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -1034,6 +1034,12 @@ impl App { .try_register_required_components_with::(constructor) } + /// Registers a component type as "disabling", + /// using [default query filters](bevy_ecs::entity_disabling::DefaultQueryFilters) to exclude entities with the component from queries. + pub fn register_disabling_component(&mut self) { + self.world_mut().register_disabling_component::(); + } + /// Returns a reference to the main [`SubApp`]'s [`World`]. This is the same as calling /// [`app.main().world()`]. /// diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index 63aac9bf21932..038ddf8469b06 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -3,7 +3,31 @@ //! While Bevy ships with a built-in [`Disabled`] component, you can also create your own //! disabling components, which will operate in the same way but can have distinct semantics. //! -//! ## Defining your own disabling components +//! ``` +//! use bevy_ecs::prelude::*; +//! +//! // Our custom disabling component! +//! #[derive(Component, Clone)] +//! struct Prefab; +//! +//! #[derive(Component)] +//! struct A; +//! +//! let mut world = World::new(); +//! world.register_disabling_component::(); +//! world.spawn((A, Prefab)); +//! world.spawn((A,)); +//! world.spawn((A,)); +//! +//! let mut normal_query = world.query::<&A>(); +//! assert_eq!(2, normal_query.iter(&world).count()); +//! +//! let mut prefab_query = world.query_filtered::<&A, With>(); +//! assert_eq!(1, prefab_query.iter(&world).count()); +//! +//! let mut maybe_prefab_query = world.query::<(&A, Has)>(); +//! assert_eq!(3, maybe_prefab_query.iter(&world).count()); +//! ``` //! //! ## Default query filters //! diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 3aafa597c30eb..c88b96ba0dcdd 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -253,6 +253,14 @@ impl World { self.components.register_component::() } + /// Registers a component type as "disabling", + /// using [default query filters](DefaultQueryFilters) to exclude entities with the component from queries. + pub fn register_disabling_component(&mut self) { + let component_id = self.register_component::(); + let mut dqf = self.resource_mut::(); + dqf.register_disabling_component(component_id); + } + /// Returns a mutable reference to the [`ComponentHooks`] for a [`Component`] type. /// /// Will panic if `T` exists in any archetypes. From 014ba3d8f86cfdcad1bc09574ffb86cac92fc089 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Sun, 9 Feb 2025 16:39:53 -0800 Subject: [PATCH 09/21] Add test for multiple disabling components --- crates/bevy_ecs/src/entity_disabling.rs | 39 +++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index 038ddf8469b06..77a0c08f14f90 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -136,6 +136,10 @@ impl DefaultQueryFilters { mod tests { use super::*; + use crate::{ + prelude::World, + query::{Has, With}, + }; use alloc::{vec, vec::Vec}; #[test] @@ -197,4 +201,39 @@ mod tests { ); assert_eq!(0, applied_access.without_filters().count()); } + + #[derive(Component)] + struct CustomDisabled; + + #[test] + fn multiple_disabling_components() { + let mut world = World::new(); + world.register_disabling_component::(); + + world.spawn_empty(); + world.spawn(Disabled); + world.spawn(CustomDisabled); + world.spawn((Disabled, CustomDisabled)); + + let mut query = world.query::<()>(); + assert_eq!(1, query.iter(&world).count()); + + let mut query = world.query_filtered::<(), With>(); + assert_eq!(1, query.iter(&world).count()); + + let mut query = world.query::>(); + assert_eq!(2, query.iter(&world).count()); + + let mut query = world.query_filtered::<(), With>(); + assert_eq!(1, query.iter(&world).count()); + + let mut query = world.query::>(); + assert_eq!(2, query.iter(&world).count()); + + let mut query = world.query_filtered::<(), (With, With)>(); + assert_eq!(1, query.iter(&world).count()); + + let mut query = world.query::<(Has, Has)>(); + assert_eq!(4, query.iter(&world).count()); + } } From 8a0dc863af3c420d2b93ffe8b69f3289e060e1e1 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Mon, 10 Feb 2025 12:16:42 -0800 Subject: [PATCH 10/21] Interop warnings --- crates/bevy_app/src/app.rs | 5 +++++ crates/bevy_ecs/src/entity_disabling.rs | 22 +++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index 8ee515c843003..b929ca503d12b 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -1036,6 +1036,11 @@ impl App { /// Registers a component type as "disabling", /// using [default query filters](bevy_ecs::entity_disabling::DefaultQueryFilters) to exclude entities with the component from queries. + /// + /// # Warning + /// + /// As discussed in the [module docs](bevy_ecs::entity_disabling), this can have performance implications, + /// as well as create interoperability issues, and should be used with caution. pub fn register_disabling_component(&mut self) { self.world_mut().register_disabling_component::(); } diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index 77a0c08f14f90..4ed7d7d82a182 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -42,7 +42,7 @@ //! Entities with disabling components are still present in the [`World`] and can be accessed directly, //! using methods on [`World`] or [`Commands`](crate::prelude::Commands). //! -//! ### Warning +//! ### Warnings //! //! Currently, only queries for which the cache is built after enabling a default query filter will have entities //! with those components filtered. As a result, they should generally only be modified before the @@ -52,6 +52,11 @@ //! the enire [`World`], especially when they cause queries to mix sparse and table components. //! See [`Query` performance] for more info. //! +//! Custom disabling components can cause significant interoperability issues within the ecosystem, +//! as users must be aware of each disabling component in use. +//! Libraries should think carefully about whether they need to use a new disabling component, +//! and clearly communicate their presence to their users to avoid the new for library compatibility flags. +//! //! [`With`]: crate::prelude::With //! [`Has`]: crate::prelude::Has //! [`World`]: crate::prelude::World @@ -91,6 +96,18 @@ pub struct Disabled; /// and if it does not, adds a [`Without`](crate::prelude::Without) filter for that component to the query. /// /// See the [module docs](crate::entity_disabling) for more info. +/// +/// +/// # Warning +/// +/// Default query filters are a global setting that affects all queries in the [`World`], +/// and incur a small performance cost for each query. +/// +/// They can cause significant interoperability issues within the ecosystem, +/// as users must be aware of each disabling component in use. +/// +/// Think carefully about whether you need to use a new disabling component, +/// and clearly communicate their presence in any libraries you publish. #[derive(Resource, Default, Debug)] #[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))] pub struct DefaultQueryFilters { @@ -105,6 +122,9 @@ impl DefaultQueryFilters { /// /// This method should only be called before the app starts, as it will not affect queries /// initialized before it is called. + /// + /// As discussed in the [module docs](crate::entity_disabling), this can have performance implications, + /// as well as create interoperability issues, and should be used with caution. pub fn register_disabling_component(&mut self, component_id: ComponentId) { self.disabling.insert(component_id); } From 00f8657d8ffdc2677eb33f38057cd43110a12849 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Mon, 10 Feb 2025 17:03:50 -0800 Subject: [PATCH 11/21] Use a SmallVec instead of a HashSet to optimize for very low N --- crates/bevy_ecs/src/entity_disabling.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index 4ed7d7d82a182..a2b9c377cda47 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -67,7 +67,7 @@ use crate::{ query::FilteredAccess, }; use bevy_ecs_macros::{Component, Resource}; -use bevy_platform_support::collections::HashSet; +use smallvec::SmallVec; #[cfg(feature = "bevy_reflect")] use {crate::reflect::ReflectComponent, bevy_reflect::Reflect}; @@ -111,7 +111,9 @@ pub struct Disabled; #[derive(Resource, Default, Debug)] #[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))] pub struct DefaultQueryFilters { - disabling: HashSet, + // We only expect a few components per application to act as disabling components, so we use a SmallVec here + // to avoid heap allocation in most cases. + disabling: SmallVec<[ComponentId; 4]>, } impl DefaultQueryFilters { @@ -126,7 +128,7 @@ impl DefaultQueryFilters { /// As discussed in the [module docs](crate::entity_disabling), this can have performance implications, /// as well as create interoperability issues, and should be used with caution. pub fn register_disabling_component(&mut self, component_id: ComponentId) { - self.disabling.insert(component_id); + self.disabling.push(component_id); } /// Get an iterator over all currently enabled filter components. From 1bbd7644e96e31449d873292a4c4101edcf65dcd Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Mon, 10 Feb 2025 17:06:35 -0800 Subject: [PATCH 12/21] Fix up docs for disabling_ids --- crates/bevy_ecs/src/entity_disabling.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index a2b9c377cda47..3b6b88ab87f1d 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -131,7 +131,7 @@ impl DefaultQueryFilters { self.disabling.push(component_id); } - /// Get an iterator over all currently enabled filter components. + /// Get an iterator over all of the components which disable entities when present. pub fn disabling_ids(&self) -> impl Iterator { self.disabling.iter() } From 37f32f6d9a2d70d3975f549ef3a3638927bf57d3 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Mon, 10 Feb 2025 17:07:53 -0800 Subject: [PATCH 13/21] Make register_disalbling_component idempotent --- crates/bevy_ecs/src/entity_disabling.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index 3b6b88ab87f1d..dd4bd94f982a5 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -120,6 +120,8 @@ impl DefaultQueryFilters { /// Adds this [`ComponentId`] to the set of [`DefaultQueryFilters`], /// causing entities with this component to be excluded from queries. /// + /// This method is idempotent, and will not add the same component multiple times. + /// /// # Warning /// /// This method should only be called before the app starts, as it will not affect queries @@ -128,7 +130,9 @@ impl DefaultQueryFilters { /// As discussed in the [module docs](crate::entity_disabling), this can have performance implications, /// as well as create interoperability issues, and should be used with caution. pub fn register_disabling_component(&mut self, component_id: ComponentId) { - self.disabling.push(component_id); + if !self.disabling.contains(&component_id) { + self.disabling.push(component_id); + } } /// Get an iterator over all of the components which disable entities when present. From 7cbe1d738417206a88103b481722fe51845401c1 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Mon, 10 Feb 2025 17:17:47 -0800 Subject: [PATCH 14/21] Use FromWorld to make DQF initialization cleaner --- crates/bevy_ecs/src/entity_disabling.rs | 31 +++++++++++++++++-- crates/bevy_ecs/src/query/state.rs | 6 ++-- crates/bevy_ecs/src/world/mod.rs | 8 ++--- .../bevy_scene/src/dynamic_scene_builder.rs | 1 + 4 files changed, 36 insertions(+), 10 deletions(-) diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index dd4bd94f982a5..5e52f390607c3 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -65,6 +65,7 @@ use crate::{ component::{ComponentId, Components, StorageType}, query::FilteredAccess, + world::{FromWorld, World}, }; use bevy_ecs_macros::{Component, Resource}; use smallvec::SmallVec; @@ -95,6 +96,12 @@ pub struct Disabled; /// To be more precise, this checks if the query's [`FilteredAccess`] contains the component, /// and if it does not, adds a [`Without`](crate::prelude::Without) filter for that component to the query. /// +/// This resource is initialized in the [`World`] whenever a new world is created, +/// with the [`Disabled`] component as a disabling component. +/// +/// Note that you can remove default query filters by overwriting the [`DefaultQueryFilters`] resource. +/// This can be useful as a last resort escape hatch, but is liable to break compatibility with other libraries. +/// /// See the [module docs](crate::entity_disabling) for more info. /// /// @@ -108,7 +115,7 @@ pub struct Disabled; /// /// Think carefully about whether you need to use a new disabling component, /// and clearly communicate their presence in any libraries you publish. -#[derive(Resource, Default, Debug)] +#[derive(Resource, Debug)] #[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))] pub struct DefaultQueryFilters { // We only expect a few components per application to act as disabling components, so we use a SmallVec here @@ -116,7 +123,27 @@ pub struct DefaultQueryFilters { disabling: SmallVec<[ComponentId; 4]>, } +impl FromWorld for DefaultQueryFilters { + fn from_world(world: &mut World) -> Self { + let mut filters = DefaultQueryFilters::new(); + let disabled_component_id = world.register_component::(); + filters.register_disabling_component(disabled_component_id); + filters + } +} + impl DefaultQueryFilters { + /// Creates a new, completely empty [`DefaultQueryFilters`]. + /// + /// This is provided as an escape hatch; in most cases you should initialize this using [`FromWorld`], + /// which is automatically called when creating a new [`World`]. + #[must_use] + pub fn new() -> Self { + DefaultQueryFilters { + disabling: SmallVec::new(), + } + } + /// Adds this [`ComponentId`] to the set of [`DefaultQueryFilters`], /// causing entities with this component to be excluded from queries. /// @@ -170,7 +197,7 @@ mod tests { #[test] fn filters_modify_access() { - let mut filters = DefaultQueryFilters::default(); + let mut filters = DefaultQueryFilters::new(); filters.register_disabling_component(ComponentId::new(1)); // A component access with an unrelated component diff --git a/crates/bevy_ecs/src/query/state.rs b/crates/bevy_ecs/src/query/state.rs index c9ef0d6cfa6dd..8b1f966becb4c 100644 --- a/crates/bevy_ecs/src/query/state.rs +++ b/crates/bevy_ecs/src/query/state.rs @@ -2454,7 +2454,7 @@ mod tests { world.spawn((B(0), C(0))); world.spawn(C(0)); - let mut df = DefaultQueryFilters::default(); + let mut df = DefaultQueryFilters::new(); df.register_disabling_component(world.register_component::()); world.insert_resource(df); @@ -2494,7 +2494,7 @@ mod tests { assert!(query.is_dense); assert_eq!(3, query.iter(&world).count()); - let mut df = DefaultQueryFilters::default(); + let mut df = DefaultQueryFilters::new(); df.register_disabling_component(world.register_component::()); world.insert_resource(df); @@ -2504,7 +2504,7 @@ mod tests { assert!(!query.is_dense); assert_eq!(1, query.iter(&world).count()); - let mut df = DefaultQueryFilters::default(); + let mut df = DefaultQueryFilters::new(); df.register_disabling_component(world.register_component::
()); world.insert_resource(df); diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index c88b96ba0dcdd..1cbbadf296e98 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -39,7 +39,7 @@ use crate::{ Components, Mutable, RequiredComponents, RequiredComponentsError, Tick, }, entity::{AllocAtWithoutReplacement, Entities, Entity, EntityLocation}, - entity_disabling::{DefaultQueryFilters, Disabled}, + entity_disabling::DefaultQueryFilters, event::{Event, EventId, Events, SendBatchIds}, observer::Observers, query::{DebugCheckedUnwrap, QueryData, QueryFilter, QueryState}, @@ -159,10 +159,8 @@ impl World { let on_despawn = OnDespawn::register_component_id(self); assert_eq!(ON_DESPAWN, on_despawn); - let disabled = self.register_component::(); - let mut filters = DefaultQueryFilters::default(); - filters.register_disabling_component(disabled); - self.insert_resource(filters); + // This sets up `Disabled` as a disabling component, via the FromWorld impl + self.init_resource::(); } /// Creates a new empty [`World`]. /// diff --git a/crates/bevy_scene/src/dynamic_scene_builder.rs b/crates/bevy_scene/src/dynamic_scene_builder.rs index e2981ed973048..c33346373bcc7 100644 --- a/crates/bevy_scene/src/dynamic_scene_builder.rs +++ b/crates/bevy_scene/src/dynamic_scene_builder.rs @@ -351,6 +351,7 @@ impl<'w> DynamicSceneBuilder<'w> { /// [`deny_resource`]: Self::deny_resource #[must_use] pub fn extract_resources(mut self) -> Self { + // Don't extract the DefaultQueryFilters resource let original_world_dqf_id = self .original_world .components() From 92806afa271349c5d6a471230a4f804f6608fa28 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Mon, 10 Feb 2025 17:21:41 -0800 Subject: [PATCH 15/21] Clippy note on new_without_default --- crates/bevy_ecs/src/entity_disabling.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index 5e52f390607c3..1d32534ec05df 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -117,6 +117,10 @@ pub struct Disabled; /// and clearly communicate their presence in any libraries you publish. #[derive(Resource, Debug)] #[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))] +#[expect( + clippy::new_without_default, + reason = "We cannot implement both Default and FromWorld due to the blanket impl for FromWorld" +)] pub struct DefaultQueryFilters { // We only expect a few components per application to act as disabling components, so we use a SmallVec here // to avoid heap allocation in most cases. From b879c3f6ff81fda44ab3c22c6a6c199f0a25a505 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Mon, 10 Feb 2025 17:26:29 -0800 Subject: [PATCH 16/21] Try moving the expect? --- crates/bevy_ecs/src/entity_disabling.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index 1d32534ec05df..46442633d6dbc 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -117,10 +117,6 @@ pub struct Disabled; /// and clearly communicate their presence in any libraries you publish. #[derive(Resource, Debug)] #[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))] -#[expect( - clippy::new_without_default, - reason = "We cannot implement both Default and FromWorld due to the blanket impl for FromWorld" -)] pub struct DefaultQueryFilters { // We only expect a few components per application to act as disabling components, so we use a SmallVec here // to avoid heap allocation in most cases. @@ -141,6 +137,10 @@ impl DefaultQueryFilters { /// /// This is provided as an escape hatch; in most cases you should initialize this using [`FromWorld`], /// which is automatically called when creating a new [`World`]. + #[expect( + clippy::new_without_default, + reason = "We cannot implement both Default and FromWorld due to the blanket impl for FromWorld" + )] #[must_use] pub fn new() -> Self { DefaultQueryFilters { From 32383b58dfd5dd7abfd997aafebfad2c170b6223 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Mon, 10 Feb 2025 17:35:00 -0800 Subject: [PATCH 17/21] Even more docs, focusing on insert_recursive --- crates/bevy_ecs/src/entity_disabling.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index 46442633d6dbc..8b4db7ff3dadd 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -1,5 +1,10 @@ //! Disabled entities do not show up in queries unless the query explicitly mentions them. //! +//! Entities which are disabled in this way are not removed from the [`World`], +//! and their relationships remain intact. +//! In many cases, you may want to disable entire trees of entities at once, +//! using [`EntityCommands::insert_recursive`](crate::prelude::EntityCommands::insert_recursive). +//! //! While Bevy ships with a built-in [`Disabled`] component, you can also create your own //! disabling components, which will operate in the same way but can have distinct semantics. //! @@ -75,6 +80,13 @@ use {crate::reflect::ReflectComponent, bevy_reflect::Reflect}; /// A marker component for disabled entities. /// +/// Semantically, this component is used to mark entities that are temporarily disabled (typically for gameplay reasons), +/// but will likely be re-enabled at some point. +/// +/// Like all disabling components, this only disables the entity itself, +/// not its children or other entities that reference it. +/// To disable an entire tree of entities, use [`EntityCommands::insert_recursive`](crate::prelude::EntityCommands::insert_recursive). +/// /// Every [`World`](crate::prelude::World) has a default query filter that excludes entities with this component, /// registered in the [`DefaultQueryFilters`] resource. /// See [the module docs] for more info. From bf1cf7d9bd94a5660d367128f32c7e2410b3d713 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Mon, 10 Feb 2025 17:49:34 -0800 Subject: [PATCH 18/21] Now redundant doc link --- crates/bevy_ecs/src/entity_disabling.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index 8b4db7ff3dadd..bdc7c94c09dc3 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -87,7 +87,7 @@ use {crate::reflect::ReflectComponent, bevy_reflect::Reflect}; /// not its children or other entities that reference it. /// To disable an entire tree of entities, use [`EntityCommands::insert_recursive`](crate::prelude::EntityCommands::insert_recursive). /// -/// Every [`World`](crate::prelude::World) has a default query filter that excludes entities with this component, +/// Every [`World`] has a default query filter that excludes entities with this component, /// registered in the [`DefaultQueryFilters`] resource. /// See [the module docs] for more info. /// From 3cb3d8d09bba4e7c8826b5771acbd6862bef413e Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Mon, 10 Feb 2025 18:04:29 -0800 Subject: [PATCH 19/21] Remember to enable the smallvec feature in bevy_reflect --- crates/bevy_ecs/Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/Cargo.toml b/crates/bevy_ecs/Cargo.toml index 0106286c52d55..bd3d02d0308eb 100644 --- a/crates/bevy_ecs/Cargo.toml +++ b/crates/bevy_ecs/Cargo.toml @@ -103,7 +103,9 @@ portable-atomic = [ [dependencies] bevy_ptr = { path = "../bevy_ptr", version = "0.16.0-dev" } -bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, optional = true } +bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [ + "smallvec", +], default-features = false, optional = true } bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false, optional = true } bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false, features = [ "alloc", From ac17cc7f6812546fa0973dee198eeb4c6e51be78 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Tue, 11 Feb 2025 10:10:08 -0800 Subject: [PATCH 20/21] Return a copied iterator --- crates/bevy_ecs/src/entity_disabling.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index bdc7c94c09dc3..a8431b47bea07 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -179,13 +179,13 @@ impl DefaultQueryFilters { } /// Get an iterator over all of the components which disable entities when present. - pub fn disabling_ids(&self) -> impl Iterator { - self.disabling.iter() + pub fn disabling_ids(&self) -> impl Iterator + use<'_> { + self.disabling.iter().copied() } /// Modifies the provided [`FilteredAccess`] to include the filters from this [`DefaultQueryFilters`]. pub(super) fn modify_access(&self, component_access: &mut FilteredAccess) { - for &component_id in self.disabling_ids() { + for component_id in self.disabling_ids() { if !component_access.contains(component_id) { component_access.and_without(component_id); } @@ -195,7 +195,7 @@ impl DefaultQueryFilters { pub(super) fn is_dense(&self, components: &Components) -> bool { self.disabling_ids().all(|component_id| { components - .get_info(*component_id) + .get_info(component_id) .is_some_and(|info| info.storage_type() == StorageType::Table) }) } From db954f5a9cc27f1c8a1f4238c0c01f3305cb7cda Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Tue, 11 Feb 2025 10:10:36 -0800 Subject: [PATCH 21/21] new -> empty --- crates/bevy_ecs/src/entity_disabling.rs | 10 +++------- crates/bevy_ecs/src/query/state.rs | 6 +++--- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/crates/bevy_ecs/src/entity_disabling.rs b/crates/bevy_ecs/src/entity_disabling.rs index a8431b47bea07..d4b1ad266c077 100644 --- a/crates/bevy_ecs/src/entity_disabling.rs +++ b/crates/bevy_ecs/src/entity_disabling.rs @@ -137,7 +137,7 @@ pub struct DefaultQueryFilters { impl FromWorld for DefaultQueryFilters { fn from_world(world: &mut World) -> Self { - let mut filters = DefaultQueryFilters::new(); + let mut filters = DefaultQueryFilters::empty(); let disabled_component_id = world.register_component::(); filters.register_disabling_component(disabled_component_id); filters @@ -149,12 +149,8 @@ impl DefaultQueryFilters { /// /// This is provided as an escape hatch; in most cases you should initialize this using [`FromWorld`], /// which is automatically called when creating a new [`World`]. - #[expect( - clippy::new_without_default, - reason = "We cannot implement both Default and FromWorld due to the blanket impl for FromWorld" - )] #[must_use] - pub fn new() -> Self { + pub fn empty() -> Self { DefaultQueryFilters { disabling: SmallVec::new(), } @@ -213,7 +209,7 @@ mod tests { #[test] fn filters_modify_access() { - let mut filters = DefaultQueryFilters::new(); + let mut filters = DefaultQueryFilters::empty(); filters.register_disabling_component(ComponentId::new(1)); // A component access with an unrelated component diff --git a/crates/bevy_ecs/src/query/state.rs b/crates/bevy_ecs/src/query/state.rs index 8b1f966becb4c..cd495251e6e33 100644 --- a/crates/bevy_ecs/src/query/state.rs +++ b/crates/bevy_ecs/src/query/state.rs @@ -2454,7 +2454,7 @@ mod tests { world.spawn((B(0), C(0))); world.spawn(C(0)); - let mut df = DefaultQueryFilters::new(); + let mut df = DefaultQueryFilters::empty(); df.register_disabling_component(world.register_component::()); world.insert_resource(df); @@ -2494,7 +2494,7 @@ mod tests { assert!(query.is_dense); assert_eq!(3, query.iter(&world).count()); - let mut df = DefaultQueryFilters::new(); + let mut df = DefaultQueryFilters::empty(); df.register_disabling_component(world.register_component::()); world.insert_resource(df); @@ -2504,7 +2504,7 @@ mod tests { assert!(!query.is_dense); assert_eq!(1, query.iter(&world).count()); - let mut df = DefaultQueryFilters::new(); + let mut df = DefaultQueryFilters::empty(); df.register_disabling_component(world.register_component::
()); world.insert_resource(df);