azalea_inventory/components/
mod.rs

1mod profile;
2
3use core::f64;
4use std::{
5    any::Any,
6    collections::HashMap,
7    fmt::{self, Display},
8    io::{self, Cursor},
9    mem::ManuallyDrop,
10};
11
12use azalea_buf::{AzBuf, AzaleaRead, AzaleaWrite, BufReadError};
13use azalea_chat::FormattedText;
14use azalea_core::{
15    attribute_modifier_operation::AttributeModifierOperation,
16    checksum::{Checksum, get_checksum},
17    codec_utils::*,
18    filterable::Filterable,
19    position::GlobalPos,
20    registry_holder::{RegistryHolder, dimension_type::DamageTypeElement},
21    sound::CustomSound,
22};
23use azalea_registry::{
24    Holder, HolderSet,
25    builtin::{
26        Attribute, BlockKind, DataComponentKind, EntityKind, ItemKind, MobEffect, Potion,
27        SoundEvent, VillagerKind,
28    },
29    data::{self, DamageKind, Enchantment, JukeboxSong, TrimMaterial, TrimPattern},
30    identifier::Identifier,
31};
32pub use profile::*;
33use serde::{Serialize, Serializer, ser::SerializeMap};
34use simdnbt::owned::{Nbt, NbtCompound};
35use tracing::trace;
36
37use crate::{ItemStack, item::consume_effect::ConsumeEffect};
38
39pub trait DataComponentTrait:
40    Send + Sync + Any + Clone + Serialize + Into<DataComponentUnion>
41{
42    const KIND: DataComponentKind;
43}
44
45pub trait EncodableDataComponent: Send + Sync + Any {
46    fn encode(&self, buf: &mut Vec<u8>) -> io::Result<()>;
47    fn crc_hash(&self, registries: &RegistryHolder) -> Checksum;
48    // using the Clone trait makes it not be object-safe, so we have our own clone
49    // function instead
50    fn clone(&self) -> Box<dyn EncodableDataComponent>;
51    // same thing here
52    fn eq(&self, other: &dyn EncodableDataComponent) -> bool;
53}
54
55impl<T> EncodableDataComponent for T
56where
57    T: DataComponentTrait + Clone + AzaleaWrite + AzaleaRead + PartialEq,
58{
59    fn encode(&self, buf: &mut Vec<u8>) -> io::Result<()> {
60        self.azalea_write(buf)
61    }
62    fn crc_hash(&self, registries: &RegistryHolder) -> Checksum {
63        get_checksum(self, registries).expect("serializing data components should always succeed")
64    }
65    fn clone(&self) -> Box<dyn EncodableDataComponent> {
66        let cloned = self.clone();
67        Box::new(cloned)
68    }
69    fn eq(&self, other: &dyn EncodableDataComponent) -> bool {
70        let other_any: &dyn Any = other;
71        match other_any.downcast_ref::<T>() {
72            Some(other) => self == other,
73            _ => false,
74        }
75    }
76}
77
78#[macro_export]
79macro_rules! define_data_components {
80    ( $( $x:ident ),* $(,)? ) => {
81        /// A union of all data components.
82        ///
83        /// You probably don't want to use this directly. Consider [`DataComponentPatch`] instead.
84        ///
85        /// This type does not know its own value, and as such every function for it requires the
86        /// `DataComponentKind` to be passed in. Passing the wrong `DataComponentKind` will result
87        /// in undefined behavior. Also, all of the values are `ManuallyDrop`.
88        ///
89        /// [`DataComponentPatch`]: crate::DataComponentPatch
90        #[allow(non_snake_case)]
91        pub union DataComponentUnion {
92            $( $x: ManuallyDrop<$x>, )*
93        }
94        impl DataComponentUnion {
95            /// # Safety
96            ///
97            /// `kind` must be the correct value for this union.
98            pub unsafe fn serialize_entry_as<S: SerializeMap>(
99                &self,
100                serializer: &mut S,
101                kind: DataComponentKind,
102            ) -> Result<(), S::Error> {
103                match kind {
104                    $( DataComponentKind::$x => { unsafe { serializer.serialize_entry(&kind, &*self.$x) } }, )*
105                }
106            }
107            /// # Safety
108            ///
109            /// `kind` must be the correct value for this union.
110            pub unsafe fn drop_as(&mut self, kind: DataComponentKind) {
111                match kind {
112                    $( DataComponentKind::$x => { unsafe { ManuallyDrop::drop(&mut self.$x) } }, )*
113                }
114            }
115            /// # Safety
116            ///
117            /// `kind` must be the correct value for this union.
118            pub unsafe fn as_kind(&self, kind: DataComponentKind) -> &dyn EncodableDataComponent {
119                match kind {
120                    $( DataComponentKind::$x => { unsafe { &**(&self.$x as &ManuallyDrop<dyn EncodableDataComponent>) } }, )*
121                }
122            }
123            pub fn azalea_read_as(
124                kind: DataComponentKind,
125                buf: &mut Cursor<&[u8]>,
126            ) -> Result<Self, BufReadError> {
127                trace!("Reading data component {kind}");
128
129                Ok(match kind {
130                    $( DataComponentKind::$x => {
131                        Self { $x: ManuallyDrop::new($x::azalea_read(buf)?) }
132                    }, )*
133                })
134            }
135            /// # Safety
136            ///
137            /// `kind` must be the correct value for this union.
138            pub unsafe fn azalea_write_as(
139                &self,
140                kind: DataComponentKind,
141                buf: &mut impl std::io::Write,
142            ) -> io::Result<()> {
143                let mut value = Vec::new();
144                match kind {
145                    $( DataComponentKind::$x => unsafe { self.$x.encode(&mut value)? }, )*
146                };
147                buf.write_all(&value)?;
148
149                Ok(())
150            }
151            /// # Safety
152            ///
153            /// `kind` must be the correct value for this union.
154            pub unsafe fn clone_as(
155                &self,
156                kind: DataComponentKind,
157            ) -> Self {
158                match kind {
159                    $( DataComponentKind::$x => {
160                        Self { $x: unsafe { self.$x.clone() } }
161                    }, )*
162                }
163            }
164            /// # Safety
165            ///
166            /// `kind` must be the correct value for this union.
167            pub unsafe fn eq_as(
168                &self,
169                other: &Self,
170                kind: DataComponentKind,
171            ) -> bool {
172                match kind {
173                    $( DataComponentKind::$x => unsafe { self.$x.eq(&other.$x) }, )*
174                }
175            }
176        }
177        $(
178            impl From<$x> for DataComponentUnion {
179                fn from(value: $x) -> Self {
180                    DataComponentUnion { $x: ManuallyDrop::new(value) }
181                }
182            }
183        )*
184
185        $(
186            impl DataComponentTrait for $x {
187                const KIND: DataComponentKind = DataComponentKind::$x;
188            }
189        )*
190    };
191}
192
193// if this is causing a compile-time error, look at DataComponents.java in the
194// decompiled vanilla code to see how to implement new components
195
196// note that this statement is updated by genitemcomponents.py
197define_data_components!(
198    CustomData,
199    MaxStackSize,
200    MaxDamage,
201    Damage,
202    Unbreakable,
203    CustomName,
204    ItemName,
205    ItemModel,
206    Lore,
207    Rarity,
208    Enchantments,
209    CanPlaceOn,
210    CanBreak,
211    AttributeModifiers,
212    CustomModelData,
213    TooltipDisplay,
214    RepairCost,
215    CreativeSlotLock,
216    EnchantmentGlintOverride,
217    IntangibleProjectile,
218    Food,
219    Consumable,
220    UseRemainder,
221    UseCooldown,
222    DamageResistant,
223    Tool,
224    Weapon,
225    Enchantable,
226    Equippable,
227    Repairable,
228    Glider,
229    TooltipStyle,
230    DeathProtection,
231    BlocksAttacks,
232    StoredEnchantments,
233    DyedColor,
234    MapColor,
235    MapId,
236    MapDecorations,
237    MapPostProcessing,
238    ChargedProjectiles,
239    BundleContents,
240    PotionContents,
241    PotionDurationScale,
242    SuspiciousStewEffects,
243    WritableBookContent,
244    WrittenBookContent,
245    Trim,
246    DebugStickState,
247    EntityData,
248    BucketEntityData,
249    BlockEntityData,
250    Instrument,
251    ProvidesTrimMaterial,
252    OminousBottleAmplifier,
253    JukeboxPlayable,
254    ProvidesBannerPatterns,
255    Recipes,
256    LodestoneTracker,
257    FireworkExplosion,
258    Fireworks,
259    Profile,
260    NoteBlockSound,
261    BannerPatterns,
262    BaseColor,
263    PotDecorations,
264    Container,
265    BlockState,
266    Bees,
267    Lock,
268    ContainerLoot,
269    BreakSound,
270    VillagerVariant,
271    WolfVariant,
272    WolfSoundVariant,
273    WolfCollar,
274    FoxVariant,
275    SalmonSize,
276    ParrotVariant,
277    TropicalFishPattern,
278    TropicalFishBaseColor,
279    TropicalFishPatternColor,
280    MooshroomVariant,
281    RabbitVariant,
282    PigVariant,
283    CowVariant,
284    ChickenVariant,
285    FrogVariant,
286    HorseVariant,
287    PaintingVariant,
288    LlamaVariant,
289    AxolotlVariant,
290    CatVariant,
291    CatCollar,
292    SheepColor,
293    ShulkerColor,
294    UseEffects,
295    MinimumAttackCharge,
296    DamageType,
297    PiercingWeapon,
298    KineticWeapon,
299    SwingAnimation,
300    ZombieNautilusVariant,
301    AttackRange,
302);
303
304#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
305#[serde(transparent)]
306pub struct CustomData {
307    pub nbt: Nbt,
308}
309
310#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
311#[serde(transparent)]
312pub struct MaxStackSize {
313    #[var]
314    pub count: i32,
315}
316
317#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
318#[serde(transparent)]
319pub struct MaxDamage {
320    #[var]
321    pub amount: i32,
322}
323
324#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
325#[serde(transparent)]
326pub struct Damage {
327    #[var]
328    pub amount: i32,
329}
330
331#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
332pub struct Unbreakable;
333
334#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
335#[serde(transparent)]
336pub struct CustomName {
337    pub name: FormattedText,
338}
339
340#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
341#[serde(transparent)]
342pub struct ItemName {
343    pub name: FormattedText,
344}
345
346#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
347#[serde(transparent)]
348pub struct Lore {
349    pub lines: Vec<FormattedText>,
350    // vanilla also has styled_lines here but it doesn't appear to be used for the protocol
351}
352
353#[derive(Clone, Copy, PartialEq, AzBuf, Debug, Serialize)]
354#[serde(rename_all = "snake_case")]
355pub enum Rarity {
356    Common,
357    Uncommon,
358    Rare,
359    Epic,
360}
361
362#[derive(Clone, PartialEq, AzBuf, Serialize, Default)]
363#[serde(transparent)]
364pub struct Enchantments {
365    /// Enchantment levels here are 1-indexed, level 0 does not exist.
366    #[var]
367    pub levels: HashMap<Enchantment, i32>,
368}
369
370#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
371pub enum BlockStateValueMatcher {
372    Exact {
373        value: String,
374    },
375    Range {
376        min: Option<String>,
377        max: Option<String>,
378    },
379}
380
381#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
382pub struct BlockStatePropertyMatcher {
383    pub name: String,
384    pub value_matcher: BlockStateValueMatcher,
385}
386
387#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
388pub struct BlockPredicate {
389    #[serde(skip_serializing_if = "is_default")]
390    pub blocks: Option<HolderSet<BlockKind, Identifier>>,
391    #[serde(skip_serializing_if = "is_default")]
392    pub properties: Option<Vec<BlockStatePropertyMatcher>>,
393    #[serde(skip_serializing_if = "is_default")]
394    pub nbt: Option<NbtCompound>,
395}
396
397#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
398#[serde(transparent)]
399pub struct AdventureModePredicate {
400    #[serde(serialize_with = "flatten_array")]
401    pub predicates: Vec<BlockPredicate>,
402}
403
404#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
405#[serde(transparent)]
406pub struct CanPlaceOn {
407    pub predicate: AdventureModePredicate,
408}
409
410#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
411#[serde(transparent)]
412pub struct CanBreak {
413    pub predicate: AdventureModePredicate,
414}
415
416#[derive(Clone, Copy, PartialEq, AzBuf, Debug, Serialize)]
417#[serde(rename_all = "snake_case")]
418pub enum EquipmentSlotGroup {
419    Any,
420    Mainhand,
421    Offhand,
422    Hand,
423    Feet,
424    Legs,
425    Chest,
426    Head,
427    Armor,
428    Body,
429}
430
431// this is duplicated in azalea-entity, BUT the one there has a different
432// protocol format (and we can't use it anyways because it would cause a
433// circular dependency)
434#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
435pub struct AttributeModifier {
436    pub id: Identifier,
437    pub amount: f64,
438    pub operation: AttributeModifierOperation,
439}
440
441#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
442pub struct AttributeModifiersEntry {
443    #[serde(rename = "type")]
444    pub kind: Attribute,
445    #[serde(flatten)]
446    pub modifier: AttributeModifier,
447    pub slot: EquipmentSlotGroup,
448    #[serde(skip_serializing_if = "is_default")]
449    pub display: AttributeModifierDisplay,
450}
451
452#[derive(Clone, PartialEq, AzBuf, Debug, Serialize, Default)]
453#[serde(transparent)]
454pub struct AttributeModifiers {
455    pub modifiers: Vec<AttributeModifiersEntry>,
456}
457
458#[derive(Clone, PartialEq, AzBuf, Debug, Default, Serialize)]
459#[serde(rename_all = "snake_case")]
460pub enum AttributeModifierDisplay {
461    #[default]
462    Default,
463    Hidden,
464    Override {
465        text: FormattedText,
466    },
467}
468
469#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
470pub struct CustomModelData {
471    #[serde(skip_serializing_if = "Vec::is_empty")]
472    pub floats: Vec<f32>,
473    #[serde(skip_serializing_if = "Vec::is_empty")]
474    pub flags: Vec<bool>,
475    #[serde(skip_serializing_if = "Vec::is_empty")]
476    pub strings: Vec<String>,
477    #[serde(skip_serializing_if = "Vec::is_empty")]
478    pub colors: Vec<i32>,
479}
480
481#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
482#[serde(transparent)]
483pub struct RepairCost {
484    #[var]
485    pub cost: u32,
486}
487
488#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
489pub struct CreativeSlotLock;
490
491#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
492#[serde(transparent)]
493pub struct EnchantmentGlintOverride {
494    pub show_glint: bool,
495}
496
497#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
498pub struct IntangibleProjectile;
499
500#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
501pub struct MobEffectDetails {
502    #[var]
503    #[serde(skip_serializing_if = "is_default")]
504    pub amplifier: i32,
505    #[var]
506    #[serde(skip_serializing_if = "is_default")]
507    pub duration: i32,
508    #[serde(skip_serializing_if = "is_default")]
509    pub ambient: bool,
510    #[serde(skip_serializing_if = "is_default")]
511    pub show_particles: bool,
512    pub show_icon: bool,
513    #[serde(skip_serializing_if = "is_default")]
514    pub hidden_effect: Option<Box<MobEffectDetails>>,
515}
516impl MobEffectDetails {
517    pub const fn new() -> Self {
518        MobEffectDetails {
519            amplifier: 0,
520            duration: 0,
521            ambient: false,
522            show_particles: true,
523            show_icon: true,
524            hidden_effect: None,
525        }
526    }
527}
528impl Default for MobEffectDetails {
529    fn default() -> Self {
530        Self::new()
531    }
532}
533
534#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
535pub struct MobEffectInstance {
536    pub id: MobEffect,
537    #[serde(flatten)]
538    pub details: MobEffectDetails,
539}
540
541#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
542pub struct PossibleEffect {
543    pub effect: MobEffectInstance,
544    pub probability: f32,
545}
546
547#[derive(Clone, PartialEq, AzBuf, Debug, Default, Serialize)]
548pub struct Food {
549    #[var]
550    pub nutrition: i32,
551    pub saturation: f32,
552    #[serde(skip_serializing_if = "is_default")]
553    pub can_always_eat: bool,
554}
555
556impl Food {
557    pub const fn new() -> Self {
558        Food {
559            nutrition: 0,
560            saturation: 0.,
561            can_always_eat: false,
562        }
563    }
564}
565
566#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
567pub struct ToolRule {
568    pub blocks: HolderSet<BlockKind, Identifier>,
569    #[serde(skip_serializing_if = "is_default")]
570    pub speed: Option<f32>,
571    #[serde(skip_serializing_if = "is_default")]
572    pub correct_for_drops: Option<bool>,
573}
574impl ToolRule {
575    pub const fn new() -> Self {
576        ToolRule {
577            blocks: HolderSet::Direct { contents: vec![] },
578            speed: None,
579            correct_for_drops: None,
580        }
581    }
582}
583impl Default for ToolRule {
584    fn default() -> Self {
585        Self::new()
586    }
587}
588
589#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
590pub struct Tool {
591    #[serde(serialize_with = "flatten_array")]
592    pub rules: Vec<ToolRule>,
593    #[serde(skip_serializing_if = "is_default")]
594    pub default_mining_speed: f32,
595    #[var]
596    #[serde(skip_serializing_if = "is_default")]
597    pub damage_per_block: i32,
598    #[serde(skip_serializing_if = "is_default")]
599    pub can_destroy_blocks_in_creative: bool,
600}
601
602impl Tool {
603    pub const fn new() -> Self {
604        Tool {
605            rules: vec![],
606            default_mining_speed: 1.,
607            damage_per_block: 1,
608            can_destroy_blocks_in_creative: true,
609        }
610    }
611}
612impl Default for Tool {
613    fn default() -> Self {
614        Self::new()
615    }
616}
617
618#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
619#[serde(transparent)]
620pub struct StoredEnchantments {
621    #[var]
622    pub enchantments: HashMap<Enchantment, i32>,
623}
624
625#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
626#[serde(transparent)]
627pub struct DyedColor {
628    pub rgb: i32,
629}
630
631#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
632#[serde(transparent)]
633pub struct MapColor {
634    pub color: i32,
635}
636
637#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
638#[serde(transparent)]
639pub struct MapId {
640    #[var]
641    pub id: i32,
642}
643
644#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
645#[serde(transparent)]
646pub struct MapDecorations {
647    pub decorations: NbtCompound,
648}
649
650#[derive(Clone, Copy, PartialEq, AzBuf, Debug, Serialize)]
651pub enum MapPostProcessing {
652    Lock,
653    Scale,
654}
655
656#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
657#[serde(transparent)]
658pub struct ChargedProjectiles {
659    pub items: Vec<ItemStack>,
660}
661
662#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
663#[serde(transparent)]
664pub struct BundleContents {
665    pub items: Vec<ItemStack>,
666}
667
668#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
669pub struct PotionContents {
670    #[serde(skip_serializing_if = "is_default")]
671    pub potion: Option<Potion>,
672    #[serde(skip_serializing_if = "is_default")]
673    pub custom_color: Option<i32>,
674    #[serde(skip_serializing_if = "is_default")]
675    pub custom_effects: Vec<MobEffectInstance>,
676    #[serde(skip_serializing_if = "is_default")]
677    pub custom_name: Option<String>,
678}
679
680impl PotionContents {
681    pub const fn new() -> Self {
682        PotionContents {
683            potion: None,
684            custom_color: None,
685            custom_effects: vec![],
686            custom_name: None,
687        }
688    }
689}
690impl Default for PotionContents {
691    fn default() -> Self {
692        Self::new()
693    }
694}
695
696#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
697pub struct SuspiciousStewEffect {
698    #[serde(rename = "id")]
699    pub effect: MobEffect,
700    #[var]
701    #[serde(skip_serializing_if = "is_default")]
702    pub duration: i32,
703}
704
705#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
706#[serde(transparent)]
707pub struct SuspiciousStewEffects {
708    pub effects: Vec<SuspiciousStewEffect>,
709}
710
711#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
712pub struct WritableBookContent {
713    pub pages: Vec<Filterable<String>>,
714}
715
716#[derive(Clone, PartialEq, AzBuf, Serialize)]
717pub struct WrittenBookContent {
718    #[limit(32)]
719    pub title: Filterable<String>,
720    pub author: String,
721    #[var]
722    #[serde(skip_serializing_if = "is_default")]
723    pub generation: i32,
724    #[serde(skip_serializing_if = "is_default")]
725    pub pages: Vec<Filterable<FormattedText>>,
726    #[serde(skip_serializing_if = "is_default")]
727    pub resolved: bool,
728}
729
730#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
731pub struct Trim {
732    pub material: TrimMaterial,
733    pub pattern: TrimPattern,
734}
735
736#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
737#[serde(transparent)]
738pub struct DebugStickState {
739    pub properties: NbtCompound,
740}
741
742#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
743pub struct EntityData {
744    #[serde(rename = "id")]
745    pub kind: EntityKind,
746    #[serde(flatten)]
747    pub data: NbtCompound,
748}
749
750#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
751#[serde(transparent)]
752pub struct BucketEntityData {
753    pub entity: NbtCompound,
754}
755
756#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
757pub struct BlockEntityData {
758    #[serde(rename = "id")]
759    pub kind: EntityKind,
760    #[serde(flatten)]
761    pub data: NbtCompound,
762}
763
764#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
765#[serde(untagged)]
766pub enum Instrument {
767    Registry(data::Instrument),
768    Holder(Holder<data::Instrument, InstrumentData>),
769}
770
771#[derive(Clone, PartialEq, Debug, AzBuf, Serialize)]
772pub struct InstrumentData {
773    pub sound_event: Holder<SoundEvent, azalea_core::sound::CustomSound>,
774    pub use_duration: f32,
775    pub range: f32,
776    pub description: FormattedText,
777}
778
779#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
780#[serde(transparent)]
781pub struct OminousBottleAmplifier {
782    #[var]
783    pub amplifier: i32,
784}
785
786#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
787#[serde(transparent)]
788pub struct Recipes {
789    pub recipes: Vec<Identifier>,
790}
791
792#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
793pub struct LodestoneTracker {
794    #[serde(skip_serializing_if = "is_default")]
795    pub target: Option<GlobalPos>,
796    #[serde(skip_serializing_if = "is_true")]
797    pub tracked: bool,
798}
799
800#[derive(Clone, Copy, PartialEq, AzBuf, Debug, Serialize)]
801#[serde(rename_all = "snake_case")]
802pub enum FireworkExplosionShape {
803    SmallBall,
804    LargeBall,
805    Star,
806    Creeper,
807    Burst,
808}
809
810#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
811pub struct FireworkExplosion {
812    pub shape: FireworkExplosionShape,
813    #[serde(skip_serializing_if = "is_default")]
814    pub colors: Vec<i32>,
815    #[serde(skip_serializing_if = "is_default")]
816    pub fade_colors: Vec<i32>,
817    #[serde(skip_serializing_if = "is_default")]
818    pub has_trail: bool,
819    #[serde(skip_serializing_if = "is_default")]
820    pub has_twinkle: bool,
821}
822
823#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
824pub struct Fireworks {
825    #[var]
826    #[serde(skip_serializing_if = "is_default")]
827    pub flight_duration: i32,
828    #[limit(256)]
829    pub explosions: Vec<FireworkExplosion>,
830}
831
832impl Fireworks {
833    pub const fn new() -> Self {
834        Fireworks {
835            flight_duration: 0,
836            explosions: vec![],
837        }
838    }
839}
840impl Default for Fireworks {
841    fn default() -> Self {
842        Self::new()
843    }
844}
845
846#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
847#[serde(transparent)]
848pub struct NoteBlockSound {
849    pub sound: Identifier,
850}
851
852#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
853pub struct BannerPattern {
854    #[var]
855    pub pattern: i32,
856    #[var]
857    pub color: i32,
858}
859
860#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
861#[serde(transparent)]
862pub struct BannerPatterns {
863    pub patterns: Vec<BannerPattern>,
864}
865
866#[derive(Clone, Copy, PartialEq, AzBuf, Debug, Serialize)]
867#[serde(rename_all = "snake_case")]
868pub enum DyeColor {
869    White,
870    Orange,
871    Magenta,
872    LightBlue,
873    Yellow,
874    Lime,
875    Pink,
876    Gray,
877    LightGray,
878    Cyan,
879    Purple,
880    Blue,
881    Brown,
882    Green,
883    Red,
884    Black,
885}
886
887#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
888#[serde(transparent)]
889pub struct BaseColor {
890    pub color: DyeColor,
891}
892
893#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
894#[serde(transparent)]
895pub struct PotDecorations {
896    pub items: Vec<ItemKind>,
897}
898
899#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
900#[serde(transparent)]
901pub struct Container {
902    pub items: Vec<ItemStack>,
903}
904
905#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
906#[serde(transparent)]
907pub struct BlockState {
908    pub properties: HashMap<String, String>,
909}
910
911#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
912pub struct BeehiveOccupant {
913    #[serde(skip_serializing_if = "is_default")]
914    pub entity_data: NbtCompound,
915    #[var]
916    pub ticks_in_hive: i32,
917    #[var]
918    pub min_ticks_in_hive: i32,
919}
920
921#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
922#[serde(transparent)]
923pub struct Bees {
924    pub occupants: Vec<BeehiveOccupant>,
925}
926
927#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
928pub struct Lock {
929    pub key: String,
930}
931
932#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
933pub struct ContainerLoot {
934    pub loot_table: NbtCompound,
935}
936
937#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
938#[serde(untagged)]
939pub enum JukeboxPlayable {
940    Referenced(Identifier),
941    Direct(Holder<JukeboxSong, JukeboxSongData>),
942}
943
944#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
945pub struct JukeboxSongData {
946    pub sound_event: Holder<SoundEvent, CustomSound>,
947    pub description: FormattedText,
948    pub length_in_seconds: f32,
949    #[var]
950    pub comparator_output: i32,
951}
952
953#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
954pub struct Consumable {
955    #[serde(skip_serializing_if = "is_default")]
956    pub consume_seconds: f32,
957    #[serde(skip_serializing_if = "is_default")]
958    pub animation: ItemUseAnimation,
959    #[serde(skip_serializing_if = "is_default_eat_sound")]
960    pub sound: azalea_registry::Holder<SoundEvent, CustomSound>,
961    #[serde(skip_serializing_if = "is_default")]
962    pub has_consume_particles: bool,
963    #[serde(skip_serializing_if = "is_default")]
964    pub on_consume_effects: Vec<ConsumeEffect>,
965}
966fn is_default_eat_sound(sound: &azalea_registry::Holder<SoundEvent, CustomSound>) -> bool {
967    matches!(
968        sound,
969        azalea_registry::Holder::Reference(SoundEvent::EntityGenericEat)
970    )
971}
972
973impl Consumable {
974    pub const fn new() -> Self {
975        Self {
976            consume_seconds: 1.6,
977            animation: ItemUseAnimation::Eat,
978            sound: azalea_registry::Holder::Reference(SoundEvent::EntityGenericEat),
979            has_consume_particles: true,
980            on_consume_effects: Vec::new(),
981        }
982    }
983}
984impl Default for Consumable {
985    fn default() -> Self {
986        Self::new()
987    }
988}
989
990#[derive(Clone, Copy, PartialEq, AzBuf, Debug, Default, Serialize)]
991#[serde(rename_all = "snake_case")]
992pub enum ItemUseAnimation {
993    #[default]
994    None,
995    Eat,
996    Drink,
997    BlockKind,
998    Bow,
999    Spear,
1000    Crossbow,
1001    Spyglass,
1002    TootHorn,
1003    Brush,
1004}
1005
1006#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1007#[serde(transparent)]
1008pub struct UseRemainder {
1009    pub convert_into: ItemStack,
1010}
1011
1012#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1013pub struct UseCooldown {
1014    pub seconds: f32,
1015    #[serde(skip_serializing_if = "is_default")]
1016    pub cooldown_group: Option<Identifier>,
1017}
1018
1019impl UseCooldown {
1020    pub const fn new() -> Self {
1021        Self {
1022            seconds: 0.,
1023            cooldown_group: None,
1024        }
1025    }
1026}
1027impl Default for UseCooldown {
1028    fn default() -> Self {
1029        Self::new()
1030    }
1031}
1032
1033#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1034pub struct Enchantable {
1035    #[var]
1036    pub value: u32,
1037}
1038
1039#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1040pub struct Repairable {
1041    pub items: HolderSet<ItemKind, Identifier>,
1042}
1043
1044#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1045#[serde(transparent)]
1046pub struct ItemModel {
1047    pub resource_location: Identifier,
1048}
1049
1050#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1051pub struct DamageResistant {
1052    /// In vanilla this only allows tag keys, i.e. it must start with '#'
1053    pub types: Identifier,
1054}
1055
1056#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1057pub struct Equippable {
1058    pub slot: EquipmentSlot,
1059    #[serde(skip_serializing_if = "is_default_equip_sound")]
1060    pub equip_sound: SoundEvent,
1061    #[serde(skip_serializing_if = "is_default")]
1062    pub asset_id: Option<Identifier>,
1063    #[serde(skip_serializing_if = "is_default")]
1064    pub camera_overlay: Option<Identifier>,
1065    #[serde(skip_serializing_if = "is_default")]
1066    pub allowed_entities: Option<HolderSet<EntityKind, Identifier>>,
1067    #[serde(skip_serializing_if = "is_true")]
1068    pub dispensable: bool,
1069    #[serde(skip_serializing_if = "is_true")]
1070    pub swappable: bool,
1071    #[serde(skip_serializing_if = "is_true")]
1072    pub damage_on_hurt: bool,
1073    #[serde(skip_serializing_if = "is_default")]
1074    pub equip_on_interact: bool,
1075    #[serde(skip_serializing_if = "is_default")]
1076    pub can_be_sheared: bool,
1077    #[serde(skip_serializing_if = "is_default_shearing_sound")]
1078    pub shearing_sound: SoundEvent,
1079}
1080fn is_default_equip_sound(sound: &SoundEvent) -> bool {
1081    matches!(sound, SoundEvent::ItemArmorEquipGeneric)
1082}
1083fn is_default_shearing_sound(sound: &SoundEvent) -> bool {
1084    matches!(sound, SoundEvent::ItemShearsSnip)
1085}
1086
1087impl Equippable {
1088    pub const fn new() -> Self {
1089        Self {
1090            slot: EquipmentSlot::Body,
1091            equip_sound: SoundEvent::ItemArmorEquipGeneric,
1092            asset_id: None,
1093            camera_overlay: None,
1094            allowed_entities: None,
1095            dispensable: true,
1096            swappable: true,
1097            damage_on_hurt: true,
1098            equip_on_interact: false,
1099            can_be_sheared: false,
1100            shearing_sound: SoundEvent::ItemShearsSnip,
1101        }
1102    }
1103}
1104impl Default for Equippable {
1105    fn default() -> Self {
1106        Self::new()
1107    }
1108}
1109
1110/// An enum that represents inventory slots that can hold items.
1111#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, AzBuf, Serialize)]
1112#[serde(rename_all = "snake_case")]
1113pub enum EquipmentSlot {
1114    Mainhand,
1115    Offhand,
1116    Feet,
1117    Legs,
1118    Chest,
1119    Head,
1120    /// This is for animal armor, use [`Self::Chest`] for the chestplate slot.
1121    Body,
1122    Saddle,
1123}
1124impl EquipmentSlot {
1125    #[must_use]
1126    pub fn from_byte(byte: u8) -> Option<Self> {
1127        let value = match byte {
1128            0 => Self::Mainhand,
1129            1 => Self::Offhand,
1130            2 => Self::Feet,
1131            3 => Self::Legs,
1132            4 => Self::Chest,
1133            5 => Self::Head,
1134            _ => return None,
1135        };
1136        Some(value)
1137    }
1138    pub fn values() -> [Self; 8] {
1139        [
1140            Self::Mainhand,
1141            Self::Offhand,
1142            Self::Feet,
1143            Self::Legs,
1144            Self::Chest,
1145            Self::Head,
1146            Self::Body,
1147            Self::Saddle,
1148        ]
1149    }
1150    /// Get the display name for the equipment slot, like "mainhand".
1151    pub fn name(self) -> &'static str {
1152        match self {
1153            Self::Mainhand => "mainhand",
1154            Self::Offhand => "offhand",
1155            Self::Feet => "feet",
1156            Self::Legs => "legs",
1157            Self::Chest => "chest",
1158            Self::Head => "head",
1159            Self::Body => "body",
1160            Self::Saddle => "saddle",
1161        }
1162    }
1163}
1164impl Display for EquipmentSlot {
1165    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1166        write!(f, "{}", self.name())
1167    }
1168}
1169
1170#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1171pub struct Glider;
1172
1173#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1174#[serde(transparent)]
1175pub struct TooltipStyle {
1176    pub resource_location: Identifier,
1177}
1178
1179#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1180pub struct DeathProtection {
1181    pub death_effects: Vec<ConsumeEffect>,
1182}
1183
1184#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1185pub struct Weapon {
1186    #[var]
1187    #[serde(skip_serializing_if = "is_default_item_damage_per_attack")]
1188    pub item_damage_per_attack: i32,
1189    #[serde(skip_serializing_if = "is_default")]
1190    pub disable_blocking_for_seconds: f32,
1191}
1192fn is_default_item_damage_per_attack(value: &i32) -> bool {
1193    *value == 1
1194}
1195
1196impl Weapon {
1197    pub const fn new() -> Self {
1198        Self {
1199            item_damage_per_attack: 1,
1200            disable_blocking_for_seconds: 0.,
1201        }
1202    }
1203}
1204impl Default for Weapon {
1205    fn default() -> Self {
1206        Self::new()
1207    }
1208}
1209
1210#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1211#[serde(transparent)]
1212pub struct PotionDurationScale {
1213    pub value: f32,
1214}
1215
1216#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1217#[serde(transparent)]
1218pub struct VillagerVariant {
1219    pub variant: VillagerKind,
1220}
1221
1222#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1223#[serde(transparent)]
1224pub struct WolfVariant {
1225    pub variant: data::WolfVariant,
1226}
1227
1228#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1229#[serde(transparent)]
1230pub struct WolfCollar {
1231    pub color: DyeColor,
1232}
1233
1234#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1235#[serde(transparent)]
1236pub struct FoxVariant {
1237    pub variant: FoxVariantKind,
1238}
1239
1240#[derive(Default, AzBuf, Clone, Copy, Debug, PartialEq)]
1241pub enum FoxVariantKind {
1242    #[default]
1243    Red,
1244    Snow,
1245}
1246impl Display for FoxVariantKind {
1247    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1248        match self {
1249            Self::Red => write!(f, "minecraft:red"),
1250            Self::Snow => write!(f, "minecraft:snow"),
1251        }
1252    }
1253}
1254impl Serialize for FoxVariantKind {
1255    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1256    where
1257        S: Serializer,
1258    {
1259        serializer.serialize_str(&self.to_string())
1260    }
1261}
1262
1263#[derive(Clone, Copy, PartialEq, AzBuf, Debug, Serialize)]
1264#[serde(rename_all = "snake_case")]
1265pub enum SalmonSize {
1266    Small,
1267    Medium,
1268    Large,
1269}
1270
1271#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1272#[serde(transparent)]
1273pub struct ParrotVariant {
1274    pub variant: ParrotVariantKind,
1275}
1276#[derive(AzBuf, Clone, Copy, Debug, PartialEq)]
1277pub enum ParrotVariantKind {
1278    RedBlue,
1279    Blue,
1280    Green,
1281    YellowBlue,
1282    Gray,
1283}
1284impl Display for ParrotVariantKind {
1285    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1286        match self {
1287            Self::RedBlue => write!(f, "minecraft:red_blue"),
1288            Self::Blue => write!(f, "minecraft:blue"),
1289            Self::Green => write!(f, "minecraft:green"),
1290            Self::YellowBlue => write!(f, "minecraft:yellow_blue"),
1291            Self::Gray => write!(f, "minecraft:gray"),
1292        }
1293    }
1294}
1295impl Serialize for ParrotVariantKind {
1296    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1297    where
1298        S: Serializer,
1299    {
1300        serializer.serialize_str(&self.to_string())
1301    }
1302}
1303
1304#[derive(Clone, Copy, PartialEq, AzBuf, Debug, Serialize)]
1305#[serde(rename_all = "snake_case")]
1306pub enum TropicalFishPattern {
1307    Kob,
1308    Sunstreak,
1309    Snooper,
1310    Dasher,
1311    Brinely,
1312    Spotty,
1313    Flopper,
1314    Stripey,
1315    Glitter,
1316    Blockfish,
1317    Betty,
1318    Clayfish,
1319}
1320
1321#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1322#[serde(transparent)]
1323pub struct TropicalFishBaseColor {
1324    pub color: DyeColor,
1325}
1326
1327#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1328#[serde(transparent)]
1329pub struct TropicalFishPatternColor {
1330    pub color: DyeColor,
1331}
1332
1333#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1334#[serde(transparent)]
1335pub struct MooshroomVariant {
1336    pub variant: MooshroomVariantKind,
1337}
1338#[derive(Default, AzBuf, Clone, Copy, Debug, PartialEq)]
1339pub enum MooshroomVariantKind {
1340    #[default]
1341    Red,
1342    Brown,
1343}
1344impl Display for MooshroomVariantKind {
1345    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1346        match self {
1347            Self::Red => write!(f, "minecraft:red"),
1348            Self::Brown => write!(f, "minecraft:brown"),
1349        }
1350    }
1351}
1352impl Serialize for MooshroomVariantKind {
1353    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1354    where
1355        S: Serializer,
1356    {
1357        serializer.serialize_str(&self.to_string())
1358    }
1359}
1360
1361#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1362#[serde(transparent)]
1363pub struct RabbitVariant {
1364    pub variant: RabbitVariantKind,
1365}
1366#[derive(Default, AzBuf, Clone, Copy, Debug, PartialEq)]
1367pub enum RabbitVariantKind {
1368    #[default]
1369    Brown,
1370    White,
1371    Black,
1372    WhiteSplotched,
1373    Gold,
1374    Salt,
1375    Evil,
1376}
1377impl Display for RabbitVariantKind {
1378    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1379        match self {
1380            Self::Brown => write!(f, "minecraft:brown"),
1381            Self::White => write!(f, "minecraft:white"),
1382            Self::Black => write!(f, "minecraft:black"),
1383            Self::WhiteSplotched => write!(f, "minecraft:white_splotched"),
1384            Self::Gold => write!(f, "minecraft:gold"),
1385            Self::Salt => write!(f, "minecraft:salt"),
1386            Self::Evil => write!(f, "minecraft:evil"),
1387        }
1388    }
1389}
1390impl Serialize for RabbitVariantKind {
1391    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1392    where
1393        S: Serializer,
1394    {
1395        serializer.serialize_str(&self.to_string())
1396    }
1397}
1398
1399#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1400#[serde(transparent)]
1401pub struct PigVariant {
1402    pub variant: data::PigVariant,
1403}
1404
1405#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1406#[serde(transparent)]
1407pub struct FrogVariant {
1408    pub variant: data::FrogVariant,
1409}
1410
1411#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1412#[serde(transparent)]
1413pub struct HorseVariant {
1414    pub variant: HorseVariantKind,
1415}
1416#[derive(Default, AzBuf, Clone, Copy, Debug, PartialEq)]
1417pub enum HorseVariantKind {
1418    #[default]
1419    White,
1420    Creamy,
1421    Chestnut,
1422    Brown,
1423    Black,
1424    Gray,
1425    DarkBrown,
1426}
1427impl Display for HorseVariantKind {
1428    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1429        match self {
1430            Self::White => write!(f, "minecraft:white"),
1431            Self::Creamy => write!(f, "minecraft:creamy"),
1432            Self::Chestnut => write!(f, "minecraft:chestnut"),
1433            Self::Brown => write!(f, "minecraft:brown"),
1434            Self::Black => write!(f, "minecraft:black"),
1435            Self::Gray => write!(f, "minecraft:gray"),
1436            Self::DarkBrown => write!(f, "minecraft:dark_brown"),
1437        }
1438    }
1439}
1440impl Serialize for HorseVariantKind {
1441    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1442    where
1443        S: Serializer,
1444    {
1445        serializer.serialize_str(&self.to_string())
1446    }
1447}
1448
1449#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1450#[serde(transparent)]
1451pub struct PaintingVariant {
1452    pub variant: Holder<data::PaintingVariant, PaintingVariantData>,
1453}
1454
1455#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1456pub struct PaintingVariantData {
1457    #[var]
1458    pub width: i32,
1459    #[var]
1460    pub height: i32,
1461    pub asset_id: Identifier,
1462    #[serde(skip_serializing_if = "is_default")]
1463    pub title: Option<FormattedText>,
1464    #[serde(skip_serializing_if = "is_default")]
1465    pub author: Option<FormattedText>,
1466}
1467
1468#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1469#[serde(transparent)]
1470pub struct LlamaVariant {
1471    pub variant: LlamaVariantKind,
1472}
1473#[derive(Default, AzBuf, Clone, Copy, Debug, PartialEq)]
1474pub enum LlamaVariantKind {
1475    #[default]
1476    Creamy,
1477    White,
1478    Brown,
1479    Gray,
1480}
1481impl Display for LlamaVariantKind {
1482    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1483        match self {
1484            Self::Creamy => write!(f, "minecraft:creamy"),
1485            Self::White => write!(f, "minecraft:white"),
1486            Self::Brown => write!(f, "minecraft:brown"),
1487            Self::Gray => write!(f, "minecraft:gray"),
1488        }
1489    }
1490}
1491impl Serialize for LlamaVariantKind {
1492    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1493    where
1494        S: Serializer,
1495    {
1496        serializer.serialize_str(&self.to_string())
1497    }
1498}
1499
1500#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1501#[serde(transparent)]
1502pub struct AxolotlVariant {
1503    pub variant: AxolotlVariantKind,
1504}
1505#[derive(Default, AzBuf, Clone, Copy, Debug, PartialEq)]
1506pub enum AxolotlVariantKind {
1507    #[default]
1508    Lucy,
1509    Wild,
1510    Gold,
1511    Cyan,
1512    Blue,
1513}
1514impl Display for AxolotlVariantKind {
1515    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1516        match self {
1517            Self::Lucy => write!(f, "minecraft:lucy"),
1518            Self::Wild => write!(f, "minecraft:wild"),
1519            Self::Gold => write!(f, "minecraft:gold"),
1520            Self::Cyan => write!(f, "minecraft:cyan"),
1521            Self::Blue => write!(f, "minecraft:blue"),
1522        }
1523    }
1524}
1525impl Serialize for AxolotlVariantKind {
1526    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1527    where
1528        S: Serializer,
1529    {
1530        serializer.serialize_str(&self.to_string())
1531    }
1532}
1533
1534#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1535#[serde(transparent)]
1536pub struct CatVariant {
1537    pub variant: data::CatVariant,
1538}
1539
1540#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1541#[serde(transparent)]
1542pub struct CatCollar {
1543    pub color: DyeColor,
1544}
1545
1546#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1547#[serde(transparent)]
1548pub struct SheepColor {
1549    pub color: DyeColor,
1550}
1551
1552#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1553#[serde(transparent)]
1554pub struct ShulkerColor {
1555    pub color: DyeColor,
1556}
1557
1558#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1559pub struct TooltipDisplay {
1560    #[serde(skip_serializing_if = "is_default")]
1561    pub hide_tooltip: bool,
1562    #[serde(skip_serializing_if = "is_default")]
1563    pub hidden_components: Vec<DataComponentKind>,
1564}
1565
1566impl TooltipDisplay {
1567    pub const fn new() -> Self {
1568        Self {
1569            hide_tooltip: false,
1570            hidden_components: Vec::new(),
1571        }
1572    }
1573}
1574impl Default for TooltipDisplay {
1575    fn default() -> Self {
1576        Self::new()
1577    }
1578}
1579
1580#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1581pub struct BlocksAttacks {
1582    #[serde(skip_serializing_if = "is_default")]
1583    pub block_delay_seconds: f32,
1584    #[serde(skip_serializing_if = "is_default_disable_cooldown_scale")]
1585    pub disable_cooldown_scale: f32,
1586    #[serde(skip_serializing_if = "is_default")]
1587    pub damage_reductions: Vec<DamageReduction>,
1588    #[serde(skip_serializing_if = "is_default")]
1589    pub item_damage: ItemDamageFunction,
1590    #[serde(skip_serializing_if = "is_default")]
1591    pub bypassed_by: Option<Identifier>,
1592    #[serde(skip_serializing_if = "is_default")]
1593    pub block_sound: Option<azalea_registry::Holder<SoundEvent, CustomSound>>,
1594    #[serde(skip_serializing_if = "is_default")]
1595    pub disabled_sound: Option<azalea_registry::Holder<SoundEvent, CustomSound>>,
1596}
1597fn is_default_disable_cooldown_scale(value: &f32) -> bool {
1598    *value == 1.
1599}
1600
1601impl BlocksAttacks {
1602    pub fn new() -> Self {
1603        Self {
1604            block_delay_seconds: 0.,
1605            disable_cooldown_scale: 1.,
1606            damage_reductions: vec![DamageReduction {
1607                horizontal_blocking_angle: 90.,
1608                kind: None,
1609                base: 0.,
1610                factor: 1.,
1611            }],
1612            item_damage: ItemDamageFunction::default(),
1613            bypassed_by: None,
1614            block_sound: None,
1615            disabled_sound: None,
1616        }
1617    }
1618}
1619impl Default for BlocksAttacks {
1620    fn default() -> Self {
1621        Self::new()
1622    }
1623}
1624
1625#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1626pub struct DamageReduction {
1627    #[serde(skip_serializing_if = "is_default_horizontal_blocking_angle")]
1628    pub horizontal_blocking_angle: f32,
1629    #[serde(skip_serializing_if = "is_default")]
1630    pub kind: Option<HolderSet<DamageKind, Identifier>>,
1631    pub base: f32,
1632    pub factor: f32,
1633}
1634fn is_default_horizontal_blocking_angle(value: &f32) -> bool {
1635    *value == 90.
1636}
1637#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1638pub struct ItemDamageFunction {
1639    pub threshold: f32,
1640    pub base: f32,
1641    pub factor: f32,
1642}
1643impl Default for ItemDamageFunction {
1644    fn default() -> Self {
1645        ItemDamageFunction {
1646            threshold: 1.,
1647            base: 0.,
1648            factor: 1.,
1649        }
1650    }
1651}
1652
1653#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1654#[serde(untagged)]
1655pub enum ProvidesTrimMaterial {
1656    Referenced(Identifier),
1657    Direct(Holder<TrimMaterial, DirectTrimMaterial>),
1658}
1659
1660#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1661pub struct DirectTrimMaterial {
1662    pub assets: MaterialAssetGroup,
1663    pub description: FormattedText,
1664}
1665#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1666pub struct MaterialAssetGroup {
1667    pub base: AssetInfo,
1668    #[serde(skip_serializing_if = "is_default")]
1669    pub overrides: Vec<(Identifier, AssetInfo)>,
1670}
1671
1672#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1673pub struct AssetInfo {
1674    pub suffix: String,
1675}
1676
1677#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1678#[serde(transparent)]
1679pub struct ProvidesBannerPatterns {
1680    pub key: Identifier,
1681}
1682
1683#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1684#[serde(transparent)]
1685pub struct BreakSound {
1686    pub sound: azalea_registry::Holder<SoundEvent, CustomSound>,
1687}
1688
1689#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1690#[serde(transparent)]
1691pub struct WolfSoundVariant {
1692    pub variant: azalea_registry::data::WolfSoundVariant,
1693}
1694
1695#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1696#[serde(transparent)]
1697pub struct CowVariant {
1698    pub variant: azalea_registry::data::CowVariant,
1699}
1700
1701#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1702#[serde(untagged)]
1703pub enum ChickenVariant {
1704    Referenced(Identifier),
1705    Direct(ChickenVariantData),
1706}
1707
1708#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1709pub struct ChickenVariantData {
1710    pub registry: azalea_registry::data::ChickenVariant,
1711}
1712
1713// TODO: check in-game if this is correct
1714#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1715pub enum ZombieNautilusVariant {
1716    Referenced(Identifier),
1717    Direct(ZombieNautilusVariantData),
1718}
1719#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1720#[serde(transparent)]
1721pub struct ZombieNautilusVariantData {
1722    pub value: azalea_registry::data::ZombieNautilusVariant,
1723}
1724
1725#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1726pub struct UseEffects {
1727    pub can_sprint: bool,
1728    pub interact_vibrations: bool,
1729    pub speed_multiplier: f32,
1730}
1731impl UseEffects {
1732    pub const fn new() -> Self {
1733        Self {
1734            can_sprint: false,
1735            interact_vibrations: true,
1736            speed_multiplier: 0.2,
1737        }
1738    }
1739}
1740impl Default for UseEffects {
1741    fn default() -> Self {
1742        Self::new()
1743    }
1744}
1745
1746#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1747#[serde(transparent)]
1748pub struct MinimumAttackCharge {
1749    pub value: f32,
1750}
1751
1752// TODO: this is probably wrong, check in-game
1753#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1754#[serde(untagged)]
1755pub enum DamageType {
1756    Registry(DamageKind),
1757    Holder(Holder<DamageKind, DamageTypeElement>),
1758}
1759
1760#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1761pub struct PiercingWeapon {
1762    pub deals_knockback: bool,
1763    pub dismounts: bool,
1764    pub sound: Option<Holder<SoundEvent, azalea_core::sound::CustomSound>>,
1765    pub hit_sound: Option<Holder<SoundEvent, azalea_core::sound::CustomSound>>,
1766}
1767impl PiercingWeapon {
1768    pub const fn new() -> Self {
1769        Self {
1770            deals_knockback: true,
1771            dismounts: false,
1772            sound: None,
1773            hit_sound: None,
1774        }
1775    }
1776}
1777impl Default for PiercingWeapon {
1778    fn default() -> Self {
1779        Self::new()
1780    }
1781}
1782
1783#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1784pub struct KineticWeapon {
1785    #[var]
1786    pub contact_cooldown_ticks: i32,
1787    #[var]
1788    pub delay_ticks: i32,
1789    pub dismount_conditions: Option<KineticWeaponCondition>,
1790    pub knockback_conditions: Option<KineticWeaponCondition>,
1791    pub damage_conditions: Option<KineticWeaponCondition>,
1792    pub forward_movement: f32,
1793    pub damage_multiplier: f32,
1794    pub sound: Option<Holder<SoundEvent, azalea_core::sound::CustomSound>>,
1795    pub hit_sound: Option<Holder<SoundEvent, azalea_core::sound::CustomSound>>,
1796}
1797impl KineticWeapon {
1798    pub const fn new() -> Self {
1799        Self {
1800            contact_cooldown_ticks: 10,
1801            delay_ticks: 0,
1802            dismount_conditions: None,
1803            knockback_conditions: None,
1804            damage_conditions: None,
1805            forward_movement: 0.,
1806            damage_multiplier: 1.,
1807            sound: None,
1808            hit_sound: None,
1809        }
1810    }
1811}
1812impl Default for KineticWeapon {
1813    fn default() -> Self {
1814        Self::new()
1815    }
1816}
1817
1818#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1819pub struct KineticWeaponCondition {
1820    #[var]
1821    pub max_duration_ticks: i32,
1822    pub min_speed: f32,
1823    pub min_relative_speed: f32,
1824}
1825impl KineticWeaponCondition {
1826    pub const fn new() -> Self {
1827        Self {
1828            max_duration_ticks: 0,
1829            min_speed: 0.,
1830            min_relative_speed: 0.,
1831        }
1832    }
1833}
1834impl Default for KineticWeaponCondition {
1835    fn default() -> Self {
1836        Self::new()
1837    }
1838}
1839
1840#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1841pub struct SwingAnimation {
1842    #[serde(rename = "type")]
1843    pub kind: SwingAnimationKind,
1844    #[var]
1845    pub duration: i32,
1846}
1847impl SwingAnimation {
1848    pub const fn new() -> Self {
1849        Self {
1850            kind: SwingAnimationKind::Whack,
1851            duration: 6,
1852        }
1853    }
1854}
1855impl Default for SwingAnimation {
1856    fn default() -> Self {
1857        Self::new()
1858    }
1859}
1860
1861#[derive(Clone, Copy, PartialEq, AzBuf, Debug, Serialize)]
1862#[serde(rename_all = "snake_case")]
1863pub enum SwingAnimationKind {
1864    None,
1865    Whack,
1866    Stab,
1867}
1868
1869#[derive(Clone, PartialEq, AzBuf, Debug, Serialize)]
1870pub struct AttackRange {
1871    pub min_reach: f32,
1872    pub max_reach: f32,
1873    pub min_creative_reach: f32,
1874    pub max_creative_reach: f32,
1875    pub hitbox_margin: f32,
1876    pub mob_factor: f32,
1877}
1878impl AttackRange {
1879    pub const fn new() -> Self {
1880        Self {
1881            min_reach: 0.,
1882            max_reach: 3.,
1883            min_creative_reach: 0.,
1884            max_creative_reach: 5.,
1885            hitbox_margin: 0.3,
1886            mob_factor: 1.,
1887        }
1888    }
1889}
1890impl Default for AttackRange {
1891    fn default() -> Self {
1892        Self::new()
1893    }
1894}