jagua_rs/collision_detection/hazards/
detector.rs

1use crate::collision_detection::hazards::HazardEntity;
2use crate::collision_detection::hazards::filter::HazardFilter;
3use crate::entities::PItemKey;
4use slotmap::SecondaryMap;
5
6/// Trait for structs that can track and store detected [`HazardEntity`]s.
7/// Used in 'collision collection' queries to avoid having to repeatedly check hazards induced by an already detected entity.
8pub trait HazardDetector: HazardFilter {
9    fn contains(&self, haz: &HazardEntity) -> bool;
10
11    fn push(&mut self, haz: HazardEntity);
12
13    fn remove(&mut self, haz: &HazardEntity);
14
15    fn is_empty(&self) -> bool {
16        self.len() == 0
17    }
18
19    fn len(&self) -> usize;
20
21    fn iter(&self) -> impl Iterator<Item = &HazardEntity>;
22}
23
24/// Implements [`HazardFilter`] for any type that implements [`HazardDetector`].
25/// Any [`HazardEntity`]s that are already in the detector are considered irrelevant.
26impl<T> HazardFilter for T
27where
28    T: HazardDetector,
29{
30    fn is_irrelevant(&self, haz: &HazardEntity) -> bool {
31        self.contains(haz)
32    }
33}
34
35/// Basic implementation of a [`HazardDetector`].
36/// Hazards from [`HazardEntity::PlacedItem`] have instant lookups, the rest are stored in a Vec.
37#[derive(Debug, Clone, Default)]
38pub struct BasicHazardDetector {
39    pi_hazards: SecondaryMap<PItemKey, HazardEntity>,
40    other: Vec<HazardEntity>,
41}
42
43impl BasicHazardDetector {
44    pub fn new() -> Self {
45        Self::default()
46    }
47
48    pub fn clear(&mut self) {
49        self.pi_hazards.clear();
50        self.other.clear();
51    }
52}
53
54impl HazardDetector for BasicHazardDetector {
55    fn contains(&self, haz: &HazardEntity) -> bool {
56        match haz {
57            HazardEntity::PlacedItem { pk, .. } => self.pi_hazards.contains_key(*pk),
58            _ => self.other.iter().any(|h| h == haz),
59        }
60    }
61
62    fn push(&mut self, haz: HazardEntity) {
63        debug_assert!(!self.contains(&haz));
64        match haz {
65            HazardEntity::PlacedItem { pk, .. } => {
66                self.pi_hazards.insert(pk, haz);
67            }
68            _ => self.other.push(haz),
69        }
70    }
71
72    fn remove(&mut self, haz: &HazardEntity) {
73        match haz {
74            HazardEntity::PlacedItem { pk, .. } => {
75                self.pi_hazards.remove(*pk);
76            }
77            _ => self.other.retain(|h| h != haz),
78        }
79    }
80
81    fn len(&self) -> usize {
82        self.pi_hazards.len() + self.other.len()
83    }
84
85    fn iter(&self) -> impl Iterator<Item = &HazardEntity> {
86        self.pi_hazards
87            .iter()
88            .map(|(_, h)| h)
89            .chain(self.other.iter())
90    }
91}