azalea_entity/
data.rs

1//! Define some types needed for entity metadata.
2
3use std::io::{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, Vec3},
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) -> Result<(), std::io::Error> {
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(Vec3),
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) -> Result<(), std::io::Error> {
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    Sneaking,
156    LongJumping,
157    Dying,
158}
159
160#[derive(Debug, Clone, AzBuf)]
161pub struct VillagerData {
162    pub kind: azalea_registry::VillagerKind,
163    pub profession: azalea_registry::VillagerProfession,
164    #[var]
165    pub level: u32,
166}
167
168#[derive(Debug, Copy, Clone, AzBuf, Default)]
169pub enum SnifferStateKind {
170    #[default]
171    Idling,
172    FeelingHappy,
173    Scenting,
174    Sniffing,
175    Searching,
176    Digging,
177    Rising,
178}