Skip to main content

steel_registry/data_components/registry/
component_map.rs

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