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