mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 14:26:04 +00:00
210 lines
5.6 KiB
Rust
Executable file
210 lines
5.6 KiB
Rust
Executable file
//! Define some types needed for entity metadata.
|
|
|
|
use std::io::{Cursor, Write};
|
|
|
|
use azalea_buf::{AzBuf, AzaleaRead, AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, BufReadError};
|
|
use azalea_chat::FormattedText;
|
|
use azalea_core::{
|
|
direction::Direction,
|
|
position::{BlockPos, GlobalPos, Vec3},
|
|
};
|
|
use azalea_inventory::ItemStack;
|
|
use bevy_ecs::component::Component;
|
|
use derive_more::Deref;
|
|
use enum_as_inner::EnumAsInner;
|
|
use nohash_hasher::IntSet;
|
|
use uuid::Uuid;
|
|
|
|
use crate::particle::Particle;
|
|
|
|
#[derive(Clone, Debug, Deref)]
|
|
pub struct EntityMetadataItems(Vec<EntityDataItem>);
|
|
|
|
#[derive(Clone, Debug)]
|
|
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 EntityMetadataItems {
|
|
pub fn new(data: Vec<EntityDataItem>) -> Self {
|
|
EntityMetadataItems(data)
|
|
}
|
|
}
|
|
|
|
impl AzaleaRead for EntityMetadataItems {
|
|
fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
|
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) -> Result<(), std::io::Error> {
|
|
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(Clone, Debug, EnumAsInner, AzBuf)]
|
|
pub enum EntityDataValue {
|
|
Byte(u8),
|
|
Int(#[var] i32),
|
|
Long(i64),
|
|
Float(f32),
|
|
String(String),
|
|
FormattedText(FormattedText),
|
|
OptionalFormattedText(Option<FormattedText>),
|
|
ItemStack(ItemStack),
|
|
Boolean(bool),
|
|
Rotations(Rotations),
|
|
BlockPos(BlockPos),
|
|
OptionalBlockPos(Option<BlockPos>),
|
|
Direction(Direction),
|
|
OptionalUuid(Option<Uuid>),
|
|
BlockState(azalea_block::BlockState),
|
|
/// If this is air, that means it's absent,
|
|
OptionalBlockState(azalea_block::BlockState),
|
|
CompoundTag(simdnbt::owned::NbtCompound),
|
|
Particle(Particle),
|
|
Particles(Vec<Particle>),
|
|
VillagerData(VillagerData),
|
|
// 0 for absent; 1 + actual value otherwise. Used for entity IDs.
|
|
OptionalUnsignedInt(OptionalUnsignedInt),
|
|
Pose(Pose),
|
|
CatVariant(azalea_registry::CatVariant),
|
|
WolfVariant(azalea_registry::WolfVariant),
|
|
FrogVariant(azalea_registry::FrogVariant),
|
|
OptionalGlobalPos(Option<GlobalPos>),
|
|
PaintingVariant(azalea_registry::PaintingVariant),
|
|
SnifferState(SnifferState),
|
|
ArmadilloState(ArmadilloStateKind),
|
|
Vector3(Vec3),
|
|
Quaternion(Quaternion),
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct OptionalUnsignedInt(pub Option<u32>);
|
|
|
|
#[derive(Clone, Debug, AzBuf)]
|
|
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(Clone, Debug, Copy, Default, AzBuf)]
|
|
pub enum ArmadilloStateKind {
|
|
#[default]
|
|
Idle,
|
|
Rolling,
|
|
Scared,
|
|
}
|
|
|
|
impl AzaleaRead for OptionalUnsignedInt {
|
|
fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
|
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) -> Result<(), std::io::Error> {
|
|
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(Clone, Debug, AzBuf, Default)]
|
|
pub struct Rotations {
|
|
pub x: f32,
|
|
pub y: f32,
|
|
pub z: f32,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Copy, AzBuf, Default, Component, Eq, PartialEq)]
|
|
pub enum Pose {
|
|
#[default]
|
|
Standing = 0,
|
|
FallFlying,
|
|
Sleeping,
|
|
Swimming,
|
|
SpinAttack,
|
|
Sneaking,
|
|
LongJumping,
|
|
Dying,
|
|
}
|
|
|
|
#[derive(Debug, Clone, AzBuf)]
|
|
pub struct VillagerData {
|
|
pub kind: azalea_registry::VillagerKind,
|
|
pub profession: azalea_registry::VillagerProfession,
|
|
#[var]
|
|
pub level: u32,
|
|
}
|
|
|
|
impl TryFrom<EntityMetadataItems> for Vec<EntityDataValue> {
|
|
type Error = String;
|
|
|
|
fn try_from(data: EntityMetadataItems) -> Result<Self, Self::Error> {
|
|
let mut data = data.0;
|
|
|
|
data.sort_by(|a, b| a.index.cmp(&b.index));
|
|
|
|
let mut prev_indexes = IntSet::default();
|
|
let len = data.len();
|
|
// check to make sure it's valid, in vanilla this is guaranteed to pass
|
|
// but it's possible there's mods that mess with it so we want to make
|
|
// sure it's good
|
|
for item in &data {
|
|
if prev_indexes.contains(&item.index) {
|
|
return Err(format!("Index {} is duplicated", item.index));
|
|
}
|
|
if item.index as usize > len {
|
|
return Err(format!("Index {} is too big", item.index));
|
|
}
|
|
prev_indexes.insert(item.index);
|
|
}
|
|
|
|
let data = data.into_iter().map(|d| d.value).collect();
|
|
|
|
Ok(data)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Copy, Clone, AzBuf, Default)]
|
|
pub enum SnifferState {
|
|
#[default]
|
|
Idling,
|
|
FeelingHappy,
|
|
Scenting,
|
|
Sniffing,
|
|
Searching,
|
|
Digging,
|
|
Rising,
|
|
}
|