Increase type safety and clarity for change detection (#7905)
This commit is contained in:
parent
b7ac5d5121
commit
2e7b915ba4
@ -224,16 +224,16 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
|
||||
unsafe fn init_fetch<'__w>(
|
||||
_world: &'__w #path::world::World,
|
||||
state: &Self::State,
|
||||
_last_change_tick: u32,
|
||||
_change_tick: u32
|
||||
_last_run: #path::component::Tick,
|
||||
_this_run: #path::component::Tick,
|
||||
) -> <Self as #path::query::WorldQuery>::Fetch<'__w> {
|
||||
#fetch_struct_name {
|
||||
#(#field_idents:
|
||||
<#field_types>::init_fetch(
|
||||
_world,
|
||||
&state.#field_idents,
|
||||
_last_change_tick,
|
||||
_change_tick
|
||||
_last_run,
|
||||
_this_run,
|
||||
),
|
||||
)*
|
||||
#(#ignored_field_idents: Default::default(),)*
|
||||
|
||||
@ -227,7 +227,7 @@ pub fn impl_param_set(_input: TokenStream) -> TokenStream {
|
||||
state: &'s mut Self::State,
|
||||
system_meta: &SystemMeta,
|
||||
world: &'w World,
|
||||
change_tick: u32,
|
||||
change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
ParamSet {
|
||||
param_states: state,
|
||||
@ -431,7 +431,7 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
|
||||
state: &'s2 mut Self::State,
|
||||
system_meta: &#path::system::SystemMeta,
|
||||
world: &'w2 #path::world::World,
|
||||
change_tick: u32,
|
||||
change_tick: #path::component::Tick,
|
||||
) -> Self::Item<'w2, 's2> {
|
||||
let (#(#tuple_patterns,)*) = <
|
||||
(#(#tuple_types,)*) as #path::system::SystemParam
|
||||
|
||||
@ -283,7 +283,7 @@ impl BundleInfo {
|
||||
components: &mut Components,
|
||||
storages: &'a mut Storages,
|
||||
archetype_id: ArchetypeId,
|
||||
change_tick: u32,
|
||||
change_tick: Tick,
|
||||
) -> BundleInserter<'a, 'b> {
|
||||
let new_archetype_id =
|
||||
self.add_bundle_to_archetype(archetypes, storages, components, archetype_id);
|
||||
@ -342,7 +342,7 @@ impl BundleInfo {
|
||||
archetypes: &'a mut Archetypes,
|
||||
components: &mut Components,
|
||||
storages: &'a mut Storages,
|
||||
change_tick: u32,
|
||||
change_tick: Tick,
|
||||
) -> BundleSpawner<'a, 'b> {
|
||||
let new_archetype_id =
|
||||
self.add_bundle_to_archetype(archetypes, storages, components, ArchetypeId::EMPTY);
|
||||
@ -383,7 +383,7 @@ impl BundleInfo {
|
||||
bundle_component_status: &S,
|
||||
entity: Entity,
|
||||
table_row: TableRow,
|
||||
change_tick: u32,
|
||||
change_tick: Tick,
|
||||
bundle: T,
|
||||
) {
|
||||
// NOTE: get_components calls this closure on each component in "bundle order".
|
||||
@ -397,7 +397,7 @@ impl BundleInfo {
|
||||
// SAFETY: bundle_component is a valid index for this bundle
|
||||
match bundle_component_status.get_status(bundle_component) {
|
||||
ComponentStatus::Added => {
|
||||
column.initialize(table_row, component_ptr, Tick::new(change_tick));
|
||||
column.initialize(table_row, component_ptr, change_tick);
|
||||
}
|
||||
ComponentStatus::Mutated => {
|
||||
column.replace(table_row, component_ptr, change_tick);
|
||||
@ -508,7 +508,7 @@ pub(crate) struct BundleInserter<'a, 'b> {
|
||||
sparse_sets: &'a mut SparseSets,
|
||||
result: InsertBundleResult<'a>,
|
||||
archetypes_ptr: *mut Archetype,
|
||||
change_tick: u32,
|
||||
change_tick: Tick,
|
||||
}
|
||||
|
||||
pub(crate) enum InsertBundleResult<'a> {
|
||||
@ -666,7 +666,7 @@ pub(crate) struct BundleSpawner<'a, 'b> {
|
||||
bundle_info: &'b BundleInfo,
|
||||
table: &'a mut Table,
|
||||
sparse_sets: &'a mut SparseSets,
|
||||
change_tick: u32,
|
||||
change_tick: Tick,
|
||||
}
|
||||
|
||||
impl<'a, 'b> BundleSpawner<'a, 'b> {
|
||||
|
||||
@ -56,7 +56,7 @@ pub trait DetectChanges {
|
||||
/// For comparison, the previous change tick of a system can be read using the
|
||||
/// [`SystemChangeTick`](crate::system::SystemChangeTick)
|
||||
/// [`SystemParam`](crate::system::SystemParam).
|
||||
fn last_changed(&self) -> u32;
|
||||
fn last_changed(&self) -> Tick;
|
||||
}
|
||||
|
||||
/// Types that implement reliable change detection.
|
||||
@ -109,7 +109,7 @@ pub trait DetectChangesMut: DetectChanges {
|
||||
/// This is a complex and error-prone operation, primarily intended for use with rollback networking strategies.
|
||||
/// If you merely want to flag this data as changed, use [`set_changed`](DetectChangesMut::set_changed) instead.
|
||||
/// If you want to avoid triggering change detection, use [`bypass_change_detection`](DetectChangesMut::bypass_change_detection) instead.
|
||||
fn set_last_changed(&mut self, last_change_tick: u32);
|
||||
fn set_last_changed(&mut self, last_changed: Tick);
|
||||
|
||||
/// Manually bypasses change detection, allowing you to mutate the underlying value without updating the change tick.
|
||||
///
|
||||
@ -145,19 +145,19 @@ macro_rules! change_detection_impl {
|
||||
fn is_added(&self) -> bool {
|
||||
self.ticks
|
||||
.added
|
||||
.is_newer_than(self.ticks.last_change_tick, self.ticks.change_tick)
|
||||
.is_newer_than(self.ticks.last_run, self.ticks.this_run)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_changed(&self) -> bool {
|
||||
self.ticks
|
||||
.changed
|
||||
.is_newer_than(self.ticks.last_change_tick, self.ticks.change_tick)
|
||||
.is_newer_than(self.ticks.last_run, self.ticks.this_run)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn last_changed(&self) -> u32 {
|
||||
self.ticks.changed.tick
|
||||
fn last_changed(&self) -> Tick {
|
||||
*self.ticks.changed
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,16 +186,12 @@ macro_rules! change_detection_mut_impl {
|
||||
|
||||
#[inline]
|
||||
fn set_changed(&mut self) {
|
||||
self.ticks
|
||||
.changed
|
||||
.set_changed(self.ticks.change_tick);
|
||||
*self.ticks.changed = self.ticks.this_run;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_last_changed(&mut self, last_changed: u32) {
|
||||
self.ticks
|
||||
.changed
|
||||
.set_changed(last_changed);
|
||||
fn set_last_changed(&mut self, last_changed: Tick) {
|
||||
*self.ticks.changed = last_changed;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -242,8 +238,8 @@ macro_rules! impl_methods {
|
||||
ticks: TicksMut {
|
||||
added: self.ticks.added,
|
||||
changed: self.ticks.changed,
|
||||
last_change_tick: self.ticks.last_change_tick,
|
||||
change_tick: self.ticks.change_tick,
|
||||
last_run: self.ticks.last_run,
|
||||
this_run: self.ticks.this_run,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -299,8 +295,8 @@ macro_rules! impl_debug {
|
||||
pub(crate) struct Ticks<'a> {
|
||||
pub(crate) added: &'a Tick,
|
||||
pub(crate) changed: &'a Tick,
|
||||
pub(crate) last_change_tick: u32,
|
||||
pub(crate) change_tick: u32,
|
||||
pub(crate) last_run: Tick,
|
||||
pub(crate) this_run: Tick,
|
||||
}
|
||||
|
||||
impl<'a> Ticks<'a> {
|
||||
@ -309,14 +305,14 @@ impl<'a> Ticks<'a> {
|
||||
#[inline]
|
||||
pub(crate) unsafe fn from_tick_cells(
|
||||
cells: TickCells<'a>,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> Self {
|
||||
Self {
|
||||
added: cells.added.deref(),
|
||||
changed: cells.changed.deref(),
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
last_run,
|
||||
this_run,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -324,8 +320,8 @@ impl<'a> Ticks<'a> {
|
||||
pub(crate) struct TicksMut<'a> {
|
||||
pub(crate) added: &'a mut Tick,
|
||||
pub(crate) changed: &'a mut Tick,
|
||||
pub(crate) last_change_tick: u32,
|
||||
pub(crate) change_tick: u32,
|
||||
pub(crate) last_run: Tick,
|
||||
pub(crate) this_run: Tick,
|
||||
}
|
||||
|
||||
impl<'a> TicksMut<'a> {
|
||||
@ -334,14 +330,14 @@ impl<'a> TicksMut<'a> {
|
||||
#[inline]
|
||||
pub(crate) unsafe fn from_tick_cells(
|
||||
cells: TickCells<'a>,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> Self {
|
||||
Self {
|
||||
added: cells.added.deref_mut(),
|
||||
changed: cells.changed.deref_mut(),
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
last_run,
|
||||
this_run,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -351,8 +347,8 @@ impl<'a> From<TicksMut<'a>> for Ticks<'a> {
|
||||
Ticks {
|
||||
added: ticks.added,
|
||||
changed: ticks.changed,
|
||||
last_change_tick: ticks.last_change_tick,
|
||||
change_tick: ticks.change_tick,
|
||||
last_run: ticks.last_run,
|
||||
this_run: ticks.this_run,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -550,23 +546,23 @@ impl<'a, T: ?Sized> Mut<'a, T> {
|
||||
/// - `last_changed` - A [`Tick`] that stores the last time the wrapped value was changed.
|
||||
/// This will be updated to the value of `change_tick` if the returned smart pointer
|
||||
/// is modified.
|
||||
/// - `last_change_tick` - A [`Tick`], occurring before `change_tick`, which is used
|
||||
/// - `last_run` - A [`Tick`], occurring before `this_run`, which is used
|
||||
/// as a reference to determine whether the wrapped value is newly added or changed.
|
||||
/// - `change_tick` - A [`Tick`] corresponding to the current point in time -- "now".
|
||||
/// - `this_run` - A [`Tick`] corresponding to the current point in time -- "now".
|
||||
pub fn new(
|
||||
value: &'a mut T,
|
||||
added: &'a mut Tick,
|
||||
last_changed: &'a mut Tick,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> Self {
|
||||
Self {
|
||||
value,
|
||||
ticks: TicksMut {
|
||||
added,
|
||||
changed: last_changed,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
last_run,
|
||||
this_run,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -643,8 +639,8 @@ impl<'a> MutUntyped<'a> {
|
||||
ticks: TicksMut {
|
||||
added: self.ticks.added,
|
||||
changed: self.ticks.changed,
|
||||
last_change_tick: self.ticks.last_change_tick,
|
||||
change_tick: self.ticks.change_tick,
|
||||
last_run: self.ticks.last_run,
|
||||
this_run: self.ticks.this_run,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -681,19 +677,19 @@ impl<'a> DetectChanges for MutUntyped<'a> {
|
||||
fn is_added(&self) -> bool {
|
||||
self.ticks
|
||||
.added
|
||||
.is_newer_than(self.ticks.last_change_tick, self.ticks.change_tick)
|
||||
.is_newer_than(self.ticks.last_run, self.ticks.this_run)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_changed(&self) -> bool {
|
||||
self.ticks
|
||||
.changed
|
||||
.is_newer_than(self.ticks.last_change_tick, self.ticks.change_tick)
|
||||
.is_newer_than(self.ticks.last_run, self.ticks.this_run)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn last_changed(&self) -> u32 {
|
||||
self.ticks.changed.tick
|
||||
fn last_changed(&self) -> Tick {
|
||||
*self.ticks.changed
|
||||
}
|
||||
}
|
||||
|
||||
@ -702,12 +698,12 @@ impl<'a> DetectChangesMut for MutUntyped<'a> {
|
||||
|
||||
#[inline]
|
||||
fn set_changed(&mut self) {
|
||||
self.ticks.changed.set_changed(self.ticks.change_tick);
|
||||
*self.ticks.changed = self.ticks.this_run;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_last_changed(&mut self, last_changed: u32) {
|
||||
self.ticks.changed.set_changed(last_changed);
|
||||
fn set_last_changed(&mut self, last_changed: Tick) {
|
||||
*self.ticks.changed = last_changed;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -792,7 +788,7 @@ mod tests {
|
||||
}
|
||||
|
||||
let mut world = World::new();
|
||||
world.last_change_tick = u32::MAX;
|
||||
world.last_change_tick = Tick::new(u32::MAX);
|
||||
*world.change_tick.get_mut() = 0;
|
||||
|
||||
// component added: 0, changed: 0
|
||||
@ -820,8 +816,8 @@ mod tests {
|
||||
|
||||
let mut query = world.query::<Ref<C>>();
|
||||
for tracker in query.iter(&world) {
|
||||
let ticks_since_insert = change_tick.wrapping_sub(tracker.ticks.added.tick);
|
||||
let ticks_since_change = change_tick.wrapping_sub(tracker.ticks.changed.tick);
|
||||
let ticks_since_insert = change_tick.relative_to(*tracker.ticks.added).get();
|
||||
let ticks_since_change = change_tick.relative_to(*tracker.ticks.changed).get();
|
||||
assert!(ticks_since_insert > MAX_CHANGE_AGE);
|
||||
assert!(ticks_since_change > MAX_CHANGE_AGE);
|
||||
}
|
||||
@ -830,8 +826,8 @@ mod tests {
|
||||
world.check_change_ticks();
|
||||
|
||||
for tracker in query.iter(&world) {
|
||||
let ticks_since_insert = change_tick.wrapping_sub(tracker.ticks.added.tick);
|
||||
let ticks_since_change = change_tick.wrapping_sub(tracker.ticks.changed.tick);
|
||||
let ticks_since_insert = change_tick.relative_to(*tracker.ticks.added).get();
|
||||
let ticks_since_change = change_tick.relative_to(*tracker.ticks.changed).get();
|
||||
assert!(ticks_since_insert == MAX_CHANGE_AGE);
|
||||
assert!(ticks_since_change == MAX_CHANGE_AGE);
|
||||
}
|
||||
@ -846,8 +842,8 @@ mod tests {
|
||||
let ticks = TicksMut {
|
||||
added: &mut component_ticks.added,
|
||||
changed: &mut component_ticks.changed,
|
||||
last_change_tick: 3,
|
||||
change_tick: 4,
|
||||
last_run: Tick::new(3),
|
||||
this_run: Tick::new(4),
|
||||
};
|
||||
let mut res = R {};
|
||||
let res_mut = ResMut {
|
||||
@ -856,10 +852,10 @@ mod tests {
|
||||
};
|
||||
|
||||
let into_mut: Mut<R> = res_mut.into();
|
||||
assert_eq!(1, into_mut.ticks.added.tick);
|
||||
assert_eq!(2, into_mut.ticks.changed.tick);
|
||||
assert_eq!(3, into_mut.ticks.last_change_tick);
|
||||
assert_eq!(4, into_mut.ticks.change_tick);
|
||||
assert_eq!(1, into_mut.ticks.added.get());
|
||||
assert_eq!(2, into_mut.ticks.changed.get());
|
||||
assert_eq!(3, into_mut.ticks.last_run.get());
|
||||
assert_eq!(4, into_mut.ticks.this_run.get());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -874,8 +870,8 @@ mod tests {
|
||||
&mut res,
|
||||
&mut component_ticks.added,
|
||||
&mut component_ticks.changed,
|
||||
2, // last_change_tick
|
||||
4, // current change_tick
|
||||
Tick::new(2), // last_run
|
||||
Tick::new(4), // this_run
|
||||
);
|
||||
|
||||
assert!(!val.is_added());
|
||||
@ -891,8 +887,8 @@ mod tests {
|
||||
let ticks = TicksMut {
|
||||
added: &mut component_ticks.added,
|
||||
changed: &mut component_ticks.changed,
|
||||
last_change_tick: 3,
|
||||
change_tick: 4,
|
||||
last_run: Tick::new(3),
|
||||
this_run: Tick::new(4),
|
||||
};
|
||||
let mut res = R {};
|
||||
let non_send_mut = NonSendMut {
|
||||
@ -901,10 +897,10 @@ mod tests {
|
||||
};
|
||||
|
||||
let into_mut: Mut<R> = non_send_mut.into();
|
||||
assert_eq!(1, into_mut.ticks.added.tick);
|
||||
assert_eq!(2, into_mut.ticks.changed.tick);
|
||||
assert_eq!(3, into_mut.ticks.last_change_tick);
|
||||
assert_eq!(4, into_mut.ticks.change_tick);
|
||||
assert_eq!(1, into_mut.ticks.added.get());
|
||||
assert_eq!(2, into_mut.ticks.changed.get());
|
||||
assert_eq!(3, into_mut.ticks.last_run.get());
|
||||
assert_eq!(4, into_mut.ticks.this_run.get());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -912,7 +908,8 @@ mod tests {
|
||||
use super::*;
|
||||
struct Outer(i64);
|
||||
|
||||
let (last_change_tick, change_tick) = (2, 3);
|
||||
let last_run = Tick::new(2);
|
||||
let this_run = Tick::new(3);
|
||||
let mut component_ticks = ComponentTicks {
|
||||
added: Tick::new(1),
|
||||
changed: Tick::new(2),
|
||||
@ -920,8 +917,8 @@ mod tests {
|
||||
let ticks = TicksMut {
|
||||
added: &mut component_ticks.added,
|
||||
changed: &mut component_ticks.changed,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
last_run,
|
||||
this_run,
|
||||
};
|
||||
|
||||
let mut outer = Outer(0);
|
||||
@ -939,7 +936,7 @@ mod tests {
|
||||
*inner = 64;
|
||||
assert!(inner.is_changed());
|
||||
// Modifying one field of a component should flag a change for the entire component.
|
||||
assert!(component_ticks.is_changed(last_change_tick, change_tick));
|
||||
assert!(component_ticks.is_changed(last_run, this_run));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@ -586,61 +586,72 @@ impl Components {
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to track changes in state between system runs, e.g. components being added or accessed mutably.
|
||||
/// A value that tracks when a system ran relative to other systems.
|
||||
/// This is used to power change detection.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Tick {
|
||||
pub(crate) tick: u32,
|
||||
tick: u32,
|
||||
}
|
||||
|
||||
impl Tick {
|
||||
/// The maximum relative age for a change tick.
|
||||
/// The value of this is equal to [`crate::change_detection::MAX_CHANGE_AGE`].
|
||||
///
|
||||
/// Since change detection will not work for any ticks older than this,
|
||||
/// ticks are periodically scanned to ensure their relative values are below this.
|
||||
pub const MAX: Self = Self::new(MAX_CHANGE_AGE);
|
||||
|
||||
pub const fn new(tick: u32) -> Self {
|
||||
Self { tick }
|
||||
}
|
||||
|
||||
/// Gets the value of this change tick.
|
||||
#[inline]
|
||||
/// Returns `true` if this `Tick` occurred since the system's `last_change_tick`.
|
||||
pub const fn get(self) -> u32 {
|
||||
self.tick
|
||||
}
|
||||
|
||||
/// Sets the value of this change tick.
|
||||
#[inline]
|
||||
pub fn set(&mut self, tick: u32) {
|
||||
self.tick = tick;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Returns `true` if this `Tick` occurred since the system's `last_run`.
|
||||
///
|
||||
/// `change_tick` is the current tick of the system, used as a reference to help deal with wraparound.
|
||||
pub fn is_newer_than(&self, last_change_tick: u32, change_tick: u32) -> bool {
|
||||
// This works even with wraparound because the world tick (`change_tick`) is always "newer" than
|
||||
// `last_change_tick` and `self.tick`, and we scan periodically to clamp `ComponentTicks` values
|
||||
/// `this_run` is the current tick of the system, used as a reference to help deal with wraparound.
|
||||
pub fn is_newer_than(self, last_run: Tick, this_run: Tick) -> bool {
|
||||
// This works even with wraparound because the world tick (`this_run`) is always "newer" than
|
||||
// `last_run` and `self.tick`, and we scan periodically to clamp `ComponentTicks` values
|
||||
// so they never get older than `u32::MAX` (the difference would overflow).
|
||||
//
|
||||
// The clamp here ensures determinism (since scans could differ between app runs).
|
||||
let ticks_since_insert = change_tick.wrapping_sub(self.tick).min(MAX_CHANGE_AGE);
|
||||
let ticks_since_system = change_tick
|
||||
.wrapping_sub(last_change_tick)
|
||||
.min(MAX_CHANGE_AGE);
|
||||
let ticks_since_insert = this_run.relative_to(self).tick.min(MAX_CHANGE_AGE);
|
||||
let ticks_since_system = this_run.relative_to(last_run).tick.min(MAX_CHANGE_AGE);
|
||||
|
||||
ticks_since_system > ticks_since_insert
|
||||
}
|
||||
|
||||
pub(crate) fn check_tick(&mut self, change_tick: u32) {
|
||||
let age = change_tick.wrapping_sub(self.tick);
|
||||
// This comparison assumes that `age` has not overflowed `u32::MAX` before, which will be true
|
||||
// so long as this check always runs before that can happen.
|
||||
if age > MAX_CHANGE_AGE {
|
||||
self.tick = change_tick.wrapping_sub(MAX_CHANGE_AGE);
|
||||
}
|
||||
/// Returns a change tick representing the relationship between `self` and `other`.
|
||||
pub(crate) fn relative_to(self, other: Self) -> Self {
|
||||
let tick = self.tick.wrapping_sub(other.tick);
|
||||
Self { tick }
|
||||
}
|
||||
|
||||
/// Manually sets the change tick.
|
||||
/// Wraps this change tick's value if it exceeds [`Tick::MAX`].
|
||||
///
|
||||
/// This is normally done automatically via the [`DerefMut`](std::ops::DerefMut) implementation
|
||||
/// on [`Mut<T>`](crate::change_detection::Mut), [`ResMut<T>`](crate::change_detection::ResMut), etc.
|
||||
/// However, components and resources that make use of interior mutability might require manual updates.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust,no_run
|
||||
/// # use bevy_ecs::{world::World, component::ComponentTicks};
|
||||
/// let world: World = unimplemented!();
|
||||
/// let component_ticks: ComponentTicks = unimplemented!();
|
||||
///
|
||||
/// component_ticks.set_changed(world.read_change_tick());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn set_changed(&mut self, change_tick: u32) {
|
||||
self.tick = change_tick;
|
||||
/// Returns `true` if wrapping was performed. Otherwise, returns `false`.
|
||||
pub(crate) fn check_tick(&mut self, tick: Tick) -> bool {
|
||||
let age = tick.relative_to(*self);
|
||||
// This comparison assumes that `age` has not overflowed `u32::MAX` before, which will be true
|
||||
// so long as this check always runs before that can happen.
|
||||
if age.get() > Self::MAX.get() {
|
||||
*self = tick.relative_to(Self::MAX);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -673,20 +684,20 @@ pub struct ComponentTicks {
|
||||
impl ComponentTicks {
|
||||
#[inline]
|
||||
/// Returns `true` if the component was added after the system last ran.
|
||||
pub fn is_added(&self, last_change_tick: u32, change_tick: u32) -> bool {
|
||||
self.added.is_newer_than(last_change_tick, change_tick)
|
||||
pub fn is_added(&self, last_run: Tick, this_run: Tick) -> bool {
|
||||
self.added.is_newer_than(last_run, this_run)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Returns `true` if the component was added or mutably dereferenced after the system last ran.
|
||||
pub fn is_changed(&self, last_change_tick: u32, change_tick: u32) -> bool {
|
||||
self.changed.is_newer_than(last_change_tick, change_tick)
|
||||
pub fn is_changed(&self, last_run: Tick, this_run: Tick) -> bool {
|
||||
self.changed.is_newer_than(last_run, this_run)
|
||||
}
|
||||
|
||||
pub(crate) fn new(change_tick: u32) -> Self {
|
||||
pub(crate) fn new(change_tick: Tick) -> Self {
|
||||
Self {
|
||||
added: Tick::new(change_tick),
|
||||
changed: Tick::new(change_tick),
|
||||
added: change_tick,
|
||||
changed: change_tick,
|
||||
}
|
||||
}
|
||||
|
||||
@ -705,8 +716,8 @@ impl ComponentTicks {
|
||||
/// component_ticks.set_changed(world.read_change_tick());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn set_changed(&mut self, change_tick: u32) {
|
||||
self.changed.set_changed(change_tick);
|
||||
pub fn set_changed(&mut self, change_tick: Tick) {
|
||||
self.changed = change_tick;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -329,8 +329,8 @@ pub unsafe trait WorldQuery {
|
||||
unsafe fn init_fetch<'w>(
|
||||
world: &'w World,
|
||||
state: &Self::State,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> Self::Fetch<'w>;
|
||||
|
||||
/// While this function can be called for any query, it is always safe to call if `Self: ReadOnlyWorldQuery` holds.
|
||||
@ -460,8 +460,8 @@ unsafe impl WorldQuery for Entity {
|
||||
unsafe fn init_fetch<'w>(
|
||||
_world: &'w World,
|
||||
_state: &Self::State,
|
||||
_last_change_tick: u32,
|
||||
_change_tick: u32,
|
||||
_last_run: Tick,
|
||||
_this_run: Tick,
|
||||
) -> Self::Fetch<'w> {
|
||||
}
|
||||
|
||||
@ -542,8 +542,8 @@ unsafe impl<T: Component> WorldQuery for &T {
|
||||
unsafe fn init_fetch<'w>(
|
||||
world: &'w World,
|
||||
&component_id: &ComponentId,
|
||||
_last_change_tick: u32,
|
||||
_change_tick: u32,
|
||||
_last_run: Tick,
|
||||
_this_run: Tick,
|
||||
) -> ReadFetch<'w, T> {
|
||||
ReadFetch {
|
||||
table_components: None,
|
||||
@ -660,8 +660,8 @@ pub struct RefFetch<'w, T> {
|
||||
// T::Storage = SparseStorage
|
||||
sparse_set: Option<&'w ComponentSparseSet>,
|
||||
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
}
|
||||
|
||||
/// SAFETY: `Self` is the same as `Self::ReadOnly`
|
||||
@ -687,8 +687,8 @@ unsafe impl<'__w, T: Component> WorldQuery for Ref<'__w, T> {
|
||||
unsafe fn init_fetch<'w>(
|
||||
world: &'w World,
|
||||
&component_id: &ComponentId,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> RefFetch<'w, T> {
|
||||
RefFetch {
|
||||
table_data: None,
|
||||
@ -699,8 +699,8 @@ unsafe impl<'__w, T: Component> WorldQuery for Ref<'__w, T> {
|
||||
.get(component_id)
|
||||
.debug_checked_unwrap()
|
||||
}),
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
last_run,
|
||||
this_run,
|
||||
}
|
||||
}
|
||||
|
||||
@ -708,8 +708,8 @@ unsafe impl<'__w, T: Component> WorldQuery for Ref<'__w, T> {
|
||||
RefFetch {
|
||||
table_data: fetch.table_data,
|
||||
sparse_set: fetch.sparse_set,
|
||||
last_change_tick: fetch.last_change_tick,
|
||||
change_tick: fetch.change_tick,
|
||||
last_run: fetch.last_run,
|
||||
this_run: fetch.this_run,
|
||||
}
|
||||
}
|
||||
|
||||
@ -754,8 +754,8 @@ unsafe impl<'__w, T: Component> WorldQuery for Ref<'__w, T> {
|
||||
ticks: Ticks {
|
||||
added: added_ticks.get(table_row.index()).deref(),
|
||||
changed: changed_ticks.get(table_row.index()).deref(),
|
||||
change_tick: fetch.change_tick,
|
||||
last_change_tick: fetch.last_change_tick,
|
||||
this_run: fetch.this_run,
|
||||
last_run: fetch.last_run,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -767,7 +767,7 @@ unsafe impl<'__w, T: Component> WorldQuery for Ref<'__w, T> {
|
||||
.debug_checked_unwrap();
|
||||
Ref {
|
||||
value: component.deref(),
|
||||
ticks: Ticks::from_tick_cells(ticks, fetch.last_change_tick, fetch.change_tick),
|
||||
ticks: Ticks::from_tick_cells(ticks, fetch.last_run, fetch.this_run),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -821,8 +821,8 @@ pub struct WriteFetch<'w, T> {
|
||||
// T::Storage = SparseStorage
|
||||
sparse_set: Option<&'w ComponentSparseSet>,
|
||||
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
}
|
||||
|
||||
/// SAFETY: access of `&T` is a subset of `&mut T`
|
||||
@ -848,8 +848,8 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
|
||||
unsafe fn init_fetch<'w>(
|
||||
world: &'w World,
|
||||
&component_id: &ComponentId,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> WriteFetch<'w, T> {
|
||||
WriteFetch {
|
||||
table_data: None,
|
||||
@ -860,8 +860,8 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
|
||||
.get(component_id)
|
||||
.debug_checked_unwrap()
|
||||
}),
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
last_run,
|
||||
this_run,
|
||||
}
|
||||
}
|
||||
|
||||
@ -869,8 +869,8 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
|
||||
WriteFetch {
|
||||
table_data: fetch.table_data,
|
||||
sparse_set: fetch.sparse_set,
|
||||
last_change_tick: fetch.last_change_tick,
|
||||
change_tick: fetch.change_tick,
|
||||
last_run: fetch.last_run,
|
||||
this_run: fetch.this_run,
|
||||
}
|
||||
}
|
||||
|
||||
@ -915,8 +915,8 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
|
||||
ticks: TicksMut {
|
||||
added: added_ticks.get(table_row.index()).deref_mut(),
|
||||
changed: changed_ticks.get(table_row.index()).deref_mut(),
|
||||
change_tick: fetch.change_tick,
|
||||
last_change_tick: fetch.last_change_tick,
|
||||
this_run: fetch.this_run,
|
||||
last_run: fetch.last_run,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -928,11 +928,7 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
|
||||
.debug_checked_unwrap();
|
||||
Mut {
|
||||
value: component.assert_unique().deref_mut(),
|
||||
ticks: TicksMut::from_tick_cells(
|
||||
ticks,
|
||||
fetch.last_change_tick,
|
||||
fetch.change_tick,
|
||||
),
|
||||
ticks: TicksMut::from_tick_cells(ticks, fetch.last_run, fetch.this_run),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -996,11 +992,11 @@ unsafe impl<T: WorldQuery> WorldQuery for Option<T> {
|
||||
unsafe fn init_fetch<'w>(
|
||||
world: &'w World,
|
||||
state: &T::State,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> OptionFetch<'w, T> {
|
||||
OptionFetch {
|
||||
fetch: T::init_fetch(world, state, last_change_tick, change_tick),
|
||||
fetch: T::init_fetch(world, state, last_run, this_run),
|
||||
matches: false,
|
||||
}
|
||||
}
|
||||
@ -1114,8 +1110,8 @@ unsafe impl<T: ReadOnlyWorldQuery> ReadOnlyWorldQuery for Option<T> {}
|
||||
#[deprecated = "`ChangeTrackers<T>` will be removed in bevy 0.11. Use `bevy_ecs::prelude::Ref<T>` instead."]
|
||||
pub struct ChangeTrackers<T: Component> {
|
||||
pub(crate) component_ticks: ComponentTicks,
|
||||
pub(crate) last_change_tick: u32,
|
||||
pub(crate) change_tick: u32,
|
||||
pub(crate) last_run: Tick,
|
||||
pub(crate) this_run: Tick,
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
@ -1134,8 +1130,8 @@ impl<T: Component> std::fmt::Debug for ChangeTrackers<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ChangeTrackers")
|
||||
.field("component_ticks", &self.component_ticks)
|
||||
.field("last_change_tick", &self.last_change_tick)
|
||||
.field("change_tick", &self.change_tick)
|
||||
.field("last_run", &self.last_run)
|
||||
.field("this_run", &self.this_run)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@ -1144,14 +1140,13 @@ impl<T: Component> std::fmt::Debug for ChangeTrackers<T> {
|
||||
impl<T: Component> ChangeTrackers<T> {
|
||||
/// Returns true if this component has been added since the last execution of this system.
|
||||
pub fn is_added(&self) -> bool {
|
||||
self.component_ticks
|
||||
.is_added(self.last_change_tick, self.change_tick)
|
||||
self.component_ticks.is_added(self.last_run, self.this_run)
|
||||
}
|
||||
|
||||
/// Returns true if this component has been changed since the last execution of this system.
|
||||
pub fn is_changed(&self) -> bool {
|
||||
self.component_ticks
|
||||
.is_changed(self.last_change_tick, self.change_tick)
|
||||
.is_changed(self.last_run, self.this_run)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1164,8 +1159,8 @@ pub struct ChangeTrackersFetch<'w, T> {
|
||||
sparse_set: Option<&'w ComponentSparseSet>,
|
||||
|
||||
marker: PhantomData<T>,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
@ -1192,8 +1187,8 @@ unsafe impl<T: Component> WorldQuery for ChangeTrackers<T> {
|
||||
unsafe fn init_fetch<'w>(
|
||||
world: &'w World,
|
||||
&component_id: &ComponentId,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> ChangeTrackersFetch<'w, T> {
|
||||
ChangeTrackersFetch {
|
||||
table_added: None,
|
||||
@ -1206,8 +1201,8 @@ unsafe impl<T: Component> WorldQuery for ChangeTrackers<T> {
|
||||
.debug_checked_unwrap()
|
||||
}),
|
||||
marker: PhantomData,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
last_run,
|
||||
this_run,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1217,8 +1212,8 @@ unsafe impl<T: Component> WorldQuery for ChangeTrackers<T> {
|
||||
table_changed: fetch.table_changed,
|
||||
sparse_set: fetch.sparse_set,
|
||||
marker: fetch.marker,
|
||||
last_change_tick: fetch.last_change_tick,
|
||||
change_tick: fetch.change_tick,
|
||||
last_run: fetch.last_run,
|
||||
this_run: fetch.this_run,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1268,8 +1263,8 @@ unsafe impl<T: Component> WorldQuery for ChangeTrackers<T> {
|
||||
}
|
||||
},
|
||||
marker: PhantomData,
|
||||
last_change_tick: fetch.last_change_tick,
|
||||
change_tick: fetch.change_tick,
|
||||
last_run: fetch.last_run,
|
||||
this_run: fetch.this_run,
|
||||
},
|
||||
StorageType::SparseSet => ChangeTrackers {
|
||||
component_ticks: fetch
|
||||
@ -1278,8 +1273,8 @@ unsafe impl<T: Component> WorldQuery for ChangeTrackers<T> {
|
||||
.get_ticks(entity)
|
||||
.debug_checked_unwrap(),
|
||||
marker: PhantomData,
|
||||
last_change_tick: fetch.last_change_tick,
|
||||
change_tick: fetch.change_tick,
|
||||
last_run: fetch.last_run,
|
||||
this_run: fetch.this_run,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1338,9 +1333,9 @@ macro_rules! impl_tuple_fetch {
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_unit)]
|
||||
unsafe fn init_fetch<'w>(_world: &'w World, state: &Self::State, _last_change_tick: u32, _change_tick: u32) -> Self::Fetch<'w> {
|
||||
unsafe fn init_fetch<'w>(_world: &'w World, state: &Self::State, _last_run: Tick, _this_run: Tick) -> Self::Fetch<'w> {
|
||||
let ($($name,)*) = state;
|
||||
($($name::init_fetch(_world, $name, _last_change_tick, _change_tick),)*)
|
||||
($($name::init_fetch(_world, $name, _last_run, _this_run),)*)
|
||||
}
|
||||
|
||||
unsafe fn clone_fetch<'w>(
|
||||
@ -1447,9 +1442,9 @@ macro_rules! impl_anytuple_fetch {
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_unit)]
|
||||
unsafe fn init_fetch<'w>(_world: &'w World, state: &Self::State, _last_change_tick: u32, _change_tick: u32) -> Self::Fetch<'w> {
|
||||
unsafe fn init_fetch<'w>(_world: &'w World, state: &Self::State, _last_run: Tick, _this_run: Tick) -> Self::Fetch<'w> {
|
||||
let ($($name,)*) = state;
|
||||
($(($name::init_fetch(_world, $name, _last_change_tick, _change_tick), false),)*)
|
||||
($(($name::init_fetch(_world, $name, _last_run, _this_run), false),)*)
|
||||
}
|
||||
|
||||
unsafe fn clone_fetch<'w>(
|
||||
@ -1585,13 +1580,7 @@ unsafe impl<Q: WorldQuery> WorldQuery for NopWorldQuery<Q> {
|
||||
const IS_ARCHETYPAL: bool = true;
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn init_fetch(
|
||||
_world: &World,
|
||||
_state: &Q::State,
|
||||
_last_change_tick: u32,
|
||||
_change_tick: u32,
|
||||
) {
|
||||
}
|
||||
unsafe fn init_fetch(_world: &World, _state: &Q::State, _last_run: Tick, _this_run: Tick) {}
|
||||
|
||||
unsafe fn clone_fetch<'w>(_fetch: &Self::Fetch<'w>) -> Self::Fetch<'w> {}
|
||||
|
||||
|
||||
@ -50,13 +50,7 @@ unsafe impl<T: Component> WorldQuery for With<T> {
|
||||
|
||||
fn shrink<'wlong: 'wshort, 'wshort>(_: Self::Item<'wlong>) -> Self::Item<'wshort> {}
|
||||
|
||||
unsafe fn init_fetch(
|
||||
_world: &World,
|
||||
_state: &ComponentId,
|
||||
_last_change_tick: u32,
|
||||
_change_tick: u32,
|
||||
) {
|
||||
}
|
||||
unsafe fn init_fetch(_world: &World, _state: &ComponentId, _last_run: Tick, _this_run: Tick) {}
|
||||
|
||||
unsafe fn clone_fetch<'w>(_fetch: &Self::Fetch<'w>) -> Self::Fetch<'w> {}
|
||||
|
||||
@ -152,13 +146,7 @@ unsafe impl<T: Component> WorldQuery for Without<T> {
|
||||
|
||||
fn shrink<'wlong: 'wshort, 'wshort>(_: Self::Item<'wlong>) -> Self::Item<'wshort> {}
|
||||
|
||||
unsafe fn init_fetch(
|
||||
_world: &World,
|
||||
_state: &ComponentId,
|
||||
_last_change_tick: u32,
|
||||
_change_tick: u32,
|
||||
) {
|
||||
}
|
||||
unsafe fn init_fetch(_world: &World, _state: &ComponentId, _last_run: Tick, _this_run: Tick) {}
|
||||
|
||||
unsafe fn clone_fetch<'w>(_fetch: &Self::Fetch<'w>) -> Self::Fetch<'w> {}
|
||||
|
||||
@ -277,10 +265,10 @@ macro_rules! impl_query_filter_tuple {
|
||||
|
||||
const IS_ARCHETYPAL: bool = true $(&& $filter::IS_ARCHETYPAL)*;
|
||||
|
||||
unsafe fn init_fetch<'w>(world: &'w World, state: &Self::State, last_change_tick: u32, change_tick: u32) -> Self::Fetch<'w> {
|
||||
unsafe fn init_fetch<'w>(world: &'w World, state: &Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
|
||||
let ($($filter,)*) = state;
|
||||
($(OrFetch {
|
||||
fetch: $filter::init_fetch(world, $filter, last_change_tick, change_tick),
|
||||
fetch: $filter::init_fetch(world, $filter, last_run, this_run),
|
||||
matches: false,
|
||||
},)*)
|
||||
}
|
||||
@ -417,8 +405,8 @@ macro_rules! impl_tick_filter {
|
||||
table_ticks: Option< ThinSlicePtr<'w, UnsafeCell<Tick>>>,
|
||||
marker: PhantomData<T>,
|
||||
sparse_set: Option<&'w ComponentSparseSet>,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
}
|
||||
|
||||
// SAFETY: `Self::ReadOnly` is the same as `Self`
|
||||
@ -432,7 +420,7 @@ macro_rules! impl_tick_filter {
|
||||
item
|
||||
}
|
||||
|
||||
unsafe fn init_fetch<'w>(world: &'w World, &id: &ComponentId, last_change_tick: u32, change_tick: u32) -> Self::Fetch<'w> {
|
||||
unsafe fn init_fetch<'w>(world: &'w World, &id: &ComponentId, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
|
||||
Self::Fetch::<'w> {
|
||||
table_ticks: None,
|
||||
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet)
|
||||
@ -443,8 +431,8 @@ macro_rules! impl_tick_filter {
|
||||
.debug_checked_unwrap()
|
||||
}),
|
||||
marker: PhantomData,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
last_run,
|
||||
this_run,
|
||||
}
|
||||
}
|
||||
|
||||
@ -454,8 +442,8 @@ macro_rules! impl_tick_filter {
|
||||
$fetch_name {
|
||||
table_ticks: fetch.table_ticks,
|
||||
sparse_set: fetch.sparse_set,
|
||||
last_change_tick: fetch.last_change_tick,
|
||||
change_tick: fetch.change_tick,
|
||||
last_run: fetch.last_run,
|
||||
this_run: fetch.this_run,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
@ -509,7 +497,7 @@ macro_rules! impl_tick_filter {
|
||||
.debug_checked_unwrap()
|
||||
.get(table_row.index())
|
||||
.deref()
|
||||
.is_newer_than(fetch.last_change_tick, fetch.change_tick)
|
||||
.is_newer_than(fetch.last_run, fetch.this_run)
|
||||
}
|
||||
StorageType::SparseSet => {
|
||||
let sparse_set = &fetch
|
||||
@ -518,7 +506,7 @@ macro_rules! impl_tick_filter {
|
||||
$get_sparse_set(sparse_set, entity)
|
||||
.debug_checked_unwrap()
|
||||
.deref()
|
||||
.is_newer_than(fetch.last_change_tick, fetch.change_tick)
|
||||
.is_newer_than(fetch.last_run, fetch.this_run)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use crate::{
|
||||
archetype::{ArchetypeEntity, ArchetypeId, Archetypes},
|
||||
component::Tick,
|
||||
entity::{Entities, Entity},
|
||||
prelude::World,
|
||||
query::{ArchetypeFilter, DebugCheckedUnwrap, QueryState, WorldQuery},
|
||||
@ -29,14 +30,14 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIter<'w, 's, Q, F> {
|
||||
pub(crate) unsafe fn new(
|
||||
world: &'w World,
|
||||
query_state: &'s QueryState<Q, F>,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> Self {
|
||||
QueryIter {
|
||||
query_state,
|
||||
tables: &world.storages().tables,
|
||||
archetypes: &world.archetypes,
|
||||
cursor: QueryIterationCursor::init(world, query_state, last_change_tick, change_tick),
|
||||
cursor: QueryIterationCursor::init(world, query_state, last_run, this_run),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -98,21 +99,11 @@ where
|
||||
world: &'w World,
|
||||
query_state: &'s QueryState<Q, F>,
|
||||
entity_list: EntityList,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> QueryManyIter<'w, 's, Q, F, I> {
|
||||
let fetch = Q::init_fetch(
|
||||
world,
|
||||
&query_state.fetch_state,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
);
|
||||
let filter = F::init_fetch(
|
||||
world,
|
||||
&query_state.filter_state,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
);
|
||||
let fetch = Q::init_fetch(world, &query_state.fetch_state, last_run, this_run);
|
||||
let filter = F::init_fetch(world, &query_state.filter_state, last_run, this_run);
|
||||
QueryManyIter {
|
||||
query_state,
|
||||
entities: &world.entities,
|
||||
@ -298,8 +289,8 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery, const K: usize>
|
||||
pub(crate) unsafe fn new(
|
||||
world: &'w World,
|
||||
query_state: &'s QueryState<Q, F>,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> Self {
|
||||
// Initialize array with cursors.
|
||||
// There is no FromIterator on arrays, so instead initialize it manually with MaybeUninit
|
||||
@ -312,16 +303,16 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery, const K: usize>
|
||||
ptr.write(QueryIterationCursor::init(
|
||||
world,
|
||||
query_state,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
last_run,
|
||||
this_run,
|
||||
));
|
||||
}
|
||||
for slot in (1..K).map(|offset| ptr.add(offset)) {
|
||||
slot.write(QueryIterationCursor::init_empty(
|
||||
world,
|
||||
query_state,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
last_run,
|
||||
this_run,
|
||||
));
|
||||
}
|
||||
|
||||
@ -496,34 +487,24 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's,
|
||||
unsafe fn init_empty(
|
||||
world: &'w World,
|
||||
query_state: &'s QueryState<Q, F>,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> Self {
|
||||
QueryIterationCursor {
|
||||
table_id_iter: [].iter(),
|
||||
archetype_id_iter: [].iter(),
|
||||
..Self::init(world, query_state, last_change_tick, change_tick)
|
||||
..Self::init(world, query_state, last_run, this_run)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn init(
|
||||
world: &'w World,
|
||||
query_state: &'s QueryState<Q, F>,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> Self {
|
||||
let fetch = Q::init_fetch(
|
||||
world,
|
||||
&query_state.fetch_state,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
);
|
||||
let filter = F::init_fetch(
|
||||
world,
|
||||
&query_state.filter_state,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
);
|
||||
let fetch = Q::init_fetch(world, &query_state.fetch_state, last_run, this_run);
|
||||
let filter = F::init_fetch(world, &query_state.filter_state, last_run, this_run);
|
||||
QueryIterationCursor {
|
||||
fetch,
|
||||
filter,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
archetype::{Archetype, ArchetypeComponentId, ArchetypeGeneration, ArchetypeId},
|
||||
component::ComponentId,
|
||||
component::{ComponentId, Tick},
|
||||
entity::Entity,
|
||||
prelude::FromWorld,
|
||||
query::{
|
||||
@ -130,11 +130,11 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||
|
||||
/// Checks if the query is empty for the given [`World`], where the last change and current tick are given.
|
||||
#[inline]
|
||||
pub fn is_empty(&self, world: &World, last_change_tick: u32, change_tick: u32) -> bool {
|
||||
pub fn is_empty(&self, world: &World, last_run: Tick, this_run: Tick) -> bool {
|
||||
// SAFETY: NopFetch does not access any members while &self ensures no one has exclusive access
|
||||
unsafe {
|
||||
self.as_nop()
|
||||
.iter_unchecked_manual(world, last_change_tick, change_tick)
|
||||
.iter_unchecked_manual(world, last_run, this_run)
|
||||
.next()
|
||||
.is_none()
|
||||
}
|
||||
@ -390,8 +390,8 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||
&self,
|
||||
world: &'w World,
|
||||
entity: Entity,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> Result<Q::Item<'w>, QueryEntityError> {
|
||||
let location = world
|
||||
.entities
|
||||
@ -407,8 +407,8 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||
.archetypes
|
||||
.get(location.archetype_id)
|
||||
.debug_checked_unwrap();
|
||||
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 mut fetch = Q::init_fetch(world, &self.fetch_state, last_run, this_run);
|
||||
let mut filter = F::init_fetch(world, &self.filter_state, last_run, this_run);
|
||||
|
||||
let table = world
|
||||
.storages()
|
||||
@ -436,20 +436,17 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||
&self,
|
||||
world: &'w World,
|
||||
entities: [Entity; N],
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> Result<[ROQueryItem<'w, Q>; N], QueryEntityError> {
|
||||
let mut values = [(); N].map(|_| MaybeUninit::uninit());
|
||||
|
||||
for (value, entity) in std::iter::zip(&mut values, entities) {
|
||||
// SAFETY: fetch is read-only
|
||||
// and world must be validated
|
||||
let item = self.as_readonly().get_unchecked_manual(
|
||||
world,
|
||||
entity,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
)?;
|
||||
let item = self
|
||||
.as_readonly()
|
||||
.get_unchecked_manual(world, entity, last_run, this_run)?;
|
||||
*value = MaybeUninit::new(item);
|
||||
}
|
||||
|
||||
@ -471,8 +468,8 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||
&self,
|
||||
world: &'w World,
|
||||
entities: [Entity; N],
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> Result<[Q::Item<'w>; N], QueryEntityError> {
|
||||
// Verify that all entities are unique
|
||||
for i in 0..N {
|
||||
@ -486,7 +483,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||
let mut values = [(); N].map(|_| MaybeUninit::uninit());
|
||||
|
||||
for (value, entity) in std::iter::zip(&mut values, entities) {
|
||||
let item = self.get_unchecked_manual(world, entity, last_change_tick, change_tick)?;
|
||||
let item = self.get_unchecked_manual(world, entity, last_run, this_run)?;
|
||||
*value = MaybeUninit::new(item);
|
||||
}
|
||||
|
||||
@ -708,10 +705,10 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||
pub(crate) unsafe fn iter_unchecked_manual<'w, 's>(
|
||||
&'s self,
|
||||
world: &'w World,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> QueryIter<'w, 's, Q, F> {
|
||||
QueryIter::new(world, self, last_change_tick, change_tick)
|
||||
QueryIter::new(world, self, last_run, this_run)
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] for the given [`World`] and list of [`Entity`]'s, where the last change and
|
||||
@ -729,13 +726,13 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||
&'s self,
|
||||
entities: EntityList,
|
||||
world: &'w World,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> QueryManyIter<'w, 's, Q, F, EntityList::IntoIter>
|
||||
where
|
||||
EntityList::Item: Borrow<Entity>,
|
||||
{
|
||||
QueryManyIter::new(world, self, entities, last_change_tick, change_tick)
|
||||
QueryManyIter::new(world, self, entities, last_run, this_run)
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] over all possible combinations of `K` query results for the
|
||||
@ -752,10 +749,10 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||
pub(crate) unsafe fn iter_combinations_unchecked_manual<'w, 's, const K: usize>(
|
||||
&'s self,
|
||||
world: &'w World,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> QueryCombinationIter<'w, 's, Q, F, K> {
|
||||
QueryCombinationIter::new(world, self, last_change_tick, change_tick)
|
||||
QueryCombinationIter::new(world, self, last_run, this_run)
|
||||
}
|
||||
|
||||
/// Runs `func` on each query result for the given [`World`]. This is faster than the equivalent
|
||||
@ -856,13 +853,13 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||
&self,
|
||||
world: &'w World,
|
||||
mut func: FN,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) {
|
||||
// NOTE: If you are changing query iteration code, remember to update the following places, where relevant:
|
||||
// QueryIter, QueryIterationCursor, QueryManyIter, QueryCombinationIter, QueryState::for_each_unchecked_manual, QueryState::par_for_each_unchecked_manual
|
||||
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 mut fetch = Q::init_fetch(world, &self.fetch_state, last_run, this_run);
|
||||
let mut filter = F::init_fetch(world, &self.filter_state, last_run, this_run);
|
||||
|
||||
let tables = &world.storages().tables;
|
||||
if Q::IS_DENSE && F::IS_DENSE {
|
||||
@ -931,8 +928,8 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||
world: &'w World,
|
||||
batch_size: usize,
|
||||
func: FN,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) {
|
||||
// NOTE: If you are changing query iteration code, remember to update the following places, where relevant:
|
||||
// QueryIter, QueryIterationCursor, QueryManyIter, QueryCombinationIter, QueryState::for_each_unchecked_manual, QueryState::par_for_each_unchecked_manual
|
||||
@ -950,18 +947,10 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||
let func = func.clone();
|
||||
let len = batch_size.min(table.entity_count() - offset);
|
||||
let task = async move {
|
||||
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 mut fetch =
|
||||
Q::init_fetch(world, &self.fetch_state, last_run, this_run);
|
||||
let mut filter =
|
||||
F::init_fetch(world, &self.filter_state, last_run, this_run);
|
||||
let tables = &world.storages().tables;
|
||||
let table = tables.get(*table_id).debug_checked_unwrap();
|
||||
let entities = table.entities();
|
||||
@ -1002,18 +991,10 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||
let func = func.clone();
|
||||
let len = batch_size.min(archetype.len() - offset);
|
||||
let task = async move {
|
||||
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 mut fetch =
|
||||
Q::init_fetch(world, &self.fetch_state, last_run, this_run);
|
||||
let mut filter =
|
||||
F::init_fetch(world, &self.filter_state, last_run, this_run);
|
||||
let tables = &world.storages().tables;
|
||||
let archetype =
|
||||
world.archetypes.get(*archetype_id).debug_checked_unwrap();
|
||||
@ -1161,10 +1142,10 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||
pub unsafe fn get_single_unchecked_manual<'w>(
|
||||
&self,
|
||||
world: &'w World,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> Result<Q::Item<'w>, QuerySingleError> {
|
||||
let mut query = self.iter_unchecked_manual(world, last_change_tick, change_tick);
|
||||
let mut query = self.iter_unchecked_manual(world, last_run, this_run);
|
||||
let first = query.next();
|
||||
let extra = query.next().is_some();
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
use crate::{
|
||||
self as bevy_ecs,
|
||||
component::{Component, ComponentId, ComponentIdFor},
|
||||
component::{Component, ComponentId, ComponentIdFor, Tick},
|
||||
entity::Entity,
|
||||
event::{EventId, Events, ManualEventIterator, ManualEventIteratorWithId, ManualEventReader},
|
||||
prelude::Local,
|
||||
@ -265,7 +265,7 @@ unsafe impl<'a> SystemParam for &'a RemovedComponentEvents {
|
||||
_state: &'s mut Self::State,
|
||||
_system_meta: &SystemMeta,
|
||||
world: &'w World,
|
||||
_change_tick: u32,
|
||||
_change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
world.removed_components()
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ use fixedbitset::FixedBitSet;
|
||||
|
||||
use crate::{
|
||||
self as bevy_ecs,
|
||||
component::{ComponentId, Components},
|
||||
component::{ComponentId, Components, Tick},
|
||||
schedule::*,
|
||||
system::{BoxedSystem, Resource, System},
|
||||
world::World,
|
||||
@ -99,7 +99,7 @@ impl Schedules {
|
||||
/// Iterates the change ticks of all systems in all stored schedules and clamps any older than
|
||||
/// [`MAX_CHANGE_AGE`](crate::change_detection::MAX_CHANGE_AGE).
|
||||
/// This prevents overflow and thus prevents false positives.
|
||||
pub(crate) fn check_change_ticks(&mut self, change_tick: u32) {
|
||||
pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
|
||||
#[cfg(feature = "trace")]
|
||||
let _all_span = info_span!("check stored schedule ticks").entered();
|
||||
// label used when trace feature is enabled
|
||||
@ -283,7 +283,7 @@ impl Schedule {
|
||||
/// Iterates the change ticks of all systems in the schedule and clamps any older than
|
||||
/// [`MAX_CHANGE_AGE`](crate::change_detection::MAX_CHANGE_AGE).
|
||||
/// This prevents overflow and thus prevents false positives.
|
||||
pub(crate) fn check_change_ticks(&mut self, change_tick: u32) {
|
||||
pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
|
||||
for system in &mut self.executable.systems {
|
||||
system.check_change_tick(change_tick);
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use crate::archetype::ArchetypeComponentId;
|
||||
use crate::change_detection::{MutUntyped, TicksMut};
|
||||
use crate::component::{ComponentId, ComponentTicks, Components, TickCells};
|
||||
use crate::component::{ComponentId, ComponentTicks, Components, Tick, TickCells};
|
||||
use crate::storage::{Column, SparseSet, TableRow};
|
||||
use bevy_ptr::{OwningPtr, Ptr, UnsafeCellDeref};
|
||||
use std::{mem::ManuallyDrop, thread::ThreadId};
|
||||
@ -111,17 +111,13 @@ impl<const SEND: bool> ResourceData<SEND> {
|
||||
/// # Panics
|
||||
/// If `SEND` is false, this will panic if a value is present and is not accessed from the
|
||||
/// original thread it was inserted in.
|
||||
pub(crate) fn get_mut(
|
||||
&mut self,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
) -> Option<MutUntyped<'_>> {
|
||||
pub(crate) fn get_mut(&mut self, last_run: Tick, this_run: Tick) -> Option<MutUntyped<'_>> {
|
||||
let (ptr, ticks) = self.get_with_ticks()?;
|
||||
Some(MutUntyped {
|
||||
// SAFETY: We have exclusive access to the underlying storage.
|
||||
value: unsafe { ptr.assert_unique() },
|
||||
// SAFETY: We have exclusive access to the underlying storage.
|
||||
ticks: unsafe { TicksMut::from_tick_cells(ticks, last_change_tick, change_tick) },
|
||||
ticks: unsafe { TicksMut::from_tick_cells(ticks, last_run, this_run) },
|
||||
})
|
||||
}
|
||||
|
||||
@ -135,7 +131,7 @@ impl<const SEND: bool> ResourceData<SEND> {
|
||||
/// # Safety
|
||||
/// - `value` must be valid for the underlying type for the resource.
|
||||
#[inline]
|
||||
pub(crate) unsafe fn insert(&mut self, value: OwningPtr<'_>, change_tick: u32) {
|
||||
pub(crate) unsafe fn insert(&mut self, value: OwningPtr<'_>, change_tick: Tick) {
|
||||
if self.is_present() {
|
||||
self.validate_access();
|
||||
self.column.replace(Self::ROW, value, change_tick);
|
||||
@ -284,7 +280,7 @@ impl<const SEND: bool> Resources<SEND> {
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn check_change_ticks(&mut self, change_tick: u32) {
|
||||
pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
|
||||
for info in self.resources.values_mut() {
|
||||
info.column.check_change_ticks(change_tick);
|
||||
}
|
||||
|
||||
@ -163,7 +163,12 @@ impl ComponentSparseSet {
|
||||
/// # Safety
|
||||
/// The `value` pointer must point to a valid address that matches the [`Layout`](std::alloc::Layout)
|
||||
/// inside the [`ComponentInfo`] given when constructing this sparse set.
|
||||
pub(crate) unsafe fn insert(&mut self, entity: Entity, value: OwningPtr<'_>, change_tick: u32) {
|
||||
pub(crate) unsafe fn insert(
|
||||
&mut self,
|
||||
entity: Entity,
|
||||
value: OwningPtr<'_>,
|
||||
change_tick: Tick,
|
||||
) {
|
||||
if let Some(&dense_index) = self.sparse.get(entity.index()) {
|
||||
#[cfg(debug_assertions)]
|
||||
assert_eq!(entity, self.entities[dense_index as usize]);
|
||||
@ -332,7 +337,7 @@ impl ComponentSparseSet {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn check_change_ticks(&mut self, change_tick: u32) {
|
||||
pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
|
||||
self.dense.check_change_ticks(change_tick);
|
||||
}
|
||||
}
|
||||
@ -614,7 +619,7 @@ impl SparseSets {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn check_change_ticks(&mut self, change_tick: u32) {
|
||||
pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
|
||||
for set in self.sets.values_mut() {
|
||||
set.check_change_ticks(change_tick);
|
||||
}
|
||||
|
||||
@ -152,13 +152,10 @@ impl Column {
|
||||
/// # Safety
|
||||
/// Assumes data has already been allocated for the given row.
|
||||
#[inline]
|
||||
pub(crate) unsafe fn replace(&mut self, row: TableRow, data: OwningPtr<'_>, change_tick: u32) {
|
||||
pub(crate) unsafe fn replace(&mut self, row: TableRow, data: OwningPtr<'_>, change_tick: Tick) {
|
||||
debug_assert!(row.index() < self.len());
|
||||
self.data.replace_unchecked(row.index(), data);
|
||||
self.changed_ticks
|
||||
.get_unchecked_mut(row.index())
|
||||
.get_mut()
|
||||
.set_changed(change_tick);
|
||||
*self.changed_ticks.get_unchecked_mut(row.index()).get_mut() = change_tick;
|
||||
}
|
||||
|
||||
/// Writes component data to the column at given row.
|
||||
@ -495,7 +492,7 @@ impl Column {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn check_change_ticks(&mut self, change_tick: u32) {
|
||||
pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
|
||||
for component_ticks in &mut self.added_ticks {
|
||||
component_ticks.get_mut().check_tick(change_tick);
|
||||
}
|
||||
@ -770,7 +767,7 @@ impl Table {
|
||||
self.entities.is_empty()
|
||||
}
|
||||
|
||||
pub(crate) fn check_change_ticks(&mut self, change_tick: u32) {
|
||||
pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
|
||||
for column in self.columns.values_mut() {
|
||||
column.check_change_ticks(change_tick);
|
||||
}
|
||||
@ -889,7 +886,7 @@ impl Tables {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn check_change_ticks(&mut self, change_tick: u32) {
|
||||
pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
|
||||
for table in &mut self.tables {
|
||||
table.check_change_ticks(change_tick);
|
||||
}
|
||||
|
||||
@ -3,7 +3,10 @@ use std::{borrow::Cow, cell::UnsafeCell, marker::PhantomData};
|
||||
use bevy_ptr::UnsafeCellDeref;
|
||||
|
||||
use crate::{
|
||||
archetype::ArchetypeComponentId, component::ComponentId, prelude::World, query::Access,
|
||||
archetype::ArchetypeComponentId,
|
||||
component::{ComponentId, Tick},
|
||||
prelude::World,
|
||||
query::Access,
|
||||
};
|
||||
|
||||
use super::{ReadOnlySystem, System};
|
||||
@ -203,18 +206,18 @@ where
|
||||
.extend(self.b.archetype_component_access());
|
||||
}
|
||||
|
||||
fn check_change_tick(&mut self, change_tick: u32) {
|
||||
fn check_change_tick(&mut self, change_tick: Tick) {
|
||||
self.a.check_change_tick(change_tick);
|
||||
self.b.check_change_tick(change_tick);
|
||||
}
|
||||
|
||||
fn get_last_change_tick(&self) -> u32 {
|
||||
self.a.get_last_change_tick()
|
||||
fn get_last_run(&self) -> Tick {
|
||||
self.a.get_last_run()
|
||||
}
|
||||
|
||||
fn set_last_change_tick(&mut self, last_change_tick: u32) {
|
||||
self.a.set_last_change_tick(last_change_tick);
|
||||
self.b.set_last_change_tick(last_change_tick);
|
||||
fn set_last_run(&mut self, last_run: Tick) {
|
||||
self.a.set_last_run(last_run);
|
||||
self.b.set_last_run(last_run);
|
||||
}
|
||||
|
||||
fn default_system_sets(&self) -> Vec<Box<dyn crate::schedule::SystemSet>> {
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
use crate::{
|
||||
archetype::ArchetypeComponentId,
|
||||
change_detection::MAX_CHANGE_AGE,
|
||||
component::ComponentId,
|
||||
component::{ComponentId, Tick},
|
||||
query::Access,
|
||||
system::{
|
||||
check_system_change_tick, ExclusiveSystemParam, ExclusiveSystemParamItem, In, IntoSystem,
|
||||
@ -95,7 +94,7 @@ where
|
||||
|
||||
fn run(&mut self, input: Self::In, world: &mut World) -> Self::Out {
|
||||
let saved_last_tick = world.last_change_tick;
|
||||
world.last_change_tick = self.system_meta.last_change_tick;
|
||||
world.last_change_tick = self.system_meta.last_run;
|
||||
|
||||
let params = F::Param::get_param(
|
||||
self.param_state.as_mut().expect(PARAM_MESSAGE),
|
||||
@ -104,7 +103,7 @@ where
|
||||
let out = self.func.run(world, input, params);
|
||||
|
||||
let change_tick = world.change_tick.get_mut();
|
||||
self.system_meta.last_change_tick = *change_tick;
|
||||
self.system_meta.last_run.set(*change_tick);
|
||||
*change_tick = change_tick.wrapping_add(1);
|
||||
world.last_change_tick = saved_last_tick;
|
||||
|
||||
@ -116,12 +115,12 @@ where
|
||||
true
|
||||
}
|
||||
|
||||
fn get_last_change_tick(&self) -> u32 {
|
||||
self.system_meta.last_change_tick
|
||||
fn get_last_run(&self) -> Tick {
|
||||
self.system_meta.last_run
|
||||
}
|
||||
|
||||
fn set_last_change_tick(&mut self, last_change_tick: u32) {
|
||||
self.system_meta.last_change_tick = last_change_tick;
|
||||
fn set_last_run(&mut self, last_run: Tick) {
|
||||
self.system_meta.last_run = last_run;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -134,16 +133,16 @@ where
|
||||
#[inline]
|
||||
fn initialize(&mut self, world: &mut World) {
|
||||
self.world_id = Some(world.id());
|
||||
self.system_meta.last_change_tick = world.change_tick().wrapping_sub(MAX_CHANGE_AGE);
|
||||
self.system_meta.last_run = world.change_tick().relative_to(Tick::MAX);
|
||||
self.param_state = Some(F::Param::init(world, &mut self.system_meta));
|
||||
}
|
||||
|
||||
fn update_archetype_component_access(&mut self, _world: &World) {}
|
||||
|
||||
#[inline]
|
||||
fn check_change_tick(&mut self, change_tick: u32) {
|
||||
fn check_change_tick(&mut self, change_tick: Tick) {
|
||||
check_system_change_tick(
|
||||
&mut self.system_meta.last_change_tick,
|
||||
&mut self.system_meta.last_run,
|
||||
change_tick,
|
||||
self.system_meta.name.as_ref(),
|
||||
);
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
use crate::{
|
||||
archetype::{ArchetypeComponentId, ArchetypeGeneration, ArchetypeId},
|
||||
change_detection::MAX_CHANGE_AGE,
|
||||
component::ComponentId,
|
||||
component::{ComponentId, Tick},
|
||||
prelude::FromWorld,
|
||||
query::{Access, FilteredAccessSet},
|
||||
system::{check_system_change_tick, ReadOnlySystemParam, System, SystemParam, SystemParamItem},
|
||||
@ -22,7 +21,7 @@ pub struct SystemMeta {
|
||||
// NOTE: this must be kept private. making a SystemMeta non-send is irreversible to prevent
|
||||
// SystemParams from overriding each other
|
||||
is_send: bool,
|
||||
pub(crate) last_change_tick: u32,
|
||||
pub(crate) last_run: Tick,
|
||||
}
|
||||
|
||||
impl SystemMeta {
|
||||
@ -32,7 +31,7 @@ impl SystemMeta {
|
||||
archetype_component_access: Access::default(),
|
||||
component_access_set: FilteredAccessSet::default(),
|
||||
is_send: true,
|
||||
last_change_tick: 0,
|
||||
last_run: Tick::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,7 +150,7 @@ pub struct SystemState<Param: SystemParam + 'static> {
|
||||
impl<Param: SystemParam> SystemState<Param> {
|
||||
pub fn new(world: &mut World) -> Self {
|
||||
let mut meta = SystemMeta::new::<Param>();
|
||||
meta.last_change_tick = world.change_tick().wrapping_sub(MAX_CHANGE_AGE);
|
||||
meta.last_run = world.change_tick().relative_to(Tick::MAX);
|
||||
let param_state = Param::init_state(world, &mut meta);
|
||||
Self {
|
||||
meta,
|
||||
@ -288,10 +287,10 @@ impl<Param: SystemParam> SystemState<Param> {
|
||||
unsafe fn fetch<'w, 's>(
|
||||
&'s mut self,
|
||||
world: &'w World,
|
||||
change_tick: u32,
|
||||
change_tick: Tick,
|
||||
) -> SystemParamItem<'w, 's, Param> {
|
||||
let param = Param::get_param(&mut self.param_state, &self.meta, world, change_tick);
|
||||
self.meta.last_change_tick = change_tick;
|
||||
self.meta.last_run = change_tick;
|
||||
param
|
||||
}
|
||||
}
|
||||
@ -464,16 +463,16 @@ where
|
||||
change_tick,
|
||||
);
|
||||
let out = self.func.run(input, params);
|
||||
self.system_meta.last_change_tick = change_tick;
|
||||
self.system_meta.last_run = change_tick;
|
||||
out
|
||||
}
|
||||
|
||||
fn get_last_change_tick(&self) -> u32 {
|
||||
self.system_meta.last_change_tick
|
||||
fn get_last_run(&self) -> Tick {
|
||||
self.system_meta.last_run
|
||||
}
|
||||
|
||||
fn set_last_change_tick(&mut self, last_change_tick: u32) {
|
||||
self.system_meta.last_change_tick = last_change_tick;
|
||||
fn set_last_run(&mut self, last_run: Tick) {
|
||||
self.system_meta.last_run = last_run;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -485,7 +484,7 @@ where
|
||||
#[inline]
|
||||
fn initialize(&mut self, world: &mut World) {
|
||||
self.world_id = Some(world.id());
|
||||
self.system_meta.last_change_tick = world.change_tick().wrapping_sub(MAX_CHANGE_AGE);
|
||||
self.system_meta.last_run = world.change_tick().relative_to(Tick::MAX);
|
||||
self.param_state = Some(F::Param::init_state(world, &mut self.system_meta));
|
||||
}
|
||||
|
||||
@ -507,9 +506,9 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn check_change_tick(&mut self, change_tick: u32) {
|
||||
fn check_change_tick(&mut self, change_tick: Tick) {
|
||||
check_system_change_tick(
|
||||
&mut self.system_meta.last_change_tick,
|
||||
&mut self.system_meta.last_run,
|
||||
change_tick,
|
||||
self.system_meta.name.as_ref(),
|
||||
);
|
||||
|
||||
@ -157,7 +157,7 @@ mod tests {
|
||||
archetype::{ArchetypeComponentId, Archetypes},
|
||||
bundle::Bundles,
|
||||
change_detection::DetectChanges,
|
||||
component::{Component, Components},
|
||||
component::{Component, Components, Tick},
|
||||
entity::{Entities, Entity},
|
||||
prelude::AnyOf,
|
||||
query::{Added, Changed, Or, With, Without},
|
||||
@ -1227,7 +1227,7 @@ mod tests {
|
||||
let world2 = World::new();
|
||||
let qstate = world1.query::<()>();
|
||||
// SAFETY: doesnt access anything
|
||||
let query = unsafe { Query::new(&world2, &qstate, 0, 0, false) };
|
||||
let query = unsafe { Query::new(&world2, &qstate, Tick::new(0), Tick::new(0), false) };
|
||||
query.iter();
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
component::Component,
|
||||
component::{Component, Tick},
|
||||
entity::Entity,
|
||||
query::{
|
||||
BatchingStrategy, QueryCombinationIter, QueryEntityError, QueryIter, QueryManyIter,
|
||||
@ -276,8 +276,8 @@ use std::{any::TypeId, borrow::Borrow, fmt::Debug};
|
||||
pub struct Query<'world, 'state, Q: WorldQuery, F: ReadOnlyWorldQuery = ()> {
|
||||
world: &'world World,
|
||||
state: &'state QueryState<Q, F>,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
// SAFETY: This is used to ensure that `get_component_mut::<C>` properly fails when a Query writes C
|
||||
// and gets converted to a read-only query using `to_readonly`. Without checking this, `get_component_mut` relies on
|
||||
// QueryState's archetype_component_access, which will continue allowing write access to C after being cast to
|
||||
@ -288,7 +288,7 @@ pub struct Query<'world, 'state, Q: WorldQuery, F: ReadOnlyWorldQuery = ()> {
|
||||
|
||||
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> std::fmt::Debug for Query<'w, 's, Q, F> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Query {{ matched entities: {}, world: {:?}, state: {:?}, last_change_tick: {}, change_tick: {} }}", self.iter().count(), self.world, self.state, self.last_change_tick, self.change_tick)
|
||||
write!(f, "Query {{ matched entities: {}, world: {:?}, state: {:?}, last_run: {:?}, this_run: {:?} }}", self.iter().count(), self.world, self.state, self.last_run, self.this_run)
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,8 +307,8 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
pub(crate) unsafe fn new(
|
||||
world: &'w World,
|
||||
state: &'s QueryState<Q, F>,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
force_read_only_component_access: bool,
|
||||
) -> Self {
|
||||
state.validate_world(world);
|
||||
@ -317,8 +317,8 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
force_read_only_component_access,
|
||||
world,
|
||||
state,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
last_run,
|
||||
this_run,
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,8 +334,8 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
Query::new(
|
||||
self.world,
|
||||
new_state,
|
||||
self.last_change_tick,
|
||||
self.change_tick,
|
||||
self.last_run,
|
||||
self.this_run,
|
||||
// SAFETY: this must be set to true or `get_component_mut` will be unsound. See the comments
|
||||
// on this field for more details
|
||||
true,
|
||||
@ -372,11 +372,9 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
// SAFETY: system runs without conflicts with other systems.
|
||||
// same-system queries have runtime borrow checks when they conflict
|
||||
unsafe {
|
||||
self.state.as_readonly().iter_unchecked_manual(
|
||||
self.world,
|
||||
self.last_change_tick,
|
||||
self.change_tick,
|
||||
)
|
||||
self.state
|
||||
.as_readonly()
|
||||
.iter_unchecked_manual(self.world, self.last_run, self.this_run)
|
||||
}
|
||||
}
|
||||
|
||||
@ -410,7 +408,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
// same-system queries have runtime borrow checks when they conflict
|
||||
unsafe {
|
||||
self.state
|
||||
.iter_unchecked_manual(self.world, self.last_change_tick, self.change_tick)
|
||||
.iter_unchecked_manual(self.world, self.last_run, self.this_run)
|
||||
}
|
||||
}
|
||||
|
||||
@ -442,8 +440,8 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
unsafe {
|
||||
self.state.as_readonly().iter_combinations_unchecked_manual(
|
||||
self.world,
|
||||
self.last_change_tick,
|
||||
self.change_tick,
|
||||
self.last_run,
|
||||
self.this_run,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -474,11 +472,8 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
// SAFETY: system runs without conflicts with other systems.
|
||||
// same-system queries have runtime borrow checks when they conflict
|
||||
unsafe {
|
||||
self.state.iter_combinations_unchecked_manual(
|
||||
self.world,
|
||||
self.last_change_tick,
|
||||
self.change_tick,
|
||||
)
|
||||
self.state
|
||||
.iter_combinations_unchecked_manual(self.world, self.last_run, self.this_run)
|
||||
}
|
||||
}
|
||||
|
||||
@ -532,8 +527,8 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
self.state.as_readonly().iter_many_unchecked_manual(
|
||||
entities,
|
||||
self.world,
|
||||
self.last_change_tick,
|
||||
self.change_tick,
|
||||
self.last_run,
|
||||
self.this_run,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -585,8 +580,8 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
self.state.iter_many_unchecked_manual(
|
||||
entities,
|
||||
self.world,
|
||||
self.last_change_tick,
|
||||
self.change_tick,
|
||||
self.last_run,
|
||||
self.this_run,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -606,7 +601,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
// SEMI-SAFETY: system runs without conflicts with other systems.
|
||||
// same-system queries have runtime borrow checks when they conflict
|
||||
self.state
|
||||
.iter_unchecked_manual(self.world, self.last_change_tick, self.change_tick)
|
||||
.iter_unchecked_manual(self.world, self.last_run, self.this_run)
|
||||
}
|
||||
|
||||
/// Iterates over all possible combinations of `K` query items without repetition.
|
||||
@ -625,11 +620,8 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
) -> QueryCombinationIter<'_, 's, Q, F, K> {
|
||||
// SEMI-SAFETY: system runs without conflicts with other systems.
|
||||
// same-system queries have runtime borrow checks when they conflict
|
||||
self.state.iter_combinations_unchecked_manual(
|
||||
self.world,
|
||||
self.last_change_tick,
|
||||
self.change_tick,
|
||||
)
|
||||
self.state
|
||||
.iter_combinations_unchecked_manual(self.world, self.last_run, self.this_run)
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] over the query items generated from an [`Entity`] list.
|
||||
@ -650,12 +642,8 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
where
|
||||
EntityList::Item: Borrow<Entity>,
|
||||
{
|
||||
self.state.iter_many_unchecked_manual(
|
||||
entities,
|
||||
self.world,
|
||||
self.last_change_tick,
|
||||
self.change_tick,
|
||||
)
|
||||
self.state
|
||||
.iter_many_unchecked_manual(entities, self.world, self.last_run, self.this_run)
|
||||
}
|
||||
|
||||
/// Runs `f` on each read-only query item.
|
||||
@ -690,8 +678,8 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
self.state.as_readonly().for_each_unchecked_manual(
|
||||
self.world,
|
||||
f,
|
||||
self.last_change_tick,
|
||||
self.change_tick,
|
||||
self.last_run,
|
||||
self.this_run,
|
||||
);
|
||||
};
|
||||
}
|
||||
@ -725,12 +713,8 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
// SAFETY: system runs without conflicts with other systems. same-system queries have runtime
|
||||
// borrow checks when they conflict
|
||||
unsafe {
|
||||
self.state.for_each_unchecked_manual(
|
||||
self.world,
|
||||
f,
|
||||
self.last_change_tick,
|
||||
self.change_tick,
|
||||
);
|
||||
self.state
|
||||
.for_each_unchecked_manual(self.world, f, self.last_run, self.this_run);
|
||||
};
|
||||
}
|
||||
|
||||
@ -801,8 +785,8 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
self.state.as_readonly().get_unchecked_manual(
|
||||
self.world,
|
||||
entity,
|
||||
self.last_change_tick,
|
||||
self.change_tick,
|
||||
self.last_run,
|
||||
self.this_run,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -823,12 +807,8 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
) -> Result<[ROQueryItem<'_, Q>; N], QueryEntityError> {
|
||||
// SAFETY: it is the scheduler's responsibility to ensure that `Query` is never handed out on the wrong `World`.
|
||||
unsafe {
|
||||
self.state.get_many_read_only_manual(
|
||||
self.world,
|
||||
entities,
|
||||
self.last_change_tick,
|
||||
self.change_tick,
|
||||
)
|
||||
self.state
|
||||
.get_many_read_only_manual(self.world, entities, self.last_run, self.this_run)
|
||||
}
|
||||
}
|
||||
|
||||
@ -910,12 +890,8 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
// SAFETY: system runs without conflicts with other systems.
|
||||
// same-system queries have runtime borrow checks when they conflict
|
||||
unsafe {
|
||||
self.state.get_unchecked_manual(
|
||||
self.world,
|
||||
entity,
|
||||
self.last_change_tick,
|
||||
self.change_tick,
|
||||
)
|
||||
self.state
|
||||
.get_unchecked_manual(self.world, entity, self.last_run, self.this_run)
|
||||
}
|
||||
}
|
||||
|
||||
@ -934,12 +910,8 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
) -> Result<[Q::Item<'_>; N], QueryEntityError> {
|
||||
// SAFETY: scheduler ensures safe Query world access
|
||||
unsafe {
|
||||
self.state.get_many_unchecked_manual(
|
||||
self.world,
|
||||
entities,
|
||||
self.last_change_tick,
|
||||
self.change_tick,
|
||||
)
|
||||
self.state
|
||||
.get_many_unchecked_manual(self.world, entities, self.last_run, self.this_run)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1013,7 +985,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
// SEMI-SAFETY: system runs without conflicts with other systems.
|
||||
// same-system queries have runtime borrow checks when they conflict
|
||||
self.state
|
||||
.get_unchecked_manual(self.world, entity, self.last_change_tick, self.change_tick)
|
||||
.get_unchecked_manual(self.world, entity, self.last_run, self.this_run)
|
||||
}
|
||||
|
||||
/// Returns a shared reference to the component `T` of the given [`Entity`].
|
||||
@ -1151,7 +1123,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
.has_write(archetype_component)
|
||||
{
|
||||
entity_ref
|
||||
.get_mut_using_ticks::<T>(self.last_change_tick, self.change_tick)
|
||||
.get_mut_using_ticks::<T>(self.last_run, self.this_run)
|
||||
.ok_or(QueryComponentError::MissingComponent)
|
||||
} else {
|
||||
Err(QueryComponentError::MissingWriteAccess)
|
||||
@ -1227,8 +1199,8 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
unsafe {
|
||||
self.state.as_readonly().get_single_unchecked_manual(
|
||||
self.world,
|
||||
self.last_change_tick,
|
||||
self.change_tick,
|
||||
self.last_run,
|
||||
self.this_run,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -1296,11 +1268,8 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
// the query ensures mutable access to the components it accesses, and the query
|
||||
// is uniquely borrowed
|
||||
unsafe {
|
||||
self.state.get_single_unchecked_manual(
|
||||
self.world,
|
||||
self.last_change_tick,
|
||||
self.change_tick,
|
||||
)
|
||||
self.state
|
||||
.get_single_unchecked_manual(self.world, self.last_run, self.this_run)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1327,7 +1296,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.state
|
||||
.is_empty(self.world, self.last_change_tick, self.change_tick)
|
||||
.is_empty(self.world, self.last_run, self.this_run)
|
||||
}
|
||||
|
||||
/// Returns `true` if the given [`Entity`] matches the query.
|
||||
@ -1358,7 +1327,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
unsafe {
|
||||
self.state
|
||||
.as_nop()
|
||||
.get_unchecked_manual(self.world, entity, self.last_change_tick, self.change_tick)
|
||||
.get_unchecked_manual(self.world, entity, self.last_run, self.this_run)
|
||||
.is_ok()
|
||||
}
|
||||
}
|
||||
@ -1459,8 +1428,8 @@ impl<'w, 's, Q: ReadOnlyWorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
self.state.as_readonly().get_unchecked_manual(
|
||||
self.world,
|
||||
entity,
|
||||
self.last_change_tick,
|
||||
self.change_tick,
|
||||
self.last_run,
|
||||
self.this_run,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -1493,11 +1462,9 @@ impl<'w, 's, Q: ReadOnlyWorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||
// SAFETY: system runs without conflicts with other systems.
|
||||
// same-system queries have runtime borrow checks when they conflict
|
||||
unsafe {
|
||||
self.state.as_readonly().iter_unchecked_manual(
|
||||
self.world,
|
||||
self.last_change_tick,
|
||||
self.change_tick,
|
||||
)
|
||||
self.state
|
||||
.as_readonly()
|
||||
.iter_unchecked_manual(self.world, self.last_run, self.this_run)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
use bevy_utils::tracing::warn;
|
||||
use core::fmt::Debug;
|
||||
|
||||
use crate::{
|
||||
archetype::ArchetypeComponentId, change_detection::MAX_CHANGE_AGE, component::ComponentId,
|
||||
query::Access, world::World,
|
||||
};
|
||||
use crate::component::Tick;
|
||||
use crate::{archetype::ArchetypeComponentId, component::ComponentId, query::Access, world::World};
|
||||
|
||||
use std::any::TypeId;
|
||||
use std::borrow::Cow;
|
||||
@ -63,19 +61,20 @@ pub trait System: Send + Sync + 'static {
|
||||
fn initialize(&mut self, _world: &mut World);
|
||||
/// Update the system's archetype component [`Access`].
|
||||
fn update_archetype_component_access(&mut self, world: &World);
|
||||
fn check_change_tick(&mut self, change_tick: u32);
|
||||
fn check_change_tick(&mut self, change_tick: Tick);
|
||||
/// Returns the system's default [system sets](crate::schedule::SystemSet).
|
||||
fn default_system_sets(&self) -> Vec<Box<dyn crate::schedule::SystemSet>> {
|
||||
Vec::new()
|
||||
}
|
||||
/// Gets the system's last change tick
|
||||
fn get_last_change_tick(&self) -> u32;
|
||||
/// Sets the system's last change tick
|
||||
/// Gets the tick indicating the last time this system ran.
|
||||
fn get_last_run(&self) -> Tick;
|
||||
/// Overwrites the tick indicating the last time this system ran.
|
||||
///
|
||||
/// # Warning
|
||||
/// This is a complex and error-prone operation, that can have unexpected consequences on any system relying on this code.
|
||||
/// However, it can be an essential escape hatch when, for example,
|
||||
/// you are trying to synchronize representations using change detection and need to avoid infinite recursion.
|
||||
fn set_last_change_tick(&mut self, last_change_tick: u32);
|
||||
fn set_last_run(&mut self, last_run: Tick);
|
||||
}
|
||||
|
||||
/// [`System`] types that do not modify the [`World`] when run.
|
||||
@ -91,23 +90,14 @@ pub unsafe trait ReadOnlySystem: System {}
|
||||
/// A convenience type alias for a boxed [`System`] trait object.
|
||||
pub type BoxedSystem<In = (), Out = ()> = Box<dyn System<In = In, Out = Out>>;
|
||||
|
||||
pub(crate) fn check_system_change_tick(
|
||||
last_change_tick: &mut u32,
|
||||
change_tick: u32,
|
||||
system_name: &str,
|
||||
) {
|
||||
let age = change_tick.wrapping_sub(*last_change_tick);
|
||||
// This comparison assumes that `age` has not overflowed `u32::MAX` before, which will be true
|
||||
// so long as this check always runs before that can happen.
|
||||
if age > MAX_CHANGE_AGE {
|
||||
pub(crate) fn check_system_change_tick(last_run: &mut Tick, this_run: Tick, system_name: &str) {
|
||||
if last_run.check_tick(this_run) {
|
||||
let age = this_run.relative_to(*last_run).get();
|
||||
warn!(
|
||||
"System '{}' has not run for {} ticks. \
|
||||
"System '{system_name}' has not run for {age} ticks. \
|
||||
Changes older than {} ticks will not be detected.",
|
||||
system_name,
|
||||
age,
|
||||
MAX_CHANGE_AGE - 1,
|
||||
Tick::MAX.get() - 1,
|
||||
);
|
||||
*last_change_tick = change_tick.wrapping_sub(MAX_CHANGE_AGE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ use crate::{
|
||||
archetype::{Archetype, Archetypes},
|
||||
bundle::Bundles,
|
||||
change_detection::{Ticks, TicksMut},
|
||||
component::{ComponentId, ComponentTicks, Components},
|
||||
component::{ComponentId, ComponentTicks, Components, Tick},
|
||||
entity::Entities,
|
||||
query::{
|
||||
Access, FilteredAccess, FilteredAccessSet, QueryState, ReadOnlyWorldQuery, WorldQuery,
|
||||
@ -169,7 +169,7 @@ pub unsafe trait SystemParam: Sized {
|
||||
state: &'state mut Self::State,
|
||||
system_meta: &SystemMeta,
|
||||
world: &'world World,
|
||||
change_tick: u32,
|
||||
change_tick: Tick,
|
||||
) -> Self::Item<'world, 'state>;
|
||||
}
|
||||
|
||||
@ -227,15 +227,9 @@ unsafe impl<Q: WorldQuery + 'static, F: ReadOnlyWorldQuery + 'static> SystemPara
|
||||
state: &'s mut Self::State,
|
||||
system_meta: &SystemMeta,
|
||||
world: &'w World,
|
||||
change_tick: u32,
|
||||
change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
Query::new(
|
||||
world,
|
||||
state,
|
||||
system_meta.last_change_tick,
|
||||
change_tick,
|
||||
false,
|
||||
)
|
||||
Query::new(world, state, system_meta.last_run, change_tick, false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -371,7 +365,7 @@ pub struct ParamSet<'w, 's, T: SystemParam> {
|
||||
param_states: &'s mut T::State,
|
||||
world: &'w World,
|
||||
system_meta: SystemMeta,
|
||||
change_tick: u32,
|
||||
change_tick: Tick,
|
||||
}
|
||||
|
||||
impl_param_set!();
|
||||
@ -445,7 +439,7 @@ unsafe impl<'a, T: Resource> SystemParam for Res<'a, T> {
|
||||
&mut component_id: &'s mut Self::State,
|
||||
system_meta: &SystemMeta,
|
||||
world: &'w World,
|
||||
change_tick: u32,
|
||||
change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
let (ptr, ticks) = world
|
||||
.as_unsafe_world_cell_migration_internal()
|
||||
@ -462,8 +456,8 @@ unsafe impl<'a, T: Resource> SystemParam for Res<'a, T> {
|
||||
ticks: Ticks {
|
||||
added: ticks.added.deref(),
|
||||
changed: ticks.changed.deref(),
|
||||
last_change_tick: system_meta.last_change_tick,
|
||||
change_tick,
|
||||
last_run: system_meta.last_run,
|
||||
this_run: change_tick,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -486,7 +480,7 @@ unsafe impl<'a, T: Resource> SystemParam for Option<Res<'a, T>> {
|
||||
&mut component_id: &'s mut Self::State,
|
||||
system_meta: &SystemMeta,
|
||||
world: &'w World,
|
||||
change_tick: u32,
|
||||
change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
world
|
||||
.as_unsafe_world_cell_migration_internal()
|
||||
@ -496,8 +490,8 @@ unsafe impl<'a, T: Resource> SystemParam for Option<Res<'a, T>> {
|
||||
ticks: Ticks {
|
||||
added: ticks.added.deref(),
|
||||
changed: ticks.changed.deref(),
|
||||
last_change_tick: system_meta.last_change_tick,
|
||||
change_tick,
|
||||
last_run: system_meta.last_run,
|
||||
this_run: change_tick,
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -540,7 +534,7 @@ unsafe impl<'a, T: Resource> SystemParam for ResMut<'a, T> {
|
||||
&mut component_id: &'s mut Self::State,
|
||||
system_meta: &SystemMeta,
|
||||
world: &'w World,
|
||||
change_tick: u32,
|
||||
change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
let value = world
|
||||
.as_unsafe_world_cell_migration_internal()
|
||||
@ -557,8 +551,8 @@ unsafe impl<'a, T: Resource> SystemParam for ResMut<'a, T> {
|
||||
ticks: TicksMut {
|
||||
added: value.ticks.added,
|
||||
changed: value.ticks.changed,
|
||||
last_change_tick: system_meta.last_change_tick,
|
||||
change_tick,
|
||||
last_run: system_meta.last_run,
|
||||
this_run: change_tick,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -578,7 +572,7 @@ unsafe impl<'a, T: Resource> SystemParam for Option<ResMut<'a, T>> {
|
||||
&mut component_id: &'s mut Self::State,
|
||||
system_meta: &SystemMeta,
|
||||
world: &'w World,
|
||||
change_tick: u32,
|
||||
change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
world
|
||||
.as_unsafe_world_cell_migration_internal()
|
||||
@ -588,8 +582,8 @@ unsafe impl<'a, T: Resource> SystemParam for Option<ResMut<'a, T>> {
|
||||
ticks: TicksMut {
|
||||
added: value.ticks.added,
|
||||
changed: value.ticks.changed,
|
||||
last_change_tick: system_meta.last_change_tick,
|
||||
change_tick,
|
||||
last_run: system_meta.last_run,
|
||||
this_run: change_tick,
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -631,7 +625,7 @@ unsafe impl SystemParam for &'_ World {
|
||||
_state: &'s mut Self::State,
|
||||
_system_meta: &SystemMeta,
|
||||
world: &'w World,
|
||||
_change_tick: u32,
|
||||
_change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
world
|
||||
}
|
||||
@ -752,7 +746,7 @@ unsafe impl<'a, T: FromWorld + Send + 'static> SystemParam for Local<'a, T> {
|
||||
state: &'s mut Self::State,
|
||||
_system_meta: &SystemMeta,
|
||||
_world: &'w World,
|
||||
_change_tick: u32,
|
||||
_change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
Local(state.get())
|
||||
}
|
||||
@ -927,7 +921,7 @@ unsafe impl<T: SystemBuffer> SystemParam for Deferred<'_, T> {
|
||||
state: &'s mut Self::State,
|
||||
_system_meta: &SystemMeta,
|
||||
_world: &'w World,
|
||||
_change_tick: u32,
|
||||
_change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
Deferred(state.get())
|
||||
}
|
||||
@ -948,8 +942,8 @@ unsafe impl<T: SystemBuffer> SystemParam for Deferred<'_, T> {
|
||||
pub struct NonSend<'w, T: 'static> {
|
||||
pub(crate) value: &'w T,
|
||||
ticks: ComponentTicks,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
}
|
||||
|
||||
// SAFETY: Only reads a single World non-send resource
|
||||
@ -967,13 +961,12 @@ where
|
||||
impl<'w, T: 'static> NonSend<'w, T> {
|
||||
/// Returns `true` if the resource was added after the system last ran.
|
||||
pub fn is_added(&self) -> bool {
|
||||
self.ticks.is_added(self.last_change_tick, self.change_tick)
|
||||
self.ticks.is_added(self.last_run, self.this_run)
|
||||
}
|
||||
|
||||
/// Returns `true` if the resource was added or mutably dereferenced after the system last ran.
|
||||
pub fn is_changed(&self) -> bool {
|
||||
self.ticks
|
||||
.is_changed(self.last_change_tick, self.change_tick)
|
||||
self.ticks.is_changed(self.last_run, self.this_run)
|
||||
}
|
||||
}
|
||||
|
||||
@ -992,8 +985,8 @@ impl<'a, T> From<NonSendMut<'a, T>> for NonSend<'a, T> {
|
||||
added: nsm.ticks.added.to_owned(),
|
||||
changed: nsm.ticks.changed.to_owned(),
|
||||
},
|
||||
change_tick: nsm.ticks.change_tick,
|
||||
last_change_tick: nsm.ticks.last_change_tick,
|
||||
this_run: nsm.ticks.this_run,
|
||||
last_run: nsm.ticks.last_run,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1034,7 +1027,7 @@ unsafe impl<'a, T: 'static> SystemParam for NonSend<'a, T> {
|
||||
&mut component_id: &'s mut Self::State,
|
||||
system_meta: &SystemMeta,
|
||||
world: &'w World,
|
||||
change_tick: u32,
|
||||
change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
let (ptr, ticks) = world
|
||||
.as_unsafe_world_cell_migration_internal()
|
||||
@ -1050,8 +1043,8 @@ unsafe impl<'a, T: 'static> SystemParam for NonSend<'a, T> {
|
||||
NonSend {
|
||||
value: ptr.deref(),
|
||||
ticks: ticks.read(),
|
||||
last_change_tick: system_meta.last_change_tick,
|
||||
change_tick,
|
||||
last_run: system_meta.last_run,
|
||||
this_run: change_tick,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1073,7 +1066,7 @@ unsafe impl<T: 'static> SystemParam for Option<NonSend<'_, T>> {
|
||||
&mut component_id: &'s mut Self::State,
|
||||
system_meta: &SystemMeta,
|
||||
world: &'w World,
|
||||
change_tick: u32,
|
||||
change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
world
|
||||
.as_unsafe_world_cell_migration_internal()
|
||||
@ -1081,8 +1074,8 @@ unsafe impl<T: 'static> SystemParam for Option<NonSend<'_, T>> {
|
||||
.map(|(ptr, ticks)| NonSend {
|
||||
value: ptr.deref(),
|
||||
ticks: ticks.read(),
|
||||
last_change_tick: system_meta.last_change_tick,
|
||||
change_tick,
|
||||
last_run: system_meta.last_run,
|
||||
this_run: change_tick,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1126,7 +1119,7 @@ unsafe impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> {
|
||||
&mut component_id: &'s mut Self::State,
|
||||
system_meta: &SystemMeta,
|
||||
world: &'w World,
|
||||
change_tick: u32,
|
||||
change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
let (ptr, ticks) = world
|
||||
.as_unsafe_world_cell_migration_internal()
|
||||
@ -1140,7 +1133,7 @@ unsafe impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> {
|
||||
});
|
||||
NonSendMut {
|
||||
value: ptr.assert_unique().deref_mut(),
|
||||
ticks: TicksMut::from_tick_cells(ticks, system_meta.last_change_tick, change_tick),
|
||||
ticks: TicksMut::from_tick_cells(ticks, system_meta.last_run, change_tick),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1159,14 +1152,14 @@ unsafe impl<'a, T: 'static> SystemParam for Option<NonSendMut<'a, T>> {
|
||||
&mut component_id: &'s mut Self::State,
|
||||
system_meta: &SystemMeta,
|
||||
world: &'w World,
|
||||
change_tick: u32,
|
||||
change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
world
|
||||
.as_unsafe_world_cell_migration_internal()
|
||||
.get_non_send_with_ticks(component_id)
|
||||
.map(|(ptr, ticks)| NonSendMut {
|
||||
value: ptr.assert_unique().deref_mut(),
|
||||
ticks: TicksMut::from_tick_cells(ticks, system_meta.last_change_tick, change_tick),
|
||||
ticks: TicksMut::from_tick_cells(ticks, system_meta.last_run, change_tick),
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1186,7 +1179,7 @@ unsafe impl<'a> SystemParam for &'a Archetypes {
|
||||
_state: &'s mut Self::State,
|
||||
_system_meta: &SystemMeta,
|
||||
world: &'w World,
|
||||
_change_tick: u32,
|
||||
_change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
world.archetypes()
|
||||
}
|
||||
@ -1207,7 +1200,7 @@ unsafe impl<'a> SystemParam for &'a Components {
|
||||
_state: &'s mut Self::State,
|
||||
_system_meta: &SystemMeta,
|
||||
world: &'w World,
|
||||
_change_tick: u32,
|
||||
_change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
world.components()
|
||||
}
|
||||
@ -1228,7 +1221,7 @@ unsafe impl<'a> SystemParam for &'a Entities {
|
||||
_state: &'s mut Self::State,
|
||||
_system_meta: &SystemMeta,
|
||||
world: &'w World,
|
||||
_change_tick: u32,
|
||||
_change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
world.entities()
|
||||
}
|
||||
@ -1249,7 +1242,7 @@ unsafe impl<'a> SystemParam for &'a Bundles {
|
||||
_state: &'s mut Self::State,
|
||||
_system_meta: &SystemMeta,
|
||||
world: &'w World,
|
||||
_change_tick: u32,
|
||||
_change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
world.bundles()
|
||||
}
|
||||
@ -1258,29 +1251,29 @@ unsafe impl<'a> SystemParam for &'a Bundles {
|
||||
/// A [`SystemParam`] that reads the previous and current change ticks of the system.
|
||||
///
|
||||
/// A system's change ticks are updated each time it runs:
|
||||
/// - `last_change_tick` copies the previous value of `change_tick`
|
||||
/// - `change_tick` copies the current value of [`World::read_change_tick`]
|
||||
/// - `last_run` copies the previous value of `change_tick`
|
||||
/// - `this_run` copies the current value of [`World::read_change_tick`]
|
||||
///
|
||||
/// Component change ticks that are more recent than `last_change_tick` will be detected by the system.
|
||||
/// Component change ticks that are more recent than `last_run` will be detected by the system.
|
||||
/// Those can be read by calling [`last_changed`](crate::change_detection::DetectChanges::last_changed)
|
||||
/// on a [`Mut<T>`](crate::change_detection::Mut) or [`ResMut<T>`](crate::change_detection::ResMut).
|
||||
#[derive(Debug)]
|
||||
pub struct SystemChangeTick {
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
}
|
||||
|
||||
impl SystemChangeTick {
|
||||
/// Returns the current [`World`] change tick seen by the system.
|
||||
#[inline]
|
||||
pub fn change_tick(&self) -> u32 {
|
||||
self.change_tick
|
||||
pub fn this_run(&self) -> Tick {
|
||||
self.this_run
|
||||
}
|
||||
|
||||
/// Returns the [`World`] change tick seen by the system the previous time it ran.
|
||||
#[inline]
|
||||
pub fn last_change_tick(&self) -> u32 {
|
||||
self.last_change_tick
|
||||
pub fn last_run(&self) -> Tick {
|
||||
self.last_run
|
||||
}
|
||||
}
|
||||
|
||||
@ -1298,11 +1291,11 @@ unsafe impl SystemParam for SystemChangeTick {
|
||||
_state: &'s mut Self::State,
|
||||
system_meta: &SystemMeta,
|
||||
_world: &'w World,
|
||||
change_tick: u32,
|
||||
change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
SystemChangeTick {
|
||||
last_change_tick: system_meta.last_change_tick,
|
||||
change_tick,
|
||||
last_run: system_meta.last_run,
|
||||
this_run: change_tick,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1368,7 +1361,7 @@ unsafe impl SystemParam for SystemName<'_> {
|
||||
name: &'s mut Self::State,
|
||||
_system_meta: &SystemMeta,
|
||||
_world: &'w World,
|
||||
_change_tick: u32,
|
||||
_change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
SystemName { name }
|
||||
}
|
||||
@ -1410,7 +1403,7 @@ macro_rules! impl_system_param_tuple {
|
||||
state: &'s mut Self::State,
|
||||
_system_meta: &SystemMeta,
|
||||
_world: &'w World,
|
||||
_change_tick: u32,
|
||||
_change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
|
||||
let ($($param,)*) = state;
|
||||
@ -1534,7 +1527,7 @@ unsafe impl<P: SystemParam + 'static> SystemParam for StaticSystemParam<'_, '_,
|
||||
state: &'state mut Self::State,
|
||||
system_meta: &SystemMeta,
|
||||
world: &'world World,
|
||||
change_tick: u32,
|
||||
change_tick: Tick,
|
||||
) -> Self::Item<'world, 'state> {
|
||||
// SAFETY: Defer to the safety of P::SystemParam
|
||||
StaticSystemParam(P::get_param(state, system_meta, world, change_tick))
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use crate::{
|
||||
component::Tick,
|
||||
storage::SparseSetIndex,
|
||||
system::{ReadOnlySystemParam, SystemParam},
|
||||
world::{FromWorld, World},
|
||||
@ -56,7 +57,7 @@ unsafe impl SystemParam for WorldId {
|
||||
_: &'state mut Self::State,
|
||||
_: &crate::system::SystemMeta,
|
||||
world: &'world super::World,
|
||||
_: u32,
|
||||
_: Tick,
|
||||
) -> Self::Item<'world, 'state> {
|
||||
world.id
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ use crate::{
|
||||
archetype::{ArchetypeComponentId, ArchetypeId, ArchetypeRow, Archetypes},
|
||||
bundle::{Bundle, BundleInserter, BundleSpawner, Bundles},
|
||||
change_detection::{MutUntyped, TicksMut},
|
||||
component::{Component, ComponentDescriptor, ComponentId, ComponentInfo, Components},
|
||||
component::{Component, ComponentDescriptor, ComponentId, ComponentInfo, Components, Tick},
|
||||
entity::{AllocAtWithoutReplacement, Entities, Entity, EntityLocation},
|
||||
event::{Event, Events},
|
||||
query::{DebugCheckedUnwrap, QueryState, ReadOnlyWorldQuery, WorldQuery},
|
||||
@ -64,8 +64,8 @@ pub struct World {
|
||||
/// Access cache used by [WorldCell]. Is only accessed in the `Drop` impl of `WorldCell`.
|
||||
pub(crate) archetype_component_access: ArchetypeComponentAccess,
|
||||
pub(crate) change_tick: AtomicU32,
|
||||
pub(crate) last_change_tick: u32,
|
||||
pub(crate) last_check_tick: u32,
|
||||
pub(crate) last_change_tick: Tick,
|
||||
pub(crate) last_check_tick: Tick,
|
||||
}
|
||||
|
||||
impl Default for World {
|
||||
@ -82,8 +82,8 @@ impl Default for World {
|
||||
// Default value is `1`, and `last_change_tick`s default to `0`, such that changes
|
||||
// are detected on first system runs and for direct world queries.
|
||||
change_tick: AtomicU32::new(1),
|
||||
last_change_tick: 0,
|
||||
last_check_tick: 0,
|
||||
last_change_tick: Tick::new(0),
|
||||
last_check_tick: Tick::new(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -493,6 +493,7 @@ impl World {
|
||||
/// ```
|
||||
pub fn spawn<B: Bundle>(&mut self, bundle: B) -> EntityMut {
|
||||
self.flush();
|
||||
let change_tick = self.change_tick();
|
||||
let entity = self.entities.alloc();
|
||||
let entity_location = {
|
||||
let bundle_info = self
|
||||
@ -503,7 +504,7 @@ impl World {
|
||||
&mut self.archetypes,
|
||||
&mut self.components,
|
||||
&mut self.storages,
|
||||
*self.change_tick.get_mut(),
|
||||
change_tick,
|
||||
);
|
||||
|
||||
// SAFETY: bundle's type matches `bundle_info`, entity is allocated but non-existent
|
||||
@ -1174,8 +1175,7 @@ impl World {
|
||||
{
|
||||
self.flush();
|
||||
|
||||
let iter = iter.into_iter();
|
||||
let change_tick = *self.change_tick.get_mut();
|
||||
let change_tick = self.change_tick();
|
||||
|
||||
let bundle_info = self
|
||||
.bundles
|
||||
@ -1306,8 +1306,8 @@ impl World {
|
||||
ticks: TicksMut {
|
||||
added: &mut ticks.added,
|
||||
changed: &mut ticks.changed,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
last_run: last_change_tick,
|
||||
this_run: change_tick,
|
||||
},
|
||||
};
|
||||
let result = f(self, value_mut);
|
||||
@ -1467,9 +1467,11 @@ impl World {
|
||||
}
|
||||
}
|
||||
|
||||
/// Increments the world's current change tick, and returns the old value.
|
||||
#[inline]
|
||||
pub fn increment_change_tick(&self) -> u32 {
|
||||
self.change_tick.fetch_add(1, Ordering::AcqRel)
|
||||
pub fn increment_change_tick(&self) -> Tick {
|
||||
let prev_tick = self.change_tick.fetch_add(1, Ordering::AcqRel);
|
||||
Tick::new(prev_tick)
|
||||
}
|
||||
|
||||
/// Reads the current change tick of this world.
|
||||
@ -1477,8 +1479,9 @@ impl World {
|
||||
/// If you have exclusive (`&mut`) access to the world, consider using [`change_tick()`](Self::change_tick),
|
||||
/// which is more efficient since it does not require atomic synchronization.
|
||||
#[inline]
|
||||
pub fn read_change_tick(&self) -> u32 {
|
||||
self.change_tick.load(Ordering::Acquire)
|
||||
pub fn read_change_tick(&self) -> Tick {
|
||||
let tick = self.change_tick.load(Ordering::Acquire);
|
||||
Tick::new(tick)
|
||||
}
|
||||
|
||||
/// Reads the current change tick of this world.
|
||||
@ -1486,12 +1489,13 @@ impl World {
|
||||
/// This does the same thing as [`read_change_tick()`](Self::read_change_tick), only this method
|
||||
/// is more efficient since it does not require atomic synchronization.
|
||||
#[inline]
|
||||
pub fn change_tick(&mut self) -> u32 {
|
||||
*self.change_tick.get_mut()
|
||||
pub fn change_tick(&mut self) -> Tick {
|
||||
let tick = *self.change_tick.get_mut();
|
||||
Tick::new(tick)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn last_change_tick(&self) -> u32 {
|
||||
pub fn last_change_tick(&self) -> Tick {
|
||||
self.last_change_tick
|
||||
}
|
||||
|
||||
@ -1503,7 +1507,7 @@ impl World {
|
||||
// TODO: benchmark and optimize
|
||||
pub fn check_change_ticks(&mut self) {
|
||||
let change_tick = self.change_tick();
|
||||
if change_tick.wrapping_sub(self.last_check_tick) < CHECK_TICK_THRESHOLD {
|
||||
if change_tick.relative_to(self.last_check_tick).get() < CHECK_TICK_THRESHOLD {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -25,6 +25,8 @@ where
|
||||
// necessary
|
||||
world.flush();
|
||||
|
||||
let change_tick = world.change_tick();
|
||||
|
||||
let (lower, upper) = iter.size_hint();
|
||||
let length = upper.unwrap_or(lower);
|
||||
|
||||
@ -37,7 +39,7 @@ where
|
||||
&mut world.archetypes,
|
||||
&mut world.components,
|
||||
&mut world.storages,
|
||||
*world.change_tick.get_mut(),
|
||||
change_tick,
|
||||
);
|
||||
spawner.reserve_storage(length);
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ use crate::{
|
||||
bundle::Bundles,
|
||||
change_detection::{MutUntyped, TicksMut},
|
||||
component::{
|
||||
ComponentId, ComponentStorage, ComponentTicks, Components, StorageType, TickCells,
|
||||
ComponentId, ComponentStorage, ComponentTicks, Components, StorageType, Tick, TickCells,
|
||||
},
|
||||
entity::{Entities, Entity, EntityLocation},
|
||||
prelude::Component,
|
||||
@ -185,16 +185,17 @@ impl<'w> UnsafeWorldCell<'w> {
|
||||
|
||||
/// Reads the current change tick of this world.
|
||||
#[inline]
|
||||
pub fn read_change_tick(self) -> u32 {
|
||||
pub fn read_change_tick(self) -> Tick {
|
||||
// SAFETY:
|
||||
// - we only access world metadata
|
||||
unsafe { self.world_metadata() }
|
||||
let tick = unsafe { self.world_metadata() }
|
||||
.change_tick
|
||||
.load(Ordering::Acquire)
|
||||
.load(Ordering::Acquire);
|
||||
Tick::new(tick)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn last_change_tick(self) -> u32 {
|
||||
pub fn last_change_tick(self) -> Tick {
|
||||
// SAFETY:
|
||||
// - we only access world metadata
|
||||
unsafe { self.world_metadata() }.last_change_tick
|
||||
@ -655,8 +656,8 @@ impl<'w> UnsafeEntityCell<'w> {
|
||||
#[inline]
|
||||
pub(crate) unsafe fn get_mut_using_ticks<T: Component>(
|
||||
&self,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
last_change_tick: Tick,
|
||||
change_tick: Tick,
|
||||
) -> Option<Mut<'w, T>> {
|
||||
let component_id = self.world.components().get_id(TypeId::of::<T>())?;
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use crate::MainWorld;
|
||||
use bevy_ecs::{
|
||||
component::Tick,
|
||||
prelude::*,
|
||||
system::{ReadOnlySystemParam, SystemMeta, SystemParam, SystemParamItem, SystemState},
|
||||
};
|
||||
@ -76,7 +77,7 @@ where
|
||||
state: &'s mut Self::State,
|
||||
system_meta: &SystemMeta,
|
||||
world: &'w World,
|
||||
change_tick: u32,
|
||||
change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
// SAFETY:
|
||||
// - The caller ensures that `world` is the same one that `init_state` was called with.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user