Skip to main content

azalea_entity/
data.rs

1//! Define some types needed for entity metadata.
2
3// TODO: this is here because of a bug in enum_as_inner. remove when it's fixed
4#![allow(clippy::double_parens)]
5
6use std::io::{self, Cursor, Write};
7
8use azalea_buf::{AzBuf, AzBufVar, BufReadError};
9use azalea_chat::FormattedText;
10use azalea_core::{
11    direction::Direction,
12    position::{BlockPos, GlobalPos, Vec3f32},
13};
14use azalea_inventory::{ItemStack, components};
15use azalea_registry::builtin::{VillagerKind, VillagerProfession};
16use derive_more::Deref;
17use enum_as_inner::EnumAsInner;
18use uuid::Uuid;
19
20use crate::particle::Particle;
21
22#[derive(Clone, Debug, Deref, PartialEq)]
23pub struct EntityMetadataItems(pub Vec<EntityDataItem>);
24
25#[derive(Clone, Debug, PartialEq)]
26pub struct EntityDataItem {
27    // we can't identify what the index is for here because we don't know the
28    // entity type
29    pub index: u8,
30    pub value: EntityDataValue,
31}
32
33impl AzBuf for EntityMetadataItems {
34    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
35        let mut metadata = Vec::new();
36        loop {
37            let id = u8::azalea_read(buf)?;
38            if id == 0xff {
39                break;
40            }
41            let value = EntityDataValue::azalea_read(buf)?;
42            metadata.push(EntityDataItem { index: id, value });
43        }
44        Ok(EntityMetadataItems(metadata))
45    }
46    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
47        for item in &self.0 {
48            item.index.azalea_write(buf)?;
49            item.value.azalea_write(buf)?;
50        }
51        0xffu8.azalea_write(buf)?;
52        Ok(())
53    }
54}
55
56// Note: This enum is partially generated and parsed by
57// codegen/lib/code/entity.py
58#[derive(AzBuf, Clone, Debug, EnumAsInner, PartialEq)]
59pub enum EntityDataValue {
60    Byte(u8),
61    Int(#[var] i32),
62    Long(#[var] i64),
63    Float(f32),
64    String(Box<str>),
65    FormattedText(Box<FormattedText>),
66    OptionalFormattedText(Option<Box<FormattedText>>),
67    ItemStack(ItemStack),
68    Boolean(bool),
69    Rotations(Rotations),
70    BlockPos(BlockPos),
71    OptionalBlockPos(Option<BlockPos>),
72    Direction(Direction),
73    OptionalLivingEntityReference(Option<Uuid>),
74    BlockState(azalea_block::BlockState),
75    /// If this is air, that means it's absent,
76    OptionalBlockState(azalea_block::BlockState),
77    Particle(Particle),
78    Particles(Box<[Particle]>),
79    VillagerData(VillagerData),
80    // 0 for absent; 1 + actual value otherwise. Used for entity IDs.
81    OptionalUnsignedInt(OptionalUnsignedInt),
82    Pose(Pose),
83    CatVariant(azalea_registry::data::CatVariant),
84    CatSoundVariant(azalea_registry::data::CatSoundVariant),
85    CowVariant(azalea_registry::data::CowVariant),
86    CowSoundVariant(azalea_registry::data::CowSoundVariant),
87    WolfVariant(azalea_registry::data::WolfVariant),
88    WolfSoundVariant(azalea_registry::data::WolfSoundVariant),
89    FrogVariant(azalea_registry::data::FrogVariant),
90    PigVariant(azalea_registry::data::PigVariant),
91    PigSoundVariant(azalea_registry::data::PigSoundVariant),
92    ChickenVariant(azalea_registry::data::ChickenVariant),
93    ChickenSoundVariant(azalea_registry::data::ChickenSoundVariant),
94    ZombieNautilusVariant(azalea_registry::data::ZombieNautilusVariant),
95    OptionalGlobalPos(Option<Box<GlobalPos>>),
96    PaintingVariant(azalea_registry::data::PaintingVariant),
97    SnifferState(SnifferStateKind),
98    ArmadilloState(ArmadilloStateKind),
99    CopperGolemState(CopperGolemStateKind),
100    WeatheringCopperState(WeatheringCopperStateKind),
101    Vector3(Vec3f32),
102    Quaternion(Quaternion),
103    ResolvableProfile(components::Profile),
104    HumanoidArm(HumanoidArm),
105}
106
107const _: () = assert!(size_of::<EntityDataValue>() == 24);
108
109#[derive(Clone, Debug, PartialEq, Default)]
110pub struct OptionalUnsignedInt(pub Option<u32>);
111
112#[derive(AzBuf, Clone, Debug, PartialEq, Default)]
113pub struct Quaternion {
114    pub x: f32,
115    pub y: f32,
116    pub z: f32,
117    pub w: f32,
118}
119
120// mojang just calls this ArmadilloState but i added "Kind" since otherwise it
121// collides with a name in metadata.rs
122#[derive(AzBuf, Clone, Copy, Debug, Default, PartialEq)]
123pub enum ArmadilloStateKind {
124    #[default]
125    Idle,
126    Rolling,
127    Scared,
128}
129
130impl AzBuf for OptionalUnsignedInt {
131    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
132        let val = u32::azalea_read_var(buf)?;
133        Ok(OptionalUnsignedInt(if val == 0 {
134            None
135        } else {
136            Some(val - 1)
137        }))
138    }
139    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
140        match self.0 {
141            Some(val) => (val + 1).azalea_write_var(buf),
142            None => 0u32.azalea_write_var(buf),
143        }
144    }
145}
146
147/// A set of x, y, and z rotations. This is used for armor stands.
148#[derive(AzBuf, Clone, Debug, Default, PartialEq)]
149pub struct Rotations {
150    pub x: f32,
151    pub y: f32,
152    pub z: f32,
153}
154
155#[cfg_attr(feature = "bevy_ecs", derive(bevy_ecs::component::Component))]
156#[derive(AzBuf, Clone, Copy, Debug, Default, Eq, PartialEq)]
157pub enum Pose {
158    #[default]
159    Standing = 0,
160    FallFlying,
161    Sleeping,
162    Swimming,
163    SpinAttack,
164    Crouching,
165    LongJumping,
166    Dying,
167    Croaking,
168    UsingTongue,
169    Sitting,
170    Roaring,
171    Sniffing,
172    Emerging,
173    Digging,
174    Sliding,
175    Shooting,
176    Inhaling,
177}
178
179#[derive(AzBuf, Clone, Debug, PartialEq)]
180pub struct VillagerData {
181    pub kind: VillagerKind,
182    pub profession: VillagerProfession,
183    #[var]
184    pub level: u32,
185}
186
187#[derive(AzBuf, Clone, Copy, Debug, Default, PartialEq)]
188pub enum SnifferStateKind {
189    #[default]
190    Idling,
191    FeelingHappy,
192    Scenting,
193    Sniffing,
194    Searching,
195    Digging,
196    Rising,
197}
198
199#[derive(AzBuf, Clone, Copy, Debug, Default, PartialEq)]
200pub enum CopperGolemStateKind {
201    #[default]
202    Idle,
203    GettingItem,
204    GettingNoItem,
205    DroppingItem,
206    DroppingNoItem,
207}
208#[derive(AzBuf, Clone, Copy, Debug, Default, PartialEq)]
209pub enum WeatheringCopperStateKind {
210    #[default]
211    Unaffected,
212    Exposed,
213    Weathered,
214    Oxidized,
215}
216
217#[derive(AzBuf, Clone, Copy, Debug, Default, Eq, PartialEq)]
218pub enum HumanoidArm {
219    Left = 0,
220    #[default]
221    Right = 1,
222}