From 0dcbb3e5542ea64b978d9cda435650ca4f6e7d07 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 5 Mar 2023 09:07:19 -0500 Subject: [PATCH 01/20] use the `Tick` type for change ticks --- crates/bevy_ecs/macros/src/fetch.rs | 8 +- crates/bevy_ecs/macros/src/lib.rs | 4 +- crates/bevy_ecs/src/bundle.rs | 12 +-- crates/bevy_ecs/src/change_detection.rs | 45 ++++---- crates/bevy_ecs/src/component.rs | 37 +++---- crates/bevy_ecs/src/query/fetch.rs | 77 +++++++------ crates/bevy_ecs/src/query/filter.rs | 30 +++--- crates/bevy_ecs/src/query/iter.rs | 47 ++++---- crates/bevy_ecs/src/query/state.rs | 101 +++++++----------- crates/bevy_ecs/src/removal_detection.rs | 4 +- crates/bevy_ecs/src/schedule/schedule.rs | 6 +- crates/bevy_ecs/src/storage/resource.rs | 14 +-- crates/bevy_ecs/src/storage/sparse_set.rs | 11 +- crates/bevy_ecs/src/storage/table.rs | 13 +-- crates/bevy_ecs/src/system/combinator.rs | 8 +- .../src/system/exclusive_function_system.rs | 14 +-- crates/bevy_ecs/src/system/function_system.rs | 21 ++-- crates/bevy_ecs/src/system/mod.rs | 4 +- crates/bevy_ecs/src/system/query.rs | 16 +-- crates/bevy_ecs/src/system/system.rs | 15 +-- crates/bevy_ecs/src/system/system_param.rs | 66 ++++++------ crates/bevy_ecs/src/world/identifier.rs | 3 +- crates/bevy_ecs/src/world/mod.rs | 34 +++--- crates/bevy_ecs/src/world/spawn_batch.rs | 4 +- .../bevy_ecs/src/world/unsafe_world_cell.rs | 15 +-- crates/bevy_render/src/extract_param.rs | 3 +- 26 files changed, 298 insertions(+), 314 deletions(-) diff --git a/crates/bevy_ecs/macros/src/fetch.rs b/crates/bevy_ecs/macros/src/fetch.rs index 418c5741e75e2..503710182c889 100644 --- a/crates/bevy_ecs/macros/src/fetch.rs +++ b/crates/bevy_ecs/macros/src/fetch.rs @@ -222,16 +222,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, ) -> ::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(),)* diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index b4dde955dd388..dbafe0d9e3ead 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -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 diff --git a/crates/bevy_ecs/src/bundle.rs b/crates/bevy_ecs/src/bundle.rs index ff4ceb03af2f7..66fe6cdbcfb8b 100644 --- a/crates/bevy_ecs/src/bundle.rs +++ b/crates/bevy_ecs/src/bundle.rs @@ -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> { diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index ad5576657830a..c8396bea9d6e4 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -186,9 +186,7 @@ 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.change_tick; } #[inline] @@ -299,8 +297,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_change_tick: Tick, + pub(crate) change_tick: Tick, } impl<'a> Ticks<'a> { @@ -309,8 +307,8 @@ impl<'a> Ticks<'a> { #[inline] pub(crate) unsafe fn from_tick_cells( cells: TickCells<'a>, - last_change_tick: u32, - change_tick: u32, + last_change_tick: Tick, + change_tick: Tick, ) -> Self { Self { added: cells.added.deref(), @@ -324,8 +322,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_change_tick: Tick, + pub(crate) change_tick: Tick, } impl<'a> TicksMut<'a> { @@ -334,8 +332,8 @@ impl<'a> TicksMut<'a> { #[inline] pub(crate) unsafe fn from_tick_cells( cells: TickCells<'a>, - last_change_tick: u32, - change_tick: u32, + last_change_tick: Tick, + change_tick: Tick, ) -> Self { Self { added: cells.added.deref_mut(), @@ -667,7 +665,7 @@ 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.change_tick; } #[inline] @@ -757,7 +755,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 @@ -781,7 +779,7 @@ mod tests { // a bunch of stuff happens, the component is now older than `MAX_CHANGE_AGE` *world.change_tick.get_mut() += MAX_CHANGE_AGE + CHECK_TICK_THRESHOLD; - let change_tick = world.change_tick(); + let change_tick = world.change_tick().tick; let mut query = world.query::>(); for tracker in query.iter(&world) { @@ -811,8 +809,8 @@ mod tests { let ticks = TicksMut { added: &mut component_ticks.added, changed: &mut component_ticks.changed, - last_change_tick: 3, - change_tick: 4, + last_change_tick: Tick::new(3), + change_tick: Tick::new(4), }; let mut res = R {}; let res_mut = ResMut { @@ -823,8 +821,8 @@ mod tests { let into_mut: Mut = 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!(3, into_mut.ticks.last_change_tick.tick); + assert_eq!(4, into_mut.ticks.change_tick.tick); } #[test] @@ -836,8 +834,8 @@ mod tests { let ticks = TicksMut { added: &mut component_ticks.added, changed: &mut component_ticks.changed, - last_change_tick: 3, - change_tick: 4, + last_change_tick: Tick::new(3), + change_tick: Tick::new(4), }; let mut res = R {}; let non_send_mut = NonSendMut { @@ -848,8 +846,8 @@ mod tests { let into_mut: Mut = 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!(3, into_mut.ticks.last_change_tick.tick); + assert_eq!(4, into_mut.ticks.change_tick.tick); } #[test] @@ -857,7 +855,8 @@ mod tests { use super::*; struct Outer(i64); - let (last_change_tick, change_tick) = (2, 3); + let last_change_tick = Tick::new(2); + let change_tick = Tick::new(3); let mut component_ticks = ComponentTicks { added: Tick::new(1), changed: Tick::new(2), diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index ade0eb6b7d0a8..9afe77a2ce2f5 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -598,29 +598,30 @@ impl Tick { } #[inline] - /// Returns `true` if this `Tick` occurred since the system's `last_change_tick`. + /// 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) + let ticks_since_insert = this_run.tick.wrapping_sub(self.tick).min(MAX_CHANGE_AGE); + let ticks_since_system = this_run + .tick + .wrapping_sub(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); + pub(crate) fn check_tick(&mut self, Tick { tick }: Tick) { + let age = 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); + self.tick = tick.wrapping_sub(MAX_CHANGE_AGE); } } @@ -673,20 +674,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, } } diff --git a/crates/bevy_ecs/src/query/fetch.rs b/crates/bevy_ecs/src/query/fetch.rs index 7e4c7a3f7434a..c43980b9ec589 100644 --- a/crates/bevy_ecs/src/query/fetch.rs +++ b/crates/bevy_ecs/src/query/fetch.rs @@ -333,8 +333,8 @@ pub unsafe trait WorldQuery { unsafe fn init_fetch<'w>( world: &'w World, state: &Self::State, - last_change_tick: u32, - change_tick: u32, + last_change_tick: Tick, + change_tick: Tick, ) -> Self::Fetch<'w>; /// While this function can be called for any query, it is always safe to call if `Self: ReadOnlyWorldQuery` holds. @@ -464,8 +464,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_change_tick: Tick, + _change_tick: Tick, ) -> Self::Fetch<'w> { } @@ -546,8 +546,8 @@ unsafe impl WorldQuery for &T { unsafe fn init_fetch<'w>( world: &'w World, &component_id: &ComponentId, - _last_change_tick: u32, - _change_tick: u32, + _last_change_tick: Tick, + _change_tick: Tick, ) -> ReadFetch<'w, T> { ReadFetch { table_components: None, @@ -664,8 +664,8 @@ pub struct RefFetch<'w, T> { // T::Storage = SparseStorage sparse_set: Option<&'w ComponentSparseSet>, - last_change_tick: u32, - change_tick: u32, + last_change_tick: Tick, + change_tick: Tick, } /// SAFETY: `Self` is the same as `Self::ReadOnly` @@ -691,8 +691,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_change_tick: Tick, + change_tick: Tick, ) -> RefFetch<'w, T> { RefFetch { table_data: None, @@ -825,8 +825,8 @@ pub struct WriteFetch<'w, T> { // T::Storage = SparseStorage sparse_set: Option<&'w ComponentSparseSet>, - last_change_tick: u32, - change_tick: u32, + last_change_tick: Tick, + change_tick: Tick, } /// SAFETY: access of `&T` is a subset of `&mut T` @@ -852,8 +852,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_change_tick: Tick, + change_tick: Tick, ) -> WriteFetch<'w, T> { WriteFetch { table_data: None, @@ -1000,8 +1000,8 @@ unsafe impl WorldQuery for Option { unsafe fn init_fetch<'w>( world: &'w World, state: &T::State, - last_change_tick: u32, - change_tick: u32, + last_change_tick: Tick, + change_tick: Tick, ) -> OptionFetch<'w, T> { OptionFetch { fetch: T::init_fetch(world, state, last_change_tick, change_tick), @@ -1118,8 +1118,8 @@ unsafe impl ReadOnlyWorldQuery for Option {} #[deprecated = "`ChangeTrackers` will be removed in bevy 0.11. Use `bevy_ecs::prelude::Ref` instead."] pub struct ChangeTrackers { 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, } @@ -1138,8 +1138,8 @@ impl std::fmt::Debug for ChangeTrackers { 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() } } @@ -1148,14 +1148,13 @@ impl std::fmt::Debug for ChangeTrackers { impl ChangeTrackers { /// 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) } } @@ -1168,8 +1167,8 @@ pub struct ChangeTrackersFetch<'w, T> { sparse_set: Option<&'w ComponentSparseSet>, marker: PhantomData, - last_change_tick: u32, - change_tick: u32, + last_run: Tick, + this_run: Tick, } #[allow(deprecated)] @@ -1196,8 +1195,8 @@ unsafe impl WorldQuery for ChangeTrackers { unsafe fn init_fetch<'w>( world: &'w World, &component_id: &ComponentId, - last_change_tick: u32, - change_tick: u32, + last_change_tick: Tick, + change_tick: Tick, ) -> ChangeTrackersFetch<'w, T> { ChangeTrackersFetch { table_added: None, @@ -1210,8 +1209,8 @@ unsafe impl WorldQuery for ChangeTrackers { .debug_checked_unwrap() }), marker: PhantomData, - last_change_tick, - change_tick, + last_run: last_change_tick, + this_run: change_tick, } } @@ -1221,8 +1220,8 @@ unsafe impl WorldQuery for ChangeTrackers { 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, } } @@ -1272,8 +1271,8 @@ unsafe impl WorldQuery for ChangeTrackers { } }, 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 @@ -1282,8 +1281,8 @@ unsafe impl WorldQuery for ChangeTrackers { .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, }, } } @@ -1342,7 +1341,7 @@ 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_change_tick: Tick, _change_tick: Tick) -> Self::Fetch<'w> { let ($($name,)*) = state; ($($name::init_fetch(_world, $name, _last_change_tick, _change_tick),)*) } @@ -1451,7 +1450,7 @@ 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_change_tick: Tick, _change_tick: Tick) -> Self::Fetch<'w> { let ($($name,)*) = state; ($(($name::init_fetch(_world, $name, _last_change_tick, _change_tick), false),)*) } @@ -1592,8 +1591,8 @@ unsafe impl WorldQuery for NopWorldQuery { unsafe fn init_fetch( _world: &World, _state: &Q::State, - _last_change_tick: u32, - _change_tick: u32, + _last_change_tick: Tick, + _change_tick: Tick, ) { } diff --git a/crates/bevy_ecs/src/query/filter.rs b/crates/bevy_ecs/src/query/filter.rs index b2dd9023a69a8..ed4b4f8a66a93 100644 --- a/crates/bevy_ecs/src/query/filter.rs +++ b/crates/bevy_ecs/src/query/filter.rs @@ -53,8 +53,8 @@ unsafe impl WorldQuery for With { unsafe fn init_fetch( _world: &World, _state: &ComponentId, - _last_change_tick: u32, - _change_tick: u32, + _last_change_tick: Tick, + _change_tick: Tick, ) { } @@ -155,8 +155,8 @@ unsafe impl WorldQuery for Without { unsafe fn init_fetch( _world: &World, _state: &ComponentId, - _last_change_tick: u32, - _change_tick: u32, + _last_change_tick: Tick, + _change_tick: Tick, ) { } @@ -277,10 +277,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 +417,8 @@ macro_rules! impl_tick_filter { table_ticks: Option< ThinSlicePtr<'w, UnsafeCell>>, marker: PhantomData, 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 +432,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 +443,8 @@ macro_rules! impl_tick_filter { .debug_checked_unwrap() }), marker: PhantomData, - last_change_tick, - change_tick, + last_run, + this_run, } } @@ -454,8 +454,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 +509,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 +518,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) } } } diff --git a/crates/bevy_ecs/src/query/iter.rs b/crates/bevy_ecs/src/query/iter.rs index d456b044106f4..5f49843ec4131 100644 --- a/crates/bevy_ecs/src/query/iter.rs +++ b/crates/bevy_ecs/src/query/iter.rs @@ -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, - 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, 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, - 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,21 +487,21 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's, unsafe fn init_empty( world: &'w World, query_state: &'s QueryState, - 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, - last_change_tick: u32, - change_tick: u32, + last_change_tick: Tick, + change_tick: Tick, ) -> Self { let fetch = Q::init_fetch( world, diff --git a/crates/bevy_ecs/src/query/state.rs b/crates/bevy_ecs/src/query/state.rs index f4ae1a6837d62..d85c2965dec27 100644 --- a/crates/bevy_ecs/src/query/state.rs +++ b/crates/bevy_ecs/src/query/state.rs @@ -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 QueryState { /// 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 QueryState { &self, world: &'w World, entity: Entity, - last_change_tick: u32, - change_tick: u32, + last_run: Tick, + this_run: Tick, ) -> Result, QueryEntityError> { let location = world .entities @@ -407,8 +407,8 @@ impl QueryState { .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 QueryState { &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 QueryState { &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 QueryState { 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 QueryState { 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 QueryState { &'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, { - 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 QueryState { 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 QueryState { &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 QueryState { 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 QueryState { 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 QueryState { 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 QueryState { 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, 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(); diff --git a/crates/bevy_ecs/src/removal_detection.rs b/crates/bevy_ecs/src/removal_detection.rs index 004f08ca347e7..139c092bb8b50 100644 --- a/crates/bevy_ecs/src/removal_detection.rs +++ b/crates/bevy_ecs/src/removal_detection.rs @@ -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() } diff --git a/crates/bevy_ecs/src/schedule/schedule.rs b/crates/bevy_ecs/src/schedule/schedule.rs index df4b26c6cb6ad..d466e8aef1e0e 100644 --- a/crates/bevy_ecs/src/schedule/schedule.rs +++ b/crates/bevy_ecs/src/schedule/schedule.rs @@ -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); } diff --git a/crates/bevy_ecs/src/storage/resource.rs b/crates/bevy_ecs/src/storage/resource.rs index f1a0e9fb53552..88d6efa595f58 100644 --- a/crates/bevy_ecs/src/storage/resource.rs +++ b/crates/bevy_ecs/src/storage/resource.rs @@ -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}; @@ -100,17 +100,13 @@ impl ResourceData { }) } - pub(crate) fn get_mut( - &mut self, - last_change_tick: u32, - change_tick: u32, - ) -> Option> { + pub(crate) fn get_mut(&mut self, last_run: Tick, this_run: Tick) -> Option> { 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) }, }) } @@ -124,7 +120,7 @@ impl ResourceData { /// # 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); @@ -273,7 +269,7 @@ impl Resources { }) } - 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); } diff --git a/crates/bevy_ecs/src/storage/sparse_set.rs b/crates/bevy_ecs/src/storage/sparse_set.rs index 54412b54c25dd..767d6729f2c42 100644 --- a/crates/bevy_ecs/src/storage/sparse_set.rs +++ b/crates/bevy_ecs/src/storage/sparse_set.rs @@ -143,7 +143,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]); @@ -293,7 +298,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); } } @@ -548,7 +553,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); } diff --git a/crates/bevy_ecs/src/storage/table.rs b/crates/bevy_ecs/src/storage/table.rs index a8077be288631..9aa7b68a21555 100644 --- a/crates/bevy_ecs/src/storage/table.rs +++ b/crates/bevy_ecs/src/storage/table.rs @@ -129,13 +129,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. @@ -364,7 +361,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); } @@ -612,7 +609,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); } @@ -716,7 +713,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); } diff --git a/crates/bevy_ecs/src/system/combinator.rs b/crates/bevy_ecs/src/system/combinator.rs index 51304831d21ce..89e4e93b1a2e1 100644 --- a/crates/bevy_ecs/src/system/combinator.rs +++ b/crates/bevy_ecs/src/system/combinator.rs @@ -3,7 +3,7 @@ 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,16 +203,16 @@ 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 { + fn get_last_change_tick(&self) -> Tick { self.a.get_last_change_tick() } - fn set_last_change_tick(&mut self, last_change_tick: u32) { + fn set_last_change_tick(&mut self, last_change_tick: Tick) { self.a.set_last_change_tick(last_change_tick); self.b.set_last_change_tick(last_change_tick); } diff --git a/crates/bevy_ecs/src/system/exclusive_function_system.rs b/crates/bevy_ecs/src/system/exclusive_function_system.rs index 1fde9619e2436..de94ba6c08a3d 100644 --- a/crates/bevy_ecs/src/system/exclusive_function_system.rs +++ b/crates/bevy_ecs/src/system/exclusive_function_system.rs @@ -1,7 +1,7 @@ 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, @@ -104,7 +104,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_change_tick.set_changed(*change_tick); *change_tick = change_tick.wrapping_add(1); world.last_change_tick = saved_last_tick; @@ -116,11 +116,11 @@ where true } - fn get_last_change_tick(&self) -> u32 { + fn get_last_change_tick(&self) -> Tick { self.system_meta.last_change_tick } - fn set_last_change_tick(&mut self, last_change_tick: u32) { + fn set_last_change_tick(&mut self, last_change_tick: Tick) { self.system_meta.last_change_tick = last_change_tick; } @@ -134,14 +134,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_change_tick + .set_changed(world.change_tick().tick.wrapping_sub(MAX_CHANGE_AGE)); 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, change_tick, diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index fe6701df605c2..62c8d68035551 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -1,7 +1,7 @@ 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 +22,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_change_tick: Tick, } impl SystemMeta { @@ -32,7 +32,7 @@ impl SystemMeta { archetype_component_access: Access::default(), component_access_set: FilteredAccessSet::default(), is_send: true, - last_change_tick: 0, + last_change_tick: Tick::new(0), } } @@ -151,7 +151,8 @@ pub struct SystemState { impl SystemState { pub fn new(world: &mut World) -> Self { let mut meta = SystemMeta::new::(); - meta.last_change_tick = world.change_tick().wrapping_sub(MAX_CHANGE_AGE); + meta.last_change_tick + .set_changed(world.change_tick().tick.wrapping_sub(MAX_CHANGE_AGE)); let param_state = Param::init_state(world, &mut meta); Self { meta, @@ -288,7 +289,7 @@ impl SystemState { 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; @@ -468,11 +469,11 @@ where out } - fn get_last_change_tick(&self) -> u32 { + fn get_last_change_tick(&self) -> Tick { self.system_meta.last_change_tick } - fn set_last_change_tick(&mut self, last_change_tick: u32) { + fn set_last_change_tick(&mut self, last_change_tick: Tick) { self.system_meta.last_change_tick = last_change_tick; } @@ -485,7 +486,9 @@ 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_change_tick + .set_changed(world.change_tick().tick.wrapping_sub(MAX_CHANGE_AGE)); self.param_state = Some(F::Param::init_state(world, &mut self.system_meta)); } @@ -507,7 +510,7 @@ 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, change_tick, diff --git a/crates/bevy_ecs/src/system/mod.rs b/crates/bevy_ecs/src/system/mod.rs index 0e88adf24e81d..61351523bc2ea 100644 --- a/crates/bevy_ecs/src/system/mod.rs +++ b/crates/bevy_ecs/src/system/mod.rs @@ -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(); } diff --git a/crates/bevy_ecs/src/system/query.rs b/crates/bevy_ecs/src/system/query.rs index 4d3a12ed49bc7..b0c9074c9eeb0 100644 --- a/crates/bevy_ecs/src/system/query.rs +++ b/crates/bevy_ecs/src/system/query.rs @@ -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, - last_change_tick: u32, - change_tick: u32, + last_change_tick: Tick, + change_tick: Tick, // SAFETY: This is used to ensure that `get_component_mut::` 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_change_tick: {:?}, change_tick: {:?} }}", self.iter().count(), self.world, self.state, self.last_change_tick, self.change_tick) } } @@ -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, - 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_change_tick: last_run, + change_tick: this_run, } } diff --git a/crates/bevy_ecs/src/system/system.rs b/crates/bevy_ecs/src/system/system.rs index 78980e9063b81..5674d20b41b3f 100644 --- a/crates/bevy_ecs/src/system/system.rs +++ b/crates/bevy_ecs/src/system/system.rs @@ -1,6 +1,7 @@ use bevy_utils::tracing::warn; use core::fmt::Debug; +use crate::component::Tick; use crate::{ archetype::ArchetypeComponentId, change_detection::MAX_CHANGE_AGE, component::ComponentId, query::Access, world::World, @@ -63,19 +64,19 @@ 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> { Vec::new() } /// Gets the system's last change tick - fn get_last_change_tick(&self) -> u32; + fn get_last_change_tick(&self) -> Tick; /// Sets the system's last change tick /// # 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_change_tick(&mut self, last_change_tick: Tick); } /// [`System`] types that do not modify the [`World`] when run. @@ -92,11 +93,11 @@ pub unsafe trait ReadOnlySystem: System {} pub type BoxedSystem = Box>; pub(crate) fn check_system_change_tick( - last_change_tick: &mut u32, - change_tick: u32, + last_change_tick: &mut Tick, + change_tick: Tick, system_name: &str, ) { - let age = change_tick.wrapping_sub(*last_change_tick); + let age = change_tick.tick.wrapping_sub(last_change_tick.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 { @@ -107,7 +108,7 @@ pub(crate) fn check_system_change_tick( age, MAX_CHANGE_AGE - 1, ); - *last_change_tick = change_tick.wrapping_sub(MAX_CHANGE_AGE); + last_change_tick.set_changed(change_tick.tick.wrapping_sub(MAX_CHANGE_AGE)); } } diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 437a726f4413d..411b219e048be 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -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,7 +227,7 @@ unsafe impl 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, @@ -371,7 +371,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 +445,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() @@ -486,7 +486,7 @@ unsafe impl<'a, T: Resource> SystemParam for Option> { &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() @@ -540,7 +540,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() @@ -578,7 +578,7 @@ unsafe impl<'a, T: Resource> SystemParam for Option> { &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() @@ -631,7 +631,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 +752,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 +927,7 @@ unsafe impl 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 +948,8 @@ unsafe impl 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_change_tick: Tick, + change_tick: Tick, } // SAFETY: Only reads a single World non-send resource @@ -1034,7 +1034,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() @@ -1073,7 +1073,7 @@ unsafe impl SystemParam for Option> { &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() @@ -1126,7 +1126,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() @@ -1159,7 +1159,7 @@ unsafe impl<'a, T: 'static> SystemParam for Option> { &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() @@ -1186,7 +1186,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 +1207,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 +1228,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 +1249,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() } @@ -1266,21 +1266,21 @@ unsafe impl<'a> SystemParam for &'a Bundles { /// on a [`Mut`](crate::change_detection::Mut) or [`ResMut`](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 change_tick(&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_change_tick(&self) -> Tick { + self.last_run } } @@ -1298,11 +1298,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_change_tick, + this_run: change_tick, } } } @@ -1368,7 +1368,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 +1410,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 +1534,7 @@ unsafe impl 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)) diff --git a/crates/bevy_ecs/src/world/identifier.rs b/crates/bevy_ecs/src/world/identifier.rs index e6a78be5ca2f4..55e2b6a5fa350 100644 --- a/crates/bevy_ecs/src/world/identifier.rs +++ b/crates/bevy_ecs/src/world/identifier.rs @@ -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 } diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 0f78884e16944..1842899eebc0c 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -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,7 +64,7 @@ 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_change_tick: Tick, pub(crate) last_check_tick: u32, } @@ -82,7 +82,7 @@ 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_change_tick: Tick::new(0), last_check_tick: 0, } } @@ -493,6 +493,7 @@ impl World { /// ``` pub fn spawn(&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 @@ -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.tick.wrapping_sub(self.last_check_tick) < CHECK_TICK_THRESHOLD { return; } @@ -1525,7 +1529,7 @@ impl World { schedules.check_change_ticks(change_tick); } - self.last_check_tick = change_tick; + self.last_check_tick = change_tick.tick; } /// Runs both [`clear_entities`](Self::clear_entities) and [`clear_resources`](Self::clear_resources), diff --git a/crates/bevy_ecs/src/world/spawn_batch.rs b/crates/bevy_ecs/src/world/spawn_batch.rs index f5e1bd2792e2b..965ff9754021c 100644 --- a/crates/bevy_ecs/src/world/spawn_batch.rs +++ b/crates/bevy_ecs/src/world/spawn_batch.rs @@ -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); diff --git a/crates/bevy_ecs/src/world/unsafe_world_cell.rs b/crates/bevy_ecs/src/world/unsafe_world_cell.rs index 364cef1bc3371..99231fe3f32ef 100644 --- a/crates/bevy_ecs/src/world/unsafe_world_cell.rs +++ b/crates/bevy_ecs/src/world/unsafe_world_cell.rs @@ -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( &self, - last_change_tick: u32, - change_tick: u32, + last_change_tick: Tick, + change_tick: Tick, ) -> Option> { let component_id = self.world.components().get_id(TypeId::of::())?; diff --git a/crates/bevy_render/src/extract_param.rs b/crates/bevy_render/src/extract_param.rs index 92290407f5b25..898dfe0e28ae0 100644 --- a/crates/bevy_render/src/extract_param.rs +++ b/crates/bevy_render/src/extract_param.rs @@ -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. From 3c6910f0103eeda44e66cf569146033979035897 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 5 Mar 2023 09:10:55 -0500 Subject: [PATCH 02/20] use `Tick` in `DetectChangesMut` --- crates/bevy_ecs/src/change_detection.rs | 12 +++++------- crates/bevy_ecs/src/query/fetch.rs | 8 ++++---- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index c8396bea9d6e4..4f149d68103e7 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -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. /// @@ -190,10 +190,8 @@ macro_rules! change_detection_mut_impl { } #[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] @@ -669,8 +667,8 @@ impl<'a> DetectChangesMut for MutUntyped<'a> { } #[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] diff --git a/crates/bevy_ecs/src/query/fetch.rs b/crates/bevy_ecs/src/query/fetch.rs index c43980b9ec589..0fe35c0e66d17 100644 --- a/crates/bevy_ecs/src/query/fetch.rs +++ b/crates/bevy_ecs/src/query/fetch.rs @@ -333,8 +333,8 @@ pub unsafe trait WorldQuery { unsafe fn init_fetch<'w>( world: &'w World, state: &Self::State, - last_change_tick: Tick, - change_tick: Tick, + 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. @@ -464,8 +464,8 @@ unsafe impl WorldQuery for Entity { unsafe fn init_fetch<'w>( _world: &'w World, _state: &Self::State, - _last_change_tick: Tick, - _change_tick: Tick, + _last_run: Tick, + _this_run: Tick, ) -> Self::Fetch<'w> { } From f7d650b13cdf9d028d12bcd42d326accfee1572f Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 5 Mar 2023 09:17:24 -0500 Subject: [PATCH 03/20] rename locals to `last_run` and `this_run` --- crates/bevy_ecs/src/change_detection.rs | 74 +++++++++---------- crates/bevy_ecs/src/query/fetch.rs | 82 ++++++++++------------ crates/bevy_ecs/src/query/filter.rs | 16 +---- crates/bevy_ecs/src/query/iter.rs | 18 ++--- crates/bevy_ecs/src/system/combinator.rs | 5 +- crates/bevy_ecs/src/system/system_param.rs | 20 +++--- crates/bevy_ecs/src/world/mod.rs | 4 +- 7 files changed, 95 insertions(+), 124 deletions(-) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index 4f149d68103e7..afae6e1faef11 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -145,14 +145,14 @@ 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] @@ -186,7 +186,7 @@ macro_rules! change_detection_mut_impl { #[inline] fn set_changed(&mut self) { - *self.ticks.changed = self.ticks.change_tick; + *self.ticks.changed = self.ticks.this_run; } #[inline] @@ -238,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, } } } @@ -295,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: Tick, - pub(crate) change_tick: Tick, + pub(crate) last_run: Tick, + pub(crate) this_run: Tick, } impl<'a> Ticks<'a> { @@ -305,14 +305,14 @@ impl<'a> Ticks<'a> { #[inline] pub(crate) unsafe fn from_tick_cells( cells: TickCells<'a>, - last_change_tick: Tick, - change_tick: Tick, + 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, } } } @@ -320,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: Tick, - pub(crate) change_tick: Tick, + pub(crate) last_run: Tick, + pub(crate) this_run: Tick, } impl<'a> TicksMut<'a> { @@ -330,14 +330,14 @@ impl<'a> TicksMut<'a> { #[inline] pub(crate) unsafe fn from_tick_cells( cells: TickCells<'a>, - last_change_tick: Tick, - change_tick: Tick, + 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, } } } @@ -347,8 +347,8 @@ impl<'a> From> 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, } } } @@ -604,8 +604,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, }, } } @@ -642,14 +642,14 @@ 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] @@ -663,7 +663,7 @@ impl<'a> DetectChangesMut for MutUntyped<'a> { #[inline] fn set_changed(&mut self) { - *self.ticks.changed = self.ticks.change_tick; + *self.ticks.changed = self.ticks.this_run; } #[inline] @@ -807,8 +807,8 @@ mod tests { let ticks = TicksMut { added: &mut component_ticks.added, changed: &mut component_ticks.changed, - last_change_tick: Tick::new(3), - change_tick: Tick::new(4), + last_run: Tick::new(3), + this_run: Tick::new(4), }; let mut res = R {}; let res_mut = ResMut { @@ -819,8 +819,8 @@ mod tests { let into_mut: Mut = 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.tick); - assert_eq!(4, into_mut.ticks.change_tick.tick); + assert_eq!(3, into_mut.ticks.last_run.tick); + assert_eq!(4, into_mut.ticks.this_run.tick); } #[test] @@ -832,8 +832,8 @@ mod tests { let ticks = TicksMut { added: &mut component_ticks.added, changed: &mut component_ticks.changed, - last_change_tick: Tick::new(3), - change_tick: Tick::new(4), + last_run: Tick::new(3), + this_run: Tick::new(4), }; let mut res = R {}; let non_send_mut = NonSendMut { @@ -844,8 +844,8 @@ mod tests { let into_mut: Mut = 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.tick); - assert_eq!(4, into_mut.ticks.change_tick.tick); + assert_eq!(3, into_mut.ticks.last_run.tick); + assert_eq!(4, into_mut.ticks.this_run.tick); } #[test] @@ -853,8 +853,8 @@ mod tests { use super::*; struct Outer(i64); - let last_change_tick = Tick::new(2); - let change_tick = Tick::new(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), @@ -862,8 +862,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); @@ -881,7 +881,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] diff --git a/crates/bevy_ecs/src/query/fetch.rs b/crates/bevy_ecs/src/query/fetch.rs index 0fe35c0e66d17..9ce6ef7598940 100644 --- a/crates/bevy_ecs/src/query/fetch.rs +++ b/crates/bevy_ecs/src/query/fetch.rs @@ -546,8 +546,8 @@ unsafe impl WorldQuery for &T { unsafe fn init_fetch<'w>( world: &'w World, &component_id: &ComponentId, - _last_change_tick: Tick, - _change_tick: Tick, + _last_run: Tick, + _this_run: Tick, ) -> ReadFetch<'w, T> { ReadFetch { table_components: None, @@ -664,8 +664,8 @@ pub struct RefFetch<'w, T> { // T::Storage = SparseStorage sparse_set: Option<&'w ComponentSparseSet>, - last_change_tick: Tick, - change_tick: Tick, + last_run: Tick, + this_run: Tick, } /// SAFETY: `Self` is the same as `Self::ReadOnly` @@ -691,8 +691,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: Tick, - change_tick: Tick, + last_run: Tick, + this_run: Tick, ) -> RefFetch<'w, T> { RefFetch { table_data: None, @@ -703,8 +703,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, } } @@ -712,8 +712,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, } } @@ -758,8 +758,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, }, } } @@ -771,7 +771,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), } } } @@ -825,8 +825,8 @@ pub struct WriteFetch<'w, T> { // T::Storage = SparseStorage sparse_set: Option<&'w ComponentSparseSet>, - last_change_tick: Tick, - change_tick: Tick, + last_run: Tick, + this_run: Tick, } /// SAFETY: access of `&T` is a subset of `&mut T` @@ -852,8 +852,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: Tick, - change_tick: Tick, + last_run: Tick, + this_run: Tick, ) -> WriteFetch<'w, T> { WriteFetch { table_data: None, @@ -864,8 +864,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, } } @@ -873,8 +873,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, } } @@ -919,8 +919,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, }, } } @@ -932,11 +932,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), } } } @@ -1000,11 +996,11 @@ unsafe impl WorldQuery for Option { unsafe fn init_fetch<'w>( world: &'w World, state: &T::State, - last_change_tick: Tick, - change_tick: Tick, + 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, } } @@ -1195,8 +1191,8 @@ unsafe impl WorldQuery for ChangeTrackers { unsafe fn init_fetch<'w>( world: &'w World, &component_id: &ComponentId, - last_change_tick: Tick, - change_tick: Tick, + last_run: Tick, + this_run: Tick, ) -> ChangeTrackersFetch<'w, T> { ChangeTrackersFetch { table_added: None, @@ -1209,8 +1205,8 @@ unsafe impl WorldQuery for ChangeTrackers { .debug_checked_unwrap() }), marker: PhantomData, - last_run: last_change_tick, - this_run: change_tick, + last_run, + this_run, } } @@ -1341,9 +1337,9 @@ macro_rules! impl_tuple_fetch { } #[allow(clippy::unused_unit)] - unsafe fn init_fetch<'w>(_world: &'w World, state: &Self::State, _last_change_tick: Tick, _change_tick: Tick) -> 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>( @@ -1450,9 +1446,9 @@ macro_rules! impl_anytuple_fetch { } #[allow(clippy::unused_unit)] - unsafe fn init_fetch<'w>(_world: &'w World, state: &Self::State, _last_change_tick: Tick, _change_tick: Tick) -> 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>( @@ -1588,13 +1584,7 @@ unsafe impl WorldQuery for NopWorldQuery { const IS_ARCHETYPAL: bool = true; #[inline(always)] - unsafe fn init_fetch( - _world: &World, - _state: &Q::State, - _last_change_tick: Tick, - _change_tick: Tick, - ) { - } + 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> {} diff --git a/crates/bevy_ecs/src/query/filter.rs b/crates/bevy_ecs/src/query/filter.rs index ed4b4f8a66a93..c0b91b54afd10 100644 --- a/crates/bevy_ecs/src/query/filter.rs +++ b/crates/bevy_ecs/src/query/filter.rs @@ -50,13 +50,7 @@ unsafe impl WorldQuery for With { fn shrink<'wlong: 'wshort, 'wshort>(_: Self::Item<'wlong>) -> Self::Item<'wshort> {} - unsafe fn init_fetch( - _world: &World, - _state: &ComponentId, - _last_change_tick: Tick, - _change_tick: Tick, - ) { - } + 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 WorldQuery for Without { fn shrink<'wlong: 'wshort, 'wshort>(_: Self::Item<'wlong>) -> Self::Item<'wshort> {} - unsafe fn init_fetch( - _world: &World, - _state: &ComponentId, - _last_change_tick: Tick, - _change_tick: Tick, - ) { - } + 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> {} diff --git a/crates/bevy_ecs/src/query/iter.rs b/crates/bevy_ecs/src/query/iter.rs index 5f49843ec4131..893df47aac3a3 100644 --- a/crates/bevy_ecs/src/query/iter.rs +++ b/crates/bevy_ecs/src/query/iter.rs @@ -500,21 +500,11 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's, unsafe fn init( world: &'w World, query_state: &'s QueryState, - last_change_tick: Tick, - change_tick: Tick, + 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, diff --git a/crates/bevy_ecs/src/system/combinator.rs b/crates/bevy_ecs/src/system/combinator.rs index 89e4e93b1a2e1..cc6b761f3e469 100644 --- a/crates/bevy_ecs/src/system/combinator.rs +++ b/crates/bevy_ecs/src/system/combinator.rs @@ -3,7 +3,10 @@ use std::{borrow::Cow, cell::UnsafeCell, marker::PhantomData}; use bevy_ptr::UnsafeCellDeref; use crate::{ - archetype::ArchetypeComponentId, component::{ComponentId, Tick}, prelude::World, query::Access, + archetype::ArchetypeComponentId, + component::{ComponentId, Tick}, + prelude::World, + query::Access, }; use super::{ReadOnlySystem, System}; diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 411b219e048be..6babb15845455 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -462,8 +462,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_change_tick, + this_run: change_tick, }, } } @@ -496,8 +496,8 @@ unsafe impl<'a, T: Resource> SystemParam for Option> { 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_change_tick, + this_run: change_tick, }, }) } @@ -557,8 +557,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_change_tick, + this_run: change_tick, }, } } @@ -588,8 +588,8 @@ unsafe impl<'a, T: Resource> SystemParam for Option> { 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_change_tick, + this_run: change_tick, }, }) } @@ -992,8 +992,8 @@ impl<'a, T> From> 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, + change_tick: nsm.ticks.this_run, + last_change_tick: nsm.ticks.last_run, } } } diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 1842899eebc0c..a03033145aaf2 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -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); From dd9bf5e64c423dad44557958ed40aa7abd87c7bb Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 5 Mar 2023 09:21:53 -0500 Subject: [PATCH 04/20] rename `{g,s}et_last_change_tick` to `last_run` --- crates/bevy_ecs/src/system/combinator.rs | 10 +++++----- .../bevy_ecs/src/system/exclusive_function_system.rs | 4 ++-- crates/bevy_ecs/src/system/function_system.rs | 4 ++-- crates/bevy_ecs/src/system/system.rs | 9 +++++---- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/crates/bevy_ecs/src/system/combinator.rs b/crates/bevy_ecs/src/system/combinator.rs index cc6b761f3e469..def5e60be5613 100644 --- a/crates/bevy_ecs/src/system/combinator.rs +++ b/crates/bevy_ecs/src/system/combinator.rs @@ -211,13 +211,13 @@ where self.b.check_change_tick(change_tick); } - fn get_last_change_tick(&self) -> Tick { - 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: Tick) { - 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_change_tick: Tick) { + self.a.set_last_run(last_change_tick); + self.b.set_last_run(last_change_tick); } fn default_system_sets(&self) -> Vec> { diff --git a/crates/bevy_ecs/src/system/exclusive_function_system.rs b/crates/bevy_ecs/src/system/exclusive_function_system.rs index de94ba6c08a3d..5d40a26f5d711 100644 --- a/crates/bevy_ecs/src/system/exclusive_function_system.rs +++ b/crates/bevy_ecs/src/system/exclusive_function_system.rs @@ -116,11 +116,11 @@ where true } - fn get_last_change_tick(&self) -> Tick { + fn get_last_run(&self) -> Tick { self.system_meta.last_change_tick } - fn set_last_change_tick(&mut self, last_change_tick: Tick) { + fn set_last_run(&mut self, last_change_tick: Tick) { self.system_meta.last_change_tick = last_change_tick; } diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index 62c8d68035551..f10fd16c21e77 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -469,11 +469,11 @@ where out } - fn get_last_change_tick(&self) -> Tick { + fn get_last_run(&self) -> Tick { self.system_meta.last_change_tick } - fn set_last_change_tick(&mut self, last_change_tick: Tick) { + fn set_last_run(&mut self, last_change_tick: Tick) { self.system_meta.last_change_tick = last_change_tick; } diff --git a/crates/bevy_ecs/src/system/system.rs b/crates/bevy_ecs/src/system/system.rs index 5674d20b41b3f..187cc380995c5 100644 --- a/crates/bevy_ecs/src/system/system.rs +++ b/crates/bevy_ecs/src/system/system.rs @@ -69,14 +69,15 @@ pub trait System: Send + Sync + 'static { fn default_system_sets(&self) -> Vec> { Vec::new() } - /// Gets the system's last change tick - fn get_last_change_tick(&self) -> Tick; - /// 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: Tick); + fn set_last_run(&mut self, last_change_tick: Tick); } /// [`System`] types that do not modify the [`World`] when run. From fdcb88bb0fe6d38ae27ed8aa0306352cb5390929 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 5 Mar 2023 09:23:07 -0500 Subject: [PATCH 05/20] rename `SystemMeta::last_change_tick` --- .../src/system/exclusive_function_system.rs | 12 ++++----- crates/bevy_ecs/src/system/function_system.rs | 18 ++++++------- crates/bevy_ecs/src/system/system_param.rs | 26 +++++++------------ 3 files changed, 25 insertions(+), 31 deletions(-) diff --git a/crates/bevy_ecs/src/system/exclusive_function_system.rs b/crates/bevy_ecs/src/system/exclusive_function_system.rs index 5d40a26f5d711..024ef8ad6d520 100644 --- a/crates/bevy_ecs/src/system/exclusive_function_system.rs +++ b/crates/bevy_ecs/src/system/exclusive_function_system.rs @@ -95,7 +95,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 +104,7 @@ where let out = self.func.run(world, input, params); let change_tick = world.change_tick.get_mut(); - self.system_meta.last_change_tick.set_changed(*change_tick); + self.system_meta.last_run.set_changed(*change_tick); *change_tick = change_tick.wrapping_add(1); world.last_change_tick = saved_last_tick; @@ -117,11 +117,11 @@ where } fn get_last_run(&self) -> Tick { - self.system_meta.last_change_tick + self.system_meta.last_run } fn set_last_run(&mut self, last_change_tick: Tick) { - self.system_meta.last_change_tick = last_change_tick; + self.system_meta.last_run = last_change_tick; } #[inline] @@ -135,7 +135,7 @@ where fn initialize(&mut self, world: &mut World) { self.world_id = Some(world.id()); self.system_meta - .last_change_tick + .last_run .set_changed(world.change_tick().tick.wrapping_sub(MAX_CHANGE_AGE)); self.param_state = Some(F::Param::init(world, &mut self.system_meta)); } @@ -145,7 +145,7 @@ where #[inline] 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(), ); diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index f10fd16c21e77..6bd67129bd5e9 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -22,7 +22,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: Tick, + pub(crate) last_run: Tick, } impl SystemMeta { @@ -32,7 +32,7 @@ impl SystemMeta { archetype_component_access: Access::default(), component_access_set: FilteredAccessSet::default(), is_send: true, - last_change_tick: Tick::new(0), + last_run: Tick::new(0), } } @@ -151,7 +151,7 @@ pub struct SystemState { impl SystemState { pub fn new(world: &mut World) -> Self { let mut meta = SystemMeta::new::(); - meta.last_change_tick + meta.last_run .set_changed(world.change_tick().tick.wrapping_sub(MAX_CHANGE_AGE)); let param_state = Param::init_state(world, &mut meta); Self { @@ -292,7 +292,7 @@ impl SystemState { 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 } } @@ -465,16 +465,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_run(&self) -> Tick { - self.system_meta.last_change_tick + self.system_meta.last_run } fn set_last_run(&mut self, last_change_tick: Tick) { - self.system_meta.last_change_tick = last_change_tick; + self.system_meta.last_run = last_change_tick; } #[inline] @@ -487,7 +487,7 @@ where fn initialize(&mut self, world: &mut World) { self.world_id = Some(world.id()); self.system_meta - .last_change_tick + .last_run .set_changed(world.change_tick().tick.wrapping_sub(MAX_CHANGE_AGE)); self.param_state = Some(F::Param::init_state(world, &mut self.system_meta)); } @@ -512,7 +512,7 @@ where #[inline] 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(), ); diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 6babb15845455..e4506f14f0823 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -229,13 +229,7 @@ unsafe impl SystemPara world: &'w World, 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) } } @@ -462,7 +456,7 @@ unsafe impl<'a, T: Resource> SystemParam for Res<'a, T> { ticks: Ticks { added: ticks.added.deref(), changed: ticks.changed.deref(), - last_run: system_meta.last_change_tick, + last_run: system_meta.last_run, this_run: change_tick, }, } @@ -496,7 +490,7 @@ unsafe impl<'a, T: Resource> SystemParam for Option> { ticks: Ticks { added: ticks.added.deref(), changed: ticks.changed.deref(), - last_run: system_meta.last_change_tick, + last_run: system_meta.last_run, this_run: change_tick, }, }) @@ -557,7 +551,7 @@ unsafe impl<'a, T: Resource> SystemParam for ResMut<'a, T> { ticks: TicksMut { added: value.ticks.added, changed: value.ticks.changed, - last_run: system_meta.last_change_tick, + last_run: system_meta.last_run, this_run: change_tick, }, } @@ -588,7 +582,7 @@ unsafe impl<'a, T: Resource> SystemParam for Option> { ticks: TicksMut { added: value.ticks.added, changed: value.ticks.changed, - last_run: system_meta.last_change_tick, + last_run: system_meta.last_run, this_run: change_tick, }, }) @@ -1050,7 +1044,7 @@ 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, + last_change_tick: system_meta.last_run, change_tick, } } @@ -1081,7 +1075,7 @@ unsafe impl SystemParam for Option> { .map(|(ptr, ticks)| NonSend { value: ptr.deref(), ticks: ticks.read(), - last_change_tick: system_meta.last_change_tick, + last_change_tick: system_meta.last_run, change_tick, }) } @@ -1140,7 +1134,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), } } } @@ -1166,7 +1160,7 @@ unsafe impl<'a, T: 'static> SystemParam for Option> { .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), }) } } @@ -1301,7 +1295,7 @@ unsafe impl SystemParam for SystemChangeTick { change_tick: Tick, ) -> Self::Item<'w, 's> { SystemChangeTick { - last_run: system_meta.last_change_tick, + last_run: system_meta.last_run, this_run: change_tick, } } From 4428354ddeb12be76c369e5e90110b4a5c6df70f Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 5 Mar 2023 09:24:50 -0500 Subject: [PATCH 06/20] rename stuff for `SystemChangeTick` --- crates/bevy_ecs/src/system/system_param.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index e4506f14f0823..3748f1267c55d 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -1252,10 +1252,10 @@ 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`](crate::change_detection::Mut) or [`ResMut`](crate::change_detection::ResMut). #[derive(Debug)] @@ -1267,13 +1267,13 @@ pub struct SystemChangeTick { impl SystemChangeTick { /// Returns the current [`World`] change tick seen by the system. #[inline] - pub fn change_tick(&self) -> 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) -> Tick { + pub fn last_run(&self) -> Tick { self.last_run } } From 66cfcd1a2a3121a09044ed3cec8cc7266788f5c9 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 5 Mar 2023 09:28:51 -0500 Subject: [PATCH 07/20] rename more things to `last_run` --- crates/bevy_ecs/src/system/combinator.rs | 6 +- .../src/system/exclusive_function_system.rs | 4 +- crates/bevy_ecs/src/system/function_system.rs | 4 +- crates/bevy_ecs/src/system/query.rs | 131 +++++++----------- crates/bevy_ecs/src/system/system.rs | 12 +- crates/bevy_ecs/src/system/system_param.rs | 21 ++- 6 files changed, 70 insertions(+), 108 deletions(-) diff --git a/crates/bevy_ecs/src/system/combinator.rs b/crates/bevy_ecs/src/system/combinator.rs index def5e60be5613..ec782e715bd19 100644 --- a/crates/bevy_ecs/src/system/combinator.rs +++ b/crates/bevy_ecs/src/system/combinator.rs @@ -215,9 +215,9 @@ where self.a.get_last_run() } - fn set_last_run(&mut self, last_change_tick: Tick) { - self.a.set_last_run(last_change_tick); - self.b.set_last_run(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> { diff --git a/crates/bevy_ecs/src/system/exclusive_function_system.rs b/crates/bevy_ecs/src/system/exclusive_function_system.rs index 024ef8ad6d520..a9ce7bbcd3a15 100644 --- a/crates/bevy_ecs/src/system/exclusive_function_system.rs +++ b/crates/bevy_ecs/src/system/exclusive_function_system.rs @@ -120,8 +120,8 @@ where self.system_meta.last_run } - fn set_last_run(&mut self, last_change_tick: Tick) { - self.system_meta.last_run = last_change_tick; + fn set_last_run(&mut self, last_run: Tick) { + self.system_meta.last_run = last_run; } #[inline] diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index 6bd67129bd5e9..46fc1b924a47d 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -473,8 +473,8 @@ where self.system_meta.last_run } - fn set_last_run(&mut self, last_change_tick: Tick) { - self.system_meta.last_run = last_change_tick; + fn set_last_run(&mut self, last_run: Tick) { + self.system_meta.last_run = last_run; } #[inline] diff --git a/crates/bevy_ecs/src/system/query.rs b/crates/bevy_ecs/src/system/query.rs index b0c9074c9eeb0..a09b1a0c38eb0 100644 --- a/crates/bevy_ecs/src/system/query.rs +++ b/crates/bevy_ecs/src/system/query.rs @@ -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, - last_change_tick: Tick, - change_tick: Tick, + last_run: Tick, + this_run: Tick, // SAFETY: This is used to ensure that `get_component_mut::` 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) } } @@ -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: last_run, - change_tick: this_run, + 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, { - 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::(self.last_change_tick, self.change_tick) + .get_mut_using_ticks::(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) } } } diff --git a/crates/bevy_ecs/src/system/system.rs b/crates/bevy_ecs/src/system/system.rs index 187cc380995c5..51f45a1f3582f 100644 --- a/crates/bevy_ecs/src/system/system.rs +++ b/crates/bevy_ecs/src/system/system.rs @@ -77,7 +77,7 @@ pub trait System: Send + Sync + 'static { /// 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_run(&mut self, last_change_tick: Tick); + fn set_last_run(&mut self, last_run: Tick); } /// [`System`] types that do not modify the [`World`] when run. @@ -93,12 +93,8 @@ pub unsafe trait ReadOnlySystem: System {} /// A convenience type alias for a boxed [`System`] trait object. pub type BoxedSystem = Box>; -pub(crate) fn check_system_change_tick( - last_change_tick: &mut Tick, - change_tick: Tick, - system_name: &str, -) { - let age = change_tick.tick.wrapping_sub(last_change_tick.tick); +pub(crate) fn check_system_change_tick(last_run: &mut Tick, this_run: Tick, system_name: &str) { + let age = this_run.tick.wrapping_sub(last_run.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 { @@ -109,7 +105,7 @@ pub(crate) fn check_system_change_tick( age, MAX_CHANGE_AGE - 1, ); - last_change_tick.set_changed(change_tick.tick.wrapping_sub(MAX_CHANGE_AGE)); + last_run.set_changed(this_run.tick.wrapping_sub(MAX_CHANGE_AGE)); } } diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 3748f1267c55d..018c79630f455 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -942,8 +942,8 @@ unsafe impl SystemParam for Deferred<'_, T> { pub struct NonSend<'w, T: 'static> { pub(crate) value: &'w T, ticks: ComponentTicks, - last_change_tick: Tick, - change_tick: Tick, + last_run: Tick, + this_run: Tick, } // SAFETY: Only reads a single World non-send resource @@ -961,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) } } @@ -986,8 +985,8 @@ impl<'a, T> From> for NonSend<'a, T> { added: nsm.ticks.added.to_owned(), changed: nsm.ticks.changed.to_owned(), }, - change_tick: nsm.ticks.this_run, - last_change_tick: nsm.ticks.last_run, + this_run: nsm.ticks.this_run, + last_run: nsm.ticks.last_run, } } } @@ -1044,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_run, - change_tick, + last_run: system_meta.last_run, + this_run: change_tick, } } } @@ -1075,8 +1074,8 @@ unsafe impl SystemParam for Option> { .map(|(ptr, ticks)| NonSend { value: ptr.deref(), ticks: ticks.read(), - last_change_tick: system_meta.last_run, - change_tick, + last_run: system_meta.last_run, + this_run: change_tick, }) } } From 5400aa511f5e3d8d741591d0b4bf87599e633d4e Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 5 Mar 2023 09:29:51 -0500 Subject: [PATCH 08/20] rewrite docs for `Tick` --- crates/bevy_ecs/src/component.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index 9afe77a2ce2f5..3630059d367ac 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -586,7 +586,8 @@ 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, From bc7267fb743bdc607c36c32f6d7ffb4b0dd3f130 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 5 Mar 2023 09:38:30 -0500 Subject: [PATCH 09/20] update `ComponentTicks::set_changed` --- crates/bevy_ecs/src/component.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index 3630059d367ac..737abdd1bf5ad 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -707,8 +707,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; } } From 4afe50f55eca67be09c1300f4c0d1b0e6c0c035c Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 5 Mar 2023 10:03:40 -0500 Subject: [PATCH 10/20] rename `Tick::set_changed` to `set` --- crates/bevy_ecs/src/component.rs | 4 ++-- crates/bevy_ecs/src/system/exclusive_function_system.rs | 4 ++-- crates/bevy_ecs/src/system/function_system.rs | 4 ++-- crates/bevy_ecs/src/system/system.rs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index 737abdd1bf5ad..bdac24c4c6a52 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -641,8 +641,8 @@ impl Tick { /// component_ticks.set_changed(world.read_change_tick()); /// ``` #[inline] - pub fn set_changed(&mut self, change_tick: u32) { - self.tick = change_tick; + pub fn set(&mut self, tick: u32) { + self.tick = tick; } } diff --git a/crates/bevy_ecs/src/system/exclusive_function_system.rs b/crates/bevy_ecs/src/system/exclusive_function_system.rs index a9ce7bbcd3a15..b973af7800768 100644 --- a/crates/bevy_ecs/src/system/exclusive_function_system.rs +++ b/crates/bevy_ecs/src/system/exclusive_function_system.rs @@ -104,7 +104,7 @@ where let out = self.func.run(world, input, params); let change_tick = world.change_tick.get_mut(); - self.system_meta.last_run.set_changed(*change_tick); + self.system_meta.last_run.set(*change_tick); *change_tick = change_tick.wrapping_add(1); world.last_change_tick = saved_last_tick; @@ -136,7 +136,7 @@ where self.world_id = Some(world.id()); self.system_meta .last_run - .set_changed(world.change_tick().tick.wrapping_sub(MAX_CHANGE_AGE)); + .set(world.change_tick().tick.wrapping_sub(MAX_CHANGE_AGE)); self.param_state = Some(F::Param::init(world, &mut self.system_meta)); } diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index 46fc1b924a47d..8dd0d23b65d4e 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -152,7 +152,7 @@ impl SystemState { pub fn new(world: &mut World) -> Self { let mut meta = SystemMeta::new::(); meta.last_run - .set_changed(world.change_tick().tick.wrapping_sub(MAX_CHANGE_AGE)); + .set(world.change_tick().tick.wrapping_sub(MAX_CHANGE_AGE)); let param_state = Param::init_state(world, &mut meta); Self { meta, @@ -488,7 +488,7 @@ where self.world_id = Some(world.id()); self.system_meta .last_run - .set_changed(world.change_tick().tick.wrapping_sub(MAX_CHANGE_AGE)); + .set(world.change_tick().tick.wrapping_sub(MAX_CHANGE_AGE)); self.param_state = Some(F::Param::init_state(world, &mut self.system_meta)); } diff --git a/crates/bevy_ecs/src/system/system.rs b/crates/bevy_ecs/src/system/system.rs index 51f45a1f3582f..6f5cc25dd0ff6 100644 --- a/crates/bevy_ecs/src/system/system.rs +++ b/crates/bevy_ecs/src/system/system.rs @@ -105,7 +105,7 @@ pub(crate) fn check_system_change_tick(last_run: &mut Tick, this_run: Tick, syst age, MAX_CHANGE_AGE - 1, ); - last_run.set_changed(this_run.tick.wrapping_sub(MAX_CHANGE_AGE)); + last_run.set(this_run.tick.wrapping_sub(MAX_CHANGE_AGE)); } } From 6fd32f8d56caec69adc7bf0a97d245be15dd1875 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 5 Mar 2023 10:21:14 -0500 Subject: [PATCH 11/20] remove incorrect duplicate docs --- crates/bevy_ecs/src/component.rs | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index bdac24c4c6a52..77a447f950ed6 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -626,20 +626,7 @@ impl Tick { } } - /// Manually sets the change tick. - /// - /// This is normally done automatically via the [`DerefMut`](std::ops::DerefMut) implementation - /// on [`Mut`](crate::change_detection::Mut), [`ResMut`](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()); - /// ``` + /// Manually set the value of this change tick. #[inline] pub fn set(&mut self, tick: u32) { self.tick = tick; From 9d945882dacbdd6b6eb383c0e6eb44bf7db8d5c1 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 5 Mar 2023 10:53:12 -0500 Subject: [PATCH 12/20] add `Tick::relative_to` to encapsulate subtraction --- crates/bevy_ecs/src/component.rs | 20 +++++++++++++------ .../src/system/exclusive_function_system.rs | 5 +---- crates/bevy_ecs/src/system/function_system.rs | 8 ++------ crates/bevy_ecs/src/system/system.rs | 4 ++-- crates/bevy_ecs/src/world/mod.rs | 8 ++++---- 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index 77a447f950ed6..86887990bed75 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -594,6 +594,11 @@ pub struct Tick { } impl Tick { + /// The maximum age for a change tick. + /// 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 = Tick::new(MAX_CHANGE_AGE); + pub const fn new(tick: u32) -> Self { Self { tick } } @@ -602,21 +607,24 @@ impl Tick { /// Returns `true` if this `Tick` occurred since the system's `last_run`. /// /// `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 { + 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 = this_run.tick.wrapping_sub(self.tick).min(MAX_CHANGE_AGE); - let ticks_since_system = this_run - .tick - .wrapping_sub(last_run.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 } + /// Returns a change tick representing the relationship between `self` and `other`. + pub fn relative_to(self, other: Self) -> Self { + let tick = self.tick.wrapping_sub(other.tick); + Self { tick } + } + pub(crate) fn check_tick(&mut self, Tick { tick }: Tick) { let age = tick.wrapping_sub(self.tick); // This comparison assumes that `age` has not overflowed `u32::MAX` before, which will be true diff --git a/crates/bevy_ecs/src/system/exclusive_function_system.rs b/crates/bevy_ecs/src/system/exclusive_function_system.rs index b973af7800768..d82c6ff153bee 100644 --- a/crates/bevy_ecs/src/system/exclusive_function_system.rs +++ b/crates/bevy_ecs/src/system/exclusive_function_system.rs @@ -1,6 +1,5 @@ use crate::{ archetype::ArchetypeComponentId, - change_detection::MAX_CHANGE_AGE, component::{ComponentId, Tick}, query::Access, system::{ @@ -134,9 +133,7 @@ where #[inline] fn initialize(&mut self, world: &mut World) { self.world_id = Some(world.id()); - self.system_meta - .last_run - .set(world.change_tick().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)); } diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index 8dd0d23b65d4e..0e88ad0187af4 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -1,6 +1,5 @@ use crate::{ archetype::{ArchetypeComponentId, ArchetypeGeneration, ArchetypeId}, - change_detection::MAX_CHANGE_AGE, component::{ComponentId, Tick}, prelude::FromWorld, query::{Access, FilteredAccessSet}, @@ -151,8 +150,7 @@ pub struct SystemState { impl SystemState { pub fn new(world: &mut World) -> Self { let mut meta = SystemMeta::new::(); - meta.last_run - .set(world.change_tick().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, @@ -486,9 +484,7 @@ where #[inline] fn initialize(&mut self, world: &mut World) { self.world_id = Some(world.id()); - self.system_meta - .last_run - .set(world.change_tick().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)); } diff --git a/crates/bevy_ecs/src/system/system.rs b/crates/bevy_ecs/src/system/system.rs index 6f5cc25dd0ff6..ef0a8390e749e 100644 --- a/crates/bevy_ecs/src/system/system.rs +++ b/crates/bevy_ecs/src/system/system.rs @@ -94,7 +94,7 @@ pub unsafe trait ReadOnlySystem: System {} pub type BoxedSystem = Box>; pub(crate) fn check_system_change_tick(last_run: &mut Tick, this_run: Tick, system_name: &str) { - let age = this_run.tick.wrapping_sub(last_run.tick); + let age = this_run.relative_to(*last_run).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 { @@ -105,7 +105,7 @@ pub(crate) fn check_system_change_tick(last_run: &mut Tick, this_run: Tick, syst age, MAX_CHANGE_AGE - 1, ); - last_run.set(this_run.tick.wrapping_sub(MAX_CHANGE_AGE)); + *last_run = this_run.relative_to(Tick::MAX); } } diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index a03033145aaf2..ca38fe54b4042 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -65,7 +65,7 @@ pub struct World { pub(crate) archetype_component_access: ArchetypeComponentAccess, pub(crate) change_tick: AtomicU32, pub(crate) last_change_tick: Tick, - pub(crate) last_check_tick: u32, + pub(crate) last_check_tick: Tick, } impl Default for World { @@ -83,7 +83,7 @@ impl Default for World { // are detected on first system runs and for direct world queries. change_tick: AtomicU32::new(1), last_change_tick: Tick::new(0), - last_check_tick: 0, + last_check_tick: Tick::new(0), } } } @@ -1507,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.tick.wrapping_sub(self.last_check_tick) < CHECK_TICK_THRESHOLD { + if change_tick.relative_to(self.last_check_tick).tick < CHECK_TICK_THRESHOLD { return; } @@ -1529,7 +1529,7 @@ impl World { schedules.check_change_ticks(change_tick); } - self.last_check_tick = change_tick.tick; + self.last_check_tick = change_tick; } /// Runs both [`clear_entities`](Self::clear_entities) and [`clear_resources`](Self::clear_resources), From 4539841301d5dd72b6015cc571c1fbce13b80dcc Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 5 Mar 2023 11:00:12 -0500 Subject: [PATCH 13/20] return `Tick` from `DetectChanges` --- crates/bevy_ecs/src/change_detection.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index afae6e1faef11..cac9d1f9a19c8 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -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. @@ -156,8 +156,8 @@ macro_rules! change_detection_impl { } #[inline] - fn last_changed(&self) -> u32 { - self.ticks.changed.tick + fn last_changed(&self) -> Tick { + *self.ticks.changed } } @@ -653,8 +653,8 @@ impl<'a> DetectChanges for MutUntyped<'a> { } #[inline] - fn last_changed(&self) -> u32 { - self.ticks.changed.tick + fn last_changed(&self) -> Tick { + *self.ticks.changed } } From 71c72710ee8e0dc1e34df1e8f099a775cc43ed4d Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 5 Mar 2023 11:02:48 -0500 Subject: [PATCH 14/20] encapsulate `Tick::tick` --- crates/bevy_ecs/src/change_detection.rs | 26 ++++++++++++------------- crates/bevy_ecs/src/component.rs | 22 +++++++++++++-------- crates/bevy_ecs/src/system/system.rs | 2 +- crates/bevy_ecs/src/world/mod.rs | 2 +- 4 files changed, 29 insertions(+), 23 deletions(-) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index cac9d1f9a19c8..aee01c43e85bd 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -777,12 +777,12 @@ mod tests { // a bunch of stuff happens, the component is now older than `MAX_CHANGE_AGE` *world.change_tick.get_mut() += MAX_CHANGE_AGE + CHECK_TICK_THRESHOLD; - let change_tick = world.change_tick().tick; + let change_tick = world.change_tick(); let mut query = world.query::>(); 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); } @@ -791,8 +791,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); } @@ -817,10 +817,10 @@ mod tests { }; let into_mut: Mut = 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_run.tick); - assert_eq!(4, into_mut.ticks.this_run.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] @@ -842,10 +842,10 @@ mod tests { }; let into_mut: Mut = 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_run.tick); - assert_eq!(4, into_mut.ticks.this_run.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] diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index 86887990bed75..0a192cba8a018 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -590,19 +590,31 @@ impl Components { /// This is used to power change detection. #[derive(Copy, Clone, Debug)] pub struct Tick { - pub(crate) tick: u32, + tick: u32, } impl Tick { /// The maximum age for a change tick. /// 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 = Tick::new(MAX_CHANGE_AGE); + 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] + 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`. /// @@ -633,12 +645,6 @@ impl Tick { self.tick = tick.wrapping_sub(MAX_CHANGE_AGE); } } - - /// Manually set the value of this change tick. - #[inline] - pub fn set(&mut self, tick: u32) { - self.tick = tick; - } } /// Wrapper around [`Tick`]s for a single component diff --git a/crates/bevy_ecs/src/system/system.rs b/crates/bevy_ecs/src/system/system.rs index ef0a8390e749e..cd7afa27ca280 100644 --- a/crates/bevy_ecs/src/system/system.rs +++ b/crates/bevy_ecs/src/system/system.rs @@ -94,7 +94,7 @@ pub unsafe trait ReadOnlySystem: System {} pub type BoxedSystem = Box>; pub(crate) fn check_system_change_tick(last_run: &mut Tick, this_run: Tick, system_name: &str) { - let age = this_run.relative_to(*last_run).tick; + let age = this_run.relative_to(*last_run).get(); // 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 { diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index ca38fe54b4042..0832141f4bf02 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -1507,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.relative_to(self.last_check_tick).tick < CHECK_TICK_THRESHOLD { + if change_tick.relative_to(self.last_check_tick).get() < CHECK_TICK_THRESHOLD { return; } From 39043c9f20db9e2297a0bcffb035345651b033ad Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 5 Mar 2023 11:09:30 -0500 Subject: [PATCH 15/20] encapsulate tick checks --- crates/bevy_ecs/src/component.rs | 8 +++++++- crates/bevy_ecs/src/system/system.rs | 11 +++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index 0a192cba8a018..f6a75323fbae6 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -637,12 +637,18 @@ impl Tick { Self { tick } } - pub(crate) fn check_tick(&mut self, Tick { tick }: Tick) { + /// Wraps this change tick's value if it exceeds [`Tick::MAX`]. + /// + /// Returns `true` if wrapping was performed. Otherwise, returns `false`. + pub(crate) fn check_tick(&mut self, Tick { tick }: Tick) -> bool { let age = 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 = tick.wrapping_sub(MAX_CHANGE_AGE); + true + } else { + false } } } diff --git a/crates/bevy_ecs/src/system/system.rs b/crates/bevy_ecs/src/system/system.rs index cd7afa27ca280..a9d51e9b75e50 100644 --- a/crates/bevy_ecs/src/system/system.rs +++ b/crates/bevy_ecs/src/system/system.rs @@ -94,18 +94,13 @@ pub unsafe trait ReadOnlySystem: System {} pub type BoxedSystem = Box>; pub(crate) fn check_system_change_tick(last_run: &mut Tick, this_run: Tick, system_name: &str) { - let age = this_run.relative_to(*last_run).get(); - // 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 { + 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, ); - *last_run = this_run.relative_to(Tick::MAX); } } From 195dfc76072bb6e2e2bf6a4ff74c828c061770da Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 5 Mar 2023 11:16:57 -0500 Subject: [PATCH 16/20] encapsulate uses of `MAX_CHANGE_TICK` --- crates/bevy_ecs/src/component.rs | 12 +++++++----- crates/bevy_ecs/src/system/system.rs | 7 ++----- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index f6a75323fbae6..5bff64e3ca595 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -594,7 +594,9 @@ pub struct Tick { } impl Tick { - /// The maximum age for a change 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); @@ -640,12 +642,12 @@ impl Tick { /// Wraps this change tick's value if it exceeds [`Tick::MAX`]. /// /// Returns `true` if wrapping was performed. Otherwise, returns `false`. - pub(crate) fn check_tick(&mut self, Tick { tick }: Tick) -> bool { - let age = tick.wrapping_sub(self.tick); + 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 > MAX_CHANGE_AGE { - self.tick = tick.wrapping_sub(MAX_CHANGE_AGE); + if age.get() > Self::MAX.get() { + *self = tick.relative_to(Self::MAX); true } else { false diff --git a/crates/bevy_ecs/src/system/system.rs b/crates/bevy_ecs/src/system/system.rs index a9d51e9b75e50..307dd2bc7da61 100644 --- a/crates/bevy_ecs/src/system/system.rs +++ b/crates/bevy_ecs/src/system/system.rs @@ -2,10 +2,7 @@ use bevy_utils::tracing::warn; use core::fmt::Debug; use crate::component::Tick; -use crate::{ - archetype::ArchetypeComponentId, change_detection::MAX_CHANGE_AGE, component::ComponentId, - query::Access, world::World, -}; +use crate::{archetype::ArchetypeComponentId, component::ComponentId, query::Access, world::World}; use std::any::TypeId; use std::borrow::Cow; @@ -99,7 +96,7 @@ pub(crate) fn check_system_change_tick(last_run: &mut Tick, this_run: Tick, syst warn!( "System '{system_name}' has not run for {age} ticks. \ Changes older than {} ticks will not be detected.", - MAX_CHANGE_AGE - 1, + Tick::MAX.get() - 1, ); } } From 7a9be9883a0d38cb43f3548b219b5e1b86dfea65 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Mon, 6 Mar 2023 09:49:47 -0500 Subject: [PATCH 17/20] make `relative_to` pub(crate) --- crates/bevy_ecs/src/component.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index 5bff64e3ca595..a7c090e0f4e42 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -634,7 +634,7 @@ impl Tick { } /// Returns a change tick representing the relationship between `self` and `other`. - pub fn relative_to(self, other: Self) -> Self { + pub(crate) fn relative_to(self, other: Self) -> Self { let tick = self.tick.wrapping_sub(other.tick); Self { tick } } From 7a4b357da53635c8244b63228137cb602ab1702a Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Thu, 9 Mar 2023 10:24:11 -0500 Subject: [PATCH 18/20] fix a merge error --- crates/bevy_ecs/src/change_detection.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index 797fc0b49502d..53188a9aecf1f 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -546,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, }, } } From bef9ce63529a5a3dd0d8846c41fd99e1e2e5294f Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Thu, 9 Mar 2023 10:27:30 -0500 Subject: [PATCH 19/20] update a unit test --- crates/bevy_ecs/src/change_detection.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index 53188a9aecf1f..273b9b119d8ef 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -870,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()); From 75d33a86bf3777e47f36d84044b518bb7ab961ad Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Thu, 9 Mar 2023 10:35:32 -0500 Subject: [PATCH 20/20] bless a compile fail test --- .../tests/ui/world_query_derive.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs_compile_fail_tests/tests/ui/world_query_derive.stderr b/crates/bevy_ecs_compile_fail_tests/tests/ui/world_query_derive.stderr index b762ac275fce3..158be3f9d7e05 100644 --- a/crates/bevy_ecs_compile_fail_tests/tests/ui/world_query_derive.stderr +++ b/crates/bevy_ecs_compile_fail_tests/tests/ui/world_query_derive.stderr @@ -18,7 +18,7 @@ note: required by a bound in `_::assert_readonly` --> tests/ui/world_query_derive.rs:7:10 | 7 | #[derive(WorldQuery)] - | ^^^^^^^^^^ required by this bound in `_::assert_readonly` + | ^^^^^^^^^^ required by this bound in `assert_readonly` = note: this error originates in the derive macro `WorldQuery` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `MutableMarked: ReadOnlyWorldQuery` is not satisfied @@ -41,5 +41,5 @@ note: required by a bound in `_::assert_readonly` --> tests/ui/world_query_derive.rs:18:10 | 18 | #[derive(WorldQuery)] - | ^^^^^^^^^^ required by this bound in `_::assert_readonly` + | ^^^^^^^^^^ required by this bound in `assert_readonly` = note: this error originates in the derive macro `WorldQuery` (in Nightly builds, run with -Z macro-backtrace for more info)