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, AzaleaRead, AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, 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 bevy_ecs::component::Component;
17use derive_more::Deref;
18use enum_as_inner::EnumAsInner;
19use uuid::Uuid;
20
21use crate::particle::Particle;
22
23#[derive(Clone, Debug, Deref, PartialEq)]
24pub struct EntityMetadataItems(pub Vec<EntityDataItem>);
25
26#[derive(Clone, Debug, PartialEq)]
27pub struct EntityDataItem {
28    // we can't identify what the index is for here because we don't know the
29    // entity type
30    pub index: u8,
31    pub value: EntityDataValue,
32}
33
34impl AzaleaRead for EntityMetadataItems {
35    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
36        let mut metadata = Vec::new();
37        loop {
38            let id = u8::azalea_read(buf)?;
39            if id == 0xff {
40                break;
41            }
42            let value = EntityDataValue::azalea_read(buf)?;
43            metadata.push(EntityDataItem { index: id, value });
44        }
45        Ok(EntityMetadataItems(metadata))
46    }
47}
48
49impl AzaleaWrite for EntityMetadataItems {
50    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
51        for item in &self.0 {
52            item.index.azalea_write(buf)?;
53            item.value.azalea_write(buf)?;
54        }
55        0xffu8.azalea_write(buf)?;
56        Ok(())
57    }
58}
59
60// Note: This enum is partially generated and parsed by
61// codegen/lib/code/entity.py
62#[derive(AzBuf, Clone, Debug, EnumAsInner, PartialEq)]
63pub enum EntityDataValue {
64    Byte(u8),
65    Int(#[var] i32),
66    Long(#[var] i64),
67    Float(f32),
68    String(Box<str>),
69    FormattedText(Box<FormattedText>),
70    OptionalFormattedText(Option<Box<FormattedText>>),
71    ItemStack(ItemStack),
72    Boolean(bool),
73    Rotations(Rotations),
74    BlockPos(BlockPos),
75    OptionalBlockPos(Option<BlockPos>),
76    Direction(Direction),
77    OptionalLivingEntityReference(Option<Uuid>),
78    BlockState(azalea_block::BlockState),
79    /// If this is air, that means it's absent,
80    OptionalBlockState(azalea_block::BlockState),
81    Particle(Particle),
82    Particles(Box<[Particle]>),
83    VillagerData(VillagerData),
84    // 0 for absent; 1 + actual value otherwise. Used for entity IDs.
85    OptionalUnsignedInt(OptionalUnsignedInt),
86    Pose(Pose),
87    CatVariant(azalea_registry::data::CatVariant),
88    CowVariant(azalea_registry::data::CowVariant),
89    WolfVariant(azalea_registry::data::WolfVariant),
90    WolfSoundVariant(azalea_registry::data::WolfSoundVariant),
91    FrogVariant(azalea_registry::data::FrogVariant),
92    PigVariant(azalea_registry::data::PigVariant),
93    ChickenVariant(azalea_registry::data::ChickenVariant),
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)]
110pub struct OptionalUnsignedInt(pub Option<u32>);
111
112#[derive(AzBuf, Clone, Debug, PartialEq)]
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 AzaleaRead 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}
140impl AzaleaWrite for OptionalUnsignedInt {
141    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
142        match self.0 {
143            Some(val) => (val + 1).azalea_write_var(buf),
144            None => 0u32.azalea_write_var(buf),
145        }
146    }
147}
148
149/// A set of x, y, and z rotations. This is used for armor stands.
150#[derive(AzBuf, Clone, Debug, Default, PartialEq)]
151pub struct Rotations {
152    pub x: f32,
153    pub y: f32,
154    pub z: f32,
155}
156
157#[derive(AzBuf, Clone, Component, Copy, Debug, Default, Eq, PartialEq)]
158pub enum Pose {
159    #[default]
160    Standing = 0,
161    FallFlying,
162    Sleeping,
163    Swimming,
164    SpinAttack,
165    Crouching,
166    LongJumping,
167    Dying,
168    Croaking,
169    UsingTongue,
170    Sitting,
171    Roaring,
172    Sniffing,
173    Emerging,
174    Digging,
175    Sliding,
176    Shooting,
177    Inhaling,
178}
179
180#[derive(AzBuf, Clone, Debug, PartialEq)]
181pub struct VillagerData {
182    pub kind: VillagerKind,
183    pub profession: VillagerProfession,
184    #[var]
185    pub level: u32,
186}
187
188#[derive(AzBuf, Clone, Copy, Debug, Default, PartialEq)]
189pub enum SnifferStateKind {
190    #[default]
191    Idling,
192    FeelingHappy,
193    Scenting,
194    Sniffing,
195    Searching,
196    Digging,
197    Rising,
198}
199
200#[derive(AzBuf, Clone, Copy, Debug, Default, PartialEq)]
201pub enum CopperGolemStateKind {
202    #[default]
203    Idle,
204    GettingItem,
205    GettingNoItem,
206    DroppingItem,
207    DroppingNoItem,
208}
209#[derive(AzBuf, Clone, Copy, Debug, Default, PartialEq)]
210pub enum WeatheringCopperStateKind {
211    #[default]
212    Unaffected,
213    Exposed,
214    Weathered,
215    Oxidized,
216}
217
218#[derive(AzBuf, Clone, Copy, Debug, Default, Eq, PartialEq)]
219pub enum HumanoidArm {
220    Left = 0,
221    #[default]
222    Right = 1,
223}