use bevy_ecs_macros::Event;
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::Reflect;
use core::{cell::UnsafeCell, panic::Location};
use crate::change_detection::{MaybeLocation, MAX_CHANGE_AGE};
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect),
reflect(Debug, Hash, PartialEq, Clone)
)]
pub struct Tick {
tick: u32,
}
impl Tick {
pub const MAX: Self = Self::new(MAX_CHANGE_AGE);
#[inline]
pub const fn new(tick: u32) -> Self {
Self { tick }
}
#[inline]
pub const fn get(self) -> u32 {
self.tick
}
#[inline]
pub fn set(&mut self, tick: u32) {
self.tick = tick;
}
#[inline]
pub fn is_newer_than(self, last_run: Tick, this_run: Tick) -> bool {
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
}
#[inline]
pub(crate) fn relative_to(self, other: Self) -> Self {
let tick = self.tick.wrapping_sub(other.tick);
Self { tick }
}
#[inline]
pub fn check_tick(&mut self, check: CheckChangeTicks) -> bool {
let age = check.present_tick().relative_to(*self);
if age.get() > Self::MAX.get() {
*self = check.present_tick().relative_to(Self::MAX);
true
} else {
false
}
}
}
#[derive(Debug, Clone, Copy, Event)]
pub struct CheckChangeTicks(pub(crate) Tick);
impl CheckChangeTicks {
pub fn present_tick(self) -> Tick {
self.0
}
}
#[derive(Copy, Clone, Debug)]
pub struct ComponentTickCells<'a> {
pub added: &'a UnsafeCell<Tick>,
pub changed: &'a UnsafeCell<Tick>,
pub changed_by: MaybeLocation<&'a UnsafeCell<&'static Location<'static>>>,
}
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, Clone))]
pub struct ComponentTicks {
pub added: Tick,
pub changed: Tick,
}
impl ComponentTicks {
#[inline]
pub fn is_added(&self, last_run: Tick, this_run: Tick) -> bool {
self.added.is_newer_than(last_run, this_run)
}
#[inline]
pub fn is_changed(&self, last_run: Tick, this_run: Tick) -> bool {
self.changed.is_newer_than(last_run, this_run)
}
pub fn new(change_tick: Tick) -> Self {
Self {
added: change_tick,
changed: change_tick,
}
}
#[inline]
pub fn set_changed(&mut self, change_tick: Tick) {
self.changed = change_tick;
}
}