Skip to main content

goud_engine/ecs/sparse_set/
tick_tracking.rs

1//! Tick-tracking extensions for [`SparseSet`].
2//!
3//! Provides methods for storing and querying per-entity change ticks
4//! alongside component values. Used by the change detection system.
5
6use super::super::Entity;
7use super::core::SparseSet;
8
9impl<T> SparseSet<T> {
10    /// Inserts a value for the given entity, recording the given `change_tick`.
11    ///
12    /// On a new insert both `added_tick` and `changed_tick` are set to
13    /// `change_tick`. On a replacement only `changed_tick` is updated.
14    ///
15    /// If the entity already has a value, the old value is returned.
16    ///
17    /// # Panics
18    ///
19    /// Panics if `entity` is a placeholder.
20    pub fn insert_with_tick(&mut self, entity: Entity, value: T, change_tick: u32) -> Option<T> {
21        assert!(
22            !entity.is_placeholder(),
23            "Cannot insert with placeholder entity"
24        );
25
26        let index = entity.index() as usize;
27
28        // Grow sparse vec if needed
29        if index >= self.sparse.len() {
30            self.sparse.resize(index + 1, None);
31        }
32
33        if let Some(dense_index) = self.sparse[index] {
34            // Entity already has a value - replace it
35            let old_value = std::mem::replace(&mut self.values[dense_index], value);
36            self.changed_ticks[dense_index] = change_tick;
37            Some(old_value)
38        } else {
39            // New entity - add to dense arrays
40            let dense_index = self.dense.len();
41            self.sparse[index] = Some(dense_index);
42            self.dense.push(entity);
43            self.values.push(value);
44            self.added_ticks.push(change_tick);
45            self.changed_ticks.push(change_tick);
46            None
47        }
48    }
49
50    /// Returns the added tick for the given entity, if present.
51    #[inline]
52    pub fn get_added_tick(&self, entity: Entity) -> Option<u32> {
53        let dense_index = self.dense_index_of(entity)?;
54        Some(self.added_ticks[dense_index])
55    }
56
57    /// Returns the changed tick for the given entity, if present.
58    #[inline]
59    pub fn get_changed_tick(&self, entity: Entity) -> Option<u32> {
60        let dense_index = self.dense_index_of(entity)?;
61        Some(self.changed_ticks[dense_index])
62    }
63
64    /// Sets the changed tick for the given entity.
65    ///
66    /// Does nothing if the entity is not in the set.
67    #[inline]
68    pub fn set_changed_tick(&mut self, entity: Entity, tick: u32) {
69        if let Some(dense_index) = self.dense_index_of(entity) {
70            self.changed_ticks[dense_index] = tick;
71        }
72    }
73
74    /// Internal helper: returns the dense index for an entity, if present.
75    #[inline]
76    pub(crate) fn dense_index_of(&self, entity: Entity) -> Option<usize> {
77        if entity.is_placeholder() {
78            return None;
79        }
80        let index = entity.index() as usize;
81        if index >= self.sparse.len() {
82            return None;
83        }
84        self.sparse[index]
85    }
86}