Skip to main content

steel_registry/data_components/registry/
component_map.rs

1use super::{
2    ATTACK_ANIMATION, ATTRIBUTE_MODIFIERS, BREAK_SOUND, Component, ComponentData,
3    DataComponentType, Debug, DowncastType, ENCHANTMENTS, FxHashMap, INTERACT_ANIMATION,
4    Identifier, ItemAttributeModifiers, ItemEnchantments, ItemLore, LORE, MAX_STACK_SIZE, RARITY,
5    REPAIR_COST, Rarity, SoundEventHolder, SwingAnimation, TOOLTIP_DISPLAY, TooltipDisplay,
6    USE_EFFECTS, UseEffects, sound_events,
7};
8
9/// Storage for component values.
10///
11/// Maps component keys to their values. Used on items to store their data components.
12#[derive(Debug, Clone)]
13pub struct DataComponentMap {
14    pub(super) map: FxHashMap<Identifier, ComponentData>,
15}
16
17impl Default for DataComponentMap {
18    fn default() -> Self {
19        Self::new()
20    }
21}
22
23impl DataComponentMap {
24    #[must_use]
25    pub fn new() -> Self {
26        Self {
27            map: FxHashMap::default(),
28        }
29    }
30
31    /// Creates a map with common item components pre-populated.
32    #[must_use]
33    pub fn common_item_components() -> Self {
34        let mut map = FxHashMap::default();
35        map.insert(MAX_STACK_SIZE.key, ComponentData::new(64_i32));
36        map.insert(LORE.key, ComponentData::new(ItemLore::empty()));
37        map.insert(
38            ENCHANTMENTS.key,
39            ComponentData::new(ItemEnchantments::empty()),
40        );
41        map.insert(REPAIR_COST.key, ComponentData::new(0_i32));
42        map.insert(USE_EFFECTS.key, ComponentData::new(UseEffects::DEFAULT));
43        map.insert(
44            ATTRIBUTE_MODIFIERS.key,
45            ComponentData::new(ItemAttributeModifiers::empty()),
46        );
47        map.insert(RARITY.key, ComponentData::new(Rarity::Common));
48        map.insert(
49            BREAK_SOUND.key,
50            ComponentData::new(SoundEventHolder::registry(&sound_events::ENTITY_ITEM_BREAK)),
51        );
52        map.insert(
53            TOOLTIP_DISPLAY.key,
54            ComponentData::new(TooltipDisplay::DEFAULT),
55        );
56        map.insert(
57            ATTACK_ANIMATION.key,
58            ComponentData::new(SwingAnimation::DEFAULT),
59        );
60        map.insert(
61            INTERACT_ANIMATION.key,
62            ComponentData::new(SwingAnimation::DEFAULT),
63        );
64        Self { map }
65    }
66
67    /// Sets a component value (builder pattern).
68    #[must_use]
69    pub fn builder_set<T: Component + DowncastType>(
70        mut self,
71        component: DataComponentType<T>,
72        value: Option<T>,
73    ) -> Self {
74        self.set(component, value);
75        self
76    }
77
78    /// Sets a component value, or removes it if `None`.
79    pub fn set<T: Component + DowncastType>(
80        &mut self,
81        component: DataComponentType<T>,
82        value: Option<T>,
83    ) {
84        if let Some(v) = value {
85            self.map.insert(component.key, ComponentData::new(v));
86        } else {
87            self.map.remove(&component.key);
88        }
89    }
90
91    /// Gets a component value by type.
92    #[must_use]
93    pub fn get<T: Component + DowncastType + Clone>(
94        &self,
95        component: DataComponentType<T>,
96    ) -> Option<T> {
97        let data = self.map.get(&component.key)?;
98        data.downcast_ref::<T>().cloned()
99    }
100
101    /// Gets a reference to a component value.
102    #[must_use]
103    pub fn get_ref<T: Component + DowncastType>(
104        &self,
105        component: DataComponentType<T>,
106    ) -> Option<&T> {
107        let data = self.map.get(&component.key)?;
108        data.downcast_ref::<T>()
109    }
110
111    /// Checks if a component is present.
112    #[must_use]
113    pub fn has<T>(&self, component: DataComponentType<T>) -> bool {
114        self.map.contains_key(&component.key)
115    }
116
117    /// Returns the number of components.
118    #[must_use]
119    pub fn len(&self) -> usize {
120        self.map.len()
121    }
122
123    /// Returns true if empty.
124    #[must_use]
125    pub fn is_empty(&self) -> bool {
126        self.map.is_empty()
127    }
128
129    /// Iterates over component keys.
130    pub fn keys(&self) -> impl Iterator<Item = &Identifier> {
131        self.map.keys()
132    }
133
134    /// Iterates over component keys and their erased values.
135    pub fn iter(&self) -> impl Iterator<Item = (&Identifier, &ComponentData)> {
136        self.map.iter()
137    }
138
139    /// Gets raw component data by key (for plugin use).
140    #[must_use]
141    pub fn get_raw(&self, key: &Identifier) -> Option<&ComponentData> {
142        self.map.get(key)
143    }
144
145    /// Sets raw component data (for plugin use).
146    ///
147    /// Returns `true` if the data was set successfully, or `false` if the key is
148    /// unregistered or the data type does not match it.
149    ///
150    /// This prevents plugins from setting invalid types on vanilla components.
151    pub fn set_raw(&mut self, key: Identifier, data: ComponentData) -> bool {
152        use crate::{REGISTRY, RegistryExt};
153
154        let Some(entry) = REGISTRY.data_components.by_key(&key) else {
155            return false;
156        };
157        if !entry.validates(&data) {
158            return false;
159        }
160
161        self.map.insert(key, data);
162        true
163    }
164
165    /// Removes a component by key.
166    pub fn remove(&mut self, key: &Identifier) -> Option<ComponentData> {
167        self.map.remove(key)
168    }
169}