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}