mirror of
https://github.com/bevyengine/bevy
synced 2024-12-19 17:43:07 +00:00
Getting QueryState
from immutable World
reference (#16434)
# Objective There is currently no way of getting `QueryState` from `&World`, so it is hard to, for example, iterate over all entities with a component, only having `&World`. ## Solution Add `try_new` function to `QueryState` that internally uses `WorldQuery`'s `get_state`. ## Testing No testing
This commit is contained in:
parent
6fe4b1440c
commit
2a1064ec5e
2 changed files with 115 additions and 1 deletions
|
@ -6,6 +6,7 @@ use crate::{
|
|||
prelude::FromWorld,
|
||||
query::{
|
||||
Access, DebugCheckedUnwrap, FilteredAccess, QueryCombinationIter, QueryIter, QueryParIter,
|
||||
WorldQuery,
|
||||
},
|
||||
storage::{SparseSetIndex, TableId},
|
||||
world::{unsafe_world_cell::UnsafeWorldCell, World, WorldId},
|
||||
|
@ -160,6 +161,16 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||
state
|
||||
}
|
||||
|
||||
/// Creates a new [`QueryState`] from an immutable [`World`] reference and inherits the result of `world.id()`.
|
||||
///
|
||||
/// This function may fail if, for example,
|
||||
/// the components that make up this query have not been registered into the world.
|
||||
pub fn try_new(world: &World) -> Option<Self> {
|
||||
let mut state = Self::try_new_uninitialized(world)?;
|
||||
state.update_archetypes(world);
|
||||
Some(state)
|
||||
}
|
||||
|
||||
/// Identical to `new`, but it populates the provided `access` with the matched results.
|
||||
pub(crate) fn new_with_access(
|
||||
world: &mut World,
|
||||
|
@ -186,7 +197,32 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||
fn new_uninitialized(world: &mut World) -> Self {
|
||||
let fetch_state = D::init_state(world);
|
||||
let filter_state = F::init_state(world);
|
||||
Self::from_states_uninitialized(world.id(), fetch_state, filter_state)
|
||||
}
|
||||
|
||||
/// Creates a new [`QueryState`] but does not populate it with the matched results from the World yet
|
||||
///
|
||||
/// `new_archetype` and its variants must be called on all of the World's archetypes before the
|
||||
/// state can return valid query results.
|
||||
fn try_new_uninitialized(world: &World) -> Option<Self> {
|
||||
let fetch_state = D::get_state(world.components())?;
|
||||
let filter_state = F::get_state(world.components())?;
|
||||
Some(Self::from_states_uninitialized(
|
||||
world.id(),
|
||||
fetch_state,
|
||||
filter_state,
|
||||
))
|
||||
}
|
||||
|
||||
/// Creates a new [`QueryState`] but does not populate it with the matched results from the World yet
|
||||
///
|
||||
/// `new_archetype` and its variants must be called on all of the World's archetypes before the
|
||||
/// state can return valid query results.
|
||||
fn from_states_uninitialized(
|
||||
world_id: WorldId,
|
||||
fetch_state: <D as WorldQuery>::State,
|
||||
filter_state: <F as WorldQuery>::State,
|
||||
) -> Self {
|
||||
let mut component_access = FilteredAccess::default();
|
||||
D::update_component_access(&fetch_state, &mut component_access);
|
||||
|
||||
|
@ -205,7 +241,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||
let is_dense = D::IS_DENSE && F::IS_DENSE;
|
||||
|
||||
Self {
|
||||
world_id: world.id(),
|
||||
world_id,
|
||||
archetype_generation: ArchetypeGeneration::initial(),
|
||||
matched_storage_ids: Vec::new(),
|
||||
is_dense,
|
||||
|
|
|
@ -1670,6 +1670,84 @@ impl World {
|
|||
QueryState::new(self)
|
||||
}
|
||||
|
||||
/// Returns [`QueryState`] for the given [`QueryData`], which is used to efficiently
|
||||
/// run queries on the [`World`] by storing and reusing the [`QueryState`].
|
||||
/// ```
|
||||
/// use bevy_ecs::{component::Component, entity::Entity, world::World};
|
||||
///
|
||||
/// #[derive(Component, Debug, PartialEq)]
|
||||
/// struct Position {
|
||||
/// x: f32,
|
||||
/// y: f32,
|
||||
/// }
|
||||
///
|
||||
/// let mut world = World::new();
|
||||
/// world.spawn_batch(vec![
|
||||
/// Position { x: 0.0, y: 0.0 },
|
||||
/// Position { x: 1.0, y: 1.0 },
|
||||
/// ]);
|
||||
///
|
||||
/// fn get_positions(world: &World) -> Vec<(Entity, &Position)> {
|
||||
/// let mut query = world.try_query::<(Entity, &Position)>().unwrap();
|
||||
/// query.iter(world).collect()
|
||||
/// }
|
||||
///
|
||||
/// let positions = get_positions(&world);
|
||||
///
|
||||
/// assert_eq!(world.get::<Position>(positions[0].0).unwrap(), positions[0].1);
|
||||
/// assert_eq!(world.get::<Position>(positions[1].0).unwrap(), positions[1].1);
|
||||
/// ```
|
||||
///
|
||||
/// Requires only an immutable world reference, but may fail if, for example,
|
||||
/// the components that make up this query have not been registered into the world.
|
||||
/// ```
|
||||
/// use bevy_ecs::{component::Component, entity::Entity, world::World};
|
||||
///
|
||||
/// #[derive(Component)]
|
||||
/// struct A;
|
||||
///
|
||||
/// let mut world = World::new();
|
||||
///
|
||||
/// let none_query = world.try_query::<&A>();
|
||||
/// assert!(none_query.is_none());
|
||||
///
|
||||
/// world.register_component::<A>();
|
||||
///
|
||||
/// let some_query = world.try_query::<&A>();
|
||||
/// assert!(some_query.is_some());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn try_query<D: QueryData>(&self) -> Option<QueryState<D, ()>> {
|
||||
self.try_query_filtered::<D, ()>()
|
||||
}
|
||||
|
||||
/// Returns [`QueryState`] for the given filtered [`QueryData`], which is used to efficiently
|
||||
/// run queries on the [`World`] by storing and reusing the [`QueryState`].
|
||||
/// ```
|
||||
/// use bevy_ecs::{component::Component, entity::Entity, world::World, query::With};
|
||||
///
|
||||
/// #[derive(Component)]
|
||||
/// struct A;
|
||||
/// #[derive(Component)]
|
||||
/// struct B;
|
||||
///
|
||||
/// let mut world = World::new();
|
||||
/// let e1 = world.spawn(A).id();
|
||||
/// let e2 = world.spawn((A, B)).id();
|
||||
///
|
||||
/// let mut query = world.try_query_filtered::<Entity, With<B>>().unwrap();
|
||||
/// let matching_entities = query.iter(&world).collect::<Vec<Entity>>();
|
||||
///
|
||||
/// assert_eq!(matching_entities, vec![e2]);
|
||||
/// ```
|
||||
///
|
||||
/// Requires only an immutable world reference, but may fail if, for example,
|
||||
/// the components that make up this query have not been registered into the world.
|
||||
#[inline]
|
||||
pub fn try_query_filtered<D: QueryData, F: QueryFilter>(&self) -> Option<QueryState<D, F>> {
|
||||
QueryState::try_new(self)
|
||||
}
|
||||
|
||||
/// Returns an iterator of entities that had components of type `T` removed
|
||||
/// since the last call to [`World::clear_trackers`].
|
||||
pub fn removed<T: Component>(&self) -> impl Iterator<Item = Entity> + '_ {
|
||||
|
|
Loading…
Reference in a new issue