Skip to main content

steel_registry/data_components/vanilla_components/
mod.rs

1//! Vanilla data component definitions and registration.
2//!
3//! This module defines all vanilla Minecraft data components and provides
4//! the registration function to add them to the registry.
5use simdnbt::FromNbtTag as _;
6use steel_utils::{Identifier, nbt::NbtNumeric as _};
7use text_components::TextComponent;
8
9use super::component_data::ComponentData;
10use super::registry::DataComponentRegistry;
11pub use super::registry::DataComponentType;
12pub use crate::attribute::AttributeModifierOperation;
13pub use crate::equipment::{EquipmentSlot, EquipmentSlotGroup};
14
15// Re-export component types for convenience
16pub use super::components::{
17    ArmorTrim, AttackRange, BannerPatternLayer, BannerPatternLayers, BeehiveOccupant, Bees,
18    BlockEntityData, BlockItemStateProperties, BlocksAttacks, BrewingFuel, BundleContents,
19    ChargedProjectiles, Compostable, Consumable, CookingFuel, CustomData, CustomModelData,
20    DamageReduction, DamageResistant, DamageTypeComponent, DeathProtection, DebugStickProperty,
21    DebugStickState, DyedItemColor, Enchantable, EntityData, Equippable, EquippableAllowedEntities,
22    Filterable, FireworkExplosion, FireworkExplosionShape, Fireworks, FoodProperties, GlobalPos,
23    InstrumentComponent, InvalidEnchantableValue, ItemAttributeModifierDisplay,
24    ItemAttributeModifierEntry, ItemAttributeModifiers, ItemContainerContents, ItemDamageFunction,
25    ItemEnchantments, ItemLore, ItemLoreTooLong, ItemUseAnimation, JukeboxPlayable, KineticWeapon,
26    KineticWeaponCondition, LodestoneTracker, MapDecorationEntry, MapDecorations, MapId,
27    MapItemColor, MapPostProcessing, MobVisibility, OminousBottleAmplifier,
28    PaintingVariantComponent, PiercingWeapon, PotDecorations, PotionContents,
29    ProvidesBannerPatterns, ProvidesPotteryPattern, ProvidesTrimMaterial, Rarity, Recipes,
30    Repairable, SeededContainerLoot, SignText, SulfurCubeContent, SuspiciousStewEffect,
31    SuspiciousStewEffects, SwingAnimation, SwingAnimationType, Tool, ToolRule, ToolRuleBlocks,
32    TooltipDisplay, UseCooldown, UseEffects, UseRemainder, VillagerFood, Weapon,
33    WritableBookContent, WrittenBookContent,
34};
35pub use crate::ItemStackTemplate;
36pub use crate::block_transformer::BlockTransformerComponent;
37pub use crate::cat_sound_variant::CatSoundVariant;
38pub use crate::cat_variant::CatVariant;
39pub use crate::chicken_sound_variant::ChickenSoundVariant;
40pub use crate::chicken_variant::ChickenVariant;
41pub use crate::cow_sound_variant::CowSoundVariant;
42pub use crate::cow_variant::CowVariant;
43pub use crate::frog_variant::FrogVariant;
44pub use crate::game_profile::{GameProfile, ProfileProperty};
45pub use crate::item_predicate::{AdventureModePredicate, BlockPredicate, ItemPredicate, LockCode};
46pub use crate::pig_sound_variant::PigSoundVariant;
47pub use crate::pig_variant::PigVariant;
48pub use crate::resolvable_profile::{
49    PartialProfile, PlayerModelType, PlayerSkinPatch, ResolvableProfile, ResolvableProfileContents,
50};
51pub use crate::sound_event::SoundEventHolder;
52pub use crate::villager_type::VillagerType;
53pub use crate::wolf_sound_variant::WolfSoundVariant;
54pub use crate::wolf_variant::WolfVariant;
55pub use crate::zombie_nautilus_variant::ZombieNautilusVariant;
56pub use crate::{
57    AxolotlVariant, DyeColor, FoxVariant, HorseVariant, LlamaVariant, MooshroomVariant,
58    ParrotVariant, RabbitVariant, RegistryReference, SalmonVariant, TropicalFishPattern,
59};
60
61pub const MAX_STACK_SIZE: DataComponentType<i32> =
62    DataComponentType::new(Identifier::vanilla_static("max_stack_size"));
63
64pub const MAX_DAMAGE: DataComponentType<i32> =
65    DataComponentType::new(Identifier::vanilla_static("max_damage"));
66
67pub const CUSTOM_NAME: DataComponentType<TextComponent> =
68    DataComponentType::new(Identifier::vanilla_static("custom_name"));
69
70pub const ITEM_NAME: DataComponentType<TextComponent> =
71    DataComponentType::new(Identifier::vanilla_static("item_name"));
72
73pub const DAMAGE: DataComponentType<i32> =
74    DataComponentType::new_ignoring_swap_animation(Identifier::vanilla_static("damage"));
75
76pub const REPAIR_COST: DataComponentType<i32> =
77    DataComponentType::new(Identifier::vanilla_static("repair_cost"));
78
79pub const UNBREAKABLE: DataComponentType<()> =
80    DataComponentType::new(Identifier::vanilla_static("unbreakable"));
81
82pub const TOOL: DataComponentType<Tool> =
83    DataComponentType::new(Identifier::vanilla_static("tool"));
84
85pub const WEAPON: DataComponentType<Weapon> =
86    DataComponentType::new(Identifier::vanilla_static("weapon"));
87
88pub const ATTACK_RANGE: DataComponentType<AttackRange> =
89    DataComponentType::new(Identifier::vanilla_static("attack_range"));
90
91pub const EQUIPPABLE: DataComponentType<Equippable> =
92    DataComponentType::new(Identifier::vanilla_static("equippable"));
93
94pub const GLIDER: DataComponentType<()> =
95    DataComponentType::new(Identifier::vanilla_static("glider"));
96
97pub const CREATIVE_SLOT_LOCK: DataComponentType<()> =
98    DataComponentType::new(Identifier::vanilla_static("creative_slot_lock"));
99
100pub const INTANGIBLE_PROJECTILE: DataComponentType<()> =
101    DataComponentType::new(Identifier::vanilla_static("intangible_projectile"));
102
103pub const ENCHANTMENT_GLINT_OVERRIDE: DataComponentType<bool> =
104    DataComponentType::new(Identifier::vanilla_static("enchantment_glint_override"));
105
106pub const POTION_DURATION_SCALE: DataComponentType<f32> =
107    DataComponentType::new(Identifier::vanilla_static("potion_duration_scale"));
108
109pub const CUSTOM_DATA: DataComponentType<CustomData> =
110    DataComponentType::new(Identifier::vanilla_static("custom_data"));
111
112pub const USE_EFFECTS: DataComponentType<UseEffects> =
113    DataComponentType::new(Identifier::vanilla_static("use_effects"));
114
115pub const MINIMUM_ATTACK_CHARGE: DataComponentType<f32> =
116    DataComponentType::new(Identifier::vanilla_static("minimum_attack_charge"));
117
118pub const DAMAGE_TYPE: DataComponentType<DamageTypeComponent> =
119    DataComponentType::new(Identifier::vanilla_static("damage_type"));
120
121pub const ITEM_MODEL: DataComponentType<Identifier> =
122    DataComponentType::new(Identifier::vanilla_static("item_model"));
123
124pub const LORE: DataComponentType<ItemLore> =
125    DataComponentType::new(Identifier::vanilla_static("lore"));
126
127pub const RARITY: DataComponentType<Rarity> =
128    DataComponentType::new(Identifier::vanilla_static("rarity"));
129
130pub const ENCHANTMENTS: DataComponentType<ItemEnchantments> =
131    DataComponentType::new(Identifier::vanilla_static("enchantments"));
132
133pub const CAN_PLACE_ON: DataComponentType<AdventureModePredicate> =
134    DataComponentType::new(Identifier::vanilla_static("can_place_on"));
135
136pub const CAN_BREAK: DataComponentType<AdventureModePredicate> =
137    DataComponentType::new(Identifier::vanilla_static("can_break"));
138
139pub const ATTRIBUTE_MODIFIERS: DataComponentType<ItemAttributeModifiers> =
140    DataComponentType::new(Identifier::vanilla_static("attribute_modifiers"));
141
142pub const CUSTOM_MODEL_DATA: DataComponentType<CustomModelData> =
143    DataComponentType::new(Identifier::vanilla_static("custom_model_data"));
144
145pub const TOOLTIP_DISPLAY: DataComponentType<TooltipDisplay> =
146    DataComponentType::new(Identifier::vanilla_static("tooltip_display"));
147
148pub const TOOLTIP_STYLE: DataComponentType<Identifier> =
149    DataComponentType::new(Identifier::vanilla_static("tooltip_style"));
150
151pub const NOTE_BLOCK_SOUND: DataComponentType<Identifier> =
152    DataComponentType::new(Identifier::vanilla_static("note_block_sound"));
153
154pub const FOOD: DataComponentType<FoodProperties> =
155    DataComponentType::new(Identifier::vanilla_static("food"));
156
157pub const CONSUMABLE: DataComponentType<Consumable> =
158    DataComponentType::new(Identifier::vanilla_static("consumable"));
159
160pub const USE_REMAINDER: DataComponentType<UseRemainder> =
161    DataComponentType::new(Identifier::vanilla_static("use_remainder"));
162
163pub const USE_COOLDOWN: DataComponentType<UseCooldown> =
164    DataComponentType::new(Identifier::vanilla_static("use_cooldown"));
165
166pub const DAMAGE_RESISTANT: DataComponentType<DamageResistant> =
167    DataComponentType::new(Identifier::vanilla_static("damage_resistant"));
168
169pub const ENCHANTABLE: DataComponentType<Enchantable> =
170    DataComponentType::new(Identifier::vanilla_static("enchantable"));
171
172pub const REPAIRABLE: DataComponentType<Repairable> =
173    DataComponentType::new(Identifier::vanilla_static("repairable"));
174
175pub const DEATH_PROTECTION: DataComponentType<DeathProtection> =
176    DataComponentType::new(Identifier::vanilla_static("death_protection"));
177
178pub const BLOCKS_ATTACKS: DataComponentType<BlocksAttacks> =
179    DataComponentType::new(Identifier::vanilla_static("blocks_attacks"));
180
181pub const PIERCING_WEAPON: DataComponentType<PiercingWeapon> =
182    DataComponentType::new(Identifier::vanilla_static("piercing_weapon"));
183
184pub const KINETIC_WEAPON: DataComponentType<KineticWeapon> =
185    DataComponentType::new(Identifier::vanilla_static("kinetic_weapon"));
186
187pub const ATTACK_ANIMATION: DataComponentType<SwingAnimation> =
188    DataComponentType::new(Identifier::vanilla_static("attack_animation"));
189
190pub const INTERACT_ANIMATION: DataComponentType<SwingAnimation> =
191    DataComponentType::new(Identifier::vanilla_static("interact_animation"));
192
193pub const ADDITIONAL_TRADE_COST: DataComponentType<i32> =
194    DataComponentType::new(Identifier::vanilla_static("additional_trade_cost"));
195
196pub const BLOCK_TRANSFORMER: DataComponentType<BlockTransformerComponent> =
197    DataComponentType::new(Identifier::vanilla_static("block_transformer"));
198
199pub const VILLAGER_FOOD: DataComponentType<VillagerFood> =
200    DataComponentType::new(Identifier::vanilla_static("villager_food"));
201
202pub const COMPOSTABLE: DataComponentType<Compostable> =
203    DataComponentType::new(Identifier::vanilla_static("compostable"));
204
205pub const COOKING_FUEL: DataComponentType<CookingFuel> =
206    DataComponentType::new(Identifier::vanilla_static("cooking_fuel"));
207
208pub const BREWING_FUEL: DataComponentType<BrewingFuel> =
209    DataComponentType::new(Identifier::vanilla_static("brewing_fuel"));
210
211pub const MOB_VISIBILITY: DataComponentType<MobVisibility> =
212    DataComponentType::new(Identifier::vanilla_static("mob_visibility"));
213
214pub const STORED_ENCHANTMENTS: DataComponentType<ItemEnchantments> =
215    DataComponentType::new(Identifier::vanilla_static("stored_enchantments"));
216
217pub const DYE: DataComponentType<DyeColor> =
218    DataComponentType::new(Identifier::vanilla_static("dye"));
219
220pub const DYED_COLOR: DataComponentType<DyedItemColor> =
221    DataComponentType::new(Identifier::vanilla_static("dyed_color"));
222
223pub const MAP_ID: DataComponentType<MapId> =
224    DataComponentType::new(Identifier::vanilla_static("map_id"));
225
226pub const MAP_DECORATIONS: DataComponentType<MapDecorations> =
227    DataComponentType::new(Identifier::vanilla_static("map_decorations"));
228
229pub const MAP_POST_PROCESSING: DataComponentType<MapPostProcessing> =
230    DataComponentType::new(Identifier::vanilla_static("map_post_processing"));
231
232pub const CHARGED_PROJECTILES: DataComponentType<ChargedProjectiles> =
233    DataComponentType::new(Identifier::vanilla_static("charged_projectiles"));
234
235pub const BUNDLE_CONTENTS: DataComponentType<BundleContents> =
236    DataComponentType::new(Identifier::vanilla_static("bundle_contents"));
237
238pub const POTION_CONTENTS: DataComponentType<PotionContents> =
239    DataComponentType::new(Identifier::vanilla_static("potion_contents"));
240
241pub const SUSPICIOUS_STEW_EFFECTS: DataComponentType<SuspiciousStewEffects> =
242    DataComponentType::new(Identifier::vanilla_static("suspicious_stew_effects"));
243
244pub const WRITABLE_BOOK_CONTENT: DataComponentType<WritableBookContent> =
245    DataComponentType::new(Identifier::vanilla_static("writable_book_content"));
246
247pub const WRITTEN_BOOK_CONTENT: DataComponentType<WrittenBookContent> =
248    DataComponentType::new(Identifier::vanilla_static("written_book_content"));
249
250pub const TRIM: DataComponentType<ArmorTrim> =
251    DataComponentType::new(Identifier::vanilla_static("trim"));
252
253pub const DEBUG_STICK_STATE: DataComponentType<DebugStickState> =
254    DataComponentType::new(Identifier::vanilla_static("debug_stick_state"));
255
256pub const ENTITY_DATA: DataComponentType<EntityData> =
257    DataComponentType::new(Identifier::vanilla_static("entity_data"));
258
259pub const BUCKET_ENTITY_DATA: DataComponentType<CustomData> =
260    DataComponentType::new(Identifier::vanilla_static("bucket_entity_data"));
261
262pub const BLOCK_ENTITY_DATA: DataComponentType<BlockEntityData> =
263    DataComponentType::new(Identifier::vanilla_static("block_entity_data"));
264
265pub const INSTRUMENT: DataComponentType<InstrumentComponent> =
266    DataComponentType::new(Identifier::vanilla_static("instrument"));
267
268pub const PROVIDES_TRIM_MATERIAL: DataComponentType<ProvidesTrimMaterial> =
269    DataComponentType::new(Identifier::vanilla_static("provides_trim_material"));
270
271pub const PROVIDES_POTTERY_PATTERN: DataComponentType<ProvidesPotteryPattern> =
272    DataComponentType::new(Identifier::vanilla_static("provides_pottery_pattern"));
273
274pub const OMINOUS_BOTTLE_AMPLIFIER: DataComponentType<OminousBottleAmplifier> =
275    DataComponentType::new(Identifier::vanilla_static("ominous_bottle_amplifier"));
276
277pub const JUKEBOX_PLAYABLE: DataComponentType<JukeboxPlayable> =
278    DataComponentType::new(Identifier::vanilla_static("jukebox_playable"));
279
280pub const PROVIDES_BANNER_PATTERNS: DataComponentType<ProvidesBannerPatterns> =
281    DataComponentType::new(Identifier::vanilla_static("provides_banner_patterns"));
282
283pub const RECIPES: DataComponentType<Recipes> =
284    DataComponentType::new(Identifier::vanilla_static("recipes"));
285
286pub const LODESTONE_TRACKER: DataComponentType<LodestoneTracker> =
287    DataComponentType::new(Identifier::vanilla_static("lodestone_tracker"));
288
289pub const FIREWORK_EXPLOSION: DataComponentType<FireworkExplosion> =
290    DataComponentType::new(Identifier::vanilla_static("firework_explosion"));
291
292pub const FIREWORKS: DataComponentType<Fireworks> =
293    DataComponentType::new(Identifier::vanilla_static("fireworks"));
294
295pub const PROFILE: DataComponentType<ResolvableProfile> =
296    DataComponentType::new(Identifier::vanilla_static("profile"));
297
298pub const BANNER_PATTERNS: DataComponentType<BannerPatternLayers> =
299    DataComponentType::new(Identifier::vanilla_static("banner_patterns"));
300
301pub const BASE_COLOR: DataComponentType<DyeColor> =
302    DataComponentType::new(Identifier::vanilla_static("base_color"));
303
304pub const POT_DECORATIONS: DataComponentType<PotDecorations> =
305    DataComponentType::new(Identifier::vanilla_static("pot_decorations"));
306
307pub const CONTAINER: DataComponentType<ItemContainerContents> =
308    DataComponentType::new(Identifier::vanilla_static("container"));
309
310pub const BLOCK_STATE: DataComponentType<BlockItemStateProperties> =
311    DataComponentType::new(Identifier::vanilla_static("block_state"));
312
313pub const BEES: DataComponentType<Bees> =
314    DataComponentType::new(Identifier::vanilla_static("bees"));
315
316pub const SULFUR_CUBE_CONTENT: DataComponentType<SulfurCubeContent> =
317    DataComponentType::new(Identifier::vanilla_static("sulfur_cube_content"));
318
319pub const LOCK: DataComponentType<LockCode> =
320    DataComponentType::new(Identifier::vanilla_static("lock"));
321
322pub const CONTAINER_LOOT: DataComponentType<SeededContainerLoot> =
323    DataComponentType::new(Identifier::vanilla_static("container_loot"));
324
325pub const BREAK_SOUND: DataComponentType<SoundEventHolder> =
326    DataComponentType::new(Identifier::vanilla_static("break_sound"));
327
328// Entity variant components
329pub const VILLAGER_VARIANT: DataComponentType<RegistryReference<VillagerType>> =
330    DataComponentType::new(Identifier::vanilla_static("villager/variant"));
331
332pub const WOLF_VARIANT: DataComponentType<RegistryReference<WolfVariant>> =
333    DataComponentType::new(Identifier::vanilla_static("wolf/variant"));
334
335pub const WOLF_SOUND_VARIANT: DataComponentType<RegistryReference<WolfSoundVariant>> =
336    DataComponentType::new(Identifier::vanilla_static("wolf/sound_variant"));
337
338pub const WOLF_COLLAR: DataComponentType<DyeColor> =
339    DataComponentType::new(Identifier::vanilla_static("wolf/collar"));
340
341pub const FOX_VARIANT: DataComponentType<FoxVariant> =
342    DataComponentType::new(Identifier::vanilla_static("fox/variant"));
343
344pub const SALMON_SIZE: DataComponentType<SalmonVariant> =
345    DataComponentType::new(Identifier::vanilla_static("salmon/size"));
346
347pub const PARROT_VARIANT: DataComponentType<ParrotVariant> =
348    DataComponentType::new(Identifier::vanilla_static("parrot/variant"));
349
350pub const TROPICAL_FISH_PATTERN: DataComponentType<TropicalFishPattern> =
351    DataComponentType::new(Identifier::vanilla_static("tropical_fish/pattern"));
352
353pub const TROPICAL_FISH_BASE_COLOR: DataComponentType<DyeColor> =
354    DataComponentType::new(Identifier::vanilla_static("tropical_fish/base_color"));
355
356pub const TROPICAL_FISH_PATTERN_COLOR: DataComponentType<DyeColor> =
357    DataComponentType::new(Identifier::vanilla_static("tropical_fish/pattern_color"));
358
359pub const MOOSHROOM_VARIANT: DataComponentType<MooshroomVariant> =
360    DataComponentType::new(Identifier::vanilla_static("mooshroom/variant"));
361
362pub const RABBIT_VARIANT: DataComponentType<RabbitVariant> =
363    DataComponentType::new(Identifier::vanilla_static("rabbit/variant"));
364
365pub const PIG_VARIANT: DataComponentType<RegistryReference<PigVariant>> =
366    DataComponentType::new(Identifier::vanilla_static("pig/variant"));
367
368pub const PIG_SOUND_VARIANT: DataComponentType<RegistryReference<PigSoundVariant>> =
369    DataComponentType::new(Identifier::vanilla_static("pig/sound_variant"));
370
371pub const COW_VARIANT: DataComponentType<RegistryReference<CowVariant>> =
372    DataComponentType::new(Identifier::vanilla_static("cow/variant"));
373
374pub const COW_SOUND_VARIANT: DataComponentType<RegistryReference<CowSoundVariant>> =
375    DataComponentType::new(Identifier::vanilla_static("cow/sound_variant"));
376
377pub const CHICKEN_VARIANT: DataComponentType<RegistryReference<ChickenVariant>> =
378    DataComponentType::new(Identifier::vanilla_static("chicken/variant"));
379
380pub const CHICKEN_SOUND_VARIANT: DataComponentType<RegistryReference<ChickenSoundVariant>> =
381    DataComponentType::new(Identifier::vanilla_static("chicken/sound_variant"));
382
383pub const ZOMBIE_NAUTILUS_VARIANT: DataComponentType<RegistryReference<ZombieNautilusVariant>> =
384    DataComponentType::new(Identifier::vanilla_static("zombie_nautilus/variant"));
385
386pub const FROG_VARIANT: DataComponentType<RegistryReference<FrogVariant>> =
387    DataComponentType::new(Identifier::vanilla_static("frog/variant"));
388
389pub const HORSE_VARIANT: DataComponentType<HorseVariant> =
390    DataComponentType::new(Identifier::vanilla_static("horse/variant"));
391
392pub const PAINTING_VARIANT: DataComponentType<PaintingVariantComponent> =
393    DataComponentType::new(Identifier::vanilla_static("painting/variant"));
394
395pub const LLAMA_VARIANT: DataComponentType<LlamaVariant> =
396    DataComponentType::new(Identifier::vanilla_static("llama/variant"));
397
398pub const AXOLOTL_VARIANT: DataComponentType<AxolotlVariant> =
399    DataComponentType::new(Identifier::vanilla_static("axolotl/variant"));
400
401pub const CAT_VARIANT: DataComponentType<RegistryReference<CatVariant>> =
402    DataComponentType::new(Identifier::vanilla_static("cat/variant"));
403
404pub const CAT_SOUND_VARIANT: DataComponentType<RegistryReference<CatSoundVariant>> =
405    DataComponentType::new(Identifier::vanilla_static("cat/sound_variant"));
406
407pub const CAT_COLLAR: DataComponentType<DyeColor> =
408    DataComponentType::new(Identifier::vanilla_static("cat/collar"));
409
410pub const SHEEP_COLOR: DataComponentType<DyeColor> =
411    DataComponentType::new(Identifier::vanilla_static("sheep/color"));
412
413pub const SHULKER_COLOR: DataComponentType<DyeColor> =
414    DataComponentType::new(Identifier::vanilla_static("shulker/color"));
415
416pub const SIGN_TEXT_FRONT: DataComponentType<SignText> =
417    DataComponentType::new(Identifier::vanilla_static("sign_text_front"));
418
419pub const SIGN_TEXT_BACK: DataComponentType<SignText> =
420    DataComponentType::new(Identifier::vanilla_static("sign_text_back"));
421
422pub const WAXED: DataComponentType<()> =
423    DataComponentType::new(Identifier::vanilla_static("waxed"));
424
425pub const CUSHION_COLOR: DataComponentType<DyeColor> =
426    DataComponentType::new(Identifier::vanilla_static("cushion/color"));
427
428/// Network reader for VarInt-encoded i32 components.
429fn varint_reader(cursor: &mut std::io::Cursor<&[u8]>) -> std::io::Result<ComponentData> {
430    use steel_utils::{codec::VarInt, serial::ReadFrom};
431    let value = VarInt::read(cursor)?;
432    Ok(ComponentData::new(value.0))
433}
434
435/// Network writer for VarInt-encoded i32 components.
436fn varint_writer(data: &ComponentData, writer: &mut Vec<u8>) -> std::io::Result<()> {
437    use steel_utils::{codec::VarInt, serial::WriteTo};
438    if let Some(v) = data.downcast_ref::<i32>() {
439        VarInt(*v).write(writer)
440    } else {
441        Err(std::io::Error::other("Component type mismatch"))
442    }
443}
444
445fn float_reader(cursor: &mut std::io::Cursor<&[u8]>) -> std::io::Result<ComponentData> {
446    use steel_utils::serial::ReadFrom;
447    Ok(ComponentData::new(f32::read(cursor)?))
448}
449
450fn float_writer(data: &ComponentData, writer: &mut Vec<u8>) -> std::io::Result<()> {
451    use steel_utils::serial::WriteTo;
452    let Some(value) = data.downcast_ref::<f32>() else {
453        return Err(std::io::Error::other("Component type mismatch"));
454    };
455    value.write(writer)
456}
457
458fn bool_reader(cursor: &mut std::io::Cursor<&[u8]>) -> std::io::Result<ComponentData> {
459    use steel_utils::serial::ReadFrom;
460    Ok(ComponentData::new(bool::read(cursor)?))
461}
462
463fn bool_writer(data: &ComponentData, writer: &mut Vec<u8>) -> std::io::Result<()> {
464    use steel_utils::serial::WriteTo;
465    let Some(value) = data.downcast_ref::<bool>() else {
466        return Err(std::io::Error::other("Component type mismatch"));
467    };
468    value.write(writer)
469}
470
471fn text_component_network_reader(
472    cursor: &mut std::io::Cursor<&[u8]>,
473) -> std::io::Result<ComponentData> {
474    use steel_utils::serial::ReadFrom as _;
475    TextComponent::read(cursor).map(ComponentData::new)
476}
477
478fn text_component_network_writer(
479    data: &ComponentData,
480    writer: &mut Vec<u8>,
481) -> std::io::Result<()> {
482    use steel_utils::serial::WriteTo as _;
483    let Some(value) = data.downcast_ref::<TextComponent>() else {
484        return Err(std::io::Error::other("Component type mismatch"));
485    };
486    value.write(writer)
487}
488
489fn text_component_nbt_reader(tag: simdnbt::borrow::NbtTag) -> Option<ComponentData> {
490    use simdnbt::FromNbtTag as _;
491    TextComponent::from_nbt_tag(tag).map(ComponentData::new)
492}
493
494fn text_component_nbt_writer(data: &ComponentData) -> std::io::Result<simdnbt::owned::NbtTag> {
495    let Some(value) = data.downcast_ref::<TextComponent>() else {
496        return Err(std::io::Error::other("Component type mismatch"));
497    };
498    Ok(value.to_codec_nbt())
499}
500
501fn custom_data_codec_reader(cursor: &mut std::io::Cursor<&[u8]>) -> std::io::Result<ComponentData> {
502    CustomData::read_codec_network(cursor).map(ComponentData::new)
503}
504
505fn custom_data_writer(data: &ComponentData, writer: &mut Vec<u8>) -> std::io::Result<()> {
506    use steel_utils::serial::WriteTo as _;
507    let Some(value) = data.downcast_ref::<CustomData>() else {
508        return Err(std::io::Error::other("Component type mismatch"));
509    };
510    value.write(writer)
511}
512
513#[expect(
514    clippy::unnecessary_wraps,
515    reason = "network reader function pointers return io::Result"
516)]
517fn unit_reader(_cursor: &mut std::io::Cursor<&[u8]>) -> std::io::Result<ComponentData> {
518    Ok(ComponentData::new(()))
519}
520
521fn unit_writer(data: &ComponentData, _writer: &mut Vec<u8>) -> std::io::Result<()> {
522    if data.downcast_ref::<()>().is_some() {
523        Ok(())
524    } else {
525        Err(std::io::Error::other("Component type mismatch"))
526    }
527}
528
529fn codec_unit_network_reader(
530    cursor: &mut std::io::Cursor<&[u8]>,
531) -> std::io::Result<ComponentData> {
532    let tag = simdnbt::owned::read_tag(cursor)
533        .map_err(|error| std::io::Error::other(format!("Invalid NBT: {error:?}")))?;
534    tag.compound()
535        .map(|_| ComponentData::new(()))
536        .ok_or_else(|| std::io::Error::other("Unit codec network value is not a compound"))
537}
538
539fn codec_unit_network_writer(data: &ComponentData, writer: &mut Vec<u8>) -> std::io::Result<()> {
540    unit_nbt_writer(data)?.write(writer);
541    Ok(())
542}
543
544fn ranged_i32_nbt_reader<const MIN: i32, const MAX: i32>(
545    tag: simdnbt::borrow::NbtTag,
546) -> Option<ComponentData> {
547    let value = tag.codec_i32()?;
548    (MIN..=MAX)
549        .contains(&value)
550        .then(|| ComponentData::new(value))
551}
552
553fn ranged_i32_nbt_writer<const MIN: i32, const MAX: i32>(
554    data: &ComponentData,
555) -> std::io::Result<simdnbt::owned::NbtTag> {
556    let Some(value) = data.downcast_ref::<i32>() else {
557        return Err(std::io::Error::other("Component type mismatch"));
558    };
559    if !(MIN..=MAX).contains(value) {
560        return Err(std::io::Error::other(format!(
561            "Value {value} outside of range [{MIN}:{MAX}]"
562        )));
563    }
564    Ok(simdnbt::owned::NbtTag::Int(*value))
565}
566
567fn minimum_attack_charge_nbt_reader(tag: simdnbt::borrow::NbtTag) -> Option<ComponentData> {
568    let value = tag.codec_f32()?;
569    (value.is_finite() && !value.is_sign_negative() && value <= 1.0)
570        .then(|| ComponentData::new(value))
571}
572
573fn potion_duration_scale_nbt_reader(tag: simdnbt::borrow::NbtTag) -> Option<ComponentData> {
574    let value = tag.codec_f32()?;
575    (value.is_finite() && !value.is_sign_negative()).then(|| ComponentData::new(value))
576}
577
578fn minimum_attack_charge_nbt_writer(
579    data: &ComponentData,
580) -> std::io::Result<simdnbt::owned::NbtTag> {
581    let Some(value) = data.downcast_ref::<f32>() else {
582        return Err(std::io::Error::other("Component type mismatch"));
583    };
584    if !value.is_finite() || value.is_sign_negative() || *value > 1.0 {
585        return Err(std::io::Error::other(format!(
586            "Value {value} outside of range [0:1]"
587        )));
588    }
589    Ok(simdnbt::owned::NbtTag::Float(*value))
590}
591
592fn potion_duration_scale_nbt_writer(
593    data: &ComponentData,
594) -> std::io::Result<simdnbt::owned::NbtTag> {
595    let Some(value) = data.downcast_ref::<f32>() else {
596        return Err(std::io::Error::other("Component type mismatch"));
597    };
598    if !value.is_finite() || value.is_sign_negative() {
599        return Err(std::io::Error::other(format!(
600            "Value {value} must be non-negative and finite"
601        )));
602    }
603    Ok(simdnbt::owned::NbtTag::Float(*value))
604}
605
606fn bool_nbt_reader(tag: simdnbt::borrow::NbtTag) -> Option<ComponentData> {
607    tag.codec_bool().map(ComponentData::new)
608}
609
610fn bool_nbt_writer(data: &ComponentData) -> std::io::Result<simdnbt::owned::NbtTag> {
611    let Some(value) = data.downcast_ref::<bool>() else {
612        return Err(std::io::Error::other("Component type mismatch"));
613    };
614    Ok(simdnbt::owned::NbtTag::Byte(i8::from(*value)))
615}
616
617fn unit_nbt_reader(tag: simdnbt::borrow::NbtTag) -> Option<ComponentData> {
618    tag.compound().map(|_| ComponentData::new(()))
619}
620
621fn unit_nbt_writer(data: &ComponentData) -> std::io::Result<simdnbt::owned::NbtTag> {
622    if data.downcast_ref::<()>().is_none() {
623        return Err(std::io::Error::other("Component type mismatch"));
624    }
625    Ok(simdnbt::owned::NbtTag::Compound(
626        simdnbt::owned::NbtCompound::new(),
627    ))
628}
629
630fn jukebox_playable_network_reader(
631    cursor: &mut std::io::Cursor<&[u8]>,
632) -> std::io::Result<ComponentData> {
633    use steel_utils::serial::ReadFrom;
634    JukeboxPlayable::read(cursor).map(ComponentData::new)
635}
636
637fn jukebox_playable_network_writer(
638    data: &ComponentData,
639    writer: &mut Vec<u8>,
640) -> std::io::Result<()> {
641    use steel_utils::serial::WriteTo;
642    let Some(value) = data.downcast_ref::<JukeboxPlayable>() else {
643        return Err(std::io::Error::other("Component type mismatch"));
644    };
645    value.write(writer)
646}
647
648fn jukebox_playable_nbt_reader(tag: simdnbt::borrow::NbtTag) -> Option<ComponentData> {
649    JukeboxPlayable::from_persistent_nbt(tag).map(ComponentData::new)
650}
651
652fn jukebox_playable_nbt_writer(data: &ComponentData) -> std::io::Result<simdnbt::owned::NbtTag> {
653    let Some(value) = data.downcast_ref::<JukeboxPlayable>() else {
654        return Err(std::io::Error::other("Component type mismatch"));
655    };
656    value.to_persistent_nbt()
657}
658
659fn fireworks_nbt_reader(tag: simdnbt::borrow::NbtTag) -> Option<ComponentData> {
660    Fireworks::from_nbt_tag(tag).map(ComponentData::new)
661}
662
663fn fireworks_network_reader(cursor: &mut std::io::Cursor<&[u8]>) -> std::io::Result<ComponentData> {
664    use steel_utils::serial::ReadFrom as _;
665    Fireworks::read(cursor).map(ComponentData::new)
666}
667
668fn fireworks_network_writer(data: &ComponentData, writer: &mut Vec<u8>) -> std::io::Result<()> {
669    use steel_utils::serial::WriteTo as _;
670    let Some(value) = data.downcast_ref::<Fireworks>() else {
671        return Err(std::io::Error::other("Component type mismatch"));
672    };
673    value.write(writer)
674}
675
676fn fireworks_nbt_writer(data: &ComponentData) -> std::io::Result<simdnbt::owned::NbtTag> {
677    let Some(value) = data.downcast_ref::<Fireworks>() else {
678        return Err(std::io::Error::other("Component type mismatch"));
679    };
680    value.try_to_persistent_nbt()
681}
682
683fn painting_variant_network_reader(
684    cursor: &mut std::io::Cursor<&[u8]>,
685) -> std::io::Result<ComponentData> {
686    use steel_utils::serial::ReadFrom as _;
687    PaintingVariantComponent::read(cursor).map(ComponentData::new)
688}
689
690fn painting_variant_network_writer(
691    data: &ComponentData,
692    writer: &mut Vec<u8>,
693) -> std::io::Result<()> {
694    use steel_utils::serial::WriteTo as _;
695    let Some(value) = data.downcast_ref::<PaintingVariantComponent>() else {
696        return Err(std::io::Error::other("Component type mismatch"));
697    };
698    value.write(writer)
699}
700
701fn painting_variant_nbt_reader(tag: simdnbt::borrow::NbtTag) -> Option<ComponentData> {
702    PaintingVariantComponent::from_nbt_tag(tag).map(ComponentData::new)
703}
704
705fn painting_variant_nbt_writer(data: &ComponentData) -> std::io::Result<simdnbt::owned::NbtTag> {
706    let Some(value) = data.downcast_ref::<PaintingVariantComponent>() else {
707        return Err(std::io::Error::other("Component type mismatch"));
708    };
709    value.try_to_persistent_nbt()
710}
711
712macro_rules! register_ranged_i32 {
713    ($registry:expr, $component:expr, $min:expr, $max:expr) => {
714        $registry.register_with_codecs(
715            $component,
716            varint_reader,
717            varint_writer,
718            ranged_i32_nbt_reader::<{ $min }, { $max }>,
719            ranged_i32_nbt_writer::<{ $min }, { $max }>,
720        );
721    };
722}
723
724macro_rules! register_stream_unit {
725    ($registry:expr, $component:expr) => {
726        $registry.register_with_codecs(
727            $component,
728            unit_reader,
729            unit_writer,
730            unit_nbt_reader,
731            unit_nbt_writer,
732        );
733    };
734}
735
736/// Registers all vanilla data components.
737///
738/// IMPORTANT: The registration order MUST match vanilla's DataComponents.java exactly,
739/// as the component's network ID is determined by its registration order.
740pub fn register_vanilla_data_components(registry: &mut DataComponentRegistry) {
741    // Order must match vanilla's DataComponents.java exactly!
742    // 0: custom_data
743    registry.register_custom_network(CUSTOM_DATA, custom_data_codec_reader, custom_data_writer);
744    // 1: max_stack_size
745    register_ranged_i32!(registry, MAX_STACK_SIZE, 1, 99);
746    // 2: max_damage
747    register_ranged_i32!(registry, MAX_DAMAGE, 1, i32::MAX);
748    // 3: damage
749    register_ranged_i32!(registry, DAMAGE, 0, i32::MAX);
750    // 4: unbreakable
751    register_stream_unit!(registry, UNBREAKABLE);
752    // 5: use_effects
753    registry.register(USE_EFFECTS);
754    // 6: custom_name
755    registry.register_with_codecs(
756        CUSTOM_NAME,
757        text_component_network_reader,
758        text_component_network_writer,
759        text_component_nbt_reader,
760        text_component_nbt_writer,
761    );
762    // 7: minimum_attack_charge
763    registry.register_with_codecs(
764        MINIMUM_ATTACK_CHARGE,
765        float_reader,
766        float_writer,
767        minimum_attack_charge_nbt_reader,
768        minimum_attack_charge_nbt_writer,
769    );
770    // 8: damage_type
771    registry.register(DAMAGE_TYPE);
772    // 9: item_name
773    registry.register_with_codecs(
774        ITEM_NAME,
775        text_component_network_reader,
776        text_component_network_writer,
777        text_component_nbt_reader,
778        text_component_nbt_writer,
779    );
780    // 10: item_model
781    registry.register(ITEM_MODEL);
782    // 11: lore
783    registry.register(LORE);
784    // 12: rarity
785    registry.register(RARITY);
786    // 13: enchantments
787    registry.register(ENCHANTMENTS);
788    // 14: can_place_on
789    registry.register(CAN_PLACE_ON);
790    // 15: can_break
791    registry.register(CAN_BREAK);
792    // 16: attribute_modifiers
793    registry.register(ATTRIBUTE_MODIFIERS);
794    // 17: custom_model_data
795    registry.register(CUSTOM_MODEL_DATA);
796    // 18: tooltip_display
797    registry.register(TOOLTIP_DISPLAY);
798    // 19: repair_cost
799    register_ranged_i32!(registry, REPAIR_COST, 0, i32::MAX);
800    // 20: creative_slot_lock
801    registry.register_transient(CREATIVE_SLOT_LOCK);
802    // 21: enchantment_glint_override
803    registry.register_with_codecs(
804        ENCHANTMENT_GLINT_OVERRIDE,
805        bool_reader,
806        bool_writer,
807        bool_nbt_reader,
808        bool_nbt_writer,
809    );
810    // 22: intangible_projectile
811    registry.register_with_codecs(
812        INTANGIBLE_PROJECTILE,
813        codec_unit_network_reader,
814        codec_unit_network_writer,
815        unit_nbt_reader,
816        unit_nbt_writer,
817    );
818    // 23: food
819    registry.register(FOOD);
820    // 24: consumable
821    registry.register(CONSUMABLE);
822    // 25: use_remainder
823    registry.register_validated(USE_REMAINDER);
824    // 26: use_cooldown
825    registry.register(USE_COOLDOWN);
826    // 27: damage_resistant
827    registry.register(DAMAGE_RESISTANT);
828    // 28: tool
829    registry.register(TOOL);
830    // 29: weapon
831    registry.register(WEAPON);
832    // 30: attack_range
833    registry.register(ATTACK_RANGE);
834    // 31: enchantable
835    registry.register(ENCHANTABLE);
836    // 32: equippable
837    registry.register(EQUIPPABLE);
838    // 33: repairable
839    registry.register(REPAIRABLE);
840    // 34: glider
841    register_stream_unit!(registry, GLIDER);
842    // 35: tooltip_style
843    registry.register(TOOLTIP_STYLE);
844    // 36: death_protection
845    registry.register(DEATH_PROTECTION);
846    // 37: blocks_attacks
847    registry.register(BLOCKS_ATTACKS);
848    // 38: piercing_weapon
849    registry.register(PIERCING_WEAPON);
850    // 39: kinetic_weapon
851    registry.register(KINETIC_WEAPON);
852    // 40: attack_animation
853    registry.register(ATTACK_ANIMATION);
854    // 41: interact_animation
855    registry.register(INTERACT_ANIMATION);
856    // 42: additional_trade_cost
857    registry.register_transient_with_codecs(ADDITIONAL_TRADE_COST, varint_reader, varint_writer);
858    // 43: block_transformer
859    registry.register(BLOCK_TRANSFORMER);
860    // 44: villager_food
861    registry.register(VILLAGER_FOOD);
862    // 45: stored_enchantments
863    registry.register(STORED_ENCHANTMENTS);
864    // 46: dye
865    registry.register(DYE);
866    // 47: dyed_color
867    registry.register(DYED_COLOR);
868    // 48: map_id
869    registry.register(MAP_ID);
870    // 49: map_decorations
871    registry.register(MAP_DECORATIONS);
872    // 50: map_post_processing
873    registry.register_transient(MAP_POST_PROCESSING);
874    // 51: charged_projectiles
875    registry.register_validated(CHARGED_PROJECTILES);
876    // 52: bundle_contents
877    registry.register_validated(BUNDLE_CONTENTS);
878    // 53: potion_contents
879    registry.register(POTION_CONTENTS);
880    // 54: potion_duration_scale
881    registry.register_with_codecs(
882        POTION_DURATION_SCALE,
883        float_reader,
884        float_writer,
885        potion_duration_scale_nbt_reader,
886        potion_duration_scale_nbt_writer,
887    );
888    // 55: suspicious_stew_effects
889    registry.register(SUSPICIOUS_STEW_EFFECTS);
890    // 56: writable_book_content
891    registry.register(WRITABLE_BOOK_CONTENT);
892    // 57: written_book_content
893    registry.register(WRITTEN_BOOK_CONTENT);
894    // 58: trim
895    registry.register(TRIM);
896    // 59: debug_stick_state
897    registry.register(DEBUG_STICK_STATE);
898    // 60: entity_data
899    registry.register(ENTITY_DATA);
900    // 61: bucket_entity_data
901    registry.register(BUCKET_ENTITY_DATA);
902    // 62: block_entity_data
903    registry.register(BLOCK_ENTITY_DATA);
904    // 63: instrument
905    registry.register(INSTRUMENT);
906    // 64: provides_trim_material
907    registry.register(PROVIDES_TRIM_MATERIAL);
908    // 65: ominous_bottle_amplifier
909    registry.register(OMINOUS_BOTTLE_AMPLIFIER);
910    // 66: jukebox_playable
911    registry.register_with_codecs(
912        JUKEBOX_PLAYABLE,
913        jukebox_playable_network_reader,
914        jukebox_playable_network_writer,
915        jukebox_playable_nbt_reader,
916        jukebox_playable_nbt_writer,
917    );
918    // 67: provides_banner_patterns
919    registry.register(PROVIDES_BANNER_PATTERNS);
920    // 68: recipes
921    registry.register(RECIPES);
922    // 69: lodestone_tracker
923    registry.register(LODESTONE_TRACKER);
924    // 70: firework_explosion
925    registry.register(FIREWORK_EXPLOSION);
926    // 71: fireworks
927    registry.register_with_codecs(
928        FIREWORKS,
929        fireworks_network_reader,
930        fireworks_network_writer,
931        fireworks_nbt_reader,
932        fireworks_nbt_writer,
933    );
934    // 72: profile
935    registry.register(PROFILE);
936    // 73: note_block_sound
937    registry.register(NOTE_BLOCK_SOUND);
938    // 74: banner_patterns
939    registry.register(BANNER_PATTERNS);
940    // 75: base_color
941    registry.register(BASE_COLOR);
942    // 76: pot_decorations
943    registry.register(POT_DECORATIONS);
944    // 77: container
945    registry.register_validated(CONTAINER);
946    // 78: block_state
947    registry.register(BLOCK_STATE);
948    // 79: bees
949    registry.register(BEES);
950    // 80: sulfur_cube_content
951    registry.register_validated(SULFUR_CUBE_CONTENT);
952    // 81: lock
953    registry.register(LOCK);
954    // 82: container_loot
955    registry.register(CONTAINER_LOOT);
956    // 83: break_sound
957    registry.register(BREAK_SOUND);
958    // 84: compostable
959    registry.register(COMPOSTABLE);
960    // 85: cooking_fuel
961    registry.register(COOKING_FUEL);
962    // 86: brewing_fuel
963    registry.register(BREWING_FUEL);
964    // 87: mob_visibility
965    registry.register(MOB_VISIBILITY);
966    // 88: villager/variant
967    registry.register(VILLAGER_VARIANT);
968    // 89: wolf/variant
969    registry.register(WOLF_VARIANT);
970    // 90: wolf/sound_variant
971    registry.register(WOLF_SOUND_VARIANT);
972    // 91: wolf/collar
973    registry.register(WOLF_COLLAR);
974    // 92: fox/variant
975    registry.register(FOX_VARIANT);
976    // 93: salmon/size
977    registry.register(SALMON_SIZE);
978    // 94: parrot/variant
979    registry.register(PARROT_VARIANT);
980    // 95: tropical_fish/pattern
981    registry.register(TROPICAL_FISH_PATTERN);
982    // 96: tropical_fish/base_color
983    registry.register(TROPICAL_FISH_BASE_COLOR);
984    // 97: tropical_fish/pattern_color
985    registry.register(TROPICAL_FISH_PATTERN_COLOR);
986    // 98: mooshroom/variant
987    registry.register(MOOSHROOM_VARIANT);
988    // 99: rabbit/variant
989    registry.register(RABBIT_VARIANT);
990    // 100: pig/variant
991    registry.register(PIG_VARIANT);
992    // 101: pig/sound_variant
993    registry.register(PIG_SOUND_VARIANT);
994    // 102: cow/variant
995    registry.register(COW_VARIANT);
996    // 103: cow/sound_variant
997    registry.register(COW_SOUND_VARIANT);
998    // 104: chicken/variant
999    registry.register(CHICKEN_VARIANT);
1000    // 105: chicken/sound_variant
1001    registry.register(CHICKEN_SOUND_VARIANT);
1002    // 106: zombie_nautilus/variant
1003    registry.register(ZOMBIE_NAUTILUS_VARIANT);
1004    // 107: frog/variant
1005    registry.register(FROG_VARIANT);
1006    // 108: horse/variant
1007    registry.register(HORSE_VARIANT);
1008    // 109: painting/variant
1009    registry.register_with_codecs(
1010        PAINTING_VARIANT,
1011        painting_variant_network_reader,
1012        painting_variant_network_writer,
1013        painting_variant_nbt_reader,
1014        painting_variant_nbt_writer,
1015    );
1016    // 110: llama/variant
1017    registry.register(LLAMA_VARIANT);
1018    // 111: axolotl/variant
1019    registry.register(AXOLOTL_VARIANT);
1020    // 112: cat/variant
1021    registry.register(CAT_VARIANT);
1022    // 113: cat/sound_variant
1023    registry.register(CAT_SOUND_VARIANT);
1024    // 114: cat/collar
1025    registry.register(CAT_COLLAR);
1026    // 115: sheep/color
1027    registry.register(SHEEP_COLOR);
1028    // 116: shulker/color
1029    registry.register(SHULKER_COLOR);
1030    // 117: provides_pottery_pattern
1031    registry.register(PROVIDES_POTTERY_PATTERN);
1032    // 118: sign_text_front
1033    registry.register(SIGN_TEXT_FRONT);
1034    // 119: sign_text_back
1035    registry.register(SIGN_TEXT_BACK);
1036    // 120: waxed
1037    register_stream_unit!(registry, WAXED);
1038    // 121: cushion/color
1039    registry.register(CUSHION_COLOR);
1040}
1041
1042#[cfg(test)]
1043mod tests;