chunkedge_item/
components.rs

1use std::io::Write;
2
3use chunkedge_binary::{Decode, Encode, IDSet, IdOr, TextComponent, VarInt};
4use chunkedge_generated::attributes::EntityAttributeOperation;
5use chunkedge_generated::registry_id::RegistryId;
6use chunkedge_ident::Ident;
7use chunkedge_nbt::Compound;
8use chunkedge_text::Text;
9use uuid::Uuid;
10
11use crate::stack::ItemStack;
12
13#[derive(Clone, PartialEq, Debug, Copy)]
14pub(crate) enum Patchable<T> {
15    #[allow(dead_code)]
16    Default(T),
17    /// `T`, `crc32c hash`
18    Added((T, i32)),
19    Removed,
20    None,
21}
22impl<T> Patchable<T> {
23    #[allow(clippy::wrong_self_convention)]
24    pub(crate) fn to_option(self) -> Option<T> {
25        match self {
26            Patchable::Default(t) => Some(t),
27            Patchable::Added((t, _)) => Some(t),
28            _ => None,
29        }
30    }
31
32    pub(crate) fn as_option(&self) -> Option<&T> {
33        match self {
34            Patchable::Default(t) => Some(t),
35            Patchable::Added((t, _)) => Some(t),
36            _ => None,
37        }
38    }
39}
40
41#[derive(Clone, PartialEq, Debug)]
42pub enum ItemComponent {
43    /// Arbitrary NBT data that does not fit into other structured components.
44    /// Used primarily by data-driven systems and server-side plugins to store
45    /// state.
46    CustomData(Compound),
47
48    /// Overrides the default maximum stack size of the item.
49    /// Allowed values are between 1 and 99.
50    MaxStackSize(VarInt),
51
52    /// The total durability of the item. This is the maximum value the 'Damage'
53    /// component can reach before the item breaks.
54    MaxDamage(VarInt),
55
56    /// The current wear/tear of the item. 0 represents a new item,
57    /// and higher values indicate more damage.
58    Damage(VarInt),
59
60    /// If present, the item will not take durability damage when used.
61    /// Mechanical equivalent to the old 'Unbreakable: 1b' NBT tag.
62    Unbreakable,
63
64    /// A custom name for the item, typically set via an anvil.
65    /// Usually rendered in italics by the client.
66    CustomName(TextComponent),
67
68    /// Overrides the base name of the item (e.g., "Stone").
69    /// Unlike `CustomName`, this is not italicized by default.
70    ItemName(TextComponent),
71
72    /// References a specific model file in a resource pack.
73    /// Allows a single Item ID to have multiple distinct visual appearances.
74    ItemModel(String),
75
76    /// Additional lines of text displayed below the item's name in the tooltip.
77    Lore(Vec<TextComponent>),
78
79    /// Determines the color of the item's name (Common/Uncommon/Rare/Epic).
80    /// Also affects the default glint behavior in some contexts.
81    Rarity(Rarity),
82
83    /// A list of enchantments applied to the item and their corresponding
84    /// levels.
85    Enchantments(Vec<(RegistryId, VarInt)>),
86
87    /// In Adventure mode, this restricts which blocks a player can place
88    /// this specific block on.
89    CanPlaceOn(Vec<BlockPredicate>),
90
91    /// In Adventure mode, this restricts which blocks the player can break
92    /// while holding this item.
93    CanBreak(Vec<BlockPredicate>),
94
95    /// Modifies the player's base attributes (like Attack Damage, Movement
96    /// Speed, or Max Health) when this item is held or equipped.
97    AttributeModifiers { modifiers: Vec<AttributeModifier> },
98
99    /// Advanced visual overrides for resource packs.
100    CustomModelData {
101        /// Generic floating point values used by shaders or model predicates.
102        floats: Vec<f32>,
103        /// Boolean flags for toggling model parts.
104        flags: Vec<bool>,
105        /// String identifiers for selecting textures or sub-models.
106        strings: Vec<String>,
107        /// RGB integer colors for tinting specific model layers.
108        colors: Vec<i32>,
109    },
110
111    /// Controls the visibility of the item's details.
112    TooltipDisplay {
113        /// If true, the entire tooltip (including name) is hidden.
114        hide_tooltip: bool,
115        /// A list of Component IDs that should not show their info in the
116        /// tooltip.
117        hidden_components: Vec<VarInt>,
118    },
119
120    /// The cumulative cost (in levels) added to anvil operations involving this
121    /// item. Increases every time the item is repaired or modified.
122    RepairCost(VarInt),
123
124    /// Internal flag used for creative mode. If present, the item cannot be
125    /// picked up or moved within specific creative tabs.
126    CreativeSlotLock,
127
128    /// Forces the "enchantment purple glow" to be either always on or always
129    /// off, regardless of whether the item is actually enchanted.
130    EnchantmentGlintOverride(bool),
131
132    /// Used for projectiles (like arrows or tridents) to mark them as "ghost"
133    /// items that cannot be picked back up by the player.
134    IntangibleProjectile(Compound),
135
136    /// Defines the nutritional value of the item when eaten.
137    Food {
138        /// How many hunger points (half-shanks) are restored.
139        nutrition: VarInt,
140        /// The multiplier applied to the nutrition to determine saturation.
141        saturation_modifier: f32,
142        /// If true, the player can eat this even if their hunger bar is full.
143        can_always_eat: bool,
144    },
145
146    /// Defines how the item is used/consumed (e.g., eating, drinking, or using
147    /// a bow).
148    Consumable {
149        /// The time in seconds required to finish using the item.
150        consume_seconds: f32,
151        /// The visual pose the player takes (Eat, Drink, Block, etc.).
152        animation: ConsumableAnimation,
153        /// The sound played during and after consumption.
154        sound: IdOr<SoundEventDefinition>,
155        /// Whether to spawn particle effects (like food crumbs) while using.
156        has_consume_particles: bool,
157        /// Status effects (like Poison or Speed) applied when consumption
158        /// finishes.
159        effects: Vec<ConsumeEffect>,
160    },
161
162    /// Defines an item that is returned to the inventory after this one is
163    /// used. Example: Eating Mushroom Stew returns an empty Bowl.
164    UseRemainder(Box<ItemStack>),
165
166    /// Prevents the item from being used again for a set duration.
167    UseCooldown {
168        /// Duration of the cooldown in seconds.
169        seconds: f32,
170        /// Optional group ID. All items with the same group will share the
171        /// cooldown.
172        cooldown_group: Option<String>,
173    },
174
175    /// Prevents the item from being destroyed by certain damage types (e.g.,
176    /// fire-resistant Netherite).
177    DamageResistant(String),
178
179    /// Configures how this item mines blocks.
180    Tool {
181        /// Specific rules for block sets (e.g., "Pickaxes mine stones fast").
182        rules: Vec<ToolRule>,
183        /// The mining speed used if no specific rule matches.
184        default_mining_speed: f32,
185        /// Durability lost per block broken.
186        damage_per_block: VarInt,
187        /// If false, this tool cannot break blocks in Creative mode.
188        can_destroy_blocks_in_creative: bool,
189    },
190
191    /// Statistics for attacking.
192    Weapon {
193        /// Base damage added to the player's attack.
194        damage_per_attack: VarInt,
195        /// The duration (in seconds) that blocking is disabled after an attack
196        /// is landed.
197        disable_blocking_for_seconds: f32,
198    },
199
200    /// Determines how many experience points the item "absorbs" in an
201    /// enchanting table.
202    Enchantable(VarInt),
203
204    /// Logic for equipping the item.
205    Equippable {
206        /// Which body slot this item fits into (Head, Chest, etc.).
207        slot: EquipSlot,
208        /// Sound played when the item is equipped.
209        equip_sound: IdOr<SoundEventDefinition>,
210        /// Reference to an equipment-specific model (like 3D armor).
211        model: Option<Ident<String>>,
212        /// Texture used when the player's camera is "inside" the item (like a
213        /// Pumpkin).
214        camera_overlay: Option<Ident<String>>,
215        /// Which entity types are allowed to wear this item.
216        allowed_entities: Option<IDSet>,
217        /// Whether a Dispenser can equip this onto an entity.
218        dispensable: bool,
219        /// Whether right-clicking allows swapping this with currently equipped
220        /// armor.
221        swappable: bool,
222        /// If true, the item takes durability damage when the wearer is hurt.
223        damage_on_hurt: bool,
224        /// `Some` If the item can be sheared off (like a pumpkin from a snow
225        /// golem) + The sound to play when the item is sheared.
226        shearing_sound: Option<IdOr<SoundEventDefinition>>,
227    },
228
229    /// Items that can be used in an anvil to repair this item.
230    Repairable(IDSet),
231
232    /// Enables Elytra-style flight physics when equipped.
233    Glider,
234
235    /// References a custom sprite used as the background of the item's tooltip.
236    TooltipStyle(String),
237
238    /// Replicates the "Totem of Undying" behavior.
239    DeathProtection(Vec<ConsumeEffect>),
240
241    /// Shield-specific combat logic.
242    BlocksAttacks {
243        /// Delay in seconds before blocking becomes active.
244        block_delay_seconds: f32,
245        /// Scale factor for cooldowns when blocking.
246        disable_cooldown_scale: f32,
247        /// How much damage is absorbed from specific sources.
248        damage_reductions: Vec<DamageReduction>,
249        /// Minimum damage required for the shield to take durability loss.
250        item_damage_threshold: f32,
251        /// Flat durability loss per block.
252        item_damage_base: f32,
253        /// Multiplier for durability loss based on damage blocked.
254        item_damage_factor: f32,
255        /// Damage type tag that pierces this shield's blocking logic.
256        bypassed_by: Option<String>,
257        /// Sound played when a hit is successfully blocked.
258        block_sound: Option<IdOr<SoundEventDefinition>>,
259        /// Sound played when the shield is disabled (e.g., by an Axe).
260        disable_sound: Option<IdOr<SoundEventDefinition>>,
261    },
262
263    /// Enchantments contained within an Enchanted Book.
264    StoredEnchantments {
265        enchantments: Vec<(RegistryId, VarInt)>,
266        show_in_tooltip: bool,
267    },
268
269    /// RGB color for leather armor or other dyeable items.
270    DyedColor {
271        /// The packed RGB integer.
272        color: i32,
273    },
274
275    /// The color used for markings on a Map item.
276    MapColor(i32),
277
278    /// The numerical ID associated with a filled Map.
279    MapId(VarInt),
280
281    /// NBT data defining markers, banners, and icons shown on a map.
282    MapDecorations(Compound),
283
284    /// Tracking state for map expansion or locking.
285    MapPostProcessing(MapPostProcessingType),
286
287    /// Items currently loaded into a Crossbow.
288    ChargedProjectiles(Vec<ItemStack>),
289
290    /// Items stored inside a Bundle.
291    BundleContents(Vec<ItemStack>),
292
293    /// Data for Potion items, including their base type and custom effects.
294    PotionContents {
295        /// The base potion type (e.g., "Invisibility").
296        potion_id: Option<RegistryId>,
297        /// Custom color for the liquid, overrides the potion's default.
298        custom_color: Option<i32>,
299        /// Additional status effects not included in the base potion type.
300        custom_effects: Vec<PotionEffect>,
301        /// An optional name for the specific potion mixture.
302        custom_name: Option<String>,
303    },
304
305    /// Multiplier for the duration of effects applied by this potion.
306    PotionDurationScale(f32),
307
308    /// Effects granted by eating Suspicious Stew.
309    SuspiciousStewEffects(Vec<(RegistryId, VarInt)>),
310
311    /// Pages and filtering information for a Book and Quill.
312    WritableBookContent { pages: Vec<WritablePage> },
313
314    /// Finalized content for a Written Book.
315    WrittenBookContent {
316        /// The displayed title.
317        raw_title: String,
318        /// The title after passing through server-side chat filters.
319        filtered_title: Option<String>,
320        /// The username of the player who signed the book.
321        author: String,
322        /// How many times the book has been copied (Original, Copy of Original,
323        /// etc.).
324        generation: VarInt,
325        /// Page contents (Rich Text).
326        pages: Vec<WrittenPage>,
327        /// Whether entity selectors (like @p) have been resolved.
328        resolved: bool,
329    },
330    /// Visual armor customization (Pattern and Material).
331    Trim {
332        material: IdOr<TrimMaterial>,
333        pattern: IdOr<TrimPattern>,
334        /// Whether the "Armor Trim" lines show in the tooltip.
335        show_in_tooltip: bool,
336    },
337
338    /// Internal state for the Debug Stick, tracking property toggles.
339    DebugStickState(Compound),
340
341    /// NBT data used to modify an entity when it is spawned from an item (Spawn
342    /// Eggs).
343    EntityData { id: RegistryId, data: Compound },
344
345    /// NBT data for entities inside a Bucket (like Fish or Axolotls).
346    BucketEntityData(Compound),
347
348    /// NBT data for the Block Entity created when this item is placed (Chests,
349    /// Signs).
350    BlockEntityData { id: RegistryId, data: Compound },
351
352    /// The specific sound and duration associated with a Goat Horn.
353    Instrument(IdOr<InstrumentDefinition>),
354
355    /// Marks an item as a valid material for the Armor Trim system.
356    ProvidesTrimMaterial(ModePair<String, IdOr<TrimMaterial>>),
357
358    /// The level of Bad Omen granted by an Ominous Bottle (0-4).
359    OminousBottleAmplifier(VarInt),
360
361    /// Configuration for items that can be played in a Jukebox.
362    JukeboxPlayable {
363        /// Reference to a Jukebox Song.
364        song: ModePair<String, IdOr<JukeboxSong>>,
365        show_in_tooltip: bool,
366    },
367
368    /// Marks an item as a valid pattern for the Loom (Banner Patterns).
369    ProvidesBannerPatterns(String),
370
371    /// A list of recipe IDs that a Knowledge Book will teach the player.
372    Recipes(Compound),
373
374    /// Tracking data for a Compass pointing to a specific Lodestone.
375    LodestoneTracker {
376        /// The dimension and coordinate of the target. None if the compass is
377        /// spinning.
378        target: Option<LodestoneTarget>,
379        /// If true, the compass becomes a normal compass if the lodestone is
380        /// destroyed.
381        tracked: bool,
382    },
383
384    /// Individual explosion properties for a Firework Star.
385    FireworkExplosion(FireworkExplosionData),
386
387    /// Flight and explosion data for a Firework Rocket.
388    Fireworks {
389        flight_duration: VarInt,
390        explosions: Vec<FireworkExplosionData>,
391    },
392
393    /// Data for a Player Head, including the skin texture and UUID.
394    Profile(ResolvableProfile),
395
396    /// The sound played by a Note Block if this player head is placed on top of
397    /// it.
398    NoteBlockSound(String),
399
400    /// Visual layers for a Banner or Shield.
401    BannerPatterns(Vec<BannerLayer>),
402
403    /// The base dye color for a Banner.
404    BaseColor(VarInt),
405
406    /// The four item IDs used as patterns on a Decorated Pot.
407    PotDecorations(Vec<RegistryId>),
408
409    /// The inventory contents of a block (like a Chest or Shulker Box).
410    Container(Vec<ItemStack>),
411
412    /// Block state property overrides (e.g., "lit: true").
413    BlockState(Vec<(String, String)>),
414
415    /// Data for bees currently inside a Beehive item.
416    Bees(Vec<BeeData>),
417
418    /// The "Key" name required to open a container if it has a Lock component.
419    Lock(String),
420
421    /// Reference to a Loot Table for an unopened chest.
422    ContainerLoot(Compound),
423
424    /// Overrides the default sound played when this specific item breaks.
425    BreakSound(IdOr<SoundEventDefinition>),
426
427    /// Biome-specific variant of a Villager (e.g., Desert, Plains).
428    VillagerVariant(RegistryId),
429
430    /// Skin variant for a Wolf.
431    WolfVariant(RegistryId),
432
433    /// Determines the bark/growl sounds for a Wolf.
434    WolfSoundVariant(RegistryId),
435
436    /// Dye color of a Wolf's collar.
437    WolfCollar(DyeColor),
438
439    /// Type of Fox (Red or Snow).
440    FoxVariant(FoxType),
441
442    /// Size of a Salmon (Small, Medium, Large).
443    SalmonSize(SalmonScale),
444
445    /// Color of a Parrot.
446    ParrotVariant(ParrotType),
447
448    /// Pattern type for a Tropical Fish.
449    TropicalFishPattern(TropicalFishPattern),
450
451    /// Primary color of a Tropical Fish.
452    TropicalFishBaseColor(DyeColor),
453
454    /// Secondary color of a Tropical Fish.
455    TropicalFishPatternColor(DyeColor),
456
457    /// Type of Mooshroom (Red or Brown).
458    MooshroomVariant(MooshroomType),
459
460    /// Breed of a Rabbit.
461    RabbitVariant(RabbitType),
462
463    /// Skin variant for a Pig.
464    PigVariant(RegistryId),
465
466    /// Skin variant for a Cow.
467    CowVariant(RegistryId),
468
469    /// Skin variant for a Chicken.
470    ChickenVariant(ModePair<String, RegistryId>),
471
472    /// Biome variant for a Frog.
473    FrogVariant(RegistryId),
474
475    /// Color and marking variant for a Horse.
476    HorseVariant(HorseColor),
477
478    /// The specific painting texture and dimensions.
479    PaintingVariant(IdOr<PaintingVariantDefinition>),
480
481    /// Color variant for a Llama.
482    LlamaVariant(LlamaColor),
483
484    /// Color variant for an Axolotl.
485    AxolotlVariant(AxolotlType),
486
487    /// Breed variant for a Cat.
488    CatVariant(RegistryId),
489
490    /// Dye color of a Cat's collar.
491    CatCollar(DyeColor),
492
493    /// Natural wool color of a Sheep.
494    SheepColor(DyeColor),
495
496    /// Shell color of a Shulker.
497    ShulkerColor(DyeColor),
498}
499
500impl ItemComponent {
501    pub fn id(&self) -> u32 {
502        match self {
503            ItemComponent::CustomData { .. } => 0,
504            ItemComponent::MaxStackSize { .. } => 1,
505            ItemComponent::MaxDamage { .. } => 2,
506            ItemComponent::Damage { .. } => 3,
507            ItemComponent::Unbreakable => 4,
508            ItemComponent::CustomName { .. } => 5,
509            ItemComponent::ItemName { .. } => 6,
510            ItemComponent::ItemModel { .. } => 7,
511            ItemComponent::Lore { .. } => 8,
512            ItemComponent::Rarity { .. } => 9,
513            ItemComponent::Enchantments { .. } => 10,
514            ItemComponent::CanPlaceOn { .. } => 11,
515            ItemComponent::CanBreak { .. } => 12,
516            ItemComponent::AttributeModifiers { .. } => 13,
517            ItemComponent::CustomModelData { .. } => 14,
518            ItemComponent::TooltipDisplay { .. } => 15,
519            ItemComponent::RepairCost { .. } => 16,
520            ItemComponent::CreativeSlotLock => 17,
521            ItemComponent::EnchantmentGlintOverride { .. } => 18,
522            ItemComponent::IntangibleProjectile { .. } => 19,
523            ItemComponent::Food { .. } => 20,
524            ItemComponent::Consumable { .. } => 21,
525            ItemComponent::UseRemainder { .. } => 22,
526            ItemComponent::UseCooldown { .. } => 23,
527            ItemComponent::DamageResistant { .. } => 24,
528            ItemComponent::Tool { .. } => 25,
529            ItemComponent::Weapon { .. } => 26,
530            ItemComponent::Enchantable { .. } => 27,
531            ItemComponent::Equippable { .. } => 28,
532            ItemComponent::Repairable { .. } => 29,
533            ItemComponent::Glider => 30,
534            ItemComponent::TooltipStyle { .. } => 31,
535            ItemComponent::DeathProtection { .. } => 32,
536            ItemComponent::BlocksAttacks { .. } => 33,
537            ItemComponent::StoredEnchantments { .. } => 34,
538            ItemComponent::DyedColor { .. } => 35,
539            ItemComponent::MapColor { .. } => 36,
540            ItemComponent::MapId { .. } => 37,
541            ItemComponent::MapDecorations { .. } => 38,
542            ItemComponent::MapPostProcessing { .. } => 39,
543            ItemComponent::ChargedProjectiles { .. } => 40,
544            ItemComponent::BundleContents { .. } => 41,
545            ItemComponent::PotionContents { .. } => 42,
546            ItemComponent::PotionDurationScale { .. } => 43,
547            ItemComponent::SuspiciousStewEffects { .. } => 44,
548            ItemComponent::WritableBookContent { .. } => 45,
549            ItemComponent::WrittenBookContent { .. } => 46,
550            ItemComponent::Trim { .. } => 47,
551            ItemComponent::DebugStickState { .. } => 48,
552            ItemComponent::EntityData { .. } => 49,
553            ItemComponent::BucketEntityData { .. } => 50,
554            ItemComponent::BlockEntityData { .. } => 51,
555            ItemComponent::Instrument { .. } => 52,
556            ItemComponent::ProvidesTrimMaterial { .. } => 53,
557            ItemComponent::OminousBottleAmplifier { .. } => 54,
558            ItemComponent::JukeboxPlayable { .. } => 55,
559            ItemComponent::ProvidesBannerPatterns { .. } => 56,
560            ItemComponent::Recipes { .. } => 57,
561            ItemComponent::LodestoneTracker { .. } => 58,
562            ItemComponent::FireworkExplosion { .. } => 59,
563            ItemComponent::Fireworks { .. } => 60,
564            ItemComponent::Profile { .. } => 61,
565            ItemComponent::NoteBlockSound { .. } => 62,
566            ItemComponent::BannerPatterns { .. } => 63,
567            ItemComponent::BaseColor { .. } => 64,
568            ItemComponent::PotDecorations { .. } => 65,
569            ItemComponent::Container { .. } => 66,
570            ItemComponent::BlockState { .. } => 67,
571            ItemComponent::Bees { .. } => 68,
572            ItemComponent::Lock { .. } => 69,
573            ItemComponent::ContainerLoot { .. } => 70,
574            ItemComponent::BreakSound { .. } => 71,
575            ItemComponent::VillagerVariant { .. } => 72,
576            ItemComponent::WolfVariant { .. } => 73,
577            ItemComponent::WolfSoundVariant { .. } => 74,
578            ItemComponent::WolfCollar { .. } => 75,
579            ItemComponent::FoxVariant { .. } => 76,
580            ItemComponent::SalmonSize { .. } => 77,
581            ItemComponent::ParrotVariant { .. } => 78,
582            ItemComponent::TropicalFishPattern { .. } => 79,
583            ItemComponent::TropicalFishBaseColor { .. } => 80,
584            ItemComponent::TropicalFishPatternColor { .. } => 81,
585            ItemComponent::MooshroomVariant { .. } => 82,
586            ItemComponent::RabbitVariant { .. } => 83,
587            ItemComponent::PigVariant { .. } => 84,
588            ItemComponent::CowVariant { .. } => 85,
589            ItemComponent::ChickenVariant { .. } => 86,
590            ItemComponent::FrogVariant { .. } => 87,
591            ItemComponent::HorseVariant { .. } => 88,
592            ItemComponent::PaintingVariant { .. } => 89,
593            ItemComponent::LlamaVariant { .. } => 90,
594            ItemComponent::AxolotlVariant { .. } => 91,
595            ItemComponent::CatVariant { .. } => 92,
596            ItemComponent::CatCollar { .. } => 93,
597            ItemComponent::SheepColor { .. } => 94,
598            ItemComponent::ShulkerColor { .. } => 95,
599        }
600    }
601
602    pub fn hash(&self) -> i32 {
603        // TODO: implement if required
604        0
605    }
606}
607
608/// A helper struct for protocol fields that start with a "Mode" byte.
609///
610/// In 1.21, several components (like Jukebox Songs or Trim Materials) are
611/// encoded as:
612/// - Byte `0`: Followed by Type A (usually a String Identifier).
613/// - Byte `1`: Followed by Type B (usually an ID or Inline Definition).
614#[derive(Clone, PartialEq, Debug)]
615pub enum ModePair<A, B> {
616    /// Mode 0: Usually references a registry key by name.
617    Mode0(A),
618    /// Mode 1: Usually references a registry ID or defines the data inline.
619    Mode1(B),
620}
621
622impl<A: Encode, B: Encode> Encode for ModePair<A, B> {
623    fn encode(&self, mut w: impl Write) -> anyhow::Result<()> {
624        match self {
625            ModePair::Mode0(a) => {
626                0_u8.encode(&mut w)?;
627                a.encode(w)
628            }
629            ModePair::Mode1(b) => {
630                1_u8.encode(&mut w)?;
631                b.encode(w)
632            }
633        }
634    }
635}
636impl<'a, A: Decode<'a>, B: Decode<'a>> Decode<'a> for ModePair<A, B> {
637    fn decode(r: &mut &'a [u8]) -> anyhow::Result<Self> {
638        let mode = u8::decode(r)?;
639        match mode {
640            0 => Ok(ModePair::Mode0(A::decode(r)?)),
641            1 => Ok(ModePair::Mode1(B::decode(r)?)),
642            _ => anyhow::bail!("Invalid ModePair byte: {mode}"),
643        }
644    }
645}
646
647/// Defines a rule for matching a block in the world.
648/// Used by `CanPlaceOn` and `CanBreak` in Adventure Mode.
649#[derive(Clone, PartialEq, Debug, Encode)]
650pub struct BlockPredicate {
651    /// If None, matches any block ID.
652    pub blocks: Option<IDSet>,
653
654    /// Matches specific block state properties (e.g., `lit=true`).
655    pub properties: Option<Vec<Property>>,
656
657    /// Matches the Block Entity's NBT data.
658    pub nbt: Option<Compound>,
659
660    /// (1.21+) Matches if the block drops an item containing these EXACT
661    /// components. This is a strict equality check.
662    pub exact_components: Vec<ExactComponentMatcher>,
663
664    /// (1.21+) Matches if the block drops an item containing specific NBT
665    /// structures within specific components.
666    pub partial_components: Vec<PartialComponentMatcher>,
667}
668
669// A specific Block State property requirement.
670#[derive(Clone, PartialEq, Debug, Encode, Decode)]
671pub struct Property {
672    /// The name of the property (e.g., "facing", "waterlogged").
673    pub name: String,
674
675    /// Either an exact value or a min/max range for the property.
676    pub value: PropertyValue,
677}
678
679#[derive(Clone, PartialEq, Debug)]
680pub enum PropertyValue {
681    /// An exact string value.
682    Exact(String),
683    /// A min max string value.
684    MinMax { min: String, max: String },
685}
686
687// encoded as bool followed by one if true or min and max if false
688impl Encode for PropertyValue {
689    fn encode(&self, mut w: impl Write) -> anyhow::Result<()> {
690        match self {
691            PropertyValue::Exact(v) => {
692                true.encode(&mut w)?;
693                v.encode(w)
694            }
695            PropertyValue::MinMax { min, max } => {
696                false.encode(&mut w)?;
697                min.encode(&mut w)?;
698                max.encode(w)
699            }
700        }
701    }
702}
703impl<'a> Decode<'a> for PropertyValue {
704    fn decode(r: &mut &'a [u8]) -> anyhow::Result<Self> {
705        let is_exact = bool::decode(r)?;
706        if is_exact {
707            let v = String::decode(r)?;
708            Ok(PropertyValue::Exact(v))
709        } else {
710            let min = String::decode(r)?;
711            let max = String::decode(r)?;
712            Ok(PropertyValue::MinMax { min, max })
713        }
714    }
715}
716
717/// Matches a component exactly.
718#[derive(Clone, PartialEq, Debug, Encode)]
719pub struct ExactComponentMatcher {
720    /// The ID of the component to check.
721    pub component_type: VarInt,
722    /// The encoded data of that component.
723    pub component_data: ItemComponent,
724}
725
726/// Matches a subset of data within a component using NBT.
727#[derive(Clone, PartialEq, Debug, Encode, Decode)]
728pub struct PartialComponentMatcher {
729    /// The ID of the component to check.
730    pub component_type: VarInt,
731    /// An NBT matcher to apply to that component's internal data.
732    pub predicate: Compound,
733}
734
735/// Modifies a player's attributes (like Strength or Speed).
736#[derive(Clone, PartialEq, Debug, Encode, Decode)]
737pub struct AttributeModifier {
738    /// The ID of the attribute to modify in the registry.
739    pub attribute_id: RegistryId,
740
741    /// A unique identifier for this modifier instance.
742    /// Used to prevent stacking the same modifier multiple times from different
743    /// sources.
744    pub modifier_id: Ident<String>,
745
746    /// The numerical amount to change the attribute by.
747    pub value: f64,
748
749    /// How the math is applied.
750    /// (Add): X = X + Value
751    /// (Multiply Base): X = X + (`BaseValue` * Value)
752    /// (Multiply Total): X = X * (1 + Value)
753    pub operation: EntityAttributeOperation,
754
755    /// Which slot the item must be in for this to work.
756    pub slot: AttributeSlot,
757}
758
759/// Defines custom mining speed logic for a tool.
760#[derive(Clone, PartialEq, Debug, Encode, Decode)]
761pub struct ToolRule {
762    /// The blocks this rule applies to.
763    pub blocks: IDSet,
764
765    /// If present, overrides the mining speed for these blocks.
766    pub speed: Option<f32>,
767
768    /// If present and true, this tool is considered "correct" for the block
769    /// (meaning the block will drop items when broken).
770    pub correct_drop_for_blocks: Option<bool>,
771}
772
773#[derive(Clone, PartialEq, Debug, Encode, Decode)]
774pub struct LodestoneTarget {
775    /// The namespaced key of the dimension (e.g., "`minecraft:the_nether`").
776    pub dimension: String,
777
778    /// The precise X, Y, Z coordinates of the Lodestone block.
779    pub position: (VarInt, VarInt, VarInt),
780}
781
782/// Defines a sound event, either by referencing the registry or defining it
783/// on the fly.
784#[derive(Clone, PartialEq, Debug, Encode, Decode)]
785pub struct SoundEventDefinition {
786    /// The identifier of the sound (e.g., "minecraft:entity.pig.ambient").
787    pub sound: Ident<String>,
788
789    /// A fixed range (in blocks) for the sound. If None, uses the default.
790    pub range: Option<f32>,
791}
792
793/// Defines a material used to trim armor (e.g., Gold, Amethyst).
794#[derive(Clone, PartialEq, Debug, Encode, Decode)]
795pub struct TrimMaterial {
796    /// Corresponds to "Suffix" in the Wiki.
797    /// This string is appended to the texture path (e.g., "amethyst" ->
798    /// "`trims/items/leggings_trim_amethyst`").
799    pub asset_name: String,
800
801    /// Allows specific armor materials to use a different texture suffix.
802    ///
803    /// Structure:
804    /// - Key: Armor Material Model Name (Identifier, e.g.,
805    ///   "minecraft:netherite")
806    /// - Value: Overridden Asset Name (String, e.g., "`amethyst_darker`")
807    pub overrides: Vec<(Ident<String>, String)>,
808
809    /// Corresponds to "Description" in the Wiki.
810    /// The text displayed in the item tooltip (e.g., "Amethyst Material").
811    pub description: TextComponent,
812}
813
814/// Defines the shape/pattern of the armor trim (e.g., Vex, Coast).
815#[derive(Clone, PartialEq, Debug, Encode, Decode)]
816pub struct TrimPattern {
817    /// The asset ID for the texture pattern.
818    pub asset_id: String,
819
820    /// The Smithing Template item required to apply this pattern.
821    pub template_item: RegistryId,
822
823    /// The text displayed in the tooltip (e.g., "Vex Armor Trim").
824    pub description: TextComponent,
825
826    /// If true, the pattern is applied as a "Decal" (no color blending).
827    pub decal: bool,
828}
829
830/// Defines a Goat Horn instrument.
831#[derive(Clone, PartialEq, Debug, Encode, Decode)]
832pub struct InstrumentDefinition {
833    /// The sound played when the horn is used.
834    pub sound_event: IdOr<SoundEventDefinition>,
835
836    /// How long the horn plays (in seconds).
837    pub use_duration: f32,
838
839    /// The audible range of the horn.
840    pub range: f32,
841
842    /// The description shown in the tooltip (e.g., "Ponder").
843    pub description: TextComponent,
844}
845
846/// Defines a Music Disc song.
847#[derive(Clone, PartialEq, Debug, Encode, Decode)]
848pub struct JukeboxSong {
849    /// The sound event to play.
850    pub sound_event: IdOr<SoundEventDefinition>,
851
852    /// The song title shown in the "Now Playing" action bar.
853    pub description: Text,
854
855    /// The duration of the song in seconds.
856    pub length_seconds: f32,
857
858    /// The Redstone signal strength (0-15) emitted by the Jukebox while
859    /// playing.
860    pub comparator_output: VarInt,
861}
862
863/// Defines a variant of a painting entity.
864#[derive(Clone, PartialEq, Debug, Encode, Decode)]
865pub struct PaintingVariantDefinition {
866    /// The path to the texture in the resource pack.
867    pub asset_id: String,
868
869    /// Width in blocks (1 block = 16 pixels).
870    pub width: VarInt,
871
872    /// Height in blocks.
873    pub height: VarInt,
874}
875
876/// Defines a single explosion in a Firework Rocket.
877#[derive(Clone, PartialEq, Debug, Encode, Decode)]
878pub struct FireworkExplosionData {
879    /// The shape (Small Ball, Large Ball, Star, Creeper, Burst).
880    pub shape: VarInt,
881
882    /// List of RGB integers for the initial explosion colors.
883    pub colors: Vec<i32>,
884
885    /// List of RGB integers that the particles fade into.
886    pub fade_colors: Vec<i32>,
887
888    /// If true, particles leave a trail behind them.
889    pub has_trail: bool,
890
891    /// If true, particles crackle/flash after the explosion.
892    pub has_twinkle: bool,
893}
894
895/// Defines a layer on a Banner.
896#[derive(Clone, PartialEq, Debug, Encode, Decode)]
897pub struct BannerLayer {
898    /// The pattern type (Flower, Skull, Stripe, etc.).
899    pub pattern: IdOr<BannerPattern>,
900
901    /// The dye color ID (0-15) for this layer.
902    pub color: DyeColor,
903}
904
905#[derive(Clone, PartialEq, Debug, Encode, Decode)]
906pub struct BannerPattern {
907    /// The texture identifier (e.g., "minecraft:flower").
908    pub asset_id: String,
909
910    /// The translation key for the pattern name (e.g.,
911    /// "block.minecraft.banner.flower").
912    pub translation_key: String,
913}
914
915/// A page in a Book and Quill (Writable).
916#[derive(Clone, PartialEq, Debug, Encode, Decode)]
917pub struct WritablePage {
918    /// The raw text entered by the player.
919    pub raw: String,
920
921    /// If the server runs a chat filter, this is the filtered version.
922    /// If None, the raw text is considered safe to display.
923    pub filtered: Option<String>,
924}
925
926/// A page in a Finished Book (Written).
927#[derive(Clone, PartialEq, Debug, Encode, Decode)]
928pub struct WrittenPage {
929    /// The JSON text component for the page content.
930    pub raw: TextComponent,
931
932    /// Optional filtered version for chat safety settings.
933    pub filtered: Option<TextComponent>,
934}
935
936/// Represents a Player's Game Profile (Skin/UUID).
937#[derive(Clone, PartialEq, Debug, Encode, Decode)]
938pub struct ResolvableProfile {
939    /// The player's username.
940    pub name: Option<String>,
941
942    /// The player's UUID.
943    pub id: Option<Uuid>,
944
945    /// Properties, primarily the "textures" property containing the skin URL.
946    pub properties: Vec<ProfileProperty>,
947}
948
949#[derive(Clone, PartialEq, Debug, Encode, Decode)]
950pub struct ProfileProperty {
951    pub name: String,
952    /// The base64 encoded value.
953    pub value: String,
954    /// The optional public key signature (Yggdrasil).
955    pub signature: Option<String>,
956}
957
958/// Information about a Bee inside a Beehive.
959#[derive(Clone, PartialEq, Debug, Encode, Decode)]
960pub struct BeeData {
961    /// The NBT data of the Bee entity itself (Health, Name, etc.).
962    pub entity_data: Compound,
963
964    /// How many ticks the bee has been inside the hive.
965    pub ticks_in_hive: VarInt,
966
967    /// The minimum ticks required before the bee can leave.
968    pub min_ticks_in_hive: VarInt,
969}
970
971/// A wrapper for the various effects caused by consuming an item.
972#[derive(Clone, PartialEq, Debug, Encode, Decode)]
973pub struct ConsumeEffect {
974    /// The registry ID of the effect type (`ApplyEffects`, Teleport, etc.).
975    pub type_id: VarInt,
976
977    /// The effect data. Note: The protocol doesn't wrap this in a neat enum,
978    /// it sends the data immediately after the ID.
979    /// You must ensure your Decode logic matches the `type_id` to the correct
980    /// variant here.
981    pub data: ConsumeEffectData,
982}
983
984#[derive(Clone, PartialEq, Debug, Encode, Decode)]
985pub enum ConsumeEffectData {
986    /// Type 0: Apply Effects
987    ApplyEffects {
988        /// List of potion effects to apply.
989        effects: Vec<PotionEffect>,
990        /// Chance (0.0 to 1.0) that these effects are applied.
991        probability: f32,
992    },
993    /// Type 1: Remove Effects
994    RemoveEffects(IDSet), // Set of Potion IDs to cure/remove.
995    /// Type 2: Clear All Effects
996    ClearAllEffects,
997    /// Type 3: Teleport Randomly (Chorus Fruit behavior)
998    TeleportRandomly {
999        /// The horizontal radius to search for a safe spot.
1000        diameter: f32,
1001    },
1002    /// Type 4: Play Sound
1003    PlaySound(IdOr<SoundEventDefinition>),
1004}
1005
1006/// A standard Potion Effect.
1007#[derive(Clone, PartialEq, Debug, Encode, Decode)]
1008pub struct PotionEffect {
1009    /// The ID of the effect (Speed, Jump Boost, etc.).
1010    pub id: RegistryId,
1011
1012    /// The level of the effect (0 = Level 1, 1 = Level 2).
1013    pub amplifier: VarInt,
1014
1015    /// Duration in ticks. -1 indicates infinite duration.
1016    pub duration: VarInt,
1017
1018    /// If true, particles are translucent (like Beacon effects).
1019    pub ambient: bool,
1020
1021    /// If false, no particles are shown.
1022    pub show_particles: bool,
1023
1024    /// If true, the effect icon is displayed in the top-right of theinventory.
1025    pub show_icon: bool,
1026}
1027
1028/// Shield logic for reducing damage.
1029#[derive(Clone, PartialEq, Debug, Encode, Decode)]
1030pub struct DamageReduction {
1031    /// The angle (in degrees) in front of the player that is blocked.
1032    pub horizontal_blocking_angle: f32,
1033
1034    /// Specific damage types this reduction applies to. None = All.
1035    pub damage_type: Option<IDSet>,
1036
1037    /// Flat amount of damage removed.
1038    pub base: f32,
1039
1040    /// Percentage of remaining damage removed (0.0 to 1.0).
1041    pub factor: f32,
1042}
1043
1044#[derive(Clone, PartialEq, Debug, Encode, Decode)]
1045pub enum Rarity {
1046    Common,   // White
1047    Uncommon, // Yellow
1048    Rare,     // Aqua
1049    Epic,     // Purple
1050}
1051
1052#[derive(Clone, PartialEq, Debug, Encode, Decode)]
1053pub enum MapPostProcessingType {
1054    Lock,  // The map has been locked in a Cartography Table.
1055    Scale, // The map is being zoomed out.
1056}
1057
1058#[derive(Clone, PartialEq, Debug, Encode, Decode)]
1059pub enum ConsumableAnimation {
1060    None,
1061    Eat,
1062    Drink,
1063    Block, // Shield block animation
1064    Bow,
1065    Spear, // Trident throw
1066    Crossbow,
1067    Spyglass,
1068    TootHorn,
1069    Brush,
1070}
1071
1072#[derive(Clone, PartialEq, Debug, Encode, Decode)]
1073pub enum EquipSlot {
1074    MainHand,
1075    Feet,
1076    Legs,
1077    Chest,
1078    Head,
1079    OffHand,
1080    Body, // Horse armor / Llama carpet
1081}
1082
1083#[derive(Clone, PartialEq, Debug, Encode, Decode)]
1084pub enum AttributeSlot {
1085    Any,
1086    MainHand,
1087    OffHand,
1088    Hand, // MainHand or OffHand
1089    Feet,
1090    Legs,
1091    Chest,
1092    Head,
1093    Armor, // Any armor slot
1094    Body,
1095}
1096
1097#[derive(Clone, Copy, PartialEq, Debug, Encode, Decode)]
1098pub enum DyeColor {
1099    White,
1100    Orange,
1101    Magenta,
1102    LightBlue,
1103    Yellow,
1104    Lime,
1105    Pink,
1106    Gray,
1107    LightGray,
1108    Cyan,
1109    Purple,
1110    Blue,
1111    Brown,
1112    Green,
1113    Red,
1114    Black,
1115}
1116
1117#[derive(Clone, Copy, PartialEq, Debug, Encode, Decode)]
1118pub enum FoxType {
1119    Red,
1120    Snow,
1121}
1122
1123#[derive(Clone, Copy, PartialEq, Debug, Encode, Decode)]
1124pub enum SalmonScale {
1125    Small,
1126    Medium,
1127    Large,
1128}
1129
1130#[derive(Clone, Copy, PartialEq, Debug, Encode, Decode)]
1131pub enum ParrotType {
1132    RedBlue,
1133    Blue,
1134    Green,
1135    YellowBlue,
1136    Gray,
1137}
1138
1139#[derive(Clone, Copy, PartialEq, Debug, Encode, Decode)]
1140pub enum TropicalFishPattern {
1141    Kob,
1142    Sunstreak,
1143    Snooper,
1144    Dasher,
1145    Brinely,
1146    Spotty,
1147    Flopper,
1148    Stripey,
1149    Glitter,
1150    Blockfish,
1151    Betty,
1152    Clayfish,
1153}
1154
1155#[derive(Clone, Copy, PartialEq, Debug, Encode, Decode)]
1156pub enum MooshroomType {
1157    Red,
1158    Brown,
1159}
1160
1161#[derive(Clone, Copy, PartialEq, Debug, Encode, Decode)]
1162pub enum RabbitType {
1163    Brown,
1164    White,
1165    Black,
1166    WhiteSplotched,
1167    Gold,
1168    Salt,
1169    Evil, // "Toast"
1170}
1171
1172#[derive(Clone, Copy, PartialEq, Debug, Encode, Decode)]
1173pub enum HorseColor {
1174    White,
1175    Creamy,
1176    Chestnut,
1177    Brown,
1178    Black,
1179    Gray,
1180    DarkBrown,
1181}
1182
1183#[derive(Clone, Copy, PartialEq, Debug, Encode, Decode)]
1184pub enum LlamaColor {
1185    Creamy,
1186    White,
1187    Brown,
1188    Gray,
1189}
1190
1191#[derive(Clone, Copy, PartialEq, Debug, Encode, Decode)]
1192pub enum AxolotlType {
1193    Lucy, // Pink
1194    Wild, // Brown
1195    Gold,
1196    Cyan,
1197    Blue,
1198}