Skip to main content

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            6 => Self::Body,
1136            7 => Self::Saddle,
1137            _ => return None,
1138        };
1139        Some(value)
1140    }
1141    pub fn values() -> [Self; 8] {
1142        [
1143            Self::Mainhand,
1144            Self::Offhand,
1145            Self::Feet,
1146            Self::Legs,
1147            Self::Chest,
1148            Self::Head,
1149            Self::Body,
1150            Self::Saddle,
1151        ]
1152    }
1153    /// Get the display name for the equipment slot, like "mainhand".
1154    pub fn name(self) -> &'static str {
1155        match self {
1156            Self::Mainhand => "mainhand",
1157            Self::Offhand => "offhand",
1158            Self::Feet => "feet",
1159            Self::Legs => "legs",
1160            Self::Chest => "chest",
1161            Self::Head => "head",
1162            Self::Body => "body",
1163            Self::Saddle => "saddle",
1164        }
1165    }
1166}
1167impl Display for EquipmentSlot {
1168    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1169        write!(f, "{}", self.name())
1170    }
1171}
1172
1173#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1174pub struct Glider;
1175
1176#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1177#[serde(transparent)]
1178pub struct TooltipStyle {
1179    pub resource_location: Identifier,
1180}
1181
1182#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1183pub struct DeathProtection {
1184    pub death_effects: Vec<ConsumeEffect>,
1185}
1186
1187#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1188pub struct Weapon {
1189    #[var]
1190    #[serde(skip_serializing_if = "is_default_item_damage_per_attack")]
1191    pub item_damage_per_attack: i32,
1192    #[serde(skip_serializing_if = "is_default")]
1193    pub disable_blocking_for_seconds: f32,
1194}
1195fn is_default_item_damage_per_attack(value: &i32) -> bool {
1196    *value == 1
1197}
1198
1199impl Weapon {
1200    pub const fn new() -> Self {
1201        Self {
1202            item_damage_per_attack: 1,
1203            disable_blocking_for_seconds: 0.,
1204        }
1205    }
1206}
1207impl Default for Weapon {
1208    fn default() -> Self {
1209        Self::new()
1210    }
1211}
1212
1213#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1214#[serde(transparent)]
1215pub struct PotionDurationScale {
1216    pub value: f32,
1217}
1218
1219#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1220#[serde(transparent)]
1221pub struct VillagerVariant {
1222    pub variant: VillagerKind,
1223}
1224
1225#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1226#[serde(transparent)]
1227pub struct WolfVariant {
1228    pub variant: data::WolfVariant,
1229}
1230
1231#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1232#[serde(transparent)]
1233pub struct WolfCollar {
1234    pub color: DyeColor,
1235}
1236
1237#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1238#[serde(transparent)]
1239pub struct FoxVariant {
1240    pub variant: FoxVariantKind,
1241}
1242
1243#[derive(AzBuf, Clone, Copy, Debug, Default, PartialEq)]
1244pub enum FoxVariantKind {
1245    #[default]
1246    Red,
1247    Snow,
1248}
1249impl Display for FoxVariantKind {
1250    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1251        match self {
1252            Self::Red => write!(f, "minecraft:red"),
1253            Self::Snow => write!(f, "minecraft:snow"),
1254        }
1255    }
1256}
1257impl Serialize for FoxVariantKind {
1258    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1259    where
1260        S: Serializer,
1261    {
1262        serializer.serialize_str(&self.to_string())
1263    }
1264}
1265
1266#[derive(AzBuf, Clone, Copy, Debug, PartialEq, Serialize)]
1267#[serde(rename_all = "snake_case")]
1268pub enum SalmonSize {
1269    Small,
1270    Medium,
1271    Large,
1272}
1273
1274#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1275#[serde(transparent)]
1276pub struct ParrotVariant {
1277    pub variant: ParrotVariantKind,
1278}
1279#[derive(AzBuf, Clone, Copy, Debug, PartialEq)]
1280pub enum ParrotVariantKind {
1281    RedBlue,
1282    Blue,
1283    Green,
1284    YellowBlue,
1285    Gray,
1286}
1287impl Display for ParrotVariantKind {
1288    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1289        match self {
1290            Self::RedBlue => write!(f, "minecraft:red_blue"),
1291            Self::Blue => write!(f, "minecraft:blue"),
1292            Self::Green => write!(f, "minecraft:green"),
1293            Self::YellowBlue => write!(f, "minecraft:yellow_blue"),
1294            Self::Gray => write!(f, "minecraft:gray"),
1295        }
1296    }
1297}
1298impl Serialize for ParrotVariantKind {
1299    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1300    where
1301        S: Serializer,
1302    {
1303        serializer.serialize_str(&self.to_string())
1304    }
1305}
1306
1307#[derive(AzBuf, Clone, Copy, Debug, PartialEq, Serialize)]
1308#[serde(rename_all = "snake_case")]
1309pub enum TropicalFishPattern {
1310    Kob,
1311    Sunstreak,
1312    Snooper,
1313    Dasher,
1314    Brinely,
1315    Spotty,
1316    Flopper,
1317    Stripey,
1318    Glitter,
1319    Blockfish,
1320    Betty,
1321    Clayfish,
1322}
1323
1324#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1325#[serde(transparent)]
1326pub struct TropicalFishBaseColor {
1327    pub color: DyeColor,
1328}
1329
1330#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1331#[serde(transparent)]
1332pub struct TropicalFishPatternColor {
1333    pub color: DyeColor,
1334}
1335
1336#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1337#[serde(transparent)]
1338pub struct MooshroomVariant {
1339    pub variant: MooshroomVariantKind,
1340}
1341#[derive(AzBuf, Clone, Copy, Debug, Default, PartialEq)]
1342pub enum MooshroomVariantKind {
1343    #[default]
1344    Red,
1345    Brown,
1346}
1347impl Display for MooshroomVariantKind {
1348    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1349        match self {
1350            Self::Red => write!(f, "minecraft:red"),
1351            Self::Brown => write!(f, "minecraft:brown"),
1352        }
1353    }
1354}
1355impl Serialize for MooshroomVariantKind {
1356    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1357    where
1358        S: Serializer,
1359    {
1360        serializer.serialize_str(&self.to_string())
1361    }
1362}
1363
1364#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1365#[serde(transparent)]
1366pub struct RabbitVariant {
1367    pub variant: RabbitVariantKind,
1368}
1369#[derive(AzBuf, Clone, Copy, Debug, Default, PartialEq)]
1370pub enum RabbitVariantKind {
1371    #[default]
1372    Brown,
1373    White,
1374    Black,
1375    WhiteSplotched,
1376    Gold,
1377    Salt,
1378    Evil,
1379}
1380impl Display for RabbitVariantKind {
1381    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1382        match self {
1383            Self::Brown => write!(f, "minecraft:brown"),
1384            Self::White => write!(f, "minecraft:white"),
1385            Self::Black => write!(f, "minecraft:black"),
1386            Self::WhiteSplotched => write!(f, "minecraft:white_splotched"),
1387            Self::Gold => write!(f, "minecraft:gold"),
1388            Self::Salt => write!(f, "minecraft:salt"),
1389            Self::Evil => write!(f, "minecraft:evil"),
1390        }
1391    }
1392}
1393impl Serialize for RabbitVariantKind {
1394    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1395    where
1396        S: Serializer,
1397    {
1398        serializer.serialize_str(&self.to_string())
1399    }
1400}
1401
1402#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1403#[serde(transparent)]
1404pub struct PigVariant {
1405    pub variant: data::PigVariant,
1406}
1407
1408#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1409#[serde(transparent)]
1410pub struct FrogVariant {
1411    pub variant: data::FrogVariant,
1412}
1413
1414#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1415#[serde(transparent)]
1416pub struct HorseVariant {
1417    pub variant: HorseVariantKind,
1418}
1419#[derive(AzBuf, Clone, Copy, Debug, Default, PartialEq)]
1420pub enum HorseVariantKind {
1421    #[default]
1422    White,
1423    Creamy,
1424    Chestnut,
1425    Brown,
1426    Black,
1427    Gray,
1428    DarkBrown,
1429}
1430impl Display for HorseVariantKind {
1431    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1432        match self {
1433            Self::White => write!(f, "minecraft:white"),
1434            Self::Creamy => write!(f, "minecraft:creamy"),
1435            Self::Chestnut => write!(f, "minecraft:chestnut"),
1436            Self::Brown => write!(f, "minecraft:brown"),
1437            Self::Black => write!(f, "minecraft:black"),
1438            Self::Gray => write!(f, "minecraft:gray"),
1439            Self::DarkBrown => write!(f, "minecraft:dark_brown"),
1440        }
1441    }
1442}
1443impl Serialize for HorseVariantKind {
1444    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1445    where
1446        S: Serializer,
1447    {
1448        serializer.serialize_str(&self.to_string())
1449    }
1450}
1451
1452#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1453#[serde(transparent)]
1454pub struct PaintingVariant {
1455    pub variant: Holder<data::PaintingVariant, PaintingVariantData>,
1456}
1457
1458#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1459pub struct PaintingVariantData {
1460    #[var]
1461    pub width: i32,
1462    #[var]
1463    pub height: i32,
1464    pub asset_id: Identifier,
1465    #[serde(skip_serializing_if = "is_default")]
1466    pub title: Option<FormattedText>,
1467    #[serde(skip_serializing_if = "is_default")]
1468    pub author: Option<FormattedText>,
1469}
1470
1471#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1472#[serde(transparent)]
1473pub struct LlamaVariant {
1474    pub variant: LlamaVariantKind,
1475}
1476#[derive(AzBuf, Clone, Copy, Debug, Default, PartialEq)]
1477pub enum LlamaVariantKind {
1478    #[default]
1479    Creamy,
1480    White,
1481    Brown,
1482    Gray,
1483}
1484impl Display for LlamaVariantKind {
1485    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1486        match self {
1487            Self::Creamy => write!(f, "minecraft:creamy"),
1488            Self::White => write!(f, "minecraft:white"),
1489            Self::Brown => write!(f, "minecraft:brown"),
1490            Self::Gray => write!(f, "minecraft:gray"),
1491        }
1492    }
1493}
1494impl Serialize for LlamaVariantKind {
1495    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1496    where
1497        S: Serializer,
1498    {
1499        serializer.serialize_str(&self.to_string())
1500    }
1501}
1502
1503#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1504#[serde(transparent)]
1505pub struct AxolotlVariant {
1506    pub variant: AxolotlVariantKind,
1507}
1508#[derive(AzBuf, Clone, Copy, Debug, Default, PartialEq)]
1509pub enum AxolotlVariantKind {
1510    #[default]
1511    Lucy,
1512    Wild,
1513    Gold,
1514    Cyan,
1515    Blue,
1516}
1517impl Display for AxolotlVariantKind {
1518    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1519        match self {
1520            Self::Lucy => write!(f, "minecraft:lucy"),
1521            Self::Wild => write!(f, "minecraft:wild"),
1522            Self::Gold => write!(f, "minecraft:gold"),
1523            Self::Cyan => write!(f, "minecraft:cyan"),
1524            Self::Blue => write!(f, "minecraft:blue"),
1525        }
1526    }
1527}
1528impl Serialize for AxolotlVariantKind {
1529    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1530    where
1531        S: Serializer,
1532    {
1533        serializer.serialize_str(&self.to_string())
1534    }
1535}
1536
1537#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1538#[serde(transparent)]
1539pub struct CatVariant {
1540    pub variant: data::CatVariant,
1541}
1542
1543#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1544#[serde(transparent)]
1545pub struct CatCollar {
1546    pub color: DyeColor,
1547}
1548
1549#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1550#[serde(transparent)]
1551pub struct SheepColor {
1552    pub color: DyeColor,
1553}
1554
1555#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1556#[serde(transparent)]
1557pub struct ShulkerColor {
1558    pub color: DyeColor,
1559}
1560
1561#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1562pub struct TooltipDisplay {
1563    #[serde(skip_serializing_if = "is_default")]
1564    pub hide_tooltip: bool,
1565    #[serde(skip_serializing_if = "is_default")]
1566    pub hidden_components: Vec<DataComponentKind>,
1567}
1568
1569impl TooltipDisplay {
1570    pub const fn new() -> Self {
1571        Self {
1572            hide_tooltip: false,
1573            hidden_components: Vec::new(),
1574        }
1575    }
1576}
1577impl Default for TooltipDisplay {
1578    fn default() -> Self {
1579        Self::new()
1580    }
1581}
1582
1583#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1584pub struct BlocksAttacks {
1585    #[serde(skip_serializing_if = "is_default")]
1586    pub block_delay_seconds: f32,
1587    #[serde(skip_serializing_if = "is_default_disable_cooldown_scale")]
1588    pub disable_cooldown_scale: f32,
1589    #[serde(skip_serializing_if = "is_default")]
1590    pub damage_reductions: Vec<DamageReduction>,
1591    #[serde(skip_serializing_if = "is_default")]
1592    pub item_damage: ItemDamageFunction,
1593    #[serde(skip_serializing_if = "is_default")]
1594    pub bypassed_by: Option<Identifier>,
1595    #[serde(skip_serializing_if = "is_default")]
1596    pub block_sound: Option<azalea_registry::Holder<SoundEvent, CustomSound>>,
1597    #[serde(skip_serializing_if = "is_default")]
1598    pub disabled_sound: Option<azalea_registry::Holder<SoundEvent, CustomSound>>,
1599}
1600fn is_default_disable_cooldown_scale(value: &f32) -> bool {
1601    *value == 1.
1602}
1603
1604impl BlocksAttacks {
1605    pub fn new() -> Self {
1606        Self {
1607            block_delay_seconds: 0.,
1608            disable_cooldown_scale: 1.,
1609            damage_reductions: vec![DamageReduction {
1610                horizontal_blocking_angle: 90.,
1611                kind: None,
1612                base: 0.,
1613                factor: 1.,
1614            }],
1615            item_damage: ItemDamageFunction::default(),
1616            bypassed_by: None,
1617            block_sound: None,
1618            disabled_sound: None,
1619        }
1620    }
1621}
1622impl Default for BlocksAttacks {
1623    fn default() -> Self {
1624        Self::new()
1625    }
1626}
1627
1628#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1629pub struct DamageReduction {
1630    #[serde(skip_serializing_if = "is_default_horizontal_blocking_angle")]
1631    pub horizontal_blocking_angle: f32,
1632    #[serde(skip_serializing_if = "is_default")]
1633    pub kind: Option<HolderSet<DamageKind, Identifier>>,
1634    pub base: f32,
1635    pub factor: f32,
1636}
1637fn is_default_horizontal_blocking_angle(value: &f32) -> bool {
1638    *value == 90.
1639}
1640#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1641pub struct ItemDamageFunction {
1642    pub threshold: f32,
1643    pub base: f32,
1644    pub factor: f32,
1645}
1646impl Default for ItemDamageFunction {
1647    fn default() -> Self {
1648        ItemDamageFunction {
1649            threshold: 1.,
1650            base: 0.,
1651            factor: 1.,
1652        }
1653    }
1654}
1655
1656#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1657#[serde(untagged)]
1658pub enum ProvidesTrimMaterial {
1659    Referenced(Identifier),
1660    Direct(Holder<TrimMaterial, DirectTrimMaterial>),
1661}
1662
1663#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1664pub struct DirectTrimMaterial {
1665    pub assets: MaterialAssetGroup,
1666    pub description: FormattedText,
1667}
1668#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1669pub struct MaterialAssetGroup {
1670    pub base: AssetInfo,
1671    #[serde(skip_serializing_if = "is_default")]
1672    pub overrides: Vec<(Identifier, AssetInfo)>,
1673}
1674
1675#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1676pub struct AssetInfo {
1677    pub suffix: String,
1678}
1679
1680#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1681#[serde(transparent)]
1682pub struct ProvidesBannerPatterns {
1683    pub key: Identifier,
1684}
1685
1686#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1687#[serde(transparent)]
1688pub struct BreakSound {
1689    pub sound: azalea_registry::Holder<SoundEvent, CustomSound>,
1690}
1691
1692#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1693#[serde(transparent)]
1694pub struct WolfSoundVariant {
1695    pub variant: azalea_registry::data::WolfSoundVariant,
1696}
1697
1698#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1699#[serde(transparent)]
1700pub struct CowVariant {
1701    pub variant: azalea_registry::data::CowVariant,
1702}
1703
1704#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1705#[serde(untagged)]
1706pub enum ChickenVariant {
1707    Referenced(Identifier),
1708    Direct(ChickenVariantData),
1709}
1710
1711#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1712pub struct ChickenVariantData {
1713    pub registry: azalea_registry::data::ChickenVariant,
1714}
1715
1716// TODO: check in-game if this is correct
1717#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1718pub enum ZombieNautilusVariant {
1719    Referenced(Identifier),
1720    Direct(ZombieNautilusVariantData),
1721}
1722#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1723#[serde(transparent)]
1724pub struct ZombieNautilusVariantData {
1725    pub value: azalea_registry::data::ZombieNautilusVariant,
1726}
1727
1728#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1729pub struct UseEffects {
1730    pub can_sprint: bool,
1731    pub interact_vibrations: bool,
1732    pub speed_multiplier: f32,
1733}
1734impl UseEffects {
1735    pub const fn new() -> Self {
1736        Self {
1737            can_sprint: false,
1738            interact_vibrations: true,
1739            speed_multiplier: 0.2,
1740        }
1741    }
1742}
1743impl Default for UseEffects {
1744    fn default() -> Self {
1745        Self::new()
1746    }
1747}
1748
1749#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1750#[serde(transparent)]
1751pub struct MinimumAttackCharge {
1752    pub value: f32,
1753}
1754
1755// TODO: this is probably wrong, check in-game
1756#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1757#[serde(untagged)]
1758pub enum DamageType {
1759    Registry(DamageKind),
1760    Holder(Holder<DamageKind, DamageTypeElement>),
1761}
1762
1763#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1764pub struct PiercingWeapon {
1765    pub deals_knockback: bool,
1766    pub dismounts: bool,
1767    pub sound: Option<Holder<SoundEvent, azalea_core::sound::CustomSound>>,
1768    pub hit_sound: Option<Holder<SoundEvent, azalea_core::sound::CustomSound>>,
1769}
1770impl PiercingWeapon {
1771    pub const fn new() -> Self {
1772        Self {
1773            deals_knockback: true,
1774            dismounts: false,
1775            sound: None,
1776            hit_sound: None,
1777        }
1778    }
1779}
1780impl Default for PiercingWeapon {
1781    fn default() -> Self {
1782        Self::new()
1783    }
1784}
1785
1786#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1787pub struct KineticWeapon {
1788    #[var]
1789    pub contact_cooldown_ticks: i32,
1790    #[var]
1791    pub delay_ticks: i32,
1792    pub dismount_conditions: Option<KineticWeaponCondition>,
1793    pub knockback_conditions: Option<KineticWeaponCondition>,
1794    pub damage_conditions: Option<KineticWeaponCondition>,
1795    pub forward_movement: f32,
1796    pub damage_multiplier: f32,
1797    pub sound: Option<Holder<SoundEvent, azalea_core::sound::CustomSound>>,
1798    pub hit_sound: Option<Holder<SoundEvent, azalea_core::sound::CustomSound>>,
1799}
1800impl KineticWeapon {
1801    pub const fn new() -> Self {
1802        Self {
1803            contact_cooldown_ticks: 10,
1804            delay_ticks: 0,
1805            dismount_conditions: None,
1806            knockback_conditions: None,
1807            damage_conditions: None,
1808            forward_movement: 0.,
1809            damage_multiplier: 1.,
1810            sound: None,
1811            hit_sound: None,
1812        }
1813    }
1814}
1815impl Default for KineticWeapon {
1816    fn default() -> Self {
1817        Self::new()
1818    }
1819}
1820
1821#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1822pub struct KineticWeaponCondition {
1823    #[var]
1824    pub max_duration_ticks: i32,
1825    pub min_speed: f32,
1826    pub min_relative_speed: f32,
1827}
1828impl KineticWeaponCondition {
1829    pub const fn new() -> Self {
1830        Self {
1831            max_duration_ticks: 0,
1832            min_speed: 0.,
1833            min_relative_speed: 0.,
1834        }
1835    }
1836}
1837impl Default for KineticWeaponCondition {
1838    fn default() -> Self {
1839        Self::new()
1840    }
1841}
1842
1843#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1844pub struct SwingAnimation {
1845    #[serde(rename = "type")]
1846    pub kind: SwingAnimationKind,
1847    #[var]
1848    pub duration: i32,
1849}
1850impl SwingAnimation {
1851    pub const fn new() -> Self {
1852        Self {
1853            kind: SwingAnimationKind::Whack,
1854            duration: 6,
1855        }
1856    }
1857}
1858impl Default for SwingAnimation {
1859    fn default() -> Self {
1860        Self::new()
1861    }
1862}
1863
1864#[derive(AzBuf, Clone, Copy, Debug, PartialEq, Serialize)]
1865#[serde(rename_all = "snake_case")]
1866pub enum SwingAnimationKind {
1867    None,
1868    Whack,
1869    Stab,
1870}
1871
1872#[derive(AzBuf, Clone, Debug, PartialEq, Serialize)]
1873pub struct AttackRange {
1874    pub min_reach: f32,
1875    pub max_reach: f32,
1876    pub min_creative_reach: f32,
1877    pub max_creative_reach: f32,
1878    pub hitbox_margin: f32,
1879    pub mob_factor: f32,
1880}
1881impl AttackRange {
1882    pub const fn new() -> Self {
1883        Self {
1884            min_reach: 0.,
1885            max_reach: 3.,
1886            min_creative_reach: 0.,
1887            max_creative_reach: 5.,
1888            hitbox_margin: 0.3,
1889            mob_factor: 1.,
1890        }
1891    }
1892}
1893impl Default for AttackRange {
1894    fn default() -> Self {
1895        Self::new()
1896    }
1897}