Add Allows filter to bypass DefaultQueryFilters (#18192)
# Objective Fixes #17803 ## Solution - Add an `Allows<T>` `QueryFilter` that adds archetypal access for `T` - Fix access merging to include archetypal from both sides ## Testing - Added a case to the unit test for the application of `DefaultQueryFilters`
This commit is contained in:
parent
bfc76c589e
commit
02d569d0e4
@ -80,7 +80,7 @@ pub mod prelude {
|
|||||||
hierarchy::{ChildOf, ChildSpawner, ChildSpawnerCommands, Children},
|
hierarchy::{ChildOf, ChildSpawner, ChildSpawnerCommands, Children},
|
||||||
name::{Name, NameOrEntity},
|
name::{Name, NameOrEntity},
|
||||||
observer::{Observer, Trigger},
|
observer::{Observer, Trigger},
|
||||||
query::{Added, AnyOf, Changed, Has, Or, QueryBuilder, QueryState, With, Without},
|
query::{Added, Allows, AnyOf, Changed, Has, Or, QueryBuilder, QueryState, With, Without},
|
||||||
related,
|
related,
|
||||||
relationship::RelationshipTarget,
|
relationship::RelationshipTarget,
|
||||||
removal_detection::RemovedComponents,
|
removal_detection::RemovedComponents,
|
||||||
|
@ -257,9 +257,10 @@ impl<T: SparseSetIndex> Access<T> {
|
|||||||
/// This is for components whose values are not accessed (and thus will never cause conflicts),
|
/// This is for components whose values are not accessed (and thus will never cause conflicts),
|
||||||
/// but whose presence in an archetype may affect query results.
|
/// but whose presence in an archetype may affect query results.
|
||||||
///
|
///
|
||||||
/// Currently, this is only used for [`Has<T>`].
|
/// Currently, this is only used for [`Has<T>`] and [`Allows<T>`].
|
||||||
///
|
///
|
||||||
/// [`Has<T>`]: crate::query::Has
|
/// [`Has<T>`]: crate::query::Has
|
||||||
|
/// [`Allows<T>`]: crate::query::filter::Allows
|
||||||
pub fn add_archetypal(&mut self, index: T) {
|
pub fn add_archetypal(&mut self, index: T) {
|
||||||
self.archetypal.grow_and_insert(index.sparse_set_index());
|
self.archetypal.grow_and_insert(index.sparse_set_index());
|
||||||
}
|
}
|
||||||
@ -499,6 +500,7 @@ impl<T: SparseSetIndex> Access<T> {
|
|||||||
self.resource_read_and_writes
|
self.resource_read_and_writes
|
||||||
.union_with(&other.resource_read_and_writes);
|
.union_with(&other.resource_read_and_writes);
|
||||||
self.resource_writes.union_with(&other.resource_writes);
|
self.resource_writes.union_with(&other.resource_writes);
|
||||||
|
self.archetypal.union_with(&other.archetypal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the access and `other` can be active at the same time,
|
/// Returns `true` if the access and `other` can be active at the same time,
|
||||||
|
@ -555,6 +555,63 @@ all_tuples!(
|
|||||||
S
|
S
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Allows a query to contain entities with the component `T`, bypassing [`DefaultQueryFilters`].
|
||||||
|
///
|
||||||
|
/// [`DefaultQueryFilters`]: crate::entity_disabling::DefaultQueryFilters
|
||||||
|
pub struct Allows<T>(PhantomData<T>);
|
||||||
|
|
||||||
|
/// SAFETY:
|
||||||
|
/// `update_component_access` does not add any accesses.
|
||||||
|
/// This is sound because [`QueryFilter::filter_fetch`] does not access any components.
|
||||||
|
/// `update_component_access` adds an archetypal filter for `T`.
|
||||||
|
/// This is sound because it doesn't affect the query
|
||||||
|
unsafe impl<T: Component> WorldQuery for Allows<T> {
|
||||||
|
type Fetch<'w> = ();
|
||||||
|
type State = ComponentId;
|
||||||
|
|
||||||
|
fn shrink_fetch<'wlong: 'wshort, 'wshort>(_: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn init_fetch(_: UnsafeWorldCell, _: &ComponentId, _: Tick, _: Tick) {}
|
||||||
|
|
||||||
|
// Even if the component is sparse, this implementation doesn't do anything with it
|
||||||
|
const IS_DENSE: bool = true;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn set_archetype(_: &mut (), _: &ComponentId, _: &Archetype, _: &Table) {}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn set_table(_: &mut (), _: &ComponentId, _: &Table) {}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess<ComponentId>) {
|
||||||
|
access.access_mut().add_archetypal(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_state(world: &mut World) -> ComponentId {
|
||||||
|
world.register_component::<T>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_state(components: &Components) -> Option<Self::State> {
|
||||||
|
components.component_id::<T>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matches_component_set(_: &ComponentId, _: &impl Fn(ComponentId) -> bool) -> bool {
|
||||||
|
// Allows<T> always matches
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAFETY: WorldQuery impl performs no access at all
|
||||||
|
unsafe impl<T: Component> QueryFilter for Allows<T> {
|
||||||
|
const IS_ARCHETYPAL: bool = true;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn filter_fetch(_: &mut Self::Fetch<'_>, _: Entity, _: TableRow) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A filter on a component that only retains results the first time after they have been added.
|
/// A filter on a component that only retains results the first time after they have been added.
|
||||||
///
|
///
|
||||||
/// A common use for this filter is one-time initialization.
|
/// A common use for this filter is one-time initialization.
|
||||||
|
@ -2315,6 +2315,10 @@ mod tests {
|
|||||||
let mut query = QueryState::<Has<C>>::new(&mut world);
|
let mut query = QueryState::<Has<C>>::new(&mut world);
|
||||||
assert_eq!(3, query.iter(&world).count());
|
assert_eq!(3, query.iter(&world).count());
|
||||||
|
|
||||||
|
// Allows should bypass the filter entirely
|
||||||
|
let mut query = QueryState::<(), Allows<C>>::new(&mut world);
|
||||||
|
assert_eq!(3, query.iter(&world).count());
|
||||||
|
|
||||||
// Other filters should still be respected
|
// Other filters should still be respected
|
||||||
let mut query = QueryState::<Has<C>, Without<B>>::new(&mut world);
|
let mut query = QueryState::<Has<C>, Without<B>>::new(&mut world);
|
||||||
assert_eq!(1, query.iter(&world).count());
|
assert_eq!(1, query.iter(&world).count());
|
||||||
|
Loading…
Reference in New Issue
Block a user