steel_registry/data_components/registry/
mod.rs1use rustc_hash::FxHashMap;
10use simdnbt::{
11 FromNbtTag, ToNbtTag,
12 borrow::{NbtTag as BorrowedNbtTag, read_tag},
13 owned::{NbtCompound, NbtTag as OwnedNbtTag},
14};
15use std::{
16 fmt::Debug,
17 io::{Cursor, Result, Write},
18 marker::PhantomData,
19};
20
21use steel_utils::{
22 DowncastType, DowncastTypeKey, Identifier,
23 codec::VarInt,
24 hash::{ComponentHasher, HashComponent, HashEntry, sort_map_entries},
25 serial::{ReadFrom, WriteTo},
26};
27use text_components::EmbeddedNbtCodec;
28
29use super::component_data::{Component, ComponentData};
30use super::components::{
31 ItemAttributeModifiers, ItemEnchantments, ItemLore, Rarity, SwingAnimation, TooltipDisplay,
32 UseEffects,
33};
34use super::vanilla_components::{
35 ATTRIBUTE_MODIFIERS, BREAK_SOUND, ENCHANTMENTS, LORE, MAX_STACK_SIZE, RARITY, REPAIR_COST,
36 SWING_ANIMATION, TOOLTIP_DISPLAY, USE_EFFECTS,
37};
38use crate::{sound_event::SoundEventHolder, sound_events};
39
40mod codecs;
41mod component_map;
42mod patch;
43mod patch_network;
44mod patch_persistence;
45
46pub(crate) use codecs::ValidatePersistentComponent;
47pub use codecs::{
48 ComponentEntry, ComponentEntryRef, NbtReader, NbtWriter, NetworkReader, NetworkWriter,
49};
50pub use component_map::DataComponentMap;
51pub use patch::{ComponentPatchEntry, DataComponentPatch};
52pub use patch_persistence::component_try_into;
53
54use codecs::{
55 PersistentCodecFns, hash_component, read_typed_nbt, read_typed_network, validate_component,
56 write_typed_nbt, write_typed_network,
57};
58
59pub struct DataComponentType<T> {
84 pub(crate) key: Identifier,
85 ignore_swap_animation: bool,
86 _phantom: PhantomData<T>,
87}
88
89impl<T> Clone for DataComponentType<T> {
90 fn clone(&self) -> Self {
91 Self {
92 key: self.key.clone(),
93 ignore_swap_animation: self.ignore_swap_animation,
94 _phantom: PhantomData,
95 }
96 }
97}
98
99impl<T> DataComponentType<T> {
100 #[must_use]
101 pub(crate) const fn new(key: Identifier) -> Self {
102 Self {
103 key,
104 ignore_swap_animation: false,
105 _phantom: PhantomData,
106 }
107 }
108
109 #[must_use]
111 pub(crate) const fn new_ignoring_swap_animation(key: Identifier) -> Self {
112 Self {
113 key,
114 ignore_swap_animation: true,
115 _phantom: PhantomData,
116 }
117 }
118
119 #[must_use]
121 pub const fn ignore_swap_animation(&self) -> bool {
122 self.ignore_swap_animation
123 }
124
125 #[must_use]
127 pub const fn key(&self) -> &Identifier {
128 &self.key
129 }
130}
131
132pub struct DataComponentRegistry {
137 entries: Vec<ComponentEntryRef>,
139 by_key: FxHashMap<Identifier, usize>,
141 allows_registering: bool,
143}
144
145impl DataComponentRegistry {
146 #[must_use]
147 pub(crate) fn new() -> Self {
148 Self {
149 entries: Vec::new(),
150 by_key: FxHashMap::default(),
151 allows_registering: true,
152 }
153 }
154
155 pub(crate) fn register<T>(&mut self, component: DataComponentType<T>)
160 where
161 T: Component
162 + DowncastType
163 + Clone
164 + WriteTo
165 + ReadFrom
166 + ToNbtTag
167 + FromNbtTag
168 + HashComponent,
169 {
170 self.register_persistent(component);
171 }
172
173 pub(crate) fn register_transient<T>(&mut self, component: DataComponentType<T>)
177 where
178 T: Component + DowncastType + WriteTo + ReadFrom,
179 {
180 self.register_implemented(
181 component,
182 read_typed_network::<T>,
183 write_typed_network::<T>,
184 None,
185 );
186 }
187
188 fn register_persistent<T>(&mut self, component: DataComponentType<T>)
189 where
190 T: Component
191 + DowncastType
192 + Clone
193 + WriteTo
194 + ReadFrom
195 + ToNbtTag
196 + FromNbtTag
197 + HashComponent,
198 {
199 self.register_implemented(
200 component,
201 read_typed_network::<T>,
202 write_typed_network::<T>,
203 Some((
204 read_typed_nbt::<T>,
205 write_typed_nbt::<T>,
206 hash_component::<T>,
207 None,
208 )),
209 );
210 }
211
212 pub(crate) fn register_validated<T>(&mut self, component: DataComponentType<T>)
213 where
214 T: Component
215 + DowncastType
216 + Clone
217 + WriteTo
218 + ReadFrom
219 + ToNbtTag
220 + FromNbtTag
221 + HashComponent
222 + ValidatePersistentComponent,
223 {
224 self.register_implemented(
225 component,
226 read_typed_network::<T>,
227 write_typed_network::<T>,
228 Some((
229 read_typed_nbt::<T>,
230 write_typed_nbt::<T>,
231 hash_component::<T>,
232 Some(validate_component::<T>),
233 )),
234 );
235 }
236
237 pub(crate) fn register_custom_network<T>(
243 &mut self,
244 component: DataComponentType<T>,
245 network_reader: NetworkReader,
246 network_writer: NetworkWriter,
247 ) where
248 T: Component + DowncastType + Clone + ToNbtTag + FromNbtTag + HashComponent,
249 {
250 self.register_implemented(
251 component,
252 network_reader,
253 network_writer,
254 Some((
255 read_typed_nbt::<T>,
256 write_typed_nbt::<T>,
257 hash_component::<T>,
258 None,
259 )),
260 );
261 }
262
263 pub(crate) fn register_with_codecs<T: Component + DowncastType + HashComponent>(
265 &mut self,
266 component: DataComponentType<T>,
267 network_reader: NetworkReader,
268 network_writer: NetworkWriter,
269 nbt_reader: NbtReader,
270 nbt_writer: NbtWriter,
271 ) -> usize {
272 self.register_implemented(
273 component,
274 network_reader,
275 network_writer,
276 Some((nbt_reader, nbt_writer, hash_component::<T>, None)),
277 )
278 }
279
280 pub(crate) fn register_transient_with_codecs<T: Component + DowncastType>(
282 &mut self,
283 component: DataComponentType<T>,
284 network_reader: NetworkReader,
285 network_writer: NetworkWriter,
286 ) -> usize {
287 self.register_implemented(component, network_reader, network_writer, None)
288 }
289
290 fn register_implemented<T: Component + DowncastType>(
291 &mut self,
292 component: DataComponentType<T>,
293 network_reader: NetworkReader,
294 network_writer: NetworkWriter,
295 persistent_codecs: Option<PersistentCodecFns>,
296 ) -> usize {
297 assert!(
298 self.allows_registering,
299 "Cannot register data components after the registry has been frozen"
300 );
301
302 let ignore_swap_animation = component.ignore_swap_animation();
303 let key = component.key;
304 assert!(
305 !self.by_key.contains_key(&key),
306 "Cannot register duplicate data component key {key}"
307 );
308 let entry = Box::leak(Box::new(ComponentEntry::implemented(
309 key.clone(),
310 T::TYPE_KEY,
311 network_reader,
312 network_writer,
313 persistent_codecs,
314 ignore_swap_animation,
315 )));
316
317 let id = self.entries.len();
318 self.by_key.insert(key, id);
319 self.entries.push(entry);
320 id
321 }
322
323 #[must_use]
325 pub fn get_id<T>(&self, component: DataComponentType<T>) -> Option<usize> {
326 self.by_key.get(&component.key).copied()
327 }
328
329 #[must_use]
331 pub fn get_key_by_id(&self, id: usize) -> Option<&Identifier> {
332 self.entries.get(id).map(|e| &e.key)
333 }
334}
335
336crate::impl_registry!(
337 DataComponentRegistry,
338 ComponentEntry,
339 entries,
340 by_key,
341 data_components
342);
343
344#[cfg(test)]
345mod tests;