azalea_entity/
data.rs

1//! Define some types needed for entity metadata.
2
3use std::io::{self, Cursor, Write};
4
5use azalea_buf::{AzBuf, AzaleaRead, AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, BufReadError};
6use azalea_chat::FormattedText;
7use azalea_core::{
8    direction::Direction,
9    position::{BlockPos, GlobalPos, Vec3f32},
10};
11use azalea_inventory::ItemStack;
12use bevy_ecs::component::Component;
13use derive_more::Deref;
14use enum_as_inner::EnumAsInner;
15use uuid::Uuid;
16
17use crate::particle::Particle;
18
19#[derive(Clone, Debug, Deref)]
20pub struct EntityMetadataItems(pub Vec<EntityDataItem>);
21
22#[derive(Clone, Debug)]
23pub struct EntityDataItem {
24    // we can't identify what the index is for here because we don't know the
25    // entity type
26    pub index: u8,
27    pub value: EntityDataValue,
28}
29
30impl AzaleaRead for EntityMetadataItems {
31    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
32        let mut metadata = Vec::new();
33        loop {
34            let id = u8::azalea_read(buf)?;
35            if id == 0xff {
36                break;
37            }
38            let value = EntityDataValue::azalea_read(buf)?;
39            metadata.push(EntityDataItem { index: id, value });
40        }
41        Ok(EntityMetadataItems(metadata))
42    }
43}
44
45impl AzaleaWrite for EntityMetadataItems {
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(Clone, Debug, EnumAsInner, AzBuf)]
59pub enum EntityDataValue {
60    Byte(u8),
61    Int(#[var] i32),
62    Long(#[var] i64),
63    Float(f32),
64    String(String),
65    FormattedText(FormattedText),
66    OptionalFormattedText(Option<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    CompoundTag(simdnbt::owned::NbtCompound),
78    Particle(Particle),
79    Particles(Vec<Particle>),
80    VillagerData(VillagerData),
81    // 0 for absent; 1 + actual value otherwise. Used for entity IDs.
82    OptionalUnsignedInt(OptionalUnsignedInt),
83    Pose(Pose),
84    CatVariant(azalea_registry::CatVariant),
85    ChickenVariant(azalea_registry::ChickenVariant),
86    CowVariant(azalea_registry::CowVariant),
87    WolfVariant(azalea_registry::WolfVariant),
88    WolfSoundVariant(azalea_registry::WolfSoundVariant),
89    FrogVariant(azalea_registry::FrogVariant),
90    PigVariant(azalea_registry::PigVariant),
91    OptionalGlobalPos(Option<GlobalPos>),
92    PaintingVariant(azalea_registry::PaintingVariant),
93    SnifferState(SnifferStateKind),
94    ArmadilloState(ArmadilloStateKind),
95    Vector3(Vec3f32),
96    Quaternion(Quaternion),
97}
98
99#[derive(Clone, Debug)]
100pub struct OptionalUnsignedInt(pub Option<u32>);
101
102#[derive(Clone, Debug, AzBuf)]
103pub struct Quaternion {
104    pub x: f32,
105    pub y: f32,
106    pub z: f32,
107    pub w: f32,
108}
109
110// mojang just calls this ArmadilloState but i added "Kind" since otherwise it
111// collides with a name in metadata.rs
112#[derive(Clone, Debug, Copy, Default, AzBuf)]
113pub enum ArmadilloStateKind {
114    #[default]
115    Idle,
116    Rolling,
117    Scared,
118}
119
120impl AzaleaRead for OptionalUnsignedInt {
121    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
122        let val = u32::azalea_read_var(buf)?;
123        Ok(OptionalUnsignedInt(if val == 0 {
124            None
125        } else {
126            Some(val - 1)
127        }))
128    }
129}
130impl AzaleaWrite for OptionalUnsignedInt {
131    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
132        match self.0 {
133            Some(val) => (val + 1).azalea_write_var(buf),
134            None => 0u32.azalea_write_var(buf),
135        }
136    }
137}
138
139/// A set of x, y, and z rotations. This is used for armor stands.
140#[derive(Clone, Debug, AzBuf, Default)]
141pub struct Rotations {
142    pub x: f32,
143    pub y: f32,
144    pub z: f32,
145}
146
147#[derive(Clone, Debug, Copy, AzBuf, Default, Component, Eq, PartialEq)]
148pub enum Pose {
149    #[default]
150    Standing = 0,
151    FallFlying,
152    Sleeping,
153    Swimming,
154    SpinAttack,
155    Crouching,
156    LongJumping,
157    Dying,
158    Croaking,
159    UsingTongue,
160    Sitting,
161    Roaring,
162    Sniffing,
163    Emerging,
164    Digging,
165    Sliding,
166    Shooting,
167    Inhaling,
168}
169
170#[derive(Debug, Clone, AzBuf)]
171pub struct VillagerData {
172    pub kind: azalea_registry::VillagerKind,
173    pub profession: azalea_registry::VillagerProfession,
174    #[var]
175    pub level: u32,
176}
177
178#[derive(Debug, Copy, Clone, AzBuf, Default)]
179pub enum SnifferStateKind {
180    #[default]
181    Idling,
182    FeelingHappy,
183    Scenting,
184    Sniffing,
185    Searching,
186    Digging,
187    Rising,
188}