diff options
Diffstat (limited to 'azalea-entity/src')
| -rw-r--r-- | azalea-entity/src/data.rs | 144 | ||||
| -rw-r--r-- | azalea-entity/src/lib.rs | 59 |
2 files changed, 203 insertions, 0 deletions
diff --git a/azalea-entity/src/data.rs b/azalea-entity/src/data.rs new file mode 100644 index 00000000..5d2a66fc --- /dev/null +++ b/azalea-entity/src/data.rs @@ -0,0 +1,144 @@ +use azalea_buf::McBufVarReadable; +use azalea_buf::{McBuf, McBufReadable, McBufWritable}; +use azalea_chat::component::Component; +use azalea_core::{BlockPos, Direction, Particle, Slot}; +use std::io::{Read, Write}; +use uuid::Uuid; + +#[derive(Clone, Debug)] +pub struct EntityMetadata(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 McBufReadable for EntityMetadata { + fn read_into(buf: &mut impl Read) -> Result<Self, String> { + let mut metadata = Vec::new(); + loop { + let index = u8::read_into(buf)?; + if index == 0xff { + break; + } + let value = EntityDataValue::read_into(buf)?; + metadata.push(EntityDataItem { index, value }); + } + Ok(EntityMetadata(metadata)) + } +} + +impl McBufWritable for EntityMetadata { + fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + for item in &self.0 { + item.index.write_into(buf)?; + item.value.write_into(buf)?; + } + 0xffu8.write_into(buf)?; + Ok(()) + } +} + +#[derive(Clone, Debug)] +pub enum EntityDataValue { + Byte(u8), + // varint + Int(i32), + Float(f32), + String(String), + Component(Component), + OptionalComponent(Option<Component>), + ItemStack(Slot), + Boolean(bool), + Rotations { x: f32, y: f32, z: f32 }, + BlockPos(BlockPos), + OptionalBlockPos(Option<BlockPos>), + Direction(Direction), + OptionalUuid(Option<Uuid>), + // 0 for absent (implies air); otherwise, a block state ID as per the global palette + // this is a varint + OptionalBlockState(Option<i32>), + CompoundTag(azalea_nbt::Tag), + Particle(Particle), + VillagerData(VillagerData), + // 0 for absent; 1 + actual value otherwise. Used for entity IDs. + OptionalUnsignedInt(Option<u32>), + Pose(Pose), +} + +impl McBufReadable for EntityDataValue { + fn read_into(buf: &mut impl Read) -> Result<Self, String> { + let data_type = i32::var_read_into(buf)?; + Ok(match data_type { + 0 => EntityDataValue::Byte(u8::read_into(buf)?), + 1 => EntityDataValue::Int(i32::var_read_into(buf)?), + 2 => EntityDataValue::Float(f32::read_into(buf)?), + 3 => EntityDataValue::String(String::read_into(buf)?), + 4 => EntityDataValue::Component(Component::read_into(buf)?), + 5 => EntityDataValue::OptionalComponent(Option::<Component>::read_into(buf)?), + 6 => EntityDataValue::ItemStack(Slot::read_into(buf)?), + 7 => EntityDataValue::Boolean(bool::read_into(buf)?), + 8 => EntityDataValue::Rotations { + x: f32::read_into(buf)?, + y: f32::read_into(buf)?, + z: f32::read_into(buf)?, + }, + 9 => EntityDataValue::BlockPos(BlockPos::read_into(buf)?), + 10 => EntityDataValue::OptionalBlockPos(Option::<BlockPos>::read_into(buf)?), + 11 => EntityDataValue::Direction(Direction::read_into(buf)?), + 12 => EntityDataValue::OptionalUuid(Option::<Uuid>::read_into(buf)?), + 13 => EntityDataValue::OptionalBlockState({ + let val = i32::read_into(buf)?; + if val == 0 { + None + } else { + Some(val) + } + }), + 14 => EntityDataValue::CompoundTag(azalea_nbt::Tag::read_into(buf)?), + 15 => EntityDataValue::Particle(Particle::read_into(buf)?), + 16 => EntityDataValue::VillagerData(VillagerData::read_into(buf)?), + 17 => EntityDataValue::OptionalUnsignedInt({ + let val = u32::var_read_into(buf)?; + if val == 0 { + None + } else { + Some((val - 1) as u32) + } + }), + 18 => EntityDataValue::Pose(Pose::read_into(buf)?), + _ => return Err(format!("Unknown entity data type: {}", data_type)), + }) + } +} + +impl McBufWritable for EntityDataValue { + fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + todo!(); + } +} + +#[derive(Clone, Debug, Copy, McBuf)] +pub enum Pose { + Standing = 0, + FallFlying = 1, + Sleeping = 2, + Swimming = 3, + SpinAttack = 4, + Sneaking = 5, + LongJumping = 6, + Dying = 7, +} + +#[derive(Debug, Clone, McBuf)] +pub struct VillagerData { + #[var] + type_: u32, + #[var] + profession: u32, + #[var] + level: u32, +} diff --git a/azalea-entity/src/lib.rs b/azalea-entity/src/lib.rs new file mode 100644 index 00000000..9436d753 --- /dev/null +++ b/azalea-entity/src/lib.rs @@ -0,0 +1,59 @@ +mod data; + +use azalea_core::{EntityPos, PositionDelta}; +pub use data::*; +use uuid::Uuid; + +#[derive(Default, Debug)] +pub struct Entity { + /// The incrementing numerical id of the entity. + pub id: u32, + pub uuid: Uuid, + /// The position of the entity right now. + pos: EntityPos, + /// The position of the entity last tick. + pub old_pos: EntityPos, + pub delta: PositionDelta, + + pub x_rot: f32, + pub y_rot: f32, +} + +impl Entity { + pub fn new(id: u32, uuid: Uuid, pos: EntityPos) -> Self { + Self { + id, + uuid, + pos, + old_pos: pos, + delta: PositionDelta::default(), + x_rot: 0.0, + y_rot: 0.0, + } + } + + pub fn pos(&self) -> &EntityPos { + &self.pos + } + + /// Sets the position of the entity. This doesn't update the cache in + /// azalea-world, and should only be used within azalea-world! + pub fn unsafe_move(&mut self, new_pos: EntityPos) { + self.pos = new_pos; + } + + pub fn set_rotation(&mut self, y_rot: f32, x_rot: f32) { + self.y_rot = y_rot.clamp(-90.0, 90.0) % 360.0; + self.x_rot = x_rot % 360.0; + // TODO: minecraft also sets yRotO and xRotO to xRot and yRot ... but idk what they're used for so + } +} + +// #[cfg(test)] +// mod tests { +// #[test] +// fn it_works() { +// let result = 2 + 2; +// assert_eq!(result, 4); +// } +// } |
