//! Define some types needed for entity metadata. // TODO: this is here because of a bug in enum_as_inner. remove when it's fixed #![allow(clippy::double_parens)] use std::io::{self, Cursor, Write}; use azalea_buf::{AzBuf, AzaleaRead, AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, BufReadError}; use azalea_chat::FormattedText; use azalea_core::{ direction::Direction, position::{BlockPos, GlobalPos, Vec3f32}, }; use azalea_inventory::{ItemStack, components}; use azalea_registry::builtin::{VillagerKind, VillagerProfession}; use bevy_ecs::component::Component; use derive_more::Deref; use enum_as_inner::EnumAsInner; use uuid::Uuid; use crate::particle::Particle; #[derive(Clone, Debug, Deref, PartialEq)] pub struct EntityMetadataItems(pub Vec); #[derive(Clone, Debug, PartialEq)] pub struct EntityDataItem { // we can't identify what the index is for here because we don't know the // entity type pub index: u8, pub value: EntityDataValue, } impl AzaleaRead for EntityMetadataItems { fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result { let mut metadata = Vec::new(); loop { let id = u8::azalea_read(buf)?; if id == 0xff { break; } let value = EntityDataValue::azalea_read(buf)?; metadata.push(EntityDataItem { index: id, value }); } Ok(EntityMetadataItems(metadata)) } } impl AzaleaWrite for EntityMetadataItems { fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> { for item in &self.0 { item.index.azalea_write(buf)?; item.value.azalea_write(buf)?; } 0xffu8.azalea_write(buf)?; Ok(()) } } // Note: This enum is partially generated and parsed by // codegen/lib/code/entity.py #[derive(AzBuf, Clone, Debug, EnumAsInner, PartialEq)] pub enum EntityDataValue { Byte(u8), Int(#[var] i32), Long(#[var] i64), Float(f32), String(String), FormattedText(FormattedText), OptionalFormattedText(Option), ItemStack(ItemStack), Boolean(bool), Rotations(Rotations), BlockPos(BlockPos), OptionalBlockPos(Option), Direction(Direction), OptionalLivingEntityReference(Option), BlockState(azalea_block::BlockState), /// If this is air, that means it's absent, OptionalBlockState(azalea_block::BlockState), Particle(Particle), Particles(Vec), VillagerData(VillagerData), // 0 for absent; 1 + actual value otherwise. Used for entity IDs. OptionalUnsignedInt(OptionalUnsignedInt), Pose(Pose), CatVariant(azalea_registry::data::CatVariant), ChickenVariant(azalea_registry::data::ChickenVariant), CowVariant(azalea_registry::data::CowVariant), WolfVariant(azalea_registry::data::WolfVariant), WolfSoundVariant(azalea_registry::data::WolfSoundVariant), FrogVariant(azalea_registry::data::FrogVariant), PigVariant(azalea_registry::data::PigVariant), ZombieNautilusVariant(azalea_registry::data::ZombieNautilusVariant), OptionalGlobalPos(Option), PaintingVariant(azalea_registry::data::PaintingVariant), SnifferState(SnifferStateKind), ArmadilloState(ArmadilloStateKind), CopperGolemState(CopperGolemStateKind), WeatheringCopperState(WeatheringCopperStateKind), Vector3(Vec3f32), Quaternion(Quaternion), ResolvableProfile(components::Profile), HumanoidArm(HumanoidArm), } #[derive(Clone, Debug, PartialEq)] pub struct OptionalUnsignedInt(pub Option); #[derive(AzBuf, Clone, Debug, PartialEq)] pub struct Quaternion { pub x: f32, pub y: f32, pub z: f32, pub w: f32, } // mojang just calls this ArmadilloState but i added "Kind" since otherwise it // collides with a name in metadata.rs #[derive(AzBuf, Clone, Copy, Debug, Default, PartialEq)] pub enum ArmadilloStateKind { #[default] Idle, Rolling, Scared, } impl AzaleaRead for OptionalUnsignedInt { fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result { let val = u32::azalea_read_var(buf)?; Ok(OptionalUnsignedInt(if val == 0 { None } else { Some(val - 1) })) } } impl AzaleaWrite for OptionalUnsignedInt { fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> { match self.0 { Some(val) => (val + 1).azalea_write_var(buf), None => 0u32.azalea_write_var(buf), } } } /// A set of x, y, and z rotations. This is used for armor stands. #[derive(AzBuf, Clone, Debug, Default, PartialEq)] pub struct Rotations { pub x: f32, pub y: f32, pub z: f32, } #[derive(AzBuf, Clone, Component, Copy, Debug, Default, Eq, PartialEq)] pub enum Pose { #[default] Standing = 0, FallFlying, Sleeping, Swimming, SpinAttack, Crouching, LongJumping, Dying, Croaking, UsingTongue, Sitting, Roaring, Sniffing, Emerging, Digging, Sliding, Shooting, Inhaling, } #[derive(AzBuf, Clone, Debug, PartialEq)] pub struct VillagerData { pub kind: VillagerKind, pub profession: VillagerProfession, #[var] pub level: u32, } #[derive(AzBuf, Clone, Copy, Debug, Default, PartialEq)] pub enum SnifferStateKind { #[default] Idling, FeelingHappy, Scenting, Sniffing, Searching, Digging, Rising, } #[derive(AzBuf, Clone, Copy, Debug, Default, PartialEq)] pub enum CopperGolemStateKind { #[default] Idle, GettingItem, GettingNoItem, DroppingItem, DroppingNoItem, } #[derive(AzBuf, Clone, Copy, Debug, Default, PartialEq)] pub enum WeatheringCopperStateKind { #[default] Unaffected, Exposed, Weathered, Oxidized, } #[derive(AzBuf, Clone, Copy, Debug, Default, Eq, PartialEq)] pub enum HumanoidArm { Left = 0, #[default] Right = 1, }