aboutsummaryrefslogtreecommitdiff
path: root/azalea-entity/src
diff options
context:
space:
mode:
Diffstat (limited to 'azalea-entity/src')
-rw-r--r--azalea-entity/src/data.rs144
-rw-r--r--azalea-entity/src/lib.rs59
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);
+// }
+// }