mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 15:14:50 +00:00
Clean up Fetch code (#4800)
# Objective Clean up code surrounding fetch by pulling out the common parts into the iteration code. ## Solution Merge `Fetch::table_fetch` and `Fetch::archetype_fetch` into a single API: `Fetch::fetch(&mut self, entity: &Entity, table_row: &usize)`. This provides everything any fetch requires to internally decide which storage to read from and get the underlying data. All of these functions are marked as `#[inline(always)]` and the arguments are passed as references to attempt to optimize out the argument that isn't being used. External to `Fetch`, Query iteration has been changed to keep track of the table row and entity outside of fetch, which moves a lot of the expensive bookkeeping `Fetch` structs had previously done internally into the outer loop. ~~TODO: Benchmark, docs~~ Done. --- ## Changelog Changed: `Fetch::table_fetch` and `Fetch::archetype_fetch` have been merged into a single `Fetch::fetch` function. ## Migration Guide TODO Co-authored-by: Brian Merchant <bhmerchang@gmail.com> Co-authored-by: Saverio Miroddi <saverio.pub2@gmail.com>
This commit is contained in:
parent
284b1f1302
commit
fe7ebd4326
9 changed files with 426 additions and 527 deletions
|
@ -261,9 +261,9 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
|
|||
_fetch: &mut <Self as #path::query::WorldQueryGats<'__w>>::Fetch,
|
||||
_state: &Self::State,
|
||||
_archetype: &'__w #path::archetype::Archetype,
|
||||
_tables: &'__w #path::storage::Tables
|
||||
_table: &'__w #path::storage::Table
|
||||
) {
|
||||
#(<#field_types>::set_archetype(&mut _fetch.#field_idents, &_state.#field_idents, _archetype, _tables);)*
|
||||
#(<#field_types>::set_archetype(&mut _fetch.#field_idents, &_state.#field_idents, _archetype, _table);)*
|
||||
}
|
||||
|
||||
/// SAFETY: we call `set_table` for each member that implements `Fetch`
|
||||
|
@ -276,40 +276,27 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
|
|||
#(<#field_types>::set_table(&mut _fetch.#field_idents, &_state.#field_idents, _table);)*
|
||||
}
|
||||
|
||||
/// SAFETY: we call `table_fetch` for each member that implements `Fetch`.
|
||||
#[inline]
|
||||
unsafe fn table_fetch<'__w>(
|
||||
/// SAFETY: we call `fetch` for each member that implements `Fetch`.
|
||||
#[inline(always)]
|
||||
unsafe fn fetch<'__w>(
|
||||
_fetch: &mut <Self as #path::query::WorldQueryGats<'__w>>::Fetch,
|
||||
_entity: Entity,
|
||||
_table_row: usize
|
||||
) -> <Self as #path::query::WorldQueryGats<'__w>>::Item {
|
||||
Self::Item {
|
||||
#(#field_idents: <#field_types>::table_fetch(&mut _fetch.#field_idents, _table_row),)*
|
||||
#(#field_idents: <#field_types>::fetch(&mut _fetch.#field_idents, _entity, _table_row),)*
|
||||
#(#ignored_field_idents: Default::default(),)*
|
||||
}
|
||||
}
|
||||
|
||||
/// SAFETY: we call `archetype_fetch` for each member that implements `Fetch`.
|
||||
#[inline]
|
||||
unsafe fn archetype_fetch<'__w>(
|
||||
#[allow(unused_variables)]
|
||||
#[inline(always)]
|
||||
unsafe fn filter_fetch<'__w>(
|
||||
_fetch: &mut <Self as #path::query::WorldQueryGats<'__w>>::Fetch,
|
||||
_archetype_index: usize
|
||||
) -> <Self as #path::query::WorldQueryGats<'__w>>::Item {
|
||||
Self::Item {
|
||||
#(#field_idents: <#field_types>::archetype_fetch(&mut _fetch.#field_idents, _archetype_index),)*
|
||||
#(#ignored_field_idents: Default::default(),)*
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[inline]
|
||||
unsafe fn table_filter_fetch<'__w>(_fetch: &mut <Self as #path::query::WorldQueryGats<'__w>>::Fetch, _table_row: usize) -> bool {
|
||||
true #(&& <#field_types>::table_filter_fetch(&mut _fetch.#field_idents, _table_row))*
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[inline]
|
||||
unsafe fn archetype_filter_fetch<'__w>(_fetch: &mut <Self as #path::query::WorldQueryGats<'__w>>::Fetch, _archetype_index: usize) -> bool {
|
||||
true #(&& <#field_types>::archetype_filter_fetch(&mut _fetch.#field_idents, _archetype_index))*
|
||||
_entity: Entity,
|
||||
_table_row: usize
|
||||
) -> bool {
|
||||
true #(&& <#field_types>::filter_fetch(&mut _fetch.#field_idents, _entity, _table_row))*
|
||||
}
|
||||
|
||||
fn update_component_access(state: &Self::State, _access: &mut #path::query::FilteredAccess<#path::component::ComponentId>) {
|
||||
|
|
|
@ -121,9 +121,19 @@ impl Edges {
|
|||
}
|
||||
}
|
||||
|
||||
struct TableInfo {
|
||||
id: TableId,
|
||||
entity_rows: Vec<usize>,
|
||||
pub struct ArchetypeEntity {
|
||||
pub(crate) entity: Entity,
|
||||
pub(crate) table_row: usize,
|
||||
}
|
||||
|
||||
impl ArchetypeEntity {
|
||||
pub fn entity(&self) -> Entity {
|
||||
self.entity
|
||||
}
|
||||
|
||||
pub fn table_row(&self) -> usize {
|
||||
self.table_row
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ArchetypeSwapRemoveResult {
|
||||
|
@ -138,9 +148,9 @@ pub(crate) struct ArchetypeComponentInfo {
|
|||
|
||||
pub struct Archetype {
|
||||
id: ArchetypeId,
|
||||
entities: Vec<Entity>,
|
||||
table_id: TableId,
|
||||
edges: Edges,
|
||||
table_info: TableInfo,
|
||||
entities: Vec<ArchetypeEntity>,
|
||||
table_components: Box<[ComponentId]>,
|
||||
sparse_set_components: Box<[ComponentId]>,
|
||||
components: SparseSet<ComponentId, ArchetypeComponentInfo>,
|
||||
|
@ -183,14 +193,11 @@ impl Archetype {
|
|||
}
|
||||
Self {
|
||||
id,
|
||||
table_info: TableInfo {
|
||||
id: table_id,
|
||||
entity_rows: Default::default(),
|
||||
},
|
||||
table_id,
|
||||
entities: Vec::new(),
|
||||
components,
|
||||
table_components,
|
||||
sparse_set_components,
|
||||
entities: Default::default(),
|
||||
edges: Default::default(),
|
||||
}
|
||||
}
|
||||
|
@ -202,19 +209,14 @@ impl Archetype {
|
|||
|
||||
#[inline]
|
||||
pub fn table_id(&self) -> TableId {
|
||||
self.table_info.id
|
||||
self.table_id
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn entities(&self) -> &[Entity] {
|
||||
pub fn entities(&self) -> &[ArchetypeEntity] {
|
||||
&self.entities
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn entity_table_rows(&self) -> &[usize] {
|
||||
&self.table_info.entity_rows
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn table_components(&self) -> &[ComponentId] {
|
||||
&self.table_components
|
||||
|
@ -242,20 +244,19 @@ impl Archetype {
|
|||
|
||||
#[inline]
|
||||
pub fn entity_table_row(&self, index: usize) -> usize {
|
||||
self.table_info.entity_rows[index]
|
||||
self.entities[index].table_row
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn set_entity_table_row(&mut self, index: usize, table_row: usize) {
|
||||
self.table_info.entity_rows[index] = table_row;
|
||||
self.entities[index].table_row = table_row;
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// valid component values must be immediately written to the relevant storages
|
||||
/// `table_row` must be valid
|
||||
pub(crate) unsafe fn allocate(&mut self, entity: Entity, table_row: usize) -> EntityLocation {
|
||||
self.entities.push(entity);
|
||||
self.table_info.entity_rows.push(table_row);
|
||||
self.entities.push(ArchetypeEntity { entity, table_row });
|
||||
|
||||
EntityLocation {
|
||||
archetype_id: self.id,
|
||||
|
@ -265,21 +266,20 @@ impl Archetype {
|
|||
|
||||
pub(crate) fn reserve(&mut self, additional: usize) {
|
||||
self.entities.reserve(additional);
|
||||
self.table_info.entity_rows.reserve(additional);
|
||||
}
|
||||
|
||||
/// Removes the entity at `index` by swapping it out. Returns the table row the entity is stored
|
||||
/// in.
|
||||
pub(crate) fn swap_remove(&mut self, index: usize) -> ArchetypeSwapRemoveResult {
|
||||
let is_last = index == self.entities.len() - 1;
|
||||
self.entities.swap_remove(index);
|
||||
let entity = self.entities.swap_remove(index);
|
||||
ArchetypeSwapRemoveResult {
|
||||
swapped_entity: if is_last {
|
||||
None
|
||||
} else {
|
||||
Some(self.entities[index])
|
||||
Some(self.entities[index].entity)
|
||||
},
|
||||
table_row: self.table_info.entity_rows.swap_remove(index),
|
||||
table_row: entity.table_row,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -317,7 +317,6 @@ impl Archetype {
|
|||
|
||||
pub(crate) fn clear_entities(&mut self) {
|
||||
self.entities.clear();
|
||||
self.table_info.entity_rows.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -540,8 +540,8 @@ mod tests {
|
|||
let f = world
|
||||
.spawn((TableStored("def"), A(456), SparseStored(1)))
|
||||
.id();
|
||||
// // this should be skipped
|
||||
// SparseStored(1).spawn("abc");
|
||||
// this should be skipped
|
||||
// world.spawn(SparseStored(1));
|
||||
let ents = world
|
||||
.query::<(Entity, Option<&SparseStored>, &A)>()
|
||||
.iter(&world)
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
|||
component::{Component, ComponentId, ComponentStorage, ComponentTicks, StorageType},
|
||||
entity::Entity,
|
||||
query::{debug_checked_unreachable, Access, FilteredAccess},
|
||||
storage::{ComponentSparseSet, Table, Tables},
|
||||
storage::{ComponentSparseSet, Table},
|
||||
world::{Mut, World},
|
||||
};
|
||||
use bevy_ecs_macros::all_tuples;
|
||||
|
@ -285,11 +285,10 @@ use std::{cell::UnsafeCell, marker::PhantomData};
|
|||
/// exactly reflects the results of the following methods:
|
||||
///
|
||||
/// - [`matches_component_set`]
|
||||
/// - [`archetype_fetch`]
|
||||
/// - [`table_fetch`]
|
||||
/// - [`fetch`]
|
||||
///
|
||||
/// [`Added`]: crate::query::Added
|
||||
/// [`archetype_fetch`]: Self::archetype_fetch
|
||||
/// [`fetch`]: Self::fetch
|
||||
/// [`Changed`]: crate::query::Changed
|
||||
/// [`Fetch`]: crate::query::WorldQueryGats::Fetch
|
||||
/// [`matches_component_set`]: Self::matches_component_set
|
||||
|
@ -297,7 +296,6 @@ use std::{cell::UnsafeCell, marker::PhantomData};
|
|||
/// [`Query`]: crate::system::Query
|
||||
/// [`ReadOnly`]: Self::ReadOnly
|
||||
/// [`State`]: Self::State
|
||||
/// [`table_fetch`]: Self::table_fetch
|
||||
/// [`update_archetype_component_access`]: Self::update_archetype_component_access
|
||||
/// [`update_component_access`]: Self::update_component_access
|
||||
/// [`With`]: crate::query::With
|
||||
|
@ -339,9 +337,10 @@ pub unsafe trait WorldQuery: for<'w> WorldQueryGats<'w> {
|
|||
|
||||
/// Returns true if (and only if) every table of every archetype matched by this fetch contains
|
||||
/// all of the matched components. This is used to select a more efficient "table iterator"
|
||||
/// for "dense" queries. If this returns true, [`WorldQuery::set_table`] and [`WorldQuery::table_fetch`]
|
||||
/// will be called for iterators. If this returns false, [`WorldQuery::set_archetype`] and
|
||||
/// [`WorldQuery::archetype_fetch`] will be called for iterators.
|
||||
/// for "dense" queries. If this returns true, [`WorldQuery::set_table`] must be used before
|
||||
/// [`WorldQuery::fetch`] can be called for iterators. If this returns false,
|
||||
/// [`WorldQuery::set_archetype`] must be used before [`WorldQuery::fetch`] can be called for
|
||||
/// iterators.
|
||||
const IS_DENSE: bool;
|
||||
|
||||
/// Returns true if (and only if) this Fetch relies strictly on archetypes to limit which
|
||||
|
@ -362,7 +361,7 @@ pub unsafe trait WorldQuery: for<'w> WorldQueryGats<'w> {
|
|||
fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
state: &Self::State,
|
||||
archetype: &'w Archetype,
|
||||
tables: &'w Tables,
|
||||
table: &'w Table,
|
||||
);
|
||||
|
||||
/// Adjusts internal state to account for the next [`Table`]. This will always be called on tables
|
||||
|
@ -378,51 +377,30 @@ pub unsafe trait WorldQuery: for<'w> WorldQueryGats<'w> {
|
|||
table: &'w Table,
|
||||
);
|
||||
|
||||
/// Fetch [`Self::Item`](`WorldQueryGats::Item`) for the given `archetype_index` in the current [`Archetype`]. This must
|
||||
/// always be called after [`WorldQuery::set_archetype`] with an `archetype_index` in the range of
|
||||
/// the current [`Archetype`]
|
||||
///
|
||||
/// # Safety
|
||||
/// Must always be called _after_ [`WorldQuery::set_archetype`]. `archetype_index` must be in the range
|
||||
/// of the current archetype
|
||||
unsafe fn archetype_fetch<'w>(
|
||||
fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
archetype_index: usize,
|
||||
) -> <Self as WorldQueryGats<'w>>::Item;
|
||||
|
||||
/// Fetch [`Self::Item`](`WorldQueryGats::Item`) for the given `table_row` in the current [`Table`]. This must always be
|
||||
/// called after [`WorldQuery::set_table`] with a `table_row` in the range of the current [`Table`]
|
||||
/// Fetch [`Self::Item`](`WorldQueryGats::Item`) for either the given `entity` in the current [`Table`],
|
||||
/// or for the given `entity` in the current [`Archetype`]. This must always be called after
|
||||
/// [`WorldQuery::set_table`] with a `table_row` in the range of the current [`Table`] or after
|
||||
/// [`WorldQuery::set_archetype`] with a `entity` in the current archetype.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Must always be called _after_ [`WorldQuery::set_table`]. `table_row` must be in the range of the
|
||||
/// current table
|
||||
unsafe fn table_fetch<'w>(
|
||||
/// Must always be called _after_ [`WorldQuery::set_table`] or [`WorldQuery::set_archetype`]. `entity` and
|
||||
/// `table_row` must be in the range of the current table and archetype.
|
||||
unsafe fn fetch<'w>(
|
||||
fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
entity: Entity,
|
||||
table_row: usize,
|
||||
) -> <Self as WorldQueryGats<'w>>::Item;
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// Must always be called _after_ [`WorldQuery::set_archetype`]. `archetype_index` must be in the range
|
||||
/// of the current archetype.
|
||||
/// Must always be called _after_ [`WorldQuery::set_table`] or [`WorldQuery::set_archetype`]. `entity` and
|
||||
/// `table_row` must be in the range of the current table and archetype.
|
||||
#[allow(unused_variables)]
|
||||
#[inline]
|
||||
unsafe fn archetype_filter_fetch(
|
||||
fetch: &mut <Self as WorldQueryGats<'_>>::Fetch,
|
||||
archetype_index: usize,
|
||||
) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// Must always be called _after_ [`WorldQuery::set_table`]. `table_row` must be in the range of the
|
||||
/// current table.
|
||||
#[allow(unused_variables)]
|
||||
#[inline]
|
||||
unsafe fn table_filter_fetch(
|
||||
#[inline(always)]
|
||||
unsafe fn filter_fetch(
|
||||
fetch: &mut <Self as WorldQueryGats<'_>>::Fetch,
|
||||
entity: Entity,
|
||||
table_row: usize,
|
||||
) -> bool {
|
||||
true
|
||||
|
@ -470,11 +448,6 @@ pub type ROQueryFetch<'w, Q> = QueryFetch<'w, <Q as WorldQuery>::ReadOnly>;
|
|||
/// The read-only variant of the item type returned when a [`WorldQuery`] is iterated over immutably
|
||||
pub type ROQueryItem<'w, Q> = QueryItem<'w, <Q as WorldQuery>::ReadOnly>;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct EntityFetch<'w> {
|
||||
entities: Option<ThinSlicePtr<'w, Entity>>,
|
||||
}
|
||||
|
||||
/// SAFETY: no component or archetype access
|
||||
unsafe impl WorldQuery for Entity {
|
||||
type ReadOnly = Self;
|
||||
|
@ -490,56 +463,41 @@ unsafe impl WorldQuery for Entity {
|
|||
|
||||
unsafe fn init_fetch<'w>(
|
||||
_world: &'w World,
|
||||
_state: &(),
|
||||
_state: &Self::State,
|
||||
_last_change_tick: u32,
|
||||
_change_tick: u32,
|
||||
) -> EntityFetch<'w> {
|
||||
EntityFetch { entities: None }
|
||||
) -> <Self as WorldQueryGats<'w>>::Fetch {
|
||||
}
|
||||
|
||||
unsafe fn clone_fetch<'w>(
|
||||
fetch: &<Self as WorldQueryGats<'w>>::Fetch,
|
||||
_fetch: &<Self as WorldQueryGats<'w>>::Fetch,
|
||||
) -> <Self as WorldQueryGats<'w>>::Fetch {
|
||||
EntityFetch {
|
||||
entities: fetch.entities,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn set_archetype<'w>(
|
||||
fetch: &mut EntityFetch<'w>,
|
||||
_state: &(),
|
||||
archetype: &'w Archetype,
|
||||
_tables: &Tables,
|
||||
_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
_state: &Self::State,
|
||||
_archetype: &'w Archetype,
|
||||
_table: &Table,
|
||||
) {
|
||||
fetch.entities = Some(archetype.entities().into());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn set_table<'w>(fetch: &mut EntityFetch<'w>, _state: &(), table: &'w Table) {
|
||||
fetch.entities = Some(table.entities().into());
|
||||
unsafe fn set_table<'w>(
|
||||
_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
_state: &Self::State,
|
||||
_table: &'w Table,
|
||||
) {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn table_fetch<'w>(
|
||||
fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
table_row: usize,
|
||||
) -> QueryItem<'w, Self> {
|
||||
let entities = fetch
|
||||
.entities
|
||||
.unwrap_or_else(|| debug_checked_unreachable());
|
||||
*entities.get(table_row)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn archetype_fetch<'w>(
|
||||
fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
archetype_index: usize,
|
||||
#[inline(always)]
|
||||
unsafe fn fetch<'w>(
|
||||
_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
entity: Entity,
|
||||
_table_row: usize,
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
let entities = fetch
|
||||
.entities
|
||||
.unwrap_or_else(|| debug_checked_unreachable());
|
||||
*entities.get(archetype_index)
|
||||
entity
|
||||
}
|
||||
|
||||
fn update_component_access(_state: &Self::State, _access: &mut FilteredAccess<ComponentId>) {}
|
||||
|
@ -562,7 +520,7 @@ unsafe impl WorldQuery for Entity {
|
|||
}
|
||||
|
||||
impl<'w> WorldQueryGats<'w> for Entity {
|
||||
type Fetch = EntityFetch<'w>;
|
||||
type Fetch = ();
|
||||
type Item = Entity;
|
||||
}
|
||||
|
||||
|
@ -573,9 +531,7 @@ unsafe impl ReadOnlyWorldQuery for Entity {}
|
|||
pub struct ReadFetch<'w, T> {
|
||||
// T::Storage = TableStorage
|
||||
table_components: Option<ThinSlicePtr<'w, UnsafeCell<T>>>,
|
||||
entity_table_rows: Option<ThinSlicePtr<'w, usize>>,
|
||||
// T::Storage = SparseStorage
|
||||
entities: Option<ThinSlicePtr<'w, Entity>>,
|
||||
sparse_set: Option<&'w ComponentSparseSet>,
|
||||
}
|
||||
|
||||
|
@ -605,10 +561,13 @@ unsafe impl<T: Component> WorldQuery for &T {
|
|||
) -> ReadFetch<'w, T> {
|
||||
ReadFetch {
|
||||
table_components: None,
|
||||
entity_table_rows: None,
|
||||
entities: None,
|
||||
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet)
|
||||
.then(|| world.storages().sparse_sets.get(component_id).unwrap()),
|
||||
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet).then(|| {
|
||||
world
|
||||
.storages()
|
||||
.sparse_sets
|
||||
.get(component_id)
|
||||
.unwrap_or_else(|| debug_checked_unreachable())
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -617,8 +576,6 @@ unsafe impl<T: Component> WorldQuery for &T {
|
|||
) -> <Self as WorldQueryGats<'w>>::Fetch {
|
||||
ReadFetch {
|
||||
table_components: fetch.table_components,
|
||||
entity_table_rows: fetch.entity_table_rows,
|
||||
entities: fetch.entities,
|
||||
sparse_set: fetch.sparse_set,
|
||||
}
|
||||
}
|
||||
|
@ -626,64 +583,49 @@ unsafe impl<T: Component> WorldQuery for &T {
|
|||
#[inline]
|
||||
unsafe fn set_archetype<'w>(
|
||||
fetch: &mut ReadFetch<'w, T>,
|
||||
&component_id: &ComponentId,
|
||||
archetype: &'w Archetype,
|
||||
tables: &'w Tables,
|
||||
component_id: &ComponentId,
|
||||
_archetype: &'w Archetype,
|
||||
table: &'w Table,
|
||||
) {
|
||||
match T::Storage::STORAGE_TYPE {
|
||||
StorageType::Table => {
|
||||
fetch.entity_table_rows = Some(archetype.entity_table_rows().into());
|
||||
let column = tables[archetype.table_id()]
|
||||
.get_column(component_id)
|
||||
.unwrap();
|
||||
fetch.table_components = Some(column.get_data_slice().into());
|
||||
}
|
||||
StorageType::SparseSet => fetch.entities = Some(archetype.entities().into()),
|
||||
if Self::IS_DENSE {
|
||||
Self::set_table(fetch, component_id, table);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn set_table<'w>(fetch: &mut ReadFetch<'w, T>, &id: &ComponentId, table: &'w Table) {
|
||||
fetch.table_components = Some(table.get_column(id).unwrap().get_data_slice().into());
|
||||
unsafe fn set_table<'w>(
|
||||
fetch: &mut ReadFetch<'w, T>,
|
||||
&component_id: &ComponentId,
|
||||
table: &'w Table,
|
||||
) {
|
||||
fetch.table_components = Some(
|
||||
table
|
||||
.get_column(component_id)
|
||||
.unwrap_or_else(|| debug_checked_unreachable())
|
||||
.get_data_slice()
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn archetype_fetch<'w>(
|
||||
fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
archetype_index: usize,
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
match T::Storage::STORAGE_TYPE {
|
||||
StorageType::Table => {
|
||||
let (entity_table_rows, table_components) = fetch
|
||||
.entity_table_rows
|
||||
.zip(fetch.table_components)
|
||||
.unwrap_or_else(|| debug_checked_unreachable());
|
||||
let table_row = *entity_table_rows.get(archetype_index);
|
||||
table_components.get(table_row).deref()
|
||||
}
|
||||
StorageType::SparseSet => {
|
||||
let (entities, sparse_set) = fetch
|
||||
.entities
|
||||
.zip(fetch.sparse_set)
|
||||
.unwrap_or_else(|| debug_checked_unreachable());
|
||||
let entity = *entities.get(archetype_index);
|
||||
sparse_set
|
||||
.get(entity)
|
||||
.unwrap_or_else(|| debug_checked_unreachable())
|
||||
.deref::<T>()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn table_fetch<'w>(
|
||||
#[inline(always)]
|
||||
unsafe fn fetch<'w>(
|
||||
fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
entity: Entity,
|
||||
table_row: usize,
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
let components = fetch
|
||||
.table_components
|
||||
.unwrap_or_else(|| debug_checked_unreachable());
|
||||
components.get(table_row).deref()
|
||||
match T::Storage::STORAGE_TYPE {
|
||||
StorageType::Table => fetch
|
||||
.table_components
|
||||
.unwrap_or_else(|| debug_checked_unreachable())
|
||||
.get(table_row)
|
||||
.deref(),
|
||||
StorageType::SparseSet => fetch
|
||||
.sparse_set
|
||||
.unwrap_or_else(|| debug_checked_unreachable())
|
||||
.get(entity)
|
||||
.unwrap_or_else(|| debug_checked_unreachable())
|
||||
.deref(),
|
||||
}
|
||||
}
|
||||
|
||||
fn update_component_access(
|
||||
|
@ -731,11 +673,11 @@ impl<'w, T: Component> WorldQueryGats<'w> for &T {
|
|||
#[doc(hidden)]
|
||||
pub struct WriteFetch<'w, T> {
|
||||
// T::Storage = TableStorage
|
||||
table_components: Option<ThinSlicePtr<'w, UnsafeCell<T>>>,
|
||||
table_ticks: Option<ThinSlicePtr<'w, UnsafeCell<ComponentTicks>>>,
|
||||
entity_table_rows: Option<ThinSlicePtr<'w, usize>>,
|
||||
table_data: Option<(
|
||||
ThinSlicePtr<'w, UnsafeCell<T>>,
|
||||
ThinSlicePtr<'w, UnsafeCell<ComponentTicks>>,
|
||||
)>,
|
||||
// T::Storage = SparseStorage
|
||||
entities: Option<ThinSlicePtr<'w, Entity>>,
|
||||
sparse_set: Option<&'w ComponentSparseSet>,
|
||||
|
||||
last_change_tick: u32,
|
||||
|
@ -767,12 +709,14 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
|
|||
change_tick: u32,
|
||||
) -> WriteFetch<'w, T> {
|
||||
WriteFetch {
|
||||
table_components: None,
|
||||
entities: None,
|
||||
entity_table_rows: None,
|
||||
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet)
|
||||
.then(|| world.storages().sparse_sets.get(component_id).unwrap()),
|
||||
table_ticks: None,
|
||||
table_data: None,
|
||||
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet).then(|| {
|
||||
world
|
||||
.storages()
|
||||
.sparse_sets
|
||||
.get(component_id)
|
||||
.unwrap_or_else(|| debug_checked_unreachable())
|
||||
}),
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
}
|
||||
|
@ -782,10 +726,7 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
|
|||
fetch: &<Self as WorldQueryGats<'w>>::Fetch,
|
||||
) -> <Self as WorldQueryGats<'w>>::Fetch {
|
||||
WriteFetch {
|
||||
table_components: fetch.table_components,
|
||||
table_ticks: fetch.table_ticks,
|
||||
entities: fetch.entities,
|
||||
entity_table_rows: fetch.entity_table_rows,
|
||||
table_data: fetch.table_data,
|
||||
sparse_set: fetch.sparse_set,
|
||||
last_change_tick: fetch.last_change_tick,
|
||||
change_tick: fetch.change_tick,
|
||||
|
@ -795,20 +736,12 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
|
|||
#[inline]
|
||||
unsafe fn set_archetype<'w>(
|
||||
fetch: &mut WriteFetch<'w, T>,
|
||||
&component_id: &ComponentId,
|
||||
archetype: &'w Archetype,
|
||||
tables: &'w Tables,
|
||||
component_id: &ComponentId,
|
||||
_archetype: &'w Archetype,
|
||||
table: &'w Table,
|
||||
) {
|
||||
match T::Storage::STORAGE_TYPE {
|
||||
StorageType::Table => {
|
||||
fetch.entity_table_rows = Some(archetype.entity_table_rows().into());
|
||||
let column = tables[archetype.table_id()]
|
||||
.get_column(component_id)
|
||||
.unwrap();
|
||||
fetch.table_components = Some(column.get_data_slice().into());
|
||||
fetch.table_ticks = Some(column.get_ticks_slice().into());
|
||||
}
|
||||
StorageType::SparseSet => fetch.entities = Some(archetype.entities().into()),
|
||||
if Self::IS_DENSE {
|
||||
Self::set_table(fetch, component_id, table);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -818,23 +751,26 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
|
|||
&component_id: &ComponentId,
|
||||
table: &'w Table,
|
||||
) {
|
||||
let column = table.get_column(component_id).unwrap();
|
||||
fetch.table_components = Some(column.get_data_slice().into());
|
||||
fetch.table_ticks = Some(column.get_ticks_slice().into());
|
||||
let column = table
|
||||
.get_column(component_id)
|
||||
.unwrap_or_else(|| debug_checked_unreachable());
|
||||
fetch.table_data = Some((
|
||||
column.get_data_slice().into(),
|
||||
column.get_ticks_slice().into(),
|
||||
));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn archetype_fetch<'w>(
|
||||
#[inline(always)]
|
||||
unsafe fn fetch<'w>(
|
||||
fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
archetype_index: usize,
|
||||
entity: Entity,
|
||||
table_row: usize,
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
match T::Storage::STORAGE_TYPE {
|
||||
StorageType::Table => {
|
||||
let (entity_table_rows, (table_components, table_ticks)) = fetch
|
||||
.entity_table_rows
|
||||
.zip(fetch.table_components.zip(fetch.table_ticks))
|
||||
let (table_components, table_ticks) = fetch
|
||||
.table_data
|
||||
.unwrap_or_else(|| debug_checked_unreachable());
|
||||
let table_row = *entity_table_rows.get(archetype_index);
|
||||
Mut {
|
||||
value: table_components.get(table_row).deref_mut(),
|
||||
ticks: Ticks {
|
||||
|
@ -845,12 +781,9 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
|
|||
}
|
||||
}
|
||||
StorageType::SparseSet => {
|
||||
let (entities, sparse_set) = fetch
|
||||
.entities
|
||||
.zip(fetch.sparse_set)
|
||||
.unwrap_or_else(|| debug_checked_unreachable());
|
||||
let entity = *entities.get(archetype_index);
|
||||
let (component, component_ticks) = sparse_set
|
||||
let (component, component_ticks) = fetch
|
||||
.sparse_set
|
||||
.unwrap_or_else(|| debug_checked_unreachable())
|
||||
.get_with_ticks(entity)
|
||||
.unwrap_or_else(|| debug_checked_unreachable());
|
||||
Mut {
|
||||
|
@ -865,25 +798,6 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn table_fetch<'w>(
|
||||
fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
table_row: usize,
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
let (table_components, table_ticks) = fetch
|
||||
.table_components
|
||||
.zip(fetch.table_ticks)
|
||||
.unwrap_or_else(|| debug_checked_unreachable());
|
||||
Mut {
|
||||
value: table_components.get(table_row).deref_mut(),
|
||||
ticks: Ticks {
|
||||
component_ticks: table_ticks.get(table_row).deref_mut(),
|
||||
change_tick: fetch.change_tick,
|
||||
last_change_tick: fetch.last_change_tick,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn update_component_access(
|
||||
&component_id: &ComponentId,
|
||||
access: &mut FilteredAccess<ComponentId>,
|
||||
|
@ -968,11 +882,11 @@ unsafe impl<T: WorldQuery> WorldQuery for Option<T> {
|
|||
fetch: &mut OptionFetch<'w, T>,
|
||||
state: &T::State,
|
||||
archetype: &'w Archetype,
|
||||
tables: &'w Tables,
|
||||
table: &'w Table,
|
||||
) {
|
||||
fetch.matches = T::matches_component_set(state, &|id| archetype.contains(id));
|
||||
if fetch.matches {
|
||||
T::set_archetype(&mut fetch.fetch, state, archetype, tables);
|
||||
T::set_archetype(&mut fetch.fetch, state, archetype, table);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -984,28 +898,15 @@ unsafe impl<T: WorldQuery> WorldQuery for Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn archetype_fetch<'w>(
|
||||
fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
archetype_index: usize,
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
if fetch.matches {
|
||||
Some(T::archetype_fetch(&mut fetch.fetch, archetype_index))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn table_fetch<'w>(
|
||||
#[inline(always)]
|
||||
unsafe fn fetch<'w>(
|
||||
fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
entity: Entity,
|
||||
table_row: usize,
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
if fetch.matches {
|
||||
Some(T::table_fetch(&mut fetch.fetch, table_row))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
fetch
|
||||
.matches
|
||||
.then(|| T::fetch(&mut fetch.fetch, entity, table_row))
|
||||
}
|
||||
|
||||
fn update_component_access(state: &T::State, access: &mut FilteredAccess<ComponentId>) {
|
||||
|
@ -1127,9 +1028,7 @@ impl<T: Component> ChangeTrackers<T> {
|
|||
pub struct ChangeTrackersFetch<'w, T> {
|
||||
// T::Storage = TableStorage
|
||||
table_ticks: Option<ThinSlicePtr<'w, UnsafeCell<ComponentTicks>>>,
|
||||
entity_table_rows: Option<ThinSlicePtr<'w, usize>>,
|
||||
// T::Storage = SparseStorage
|
||||
entities: Option<ThinSlicePtr<'w, Entity>>,
|
||||
sparse_set: Option<&'w ComponentSparseSet>,
|
||||
|
||||
marker: PhantomData<T>,
|
||||
|
@ -1157,16 +1056,19 @@ unsafe impl<T: Component> WorldQuery for ChangeTrackers<T> {
|
|||
|
||||
unsafe fn init_fetch<'w>(
|
||||
world: &'w World,
|
||||
&id: &ComponentId,
|
||||
&component_id: &ComponentId,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
) -> ChangeTrackersFetch<'w, T> {
|
||||
ChangeTrackersFetch {
|
||||
table_ticks: None,
|
||||
entities: None,
|
||||
entity_table_rows: None,
|
||||
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet)
|
||||
.then(|| world.storages().sparse_sets.get(id).unwrap()),
|
||||
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet).then(|| {
|
||||
world
|
||||
.storages()
|
||||
.sparse_sets
|
||||
.get(component_id)
|
||||
.unwrap_or_else(|| debug_checked_unreachable())
|
||||
}),
|
||||
marker: PhantomData,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
|
@ -1178,8 +1080,6 @@ unsafe impl<T: Component> WorldQuery for ChangeTrackers<T> {
|
|||
) -> <Self as WorldQueryGats<'w>>::Fetch {
|
||||
ChangeTrackersFetch {
|
||||
table_ticks: fetch.table_ticks,
|
||||
entity_table_rows: fetch.entity_table_rows,
|
||||
entities: fetch.entities,
|
||||
sparse_set: fetch.sparse_set,
|
||||
marker: fetch.marker,
|
||||
last_change_tick: fetch.last_change_tick,
|
||||
|
@ -1190,17 +1090,12 @@ unsafe impl<T: Component> WorldQuery for ChangeTrackers<T> {
|
|||
#[inline]
|
||||
unsafe fn set_archetype<'w>(
|
||||
fetch: &mut ChangeTrackersFetch<'w, T>,
|
||||
&id: &ComponentId,
|
||||
archetype: &'w Archetype,
|
||||
tables: &'w Tables,
|
||||
component_id: &ComponentId,
|
||||
_archetype: &'w Archetype,
|
||||
table: &'w Table,
|
||||
) {
|
||||
match T::Storage::STORAGE_TYPE {
|
||||
StorageType::Table => {
|
||||
fetch.entity_table_rows = Some(archetype.entity_table_rows().into());
|
||||
let column = tables[archetype.table_id()].get_column(id).unwrap();
|
||||
fetch.table_ticks = Some(column.get_ticks_slice().into());
|
||||
}
|
||||
StorageType::SparseSet => fetch.entities = Some(archetype.entities().into()),
|
||||
if Self::IS_DENSE {
|
||||
Self::set_table(fetch, component_id, table);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1210,68 +1105,44 @@ unsafe impl<T: Component> WorldQuery for ChangeTrackers<T> {
|
|||
&id: &ComponentId,
|
||||
table: &'w Table,
|
||||
) {
|
||||
fetch.table_ticks = Some(table.get_column(id).unwrap().get_ticks_slice().into());
|
||||
fetch.table_ticks = Some(
|
||||
table
|
||||
.get_column(id)
|
||||
.unwrap_or_else(|| debug_checked_unreachable())
|
||||
.get_ticks_slice()
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn archetype_fetch<'w>(
|
||||
fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
archetype_index: usize,
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
match T::Storage::STORAGE_TYPE {
|
||||
StorageType::Table => {
|
||||
let entity_table_rows = fetch
|
||||
.entity_table_rows
|
||||
.unwrap_or_else(|| debug_checked_unreachable());
|
||||
let table_row = *entity_table_rows.get(archetype_index);
|
||||
ChangeTrackers {
|
||||
component_ticks: {
|
||||
let table_ticks = fetch
|
||||
.table_ticks
|
||||
.unwrap_or_else(|| debug_checked_unreachable());
|
||||
table_ticks.get(table_row).read()
|
||||
},
|
||||
marker: PhantomData,
|
||||
last_change_tick: fetch.last_change_tick,
|
||||
change_tick: fetch.change_tick,
|
||||
}
|
||||
}
|
||||
StorageType::SparseSet => {
|
||||
let entities = fetch
|
||||
.entities
|
||||
.unwrap_or_else(|| debug_checked_unreachable());
|
||||
let entity = *entities.get(archetype_index);
|
||||
ChangeTrackers {
|
||||
component_ticks: fetch
|
||||
.sparse_set
|
||||
.unwrap_or_else(|| debug_checked_unreachable())
|
||||
.get_ticks(entity)
|
||||
.map(|ticks| &*ticks.get())
|
||||
.cloned()
|
||||
.unwrap_or_else(|| debug_checked_unreachable()),
|
||||
marker: PhantomData,
|
||||
last_change_tick: fetch.last_change_tick,
|
||||
change_tick: fetch.change_tick,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn table_fetch<'w>(
|
||||
#[inline(always)]
|
||||
unsafe fn fetch<'w>(
|
||||
fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
entity: Entity,
|
||||
table_row: usize,
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
ChangeTrackers {
|
||||
component_ticks: {
|
||||
let table_ticks = fetch
|
||||
.table_ticks
|
||||
.unwrap_or_else(|| debug_checked_unreachable());
|
||||
table_ticks.get(table_row).read()
|
||||
match T::Storage::STORAGE_TYPE {
|
||||
StorageType::Table => ChangeTrackers {
|
||||
component_ticks: {
|
||||
let table_ticks = fetch
|
||||
.table_ticks
|
||||
.unwrap_or_else(|| debug_checked_unreachable());
|
||||
table_ticks.get(table_row).read()
|
||||
},
|
||||
marker: PhantomData,
|
||||
last_change_tick: fetch.last_change_tick,
|
||||
change_tick: fetch.change_tick,
|
||||
},
|
||||
StorageType::SparseSet => ChangeTrackers {
|
||||
component_ticks: *fetch
|
||||
.sparse_set
|
||||
.unwrap_or_else(|| debug_checked_unreachable())
|
||||
.get_ticks(entity)
|
||||
.unwrap_or_else(|| debug_checked_unreachable())
|
||||
.get(),
|
||||
marker: PhantomData,
|
||||
last_change_tick: fetch.last_change_tick,
|
||||
change_tick: fetch.change_tick,
|
||||
},
|
||||
marker: PhantomData,
|
||||
last_change_tick: fetch.last_change_tick,
|
||||
change_tick: fetch.change_tick,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1355,10 +1226,15 @@ macro_rules! impl_tuple_fetch {
|
|||
const IS_ARCHETYPAL: bool = true $(&& $name::IS_ARCHETYPAL)*;
|
||||
|
||||
#[inline]
|
||||
unsafe fn set_archetype<'w>(_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, _state: &Self::State, _archetype: &'w Archetype, _tables: &'w Tables) {
|
||||
unsafe fn set_archetype<'w>(
|
||||
_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
_state: &Self::State,
|
||||
_archetype: &'w Archetype,
|
||||
_table: &'w Table
|
||||
) {
|
||||
let ($($name,)*) = _fetch;
|
||||
let ($($state,)*) = _state;
|
||||
$($name::set_archetype($name, $state, _archetype, _tables);)*
|
||||
$($name::set_archetype($name, $state, _archetype, _table);)*
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -1368,32 +1244,25 @@ macro_rules! impl_tuple_fetch {
|
|||
$($name::set_table($name, $state, _table);)*
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
#[allow(clippy::unused_unit)]
|
||||
unsafe fn table_fetch<'w>(_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, _table_row: usize) -> QueryItem<'w, Self> {
|
||||
unsafe fn fetch<'w>(
|
||||
_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
_entity: Entity,
|
||||
_table_row: usize
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
let ($($name,)*) = _fetch;
|
||||
($($name::table_fetch($name, _table_row),)*)
|
||||
($($name::fetch($name, _entity, _table_row),)*)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(clippy::unused_unit)]
|
||||
unsafe fn archetype_fetch<'w>(_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, _archetype_index: usize) -> QueryItem<'w, Self> {
|
||||
#[inline(always)]
|
||||
unsafe fn filter_fetch<'w>(
|
||||
_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
_entity: Entity,
|
||||
_table_row: usize
|
||||
) -> bool {
|
||||
let ($($name,)*) = _fetch;
|
||||
($($name::archetype_fetch($name, _archetype_index),)*)
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[inline]
|
||||
unsafe fn table_filter_fetch(_fetch: &mut QueryFetch<'_, Self>, table_row: usize) -> bool {
|
||||
let ($($name,)*) = _fetch;
|
||||
true $(&& $name::table_filter_fetch($name, table_row))*
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[inline]
|
||||
unsafe fn archetype_filter_fetch(_fetch: &mut QueryFetch<'_, Self>, archetype_index: usize) -> bool {
|
||||
let ($($name,)*) = _fetch;
|
||||
true $(&& $name::archetype_filter_fetch($name, archetype_index))*
|
||||
true $(&& $name::filter_fetch($name, _entity, _table_row))*
|
||||
}
|
||||
|
||||
fn update_component_access(state: &Self::State, _access: &mut FilteredAccess<ComponentId>) {
|
||||
|
@ -1471,13 +1340,18 @@ macro_rules! impl_anytuple_fetch {
|
|||
const IS_ARCHETYPAL: bool = true $(&& $name::IS_ARCHETYPAL)*;
|
||||
|
||||
#[inline]
|
||||
unsafe fn set_archetype<'w>(_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, _state: &Self::State, _archetype: &'w Archetype, _tables: &'w Tables) {
|
||||
unsafe fn set_archetype<'w>(
|
||||
_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
_state: &Self::State,
|
||||
_archetype: &'w Archetype,
|
||||
_table: &'w Table
|
||||
) {
|
||||
let ($($name,)*) = _fetch;
|
||||
let ($($state,)*) = _state;
|
||||
$(
|
||||
$name.1 = $name::matches_component_set($state, &|id| _archetype.contains(id));
|
||||
if $name.1 {
|
||||
$name::set_archetype(&mut $name.0, $state, _archetype, _tables);
|
||||
$name::set_archetype(&mut $name.0, $state, _archetype, _table);
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
@ -1494,21 +1368,16 @@ macro_rules! impl_anytuple_fetch {
|
|||
)*
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
#[allow(clippy::unused_unit)]
|
||||
unsafe fn table_fetch<'w>(_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, _table_row: usize) -> QueryItem<'w, Self> {
|
||||
unsafe fn fetch<'w>(
|
||||
_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
_entity: Entity,
|
||||
_table_row: usize
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
let ($($name,)*) = _fetch;
|
||||
($(
|
||||
$name.1.then(|| $name::table_fetch(&mut $name.0, _table_row)),
|
||||
)*)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(clippy::unused_unit)]
|
||||
unsafe fn archetype_fetch<'w>(_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, _archetype_index: usize) -> QueryItem<'w, Self> {
|
||||
let ($($name,)*) = _fetch;
|
||||
($(
|
||||
$name.1.then(|| $name::archetype_fetch(&mut $name.0, _archetype_index)),
|
||||
$name.1.then(|| $name::fetch(&mut $name.0, _entity, _table_row)),
|
||||
)*)
|
||||
}
|
||||
|
||||
|
@ -1608,7 +1477,7 @@ unsafe impl<Q: WorldQuery> WorldQuery for NopWorldQuery<Q> {
|
|||
_fetch: &mut (),
|
||||
_state: &Q::State,
|
||||
_archetype: &Archetype,
|
||||
_tables: &Tables,
|
||||
_tables: &Table,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -1616,15 +1485,9 @@ unsafe impl<Q: WorldQuery> WorldQuery for NopWorldQuery<Q> {
|
|||
unsafe fn set_table<'w>(_fetch: &mut (), _state: &Q::State, _table: &Table) {}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn archetype_fetch<'w>(
|
||||
unsafe fn fetch<'w>(
|
||||
_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
_archetype_index: usize,
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn table_fetch<'w>(
|
||||
_fetch: &mut (),
|
||||
_entity: Entity,
|
||||
_table_row: usize,
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
query::{
|
||||
debug_checked_unreachable, Access, FilteredAccess, QueryFetch, WorldQuery, WorldQueryGats,
|
||||
},
|
||||
storage::{ComponentSparseSet, Table, Tables},
|
||||
storage::{ComponentSparseSet, Table},
|
||||
world::World,
|
||||
};
|
||||
use bevy_ecs_macros::all_tuples;
|
||||
|
@ -88,20 +88,14 @@ unsafe impl<T: Component> WorldQuery for With<T> {
|
|||
_fetch: &mut (),
|
||||
_state: &ComponentId,
|
||||
_archetype: &Archetype,
|
||||
_tables: &Tables,
|
||||
_table: &Table,
|
||||
) {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn archetype_fetch<'w>(
|
||||
_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
_archetype_index: usize,
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn table_fetch<'w>(
|
||||
#[inline(always)]
|
||||
unsafe fn fetch<'w>(
|
||||
_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
_entity: Entity,
|
||||
_table_row: usize,
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
}
|
||||
|
@ -200,20 +194,14 @@ unsafe impl<T: Component> WorldQuery for Without<T> {
|
|||
_fetch: &mut (),
|
||||
_state: &ComponentId,
|
||||
_archetype: &Archetype,
|
||||
_tables: &Tables,
|
||||
_table: &Table,
|
||||
) {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn archetype_fetch<'w>(
|
||||
_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
_archetype_index: usize,
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn table_fetch<'w>(
|
||||
#[inline(always)]
|
||||
unsafe fn fetch<'w>(
|
||||
_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
_entity: Entity,
|
||||
_table_row: usize,
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
}
|
||||
|
@ -348,37 +336,39 @@ macro_rules! impl_query_filter_tuple {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn set_archetype<'w>(fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, state: &Self::State, archetype: &'w Archetype, tables: &'w Tables) {
|
||||
unsafe fn set_archetype<'w>(
|
||||
fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
state: & Self::State,
|
||||
archetype: &'w Archetype,
|
||||
table: &'w Table
|
||||
) {
|
||||
let ($($filter,)*) = fetch;
|
||||
let ($($state,)*) = state;
|
||||
let ($($state,)*) = &state;
|
||||
$(
|
||||
$filter.matches = $filter::matches_component_set($state, &|id| archetype.contains(id));
|
||||
if $filter.matches {
|
||||
$filter::set_archetype(&mut $filter.fetch, $state, archetype, tables);
|
||||
$filter::set_archetype(&mut $filter.fetch, $state, archetype, table);
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn table_fetch<'w>(fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, table_row: usize) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
#[inline(always)]
|
||||
unsafe fn fetch<'w>(
|
||||
fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
_entity: Entity,
|
||||
_table_row: usize
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
let ($($filter,)*) = fetch;
|
||||
false $(|| ($filter.matches && $filter::table_filter_fetch(&mut $filter.fetch, table_row)))*
|
||||
false $(|| ($filter.matches && $filter::filter_fetch(&mut $filter.fetch, _entity, _table_row)))*
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn archetype_fetch<'w>(fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, archetype_index: usize) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
let ($($filter,)*) = fetch;
|
||||
false $(|| ($filter.matches && $filter::archetype_filter_fetch(&mut $filter.fetch, archetype_index)))*
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn table_filter_fetch(fetch: &mut QueryFetch<'_, Self>, table_row: usize) -> bool {
|
||||
Self::table_fetch(fetch, table_row)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn archetype_filter_fetch(fetch: &mut QueryFetch<'_, Self>, archetype_index: usize) -> bool {
|
||||
Self::archetype_fetch(fetch, archetype_index)
|
||||
#[inline(always)]
|
||||
unsafe fn filter_fetch<'w>(
|
||||
fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
entity: Entity,
|
||||
table_row: usize
|
||||
) -> bool {
|
||||
Self::fetch(fetch, entity, table_row)
|
||||
}
|
||||
|
||||
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>) {
|
||||
|
@ -450,9 +440,7 @@ macro_rules! impl_tick_filter {
|
|||
$(#[$fetch_meta])*
|
||||
pub struct $fetch_name<'w, T> {
|
||||
table_ticks: Option<ThinSlicePtr<'w, UnsafeCell<ComponentTicks>>>,
|
||||
entity_table_rows: Option<ThinSlicePtr<'w, usize>>,
|
||||
marker: PhantomData<T>,
|
||||
entities: Option<ThinSlicePtr<'w, Entity>>,
|
||||
sparse_set: Option<&'w ComponentSparseSet>,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
|
@ -470,10 +458,13 @@ macro_rules! impl_tick_filter {
|
|||
unsafe fn init_fetch<'w>(world: &'w World, &id: &ComponentId, last_change_tick: u32, change_tick: u32) -> <Self as WorldQueryGats<'w>>::Fetch {
|
||||
QueryFetch::<'w, Self> {
|
||||
table_ticks: None,
|
||||
entities: None,
|
||||
entity_table_rows: None,
|
||||
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet)
|
||||
.then(|| world.storages().sparse_sets.get(id).unwrap()),
|
||||
.then(|| {
|
||||
world.storages()
|
||||
.sparse_sets
|
||||
.get(id)
|
||||
.unwrap_or_else(|| debug_checked_unreachable())
|
||||
}),
|
||||
marker: PhantomData,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
|
@ -485,8 +476,6 @@ macro_rules! impl_tick_filter {
|
|||
) -> <Self as WorldQueryGats<'w>>::Fetch {
|
||||
$fetch_name {
|
||||
table_ticks: fetch.table_ticks,
|
||||
entity_table_rows: fetch.entity_table_rows,
|
||||
entities: fetch.entities,
|
||||
sparse_set: fetch.sparse_set,
|
||||
last_change_tick: fetch.last_change_tick,
|
||||
change_tick: fetch.change_tick,
|
||||
|
@ -503,53 +492,68 @@ macro_rules! impl_tick_filter {
|
|||
|
||||
const IS_ARCHETYPAL: bool = false;
|
||||
|
||||
unsafe fn set_table<'w>(fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, &id: &ComponentId, table: &'w Table) {
|
||||
fetch.table_ticks = Some(table.get_column(id).unwrap().get_ticks_slice().into());
|
||||
#[inline]
|
||||
unsafe fn set_table<'w>(
|
||||
fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
&component_id: &ComponentId,
|
||||
table: &'w Table
|
||||
) {
|
||||
fetch.table_ticks = Some(
|
||||
table.get_column(component_id)
|
||||
.unwrap_or_else(|| debug_checked_unreachable())
|
||||
.get_ticks_slice()
|
||||
.into()
|
||||
);
|
||||
}
|
||||
|
||||
unsafe fn set_archetype<'w>(fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, &id: &ComponentId, archetype: &'w Archetype, tables: &'w Tables) {
|
||||
match T::Storage::STORAGE_TYPE {
|
||||
StorageType::Table => {
|
||||
fetch.entity_table_rows = Some(archetype.entity_table_rows().into());
|
||||
let table = &tables[archetype.table_id()];
|
||||
fetch.table_ticks = Some(table.get_column(id).unwrap().get_ticks_slice().into());
|
||||
}
|
||||
StorageType::SparseSet => fetch.entities = Some(archetype.entities().into()),
|
||||
#[inline]
|
||||
unsafe fn set_archetype<'w>(
|
||||
fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
component_id: &ComponentId,
|
||||
_archetype: &'w Archetype,
|
||||
table: &'w Table
|
||||
) {
|
||||
if Self::IS_DENSE {
|
||||
Self::set_table(fetch, component_id, table);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn table_fetch<'w>(fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, table_row: usize) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
$is_detected(&*(fetch.table_ticks.unwrap_or_else(|| debug_checked_unreachable()).get(table_row)).deref(), fetch.last_change_tick, fetch.change_tick)
|
||||
}
|
||||
|
||||
unsafe fn archetype_fetch<'w>(fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, archetype_index: usize) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
#[inline(always)]
|
||||
unsafe fn fetch<'w>(
|
||||
fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
entity: Entity,
|
||||
table_row: usize
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
match T::Storage::STORAGE_TYPE {
|
||||
StorageType::Table => {
|
||||
let table_row = *fetch.entity_table_rows.unwrap_or_else(|| debug_checked_unreachable()).get(archetype_index);
|
||||
$is_detected(&*(fetch.table_ticks.unwrap_or_else(|| debug_checked_unreachable()).get(table_row)).deref(), fetch.last_change_tick, fetch.change_tick)
|
||||
$is_detected(&*(
|
||||
fetch.table_ticks
|
||||
.unwrap_or_else(|| debug_checked_unreachable())
|
||||
.get(table_row))
|
||||
.deref(),
|
||||
fetch.last_change_tick,
|
||||
fetch.change_tick
|
||||
)
|
||||
}
|
||||
StorageType::SparseSet => {
|
||||
let entity = *fetch.entities.unwrap_or_else(|| debug_checked_unreachable()).get(archetype_index);
|
||||
let ticks = fetch
|
||||
let ticks = &*fetch
|
||||
.sparse_set
|
||||
.unwrap_or_else(|| debug_checked_unreachable())
|
||||
.get_ticks(entity)
|
||||
.map(|ticks| &*ticks.get())
|
||||
.cloned()
|
||||
.unwrap();
|
||||
$is_detected(&ticks, fetch.last_change_tick, fetch.change_tick)
|
||||
.unwrap_or_else(|| debug_checked_unreachable())
|
||||
.get();
|
||||
$is_detected(ticks, fetch.last_change_tick, fetch.change_tick)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn table_filter_fetch(fetch: &mut QueryFetch<'_, Self>, table_row: usize) -> bool {
|
||||
Self::table_fetch(fetch, table_row)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn archetype_filter_fetch(fetch: &mut QueryFetch<'_, Self>, archetype_index: usize) -> bool {
|
||||
Self::archetype_fetch(fetch, archetype_index)
|
||||
#[inline(always)]
|
||||
unsafe fn filter_fetch<'w>(
|
||||
fetch: &mut QueryFetch<'w, Self>,
|
||||
entity: Entity,
|
||||
table_row: usize
|
||||
) -> bool {
|
||||
Self::fetch(fetch, entity, table_row)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -625,7 +629,7 @@ impl_tick_filter!(
|
|||
|
||||
impl_tick_filter!(
|
||||
/// A filter on a component that only retains results added or mutably dereferenced after the system last ran.
|
||||
///
|
||||
///
|
||||
/// A common use for this filter is avoiding redundant work when values have not changed.
|
||||
///
|
||||
/// **Note** that simply *mutably dereferencing* a component is considered a change ([`DerefMut`](std::ops::DerefMut)).
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
archetype::{ArchetypeId, Archetypes},
|
||||
archetype::{ArchetypeEntity, ArchetypeId, Archetypes},
|
||||
entity::{Entities, Entity},
|
||||
prelude::World,
|
||||
query::{ArchetypeFilter, QueryState, WorldQuery},
|
||||
|
@ -139,7 +139,8 @@ where
|
|||
#[inline(always)]
|
||||
unsafe fn fetch_next_aliased_unchecked(&mut self) -> Option<QueryItem<'w, Q>> {
|
||||
for entity in self.entity_iter.by_ref() {
|
||||
let location = match self.entities.get(*entity.borrow()) {
|
||||
let entity = *entity.borrow();
|
||||
let location = match self.entities.get(entity) {
|
||||
Some(location) => location,
|
||||
None => continue,
|
||||
};
|
||||
|
@ -153,6 +154,7 @@ where
|
|||
}
|
||||
|
||||
let archetype = &self.archetypes[location.archetype_id];
|
||||
let table = &self.tables[archetype.table_id()];
|
||||
|
||||
// SAFETY: `archetype` is from the world that `fetch/filter` were created for,
|
||||
// `fetch_state`/`filter_state` are the states that `fetch/filter` were initialized with
|
||||
|
@ -160,7 +162,7 @@ where
|
|||
&mut self.fetch,
|
||||
&self.query_state.fetch_state,
|
||||
archetype,
|
||||
self.tables,
|
||||
table,
|
||||
);
|
||||
// SAFETY: `table` is from the world that `fetch/filter` were created for,
|
||||
// `fetch_state`/`filter_state` are the states that `fetch/filter` were initialized with
|
||||
|
@ -168,13 +170,15 @@ where
|
|||
&mut self.filter,
|
||||
&self.query_state.filter_state,
|
||||
archetype,
|
||||
self.tables,
|
||||
table,
|
||||
);
|
||||
|
||||
let table_row = archetype.entity_table_row(location.index);
|
||||
// SAFETY: set_archetype was called prior.
|
||||
// `location.index` is an archetype index row in range of the current archetype, because if it was not, the match above would have `continue`d
|
||||
if F::archetype_filter_fetch(&mut self.filter, location.index) {
|
||||
if F::filter_fetch(&mut self.filter, entity, table_row) {
|
||||
// SAFETY: set_archetype was called prior, `location.index` is an archetype index in range of the current archetype
|
||||
return Some(Q::archetype_fetch(&mut self.fetch, location.index));
|
||||
return Some(Q::fetch(&mut self.fetch, entity, table_row));
|
||||
}
|
||||
}
|
||||
None
|
||||
|
@ -462,6 +466,8 @@ impl<'w, 's, Q: ReadOnlyWorldQuery, F: ReadOnlyWorldQuery, const K: usize> Fused
|
|||
struct QueryIterationCursor<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> {
|
||||
table_id_iter: std::slice::Iter<'s, TableId>,
|
||||
archetype_id_iter: std::slice::Iter<'s, ArchetypeId>,
|
||||
table_entities: &'w [Entity],
|
||||
archetype_entities: &'w [ArchetypeEntity],
|
||||
fetch: QueryFetch<'w, Q>,
|
||||
filter: QueryFetch<'w, F>,
|
||||
// length of the table table or length of the archetype, depending on whether both `Q`'s and `F`'s fetches are dense
|
||||
|
@ -482,6 +488,8 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's,
|
|||
Self {
|
||||
table_id_iter: self.table_id_iter.clone(),
|
||||
archetype_id_iter: self.archetype_id_iter.clone(),
|
||||
table_entities: self.table_entities,
|
||||
archetype_entities: self.archetype_entities,
|
||||
// SAFETY: upheld by caller invariants
|
||||
fetch: Q::clone_fetch(&self.fetch),
|
||||
filter: F::clone_fetch(&self.filter),
|
||||
|
@ -529,6 +537,8 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's,
|
|||
QueryIterationCursor {
|
||||
fetch,
|
||||
filter,
|
||||
table_entities: &[],
|
||||
archetype_entities: &[],
|
||||
table_id_iter: query_state.matched_table_ids.iter(),
|
||||
archetype_id_iter: query_state.matched_archetype_ids.iter(),
|
||||
current_len: 0,
|
||||
|
@ -541,10 +551,17 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's,
|
|||
#[inline]
|
||||
unsafe fn peek_last(&mut self) -> Option<QueryItem<'w, Q>> {
|
||||
if self.current_index > 0 {
|
||||
let index = self.current_index - 1;
|
||||
if Self::IS_DENSE {
|
||||
Some(Q::table_fetch(&mut self.fetch, self.current_index - 1))
|
||||
let entity = self.table_entities.get_unchecked(index);
|
||||
Some(Q::fetch(&mut self.fetch, *entity, index))
|
||||
} else {
|
||||
Some(Q::archetype_fetch(&mut self.fetch, self.current_index - 1))
|
||||
let archetype_entity = self.archetype_entities.get_unchecked(index);
|
||||
Some(Q::fetch(
|
||||
&mut self.fetch,
|
||||
archetype_entity.entity,
|
||||
archetype_entity.table_row,
|
||||
))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
|
@ -574,6 +591,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's,
|
|||
// `fetch_state`/`filter_state` are the states that `fetch/filter` were initialized with
|
||||
Q::set_table(&mut self.fetch, &query_state.fetch_state, table);
|
||||
F::set_table(&mut self.filter, &query_state.filter_state, table);
|
||||
self.table_entities = table.entities();
|
||||
self.current_len = table.entity_count();
|
||||
self.current_index = 0;
|
||||
continue;
|
||||
|
@ -581,14 +599,15 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's,
|
|||
|
||||
// SAFETY: set_table was called prior.
|
||||
// `current_index` is a table row in range of the current table, because if it was not, then the if above would have been executed.
|
||||
if !F::table_filter_fetch(&mut self.filter, self.current_index) {
|
||||
let entity = self.table_entities.get_unchecked(self.current_index);
|
||||
if !F::filter_fetch(&mut self.filter, *entity, self.current_index) {
|
||||
self.current_index += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// SAFETY: set_table was called prior.
|
||||
// `current_index` is a table row in range of the current table, because if it was not, then the if above would have been executed.
|
||||
let item = Q::table_fetch(&mut self.fetch, self.current_index);
|
||||
let item = Q::fetch(&mut self.fetch, *entity, self.current_index);
|
||||
|
||||
self.current_index += 1;
|
||||
return Some(item);
|
||||
|
@ -600,13 +619,15 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's,
|
|||
let archetype = &archetypes[*archetype_id];
|
||||
// SAFETY: `archetype` and `tables` are from the world that `fetch/filter` were created for,
|
||||
// `fetch_state`/`filter_state` are the states that `fetch/filter` were initialized with
|
||||
Q::set_archetype(&mut self.fetch, &query_state.fetch_state, archetype, tables);
|
||||
let table = &tables[archetype.table_id()];
|
||||
Q::set_archetype(&mut self.fetch, &query_state.fetch_state, archetype, table);
|
||||
F::set_archetype(
|
||||
&mut self.filter,
|
||||
&query_state.filter_state,
|
||||
archetype,
|
||||
tables,
|
||||
table,
|
||||
);
|
||||
self.archetype_entities = archetype.entities();
|
||||
self.current_len = archetype.len();
|
||||
self.current_index = 0;
|
||||
continue;
|
||||
|
@ -614,14 +635,23 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's,
|
|||
|
||||
// SAFETY: set_archetype was called prior.
|
||||
// `current_index` is an archetype index row in range of the current archetype, because if it was not, then the if above would have been executed.
|
||||
if !F::archetype_filter_fetch(&mut self.filter, self.current_index) {
|
||||
let archetype_entity = self.archetype_entities.get_unchecked(self.current_index);
|
||||
if !F::filter_fetch(
|
||||
&mut self.filter,
|
||||
archetype_entity.entity,
|
||||
archetype_entity.table_row,
|
||||
) {
|
||||
self.current_index += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// SAFETY: set_archetype was called prior, `current_index` is an archetype index in range of the current archetype
|
||||
// `current_index` is an archetype index row in range of the current archetype, because if it was not, then the if above would have been executed.
|
||||
let item = Q::archetype_fetch(&mut self.fetch, self.current_index);
|
||||
let item = Q::fetch(
|
||||
&mut self.fetch,
|
||||
archetype_entity.entity,
|
||||
archetype_entity.table_row,
|
||||
);
|
||||
self.current_index += 1;
|
||||
return Some(item);
|
||||
}
|
||||
|
|
|
@ -413,20 +413,12 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||
let mut fetch = Q::init_fetch(world, &self.fetch_state, last_change_tick, change_tick);
|
||||
let mut filter = F::init_fetch(world, &self.filter_state, last_change_tick, change_tick);
|
||||
|
||||
Q::set_archetype(
|
||||
&mut fetch,
|
||||
&self.fetch_state,
|
||||
archetype,
|
||||
&world.storages().tables,
|
||||
);
|
||||
F::set_archetype(
|
||||
&mut filter,
|
||||
&self.filter_state,
|
||||
archetype,
|
||||
&world.storages().tables,
|
||||
);
|
||||
if F::archetype_filter_fetch(&mut filter, location.index) {
|
||||
Ok(Q::archetype_fetch(&mut fetch, location.index))
|
||||
let table = &world.storages().tables[archetype.table_id()];
|
||||
Q::set_archetype(&mut fetch, &self.fetch_state, archetype, table);
|
||||
F::set_archetype(&mut filter, &self.filter_state, archetype, table);
|
||||
|
||||
if F::filter_fetch(&mut filter, entity, location.index) {
|
||||
Ok(Q::fetch(&mut fetch, entity, location.index))
|
||||
} else {
|
||||
Err(QueryEntityError::QueryDoesNotMatch(entity))
|
||||
}
|
||||
|
@ -945,34 +937,45 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||
let mut fetch = Q::init_fetch(world, &self.fetch_state, last_change_tick, change_tick);
|
||||
let mut filter = F::init_fetch(world, &self.filter_state, last_change_tick, change_tick);
|
||||
|
||||
let tables = &world.storages().tables;
|
||||
if Q::IS_DENSE && F::IS_DENSE {
|
||||
let tables = &world.storages().tables;
|
||||
for table_id in &self.matched_table_ids {
|
||||
let table = &tables[*table_id];
|
||||
Q::set_table(&mut fetch, &self.fetch_state, table);
|
||||
F::set_table(&mut filter, &self.filter_state, table);
|
||||
|
||||
for table_index in 0..table.entity_count() {
|
||||
if !F::table_filter_fetch(&mut filter, table_index) {
|
||||
let entities = table.entities();
|
||||
for row in 0..table.entity_count() {
|
||||
let entity = entities.get_unchecked(row);
|
||||
if !F::filter_fetch(&mut filter, *entity, row) {
|
||||
continue;
|
||||
}
|
||||
let item = Q::table_fetch(&mut fetch, table_index);
|
||||
func(item);
|
||||
func(Q::fetch(&mut fetch, *entity, row));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let archetypes = &world.archetypes;
|
||||
let tables = &world.storages().tables;
|
||||
for archetype_id in &self.matched_archetype_ids {
|
||||
let archetype = &archetypes[*archetype_id];
|
||||
Q::set_archetype(&mut fetch, &self.fetch_state, archetype, tables);
|
||||
F::set_archetype(&mut filter, &self.filter_state, archetype, tables);
|
||||
let table = &tables[archetype.table_id()];
|
||||
Q::set_archetype(&mut fetch, &self.fetch_state, archetype, table);
|
||||
F::set_archetype(&mut filter, &self.filter_state, archetype, table);
|
||||
|
||||
for archetype_index in 0..archetype.len() {
|
||||
if !F::archetype_filter_fetch(&mut filter, archetype_index) {
|
||||
let entities = archetype.entities();
|
||||
for idx in 0..archetype.len() {
|
||||
let archetype_entity = entities.get_unchecked(idx);
|
||||
if !F::filter_fetch(
|
||||
&mut filter,
|
||||
archetype_entity.entity,
|
||||
archetype_entity.table_row,
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
func(Q::archetype_fetch(&mut fetch, archetype_index));
|
||||
func(Q::fetch(
|
||||
&mut fetch,
|
||||
archetype_entity.entity,
|
||||
archetype_entity.table_row,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1033,14 +1036,15 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||
);
|
||||
let tables = &world.storages().tables;
|
||||
let table = &tables[*table_id];
|
||||
let entities = table.entities();
|
||||
Q::set_table(&mut fetch, &self.fetch_state, table);
|
||||
F::set_table(&mut filter, &self.filter_state, table);
|
||||
for table_index in offset..offset + len {
|
||||
if !F::table_filter_fetch(&mut filter, table_index) {
|
||||
for row in offset..offset + len {
|
||||
let entity = entities.get_unchecked(row);
|
||||
if !F::filter_fetch(&mut filter, *entity, row) {
|
||||
continue;
|
||||
}
|
||||
let item = Q::table_fetch(&mut fetch, table_index);
|
||||
func(item);
|
||||
func(Q::fetch(&mut fetch, *entity, row));
|
||||
}
|
||||
};
|
||||
#[cfg(feature = "trace")]
|
||||
|
@ -1083,14 +1087,25 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||
);
|
||||
let tables = &world.storages().tables;
|
||||
let archetype = &world.archetypes[*archetype_id];
|
||||
Q::set_archetype(&mut fetch, &self.fetch_state, archetype, tables);
|
||||
F::set_archetype(&mut filter, &self.filter_state, archetype, tables);
|
||||
let table = &tables[archetype.table_id()];
|
||||
Q::set_archetype(&mut fetch, &self.fetch_state, archetype, table);
|
||||
F::set_archetype(&mut filter, &self.filter_state, archetype, table);
|
||||
|
||||
let entities = archetype.entities();
|
||||
for archetype_index in offset..offset + len {
|
||||
if !F::archetype_filter_fetch(&mut filter, archetype_index) {
|
||||
let archetype_entity = entities.get_unchecked(archetype_index);
|
||||
if !F::filter_fetch(
|
||||
&mut filter,
|
||||
archetype_entity.entity,
|
||||
archetype_entity.table_row,
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
func(Q::archetype_fetch(&mut fetch, archetype_index));
|
||||
func(Q::fetch(
|
||||
&mut fetch,
|
||||
archetype_entity.entity,
|
||||
archetype_entity.table_row,
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -327,7 +327,8 @@ impl World {
|
|||
pub fn iter_entities(&self) -> impl Iterator<Item = Entity> + '_ {
|
||||
self.archetypes
|
||||
.iter()
|
||||
.flat_map(|archetype| archetype.entities().iter().copied())
|
||||
.flat_map(|archetype| archetype.entities().iter())
|
||||
.map(|archetype_entity| archetype_entity.entity)
|
||||
}
|
||||
|
||||
/// Retrieves an [`EntityMut`] that exposes read and write operations for the given `entity`.
|
||||
|
|
|
@ -65,7 +65,7 @@ impl Scene {
|
|||
for scene_entity in archetype.entities() {
|
||||
let entity = *instance_info
|
||||
.entity_map
|
||||
.entry(*scene_entity)
|
||||
.entry(scene_entity.entity())
|
||||
.or_insert_with(|| world.spawn_empty().id());
|
||||
for component_id in archetype.components() {
|
||||
let component_info = self
|
||||
|
@ -86,7 +86,7 @@ impl Scene {
|
|||
}
|
||||
})
|
||||
})?;
|
||||
reflect_component.copy(&self.world, world, *scene_entity, entity);
|
||||
reflect_component.copy(&self.world, world, scene_entity.entity(), entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue