Skip to main content

steel_registry/
attribute.rs

1use rustc_hash::FxHashMap;
2use steel_utils::Identifier;
3
4/// Vanilla entity attribute definition
5///
6/// Unlike vanilla's separate `Attribute` / `RangedAttribute` hierarchy, we
7/// fold min/max directly into the struct since every attribute is ranged
8#[derive(Debug)]
9pub struct Attribute {
10    pub key: Identifier,
11    pub translation_key: &'static str,
12    pub default_value: f64,
13    pub min_value: f64,
14    pub max_value: f64,
15    pub syncable: bool,
16}
17
18impl Attribute {
19    /// Clamps a value to this attribute's valid range
20    #[must_use]
21    pub fn sanitize_value(&self, value: f64) -> f64 {
22        value.clamp(self.min_value, self.max_value)
23    }
24}
25
26pub type AttributeRef = &'static Attribute;
27
28pub struct AttributeRegistry {
29    attributes_by_id: Vec<AttributeRef>,
30    attributes_by_key: FxHashMap<Identifier, usize>,
31    allows_registering: bool,
32}
33
34impl Default for AttributeRegistry {
35    fn default() -> Self {
36        Self::new()
37    }
38}
39
40impl AttributeRegistry {
41    #[must_use]
42    pub fn new() -> Self {
43        Self {
44            attributes_by_id: Vec::new(),
45            attributes_by_key: FxHashMap::default(),
46            allows_registering: true,
47        }
48    }
49
50    /// Registers a new attribute
51    pub fn register(&mut self, attribute: AttributeRef) {
52        assert!(
53            self.allows_registering,
54            "Cannot register attributes after the registry has been frozen"
55        );
56        let idx = self.attributes_by_id.len();
57        self.attributes_by_key.insert(attribute.key.clone(), idx);
58        self.attributes_by_id.push(attribute);
59    }
60
61    /// Replaces an attribute at a given index
62    #[must_use]
63    pub fn replace(&mut self, attribute: AttributeRef, id: usize) -> bool {
64        if id >= self.attributes_by_id.len() {
65            return false;
66        }
67        self.attributes_by_id[id] = attribute;
68        true
69    }
70
71    pub fn iter(&self) -> impl Iterator<Item = (usize, AttributeRef)> + '_ {
72        self.attributes_by_id
73            .iter()
74            .enumerate()
75            .map(|(id, &attr)| (id, attr))
76    }
77}
78
79crate::impl_registry!(
80    AttributeRegistry,
81    Attribute,
82    attributes_by_id,
83    attributes_by_key,
84    attributes
85);