use bevy_ecs_macros::Event;1use bevy_ptr::UnsafeCellDeref;2#[cfg(feature = "bevy_reflect")]3use bevy_reflect::Reflect;4use core::cell::UnsafeCell;56use crate::change_detection::MAX_CHANGE_AGE;78/// A value that tracks when a system ran relative to other systems.9/// This is used to power change detection.10///11/// *Note* that a system that hasn't been run yet has a `Tick` of 0.12#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq)]13#[cfg_attr(14feature = "bevy_reflect",15derive(Reflect),16reflect(Debug, Hash, PartialEq, Clone)17)]18pub struct Tick {19tick: u32,20}2122impl Tick {23/// The maximum relative age for a change tick.24/// The value of this is equal to [`MAX_CHANGE_AGE`].25///26/// Since change detection will not work for any ticks older than this,27/// ticks are periodically scanned to ensure their relative values are below this.28pub const MAX: Self = Self::new(MAX_CHANGE_AGE);2930/// Creates a new [`Tick`] wrapping the given value.31#[inline]32pub const fn new(tick: u32) -> Self {33Self { tick }34}3536/// Gets the value of this change tick.37#[inline]38pub const fn get(self) -> u32 {39self.tick40}4142/// Sets the value of this change tick.43#[inline]44pub fn set(&mut self, tick: u32) {45self.tick = tick;46}4748/// Returns `true` if this `Tick` occurred since the system's `last_run`.49///50/// `this_run` is the current tick of the system, used as a reference to help deal with wraparound.51#[inline]52pub fn is_newer_than(self, last_run: Tick, this_run: Tick) -> bool {53// This works even with wraparound because the world tick (`this_run`) is always "newer" than54// `last_run` and `self.tick`, and we scan periodically to clamp `ComponentTicks` values55// so they never get older than `u32::MAX` (the difference would overflow).56//57// The clamp here ensures determinism (since scans could differ between app runs).58let ticks_since_insert = this_run.relative_to(self).tick.min(MAX_CHANGE_AGE);59let ticks_since_system = this_run.relative_to(last_run).tick.min(MAX_CHANGE_AGE);6061ticks_since_system > ticks_since_insert62}6364/// Returns a change tick representing the relationship between `self` and `other`.65#[inline]66pub(crate) fn relative_to(self, other: Self) -> Self {67let tick = self.tick.wrapping_sub(other.tick);68Self { tick }69}7071/// Wraps this change tick's value if it exceeds [`Tick::MAX`].72///73/// Returns `true` if wrapping was performed. Otherwise, returns `false`.74#[inline]75pub fn check_tick(&mut self, check: CheckChangeTicks) -> bool {76let age = check.present_tick().relative_to(*self);77// This comparison assumes that `age` has not overflowed `u32::MAX` before, which will be true78// so long as this check always runs before that can happen.79if age.get() > Self::MAX.get() {80*self = check.present_tick().relative_to(Self::MAX);81true82} else {83false84}85}86}8788/// An observer [`Event`] that can be used to maintain [`Tick`]s in custom data structures, enabling to make89/// use of bevy's periodic checks that clamps ticks to a certain range, preventing overflows and thus90/// keeping methods like [`Tick::is_newer_than`] reliably return `false` for ticks that got too old.91///92/// # Example93///94/// Here a schedule is stored in a custom resource. This way the systems in it would not have their change95/// ticks automatically updated via [`World::check_change_ticks`](crate::world::World::check_change_ticks),96/// possibly causing `Tick`-related bugs on long-running apps.97///98/// To fix that, add an observer for this event that calls the schedule's99/// [`Schedule::check_change_ticks`](bevy_ecs::schedule::Schedule::check_change_ticks).100///101/// ```102/// use bevy_ecs::prelude::*;103/// use bevy_ecs::component::CheckChangeTicks;104///105/// #[derive(Resource)]106/// struct CustomSchedule(Schedule);107///108/// # let mut world = World::new();109/// world.add_observer(|check: On<CheckChangeTicks>, mut schedule: ResMut<CustomSchedule>| {110/// schedule.0.check_change_ticks(*check);111/// });112/// ```113#[derive(Debug, Clone, Copy, Event)]114pub struct CheckChangeTicks(pub(crate) Tick);115116impl CheckChangeTicks {117/// Get the present `Tick` that other ticks get compared to.118pub fn present_tick(self) -> Tick {119self.0120}121}122123/// Interior-mutable access to the [`Tick`]s for a single component or resource.124#[derive(Copy, Clone, Debug)]125pub struct TickCells<'a> {126/// The tick indicating when the value was added to the world.127pub added: &'a UnsafeCell<Tick>,128/// The tick indicating the last time the value was modified.129pub changed: &'a UnsafeCell<Tick>,130}131132impl<'a> TickCells<'a> {133/// # Safety134/// All cells contained within must uphold the safety invariants of [`UnsafeCellDeref::read`].135#[inline]136pub(crate) unsafe fn read(&self) -> ComponentTicks {137ComponentTicks {138// SAFETY: The callers uphold the invariants for `read`.139added: unsafe { self.added.read() },140// SAFETY: The callers uphold the invariants for `read`.141changed: unsafe { self.changed.read() },142}143}144}145146/// Records when a component or resource was added and when it was last mutably dereferenced (or added).147#[derive(Copy, Clone, Debug)]148#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, Clone))]149pub struct ComponentTicks {150/// Tick recording the time this component or resource was added.151pub added: Tick,152153/// Tick recording the time this component or resource was most recently changed.154pub changed: Tick,155}156157impl ComponentTicks {158/// Returns `true` if the component or resource was added after the system last ran159/// (or the system is running for the first time).160#[inline]161pub fn is_added(&self, last_run: Tick, this_run: Tick) -> bool {162self.added.is_newer_than(last_run, this_run)163}164165/// Returns `true` if the component or resource was added or mutably dereferenced after the system last ran166/// (or the system is running for the first time).167#[inline]168pub fn is_changed(&self, last_run: Tick, this_run: Tick) -> bool {169self.changed.is_newer_than(last_run, this_run)170}171172/// Creates a new instance with the same change tick for `added` and `changed`.173pub fn new(change_tick: Tick) -> Self {174Self {175added: change_tick,176changed: change_tick,177}178}179180/// Manually sets the change tick.181///182/// This is normally done automatically via the [`DerefMut`](core::ops::DerefMut) implementation183/// on [`Mut<T>`](crate::change_detection::Mut), [`ResMut<T>`](crate::change_detection::ResMut), etc.184/// However, components and resources that make use of interior mutability might require manual updates.185///186/// # Example187/// ```no_run188/// # use bevy_ecs::{world::World, component::ComponentTicks};189/// let world: World = unimplemented!();190/// let component_ticks: ComponentTicks = unimplemented!();191///192/// component_ticks.set_changed(world.read_change_tick());193/// ```194#[inline]195pub fn set_changed(&mut self, change_tick: Tick) {196self.changed = change_tick;197}198}199200201