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},
|
||||
name::{Name, NameOrEntity},
|
||||
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,
|
||||
relationship::RelationshipTarget,
|
||||
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),
|
||||
/// 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
|
||||
/// [`Allows<T>`]: crate::query::filter::Allows
|
||||
pub fn add_archetypal(&mut self, index: T) {
|
||||
self.archetypal.grow_and_insert(index.sparse_set_index());
|
||||
}
|
||||
@ -499,6 +500,7 @@ impl<T: SparseSetIndex> Access<T> {
|
||||
self.resource_read_and_writes
|
||||
.union_with(&other.resource_read_and_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,
|
||||
|
@ -555,6 +555,63 @@ all_tuples!(
|
||||
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 common use for this filter is one-time initialization.
|
||||
|
@ -2315,6 +2315,10 @@ mod tests {
|
||||
let mut query = QueryState::<Has<C>>::new(&mut world);
|
||||
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
|
||||
let mut query = QueryState::<Has<C>, Without<B>>::new(&mut world);
|
||||
assert_eq!(1, query.iter(&world).count());
|
||||
|
Loading…
Reference in New Issue
Block a user