1//! Disabled entities do not show up in queries unless the query explicitly mentions them.
2//!
3//! Entities which are disabled in this way are not removed from the [`World`],
4//! and their relationships remain intact.
5//! In many cases, you may want to disable entire trees of entities at once,
6//! using [`EntityCommands::insert_recursive`](crate::prelude::EntityCommands::insert_recursive).
7//!
8//! While Bevy ships with a built-in [`Disabled`] component, you can also create your own
9//! disabling components, which will operate in the same way but can have distinct semantics.
10//!
11//! ```
12//! use bevy_ecs::prelude::*;
13//!
14//! // Our custom disabling component!
15//! #[derive(Component, Clone)]
16//! struct Prefab;
17//!
18//! #[derive(Component)]
19//! struct A;
20//!
21//! let mut world = World::new();
22//! world.register_disabling_component::<Prefab>();
23//! world.spawn((A, Prefab));
24//! world.spawn((A,));
25//! world.spawn((A,));
26//!
27//! let mut normal_query = world.query::<&A>();
28//! assert_eq!(2, normal_query.iter(&world).count());
29//!
30//! let mut prefab_query = world.query_filtered::<&A, With<Prefab>>();
31//! assert_eq!(1, prefab_query.iter(&world).count());
32//!
33//! let mut maybe_prefab_query = world.query::<(&A, Has<Prefab>)>();
34//! assert_eq!(3, maybe_prefab_query.iter(&world).count());
35//! ```
36//!
37//! ## Default query filters
38//!
39//! In Bevy, entity disabling is implemented through the construction of a global "default query filter" resource.
40//! Queries which do not explicitly mention the disabled component will not include entities with that component.
41//! If an entity has multiple disabling components, it will only be included in queries that mention all of them.
42//!
43//! For example, `Query<&Position>` will not include entities with the [`Disabled`] component,
44//! even if they have a `Position` component,
45//! but `Query<&Position, With<Disabled>>` or `Query<(&Position, Has<Disabled>)>` will see them.
46//!
47//! The [`Allow`](crate::query::Allow) query filter is designed to be used with default query filters,
48//! and ensures that the query will include entities both with and without the specified disabling component.
49//!
50//! Entities with disabling components are still present in the [`World`] and can be accessed directly,
51//! using methods on [`World`] or [`Commands`](crate::prelude::Commands).
52//!
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().count_spawned() as usize);
76//! })
77//! ```
78//!
79//! ### Warnings
80//!
81//! Currently, only queries for which the cache is built after enabling a default query filter will have entities
82//! with those components filtered. As a result, they should generally only be modified before the
83//! app starts.
84//!
85//! Because filters are applied to all queries they can have performance implication for
86//! the entire [`World`], especially when they cause queries to mix sparse and table components.
87//! See [`Query` performance] for more info.
88//!
89//! Custom disabling components can cause significant interoperability issues within the ecosystem,
90//! as users must be aware of each disabling component in use.
91//! Libraries should think carefully about whether they need to use a new disabling component,
92//! and clearly communicate their presence to their users to avoid the new for library compatibility flags.
93//!
94//! [`With`]: crate::prelude::With
95//! [`Has`]: crate::prelude::Has
96//! [`World`]: crate::prelude::World
97//! [`Query` performance]: crate::prelude::Query#performance
9899use crate::{
100 component::{ComponentId, Components, StorageType},
101query::FilteredAccess,
102 world::{FromWorld, World},
103};
104use bevy_ecs_macros::{Component, Resource};
105use smallvec::SmallVec;
106107#[cfg(feature = "bevy_reflect")]
108use {
109crate::reflect::{ReflectComponent, ReflectResource},
110bevy_reflect::std_traits::ReflectDefault,
111bevy_reflect::Reflect,
112};
113114/// A marker component for disabled entities.
115///
116/// Semantically, this component is used to mark entities that are temporarily disabled (typically for gameplay reasons),
117/// but will likely be re-enabled at some point.
118///
119/// Like all disabling components, this only disables the entity itself,
120/// not its children or other entities that reference it.
121/// To disable an entire tree of entities, use [`EntityCommands::insert_recursive`](crate::prelude::EntityCommands::insert_recursive).
122///
123/// Every [`World`] has a default query filter that excludes entities with this component,
124/// registered in the [`DefaultQueryFilters`] resource.
125/// See [the module docs] for more info.
126///
127/// [the module docs]: crate::entity_disabling
128#[derive(impl bevy_ecs::component::Component for Disabled where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {
const STORAGE_TYPE: bevy_ecs::component::StorageType =
bevy_ecs::component::StorageType::Table;
type Mutability = bevy_ecs::component::Mutable;
fn register_required_components(_requiree:
bevy_ecs::component::ComponentId,
required_components:
&mut bevy_ecs::component::RequiredComponentsRegistrator) {}
fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
use bevy_ecs::component::{
DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
};
(&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
}
fn relationship_accessor()
->
::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
::core::option::Option::None
}
}Component, #[automatically_derived]
impl ::core::clone::Clone for Disabled {
#[inline]
fn clone(&self) -> Self { Self }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for Disabled {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "Disabled")
}
}Debug, #[automatically_derived]
impl ::core::default::Default for Disabled {
#[inline]
fn default() -> Self { Self }
}Default)]
129#[cfg_attr(
130 feature = "bevy_reflect",
131 derive(const _: () =
{
impl bevy_reflect::GetTypeRegistration for Disabled where {
fn get_type_registration() -> bevy_reflect::TypeRegistration {
let mut registration =
bevy_reflect::TypeRegistration::of::<Self>();
registration.insert(<bevy_reflect::ReflectFromPtr as
bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
registration.insert(<bevy_reflect::ReflectFromReflect as
bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
registration.register_type_data_with::<ReflectComponent, Self,
_>(());
registration.register_type_data_with::<ReflectDefault, Self,
_>(());
registration
}
#[inline(never)]
fn register_type_dependencies(registry:
&mut bevy_reflect::TypeRegistry) {}
}
impl bevy_reflect::Typed for Disabled where {
#[inline(never)]
fn type_info() -> &'static bevy_reflect::TypeInfo {
static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
bevy_reflect::utility::NonGenericTypeInfoCell::new();
CELL.get_or_set(#[inline(never)] ||
{
bevy_reflect::TypeInfo::Struct(bevy_reflect::structs::StructInfo::new::<Self>(&[]))
})
}
}
#[allow(deprecated, reason =
"derives on a deprecated type shouldn't be considered a usage")]
impl bevy_reflect::TypePath for Disabled where {
fn type_path() -> &'static str {
"bevy_ecs::entity_disabling::Disabled"
}
fn short_type_path() -> &'static str { "Disabled" }
fn type_ident() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("Disabled")
}
fn crate_name() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_ecs::entity_disabling".split(':').next().unwrap())
}
fn module_path() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_ecs::entity_disabling")
}
}
impl bevy_reflect::Reflect for Disabled where {
#[inline]
fn into_any(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
self
}
#[inline]
fn as_any(&self) -> &dyn ::core::any::Any { self }
#[inline]
fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
#[inline]
fn into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
self
}
#[inline]
fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
self
}
#[inline]
fn set(&mut self,
value:
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
->
::core::result::Result<(),
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
*self = <dyn bevy_reflect::Reflect>::take(value)?;
::core::result::Result::Ok(())
}
}
impl bevy_reflect::func::args::GetOwnership for Disabled where {
fn ownership() -> bevy_reflect::func::args::Ownership {
bevy_reflect::func::args::Ownership::Owned
}
}
impl bevy_reflect::func::args::FromArg for Disabled where {
type This<'from_arg> = Disabled;
fn from_arg(arg: bevy_reflect::func::args::Arg)
->
::core::result::Result<Self::This<'_>,
bevy_reflect::func::args::ArgError> {
arg.take_owned()
}
}
impl bevy_reflect::func::IntoReturn for Disabled where {
fn into_return<'into_return>(self)
-> bevy_reflect::func::Return<'into_return> where
Self: 'into_return {
bevy_reflect::func::Return::Owned(bevy_reflect::__macro_exports::alloc_utils::Box::new(self))
}
}
impl bevy_reflect::structs::Struct for Disabled where {
fn field(&self, name: &str)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match name { _ => ::core::option::Option::None, }
}
fn field_mut(&mut self, name: &str)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match name { _ => ::core::option::Option::None, }
}
fn field_at(&self, index: usize)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match index { _ => ::core::option::Option::None, }
}
fn field_at_mut(&mut self, index: usize)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match index { _ => ::core::option::Option::None, }
}
fn name_at(&self, index: usize) -> ::core::option::Option<&str> {
match index { _ => ::core::option::Option::None, }
}
fn index_of_name(&self, name: &str)
-> ::core::option::Option<usize> {
match name { _ => ::core::option::Option::None, }
}
fn field_len(&self) -> usize { 0usize }
fn iter_fields(&self) -> bevy_reflect::structs::FieldIter {
bevy_reflect::structs::FieldIter::new(self)
}
fn to_dynamic_struct(&self)
->
::core::result::Result<bevy_reflect::structs::DynamicStruct,
bevy_reflect::ReflectCloneError> {
let mut dynamic: bevy_reflect::structs::DynamicStruct =
::core::default::Default::default();
dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(self));
::core::result::Result::Ok(dynamic)
}
}
impl bevy_reflect::PartialReflect for Disabled where {
#[inline]
fn get_represented_type_info(&self)
-> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
::core::option::Option::Some(<Self as
bevy_reflect::Typed>::type_info())
}
#[inline]
fn try_apply(&mut self, value: &dyn bevy_reflect::PartialReflect)
-> ::core::result::Result<(), bevy_reflect::ApplyError> {
if let bevy_reflect::ReflectRef::Struct(struct_value) =
bevy_reflect::PartialReflect::reflect_ref(value) {
for (name, value) in
bevy_reflect::structs::Struct::iter_fields(struct_value) {
if let ::core::option::Option::Some(v) =
bevy_reflect::structs::Struct::field_mut(self, name) {
bevy_reflect::PartialReflect::try_apply(v, value)?;
}
}
} else {
return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
from_kind: bevy_reflect::PartialReflect::reflect_kind(value),
to_kind: bevy_reflect::ReflectKind::Struct,
});
}
::core::result::Result::Ok(())
}
#[inline]
fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
bevy_reflect::ReflectKind::Struct
}
#[inline]
fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
bevy_reflect::ReflectRef::Struct(self)
}
#[inline]
fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
bevy_reflect::ReflectMut::Struct(self)
}
#[inline]
fn reflect_owned(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
-> bevy_reflect::ReflectOwned {
bevy_reflect::ReflectOwned::Struct(self)
}
#[inline]
fn try_into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
::core::result::Result::Ok(self)
}
#[inline]
fn try_as_reflect(&self)
-> ::core::option::Option<&dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn try_as_reflect_mut(&mut self)
-> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn into_partial_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self)
-> &dyn bevy_reflect::PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self)
-> &mut dyn bevy_reflect::PartialReflect {
self
}
fn reflect_partial_eq(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<bool> {
(bevy_reflect::structs::struct_partial_eq)(self, value)
}
fn reflect_partial_cmp(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<::core::cmp::Ordering> {
(bevy_reflect::structs::struct_partial_cmp)(self, value)
}
fn debug(&self, f: &mut ::core::fmt::Formatter<'_>)
-> ::core::fmt::Result {
::core::fmt::Debug::fmt(self, f)
}
#[inline]
fn reflect_clone(&self)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::ReflectCloneError> {
::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(::core::clone::Clone::clone(self)))
}
}
impl bevy_reflect::FromReflect for Disabled where {
fn from_reflect(reflect: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<Self> {
if let bevy_reflect::ReflectRef::Struct(__ref_struct) =
bevy_reflect::PartialReflect::reflect_ref(reflect) {
let mut __this =
<Self as ::core::default::Default>::default();
::core::option::Option::Some(__this)
} else { ::core::option::Option::None }
}
}
};Reflect),
132 reflect(Component),
133 reflect(Debug, Clone, Default)
134)]
135// This component is registered as a disabling component during World::bootstrap
136pub struct Disabled;
137138/// Default query filters work by excluding entities with certain components from most queries.
139///
140/// If a query does not explicitly mention a given disabling component, it will not include entities with that component.
141/// To be more precise, this checks if the query's [`FilteredAccess`] contains the component,
142/// and if it does not, adds a [`Without`](crate::prelude::Without) filter for that component to the query.
143///
144/// [`Allow`](crate::query::Allow) and [`Has`](crate::prelude::Has) can be used to include entities
145/// with and without the disabling component.
146/// [`Allow`](crate::query::Allow) is a [`QueryFilter`](crate::query::QueryFilter) and will simply change
147/// the list of shown entities, while [`Has`](crate::prelude::Has) is a [`QueryData`](crate::query::QueryData)
148/// and will allow you to see if each entity has the disabling component or not.
149///
150/// This resource is initialized in the [`World`] whenever a new world is created,
151/// with the [`Disabled`] component as a disabling component.
152///
153/// Note that you can remove default query filters by overwriting the [`DefaultQueryFilters`] resource.
154/// This can be useful as a last resort escape hatch, but is liable to break compatibility with other libraries.
155///
156/// See the [module docs](crate::entity_disabling) for more info.
157///
158///
159/// # Warning
160///
161/// Default query filters are a global setting that affects all queries in the [`World`],
162/// and incur a small performance cost for each query.
163///
164/// They can cause significant interoperability issues within the ecosystem,
165/// as users must be aware of each disabling component in use.
166///
167/// Think carefully about whether you need to use a new disabling component,
168/// and clearly communicate their presence in any libraries you publish.
169#[derive(impl bevy_ecs::component::Component for DefaultQueryFilters where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {
const STORAGE_TYPE: bevy_ecs::component::StorageType =
bevy_ecs::component::StorageType::SparseSet;
type Mutability = bevy_ecs::component::Mutable;
fn register_required_components(_requiree:
bevy_ecs::component::ComponentId,
required_components:
&mut bevy_ecs::component::RequiredComponentsRegistrator) {
let resource_component_id =
if let ::core::option::Option::Some(id) =
required_components.components_registrator().component_id::<DefaultQueryFilters>()
{
id
} else {
required_components.components_registrator().register_component::<DefaultQueryFilters>()
};
required_components.register_required::<bevy_ecs::resource::IsResource>(move
||
bevy_ecs::resource::IsResource::new(resource_component_id));
}
fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
use bevy_ecs::component::{
DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
};
(&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
}
fn relationship_accessor()
->
::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
::core::option::Option::None
}
}
impl bevy_ecs::resource::Resource for DefaultQueryFilters where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource, #[automatically_derived]
impl ::core::fmt::Debug for DefaultQueryFilters {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field1_finish(f,
"DefaultQueryFilters", "disabling", &&self.disabling)
}
}Debug)]
170#[cfg_attr(
171 feature = "bevy_reflect",
172 derive(const _: () =
{
impl bevy_reflect::GetTypeRegistration for DefaultQueryFilters where
{
fn get_type_registration() -> bevy_reflect::TypeRegistration {
let mut registration =
bevy_reflect::TypeRegistration::of::<Self>();
registration.insert(<bevy_reflect::ReflectFromPtr as
bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
registration.insert(<bevy_reflect::ReflectFromReflect as
bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
registration.register_type_data_with::<ReflectResource, Self,
_>(());
registration
}
#[inline(never)]
fn register_type_dependencies(registry:
&mut bevy_reflect::TypeRegistry) {
<SmallVec<[ComponentId; 4]> as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
}
}
impl bevy_reflect::Typed for DefaultQueryFilters where {
#[inline(never)]
fn type_info() -> &'static bevy_reflect::TypeInfo {
static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
bevy_reflect::utility::NonGenericTypeInfoCell::new();
CELL.get_or_set(#[inline(never)] ||
{
bevy_reflect::TypeInfo::Struct(bevy_reflect::structs::StructInfo::new::<Self>(&[bevy_reflect::NamedField::new::<SmallVec<[ComponentId; 4]>>("disabling")]))
})
}
}
#[allow(deprecated, reason =
"derives on a deprecated type shouldn't be considered a usage")]
impl bevy_reflect::TypePath for DefaultQueryFilters where {
fn type_path() -> &'static str {
"bevy_ecs::entity_disabling::DefaultQueryFilters"
}
fn short_type_path() -> &'static str { "DefaultQueryFilters" }
fn type_ident() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("DefaultQueryFilters")
}
fn crate_name() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_ecs::entity_disabling".split(':').next().unwrap())
}
fn module_path() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_ecs::entity_disabling")
}
}
impl bevy_reflect::Reflect for DefaultQueryFilters where {
#[inline]
fn into_any(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
self
}
#[inline]
fn as_any(&self) -> &dyn ::core::any::Any { self }
#[inline]
fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
#[inline]
fn into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
self
}
#[inline]
fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
self
}
#[inline]
fn set(&mut self,
value:
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
->
::core::result::Result<(),
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
*self = <dyn bevy_reflect::Reflect>::take(value)?;
::core::result::Result::Ok(())
}
}
impl bevy_reflect::func::args::GetOwnership for DefaultQueryFilters
where {
fn ownership() -> bevy_reflect::func::args::Ownership {
bevy_reflect::func::args::Ownership::Owned
}
}
impl bevy_reflect::func::args::FromArg for DefaultQueryFilters where
{
type This<'from_arg> = DefaultQueryFilters;
fn from_arg(arg: bevy_reflect::func::args::Arg)
->
::core::result::Result<Self::This<'_>,
bevy_reflect::func::args::ArgError> {
arg.take_owned()
}
}
impl bevy_reflect::func::IntoReturn for DefaultQueryFilters where {
fn into_return<'into_return>(self)
-> bevy_reflect::func::Return<'into_return> where
Self: 'into_return {
bevy_reflect::func::Return::Owned(bevy_reflect::__macro_exports::alloc_utils::Box::new(self))
}
}
impl bevy_reflect::structs::Struct for DefaultQueryFilters where {
fn field(&self, name: &str)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match name {
"disabling" =>
::core::option::Option::Some(&self.disabling),
_ => ::core::option::Option::None,
}
}
fn field_mut(&mut self, name: &str)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match name {
"disabling" =>
::core::option::Option::Some(&mut self.disabling),
_ => ::core::option::Option::None,
}
}
fn field_at(&self, index: usize)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match index {
0usize => ::core::option::Option::Some(&self.disabling),
_ => ::core::option::Option::None,
}
}
fn field_at_mut(&mut self, index: usize)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match index {
0usize => ::core::option::Option::Some(&mut self.disabling),
_ => ::core::option::Option::None,
}
}
fn name_at(&self, index: usize) -> ::core::option::Option<&str> {
match index {
0usize => ::core::option::Option::Some("disabling"),
_ => ::core::option::Option::None,
}
}
fn index_of_name(&self, name: &str)
-> ::core::option::Option<usize> {
match name {
"disabling" => ::core::option::Option::Some(0usize),
_ => ::core::option::Option::None,
}
}
fn field_len(&self) -> usize { 1usize }
fn iter_fields(&self) -> bevy_reflect::structs::FieldIter {
bevy_reflect::structs::FieldIter::new(self)
}
fn to_dynamic_struct(&self)
->
::core::result::Result<bevy_reflect::structs::DynamicStruct,
bevy_reflect::ReflectCloneError> {
let mut dynamic: bevy_reflect::structs::DynamicStruct =
::core::default::Default::default();
dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(self));
dynamic.insert_boxed("disabling",
bevy_reflect::PartialReflect::to_dynamic(&self.disabling)?);
::core::result::Result::Ok(dynamic)
}
}
impl bevy_reflect::PartialReflect for DefaultQueryFilters where {
#[inline]
fn get_represented_type_info(&self)
-> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
::core::option::Option::Some(<Self as
bevy_reflect::Typed>::type_info())
}
#[inline]
fn try_apply(&mut self, value: &dyn bevy_reflect::PartialReflect)
-> ::core::result::Result<(), bevy_reflect::ApplyError> {
if let bevy_reflect::ReflectRef::Struct(struct_value) =
bevy_reflect::PartialReflect::reflect_ref(value) {
for (name, value) in
bevy_reflect::structs::Struct::iter_fields(struct_value) {
if let ::core::option::Option::Some(v) =
bevy_reflect::structs::Struct::field_mut(self, name) {
bevy_reflect::PartialReflect::try_apply(v, value)?;
}
}
} else {
return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
from_kind: bevy_reflect::PartialReflect::reflect_kind(value),
to_kind: bevy_reflect::ReflectKind::Struct,
});
}
::core::result::Result::Ok(())
}
#[inline]
fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
bevy_reflect::ReflectKind::Struct
}
#[inline]
fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
bevy_reflect::ReflectRef::Struct(self)
}
#[inline]
fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
bevy_reflect::ReflectMut::Struct(self)
}
#[inline]
fn reflect_owned(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
-> bevy_reflect::ReflectOwned {
bevy_reflect::ReflectOwned::Struct(self)
}
#[inline]
fn try_into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
::core::result::Result::Ok(self)
}
#[inline]
fn try_as_reflect(&self)
-> ::core::option::Option<&dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn try_as_reflect_mut(&mut self)
-> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn into_partial_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self)
-> &dyn bevy_reflect::PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self)
-> &mut dyn bevy_reflect::PartialReflect {
self
}
fn reflect_partial_eq(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<bool> {
(bevy_reflect::structs::struct_partial_eq)(self, value)
}
fn reflect_partial_cmp(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<::core::cmp::Ordering> {
(bevy_reflect::structs::struct_partial_cmp)(self, value)
}
#[inline]
#[allow(unreachable_code, reason =
"Ignored fields without a `clone` attribute will early-return with an error")]
fn reflect_clone(&self)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::ReflectCloneError> {
::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(Self {
disabling: <SmallVec<[ComponentId; 4]> as
bevy_reflect::PartialReflect>::reflect_clone_and_take(&self.disabling)?,
}))
}
}
impl bevy_reflect::FromReflect for DefaultQueryFilters where {
fn from_reflect(reflect: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<Self> {
if let bevy_reflect::ReflectRef::Struct(__ref_struct) =
bevy_reflect::PartialReflect::reflect_ref(reflect) {
let __this =
Self {
disabling: <SmallVec<[ComponentId; 4]> as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"disabling")?)?,
};
::core::option::Option::Some(__this)
} else { ::core::option::Option::None }
}
}
};bevy_reflect::Reflect),
173 reflect(Resource)
174)]
175pub struct DefaultQueryFilters {
176// We only expect a few components per application to act as disabling components, so we use a SmallVec here
177 // to avoid heap allocation in most cases.
178disabling: SmallVec<[ComponentId; 4]>,
179}
180181impl FromWorldfor DefaultQueryFilters {
182fn from_world(world: &mut World) -> Self {
183let mut filters = DefaultQueryFilters::empty();
184let disabled_component_id = world.register_component::<Disabled>();
185filters.register_disabling_component(disabled_component_id);
186filters187 }
188}
189190impl DefaultQueryFilters {
191/// Creates a new, completely empty [`DefaultQueryFilters`].
192 ///
193 /// This is provided as an escape hatch; in most cases you should initialize this using [`FromWorld`],
194 /// which is automatically called when creating a new [`World`].
195#[must_use]
196pub fn empty() -> Self {
197DefaultQueryFilters {
198 disabling: SmallVec::new(),
199 }
200 }
201202/// Adds this [`ComponentId`] to the set of [`DefaultQueryFilters`],
203 /// causing entities with this component to be excluded from queries.
204 ///
205 /// This method is idempotent, and will not add the same component multiple times.
206 ///
207 /// # Warning
208 ///
209 /// This method should only be called before the app starts, as it will not affect queries
210 /// initialized before it is called.
211 ///
212 /// As discussed in the [module docs](crate::entity_disabling), this can have performance implications,
213 /// as well as create interoperability issues, and should be used with caution.
214pub fn register_disabling_component(&mut self, component_id: ComponentId) {
215if !self.disabling.contains(&component_id) {
216self.disabling.push(component_id);
217 }
218 }
219220/// Get an iterator over all of the components which disable entities when present.
221pub fn disabling_ids(&self) -> impl Iterator<Item = ComponentId> {
222self.disabling.iter().copied()
223 }
224225/// Modifies the provided [`FilteredAccess`] to include the filters from this [`DefaultQueryFilters`].
226pub(super) fn modify_access(&self, component_access: &mut FilteredAccess) {
227for component_id in self.disabling_ids() {
228if !component_access.contains(component_id) {
229 component_access.and_without(component_id);
230 }
231 }
232 }
233234pub(super) fn is_dense(&self, components: &Components) -> bool {
235self.disabling_ids().all(|component_id| {
236components237 .get_info(component_id)
238 .is_some_and(|info| info.storage_type() == StorageType::Table)
239 })
240 }
241}
242243#[cfg(test)]
244mod tests {
245246use super::*;
247use crate::{
248 component::ComponentIds,
249 prelude::{EntityMut, EntityRef, World},
250 query::{Has, With},
251 };
252use alloc::{vec, vec::Vec};
253254#[test]
255fn filters_modify_access() {
256let mut ids = ComponentIds::default();
257let id_1 = ids.next_mut();
258let id_2 = ids.next_mut();
259let id_4 = ids.next_mut();
260261let mut filters = DefaultQueryFilters::empty();
262 filters.register_disabling_component(id_1);
263264// A component access with an unrelated component
265let mut component_access = FilteredAccess::default();
266 component_access.access_mut().add_read(id_2);
267268let mut applied_access = component_access.clone();
269 filters.modify_access(&mut applied_access);
270assert_eq!(0, applied_access.with_filters().count());
271assert_eq!(
272vec![id_1],
273 applied_access.without_filters().collect::<Vec<_>>()
274 );
275276// We add a with filter, now we expect to see both filters
277component_access.and_with(id_4);
278279let mut applied_access = component_access.clone();
280 filters.modify_access(&mut applied_access);
281assert_eq!(
282vec![id_4],
283 applied_access.with_filters().collect::<Vec<_>>()
284 );
285assert_eq!(
286vec![id_1],
287 applied_access.without_filters().collect::<Vec<_>>()
288 );
289290let copy = component_access.clone();
291// We add a rule targeting a default component, that filter should no longer be added
292component_access.and_with(id_1);
293294let mut applied_access = component_access.clone();
295 filters.modify_access(&mut applied_access);
296assert_eq!(
297vec![id_1, id_4],
298 applied_access.with_filters().collect::<Vec<_>>()
299 );
300assert_eq!(0, applied_access.without_filters().count());
301302// Archetypal access should also filter rules
303component_access = copy.clone();
304 component_access.access_mut().add_archetypal(id_1);
305306let mut applied_access = component_access.clone();
307 filters.modify_access(&mut applied_access);
308assert_eq!(
309vec![id_4],
310 applied_access.with_filters().collect::<Vec<_>>()
311 );
312assert_eq!(0, applied_access.without_filters().count());
313 }
314315#[derive(Component)]
316struct CustomDisabled;
317318#[derive(Component)]
319struct Dummy;
320321#[test]
322fn multiple_disabling_components() {
323let mut world = World::new();
324 world.register_disabling_component::<CustomDisabled>();
325326// Use powers of two so we can uniquely identify the set of matching archetypes from the count.
327world.spawn(Dummy);
328 world.spawn_batch((0..2).map(|_| (Dummy, Disabled)));
329 world.spawn_batch((0..4).map(|_| (Dummy, CustomDisabled)));
330 world.spawn_batch((0..8).map(|_| (Dummy, Disabled, CustomDisabled)));
331332let mut query = world.query::<&Dummy>();
333assert_eq!(1, query.iter(&world).count());
334335let mut query = world.query_filtered::<EntityRef, With<Dummy>>();
336assert_eq!(1, query.iter(&world).count());
337338let mut query = world.query_filtered::<EntityMut, With<Dummy>>();
339assert_eq!(1, query.iter(&world).count());
340341let mut query = world.query_filtered::<&Dummy, With<Disabled>>();
342assert_eq!(2, query.iter(&world).count());
343344let mut query = world.query_filtered::<Has<Disabled>, With<Dummy>>();
345assert_eq!(3, query.iter(&world).count());
346347let mut query = world.query_filtered::<&Dummy, With<CustomDisabled>>();
348assert_eq!(4, query.iter(&world).count());
349350let mut query = world.query_filtered::<Has<CustomDisabled>, With<Dummy>>();
351assert_eq!(5, query.iter(&world).count());
352353let mut query = world.query_filtered::<&Dummy, (With<Disabled>, With<CustomDisabled>)>();
354assert_eq!(8, query.iter(&world).count());
355356let mut query = world.query_filtered::<(Has<Disabled>, Has<CustomDisabled>), With<Dummy>>();
357assert_eq!(15, query.iter(&world).count());
358359// This seems like it ought to count as a mention of `Disabled`, but it does not.
360 // We don't consider read access, since that would count `EntityRef` as a mention of *all* components.
361let mut query = world.query_filtered::<Option<&Disabled>, With<Dummy>>();
362assert_eq!(1, query.iter(&world).count());
363 }
364}