diff --git a/protocol/src/protocol/mod.rs b/protocol/src/protocol/mod.rs index 4ded3fc..bfdd683 100644 --- a/protocol/src/protocol/mod.rs +++ b/protocol/src/protocol/mod.rs @@ -597,6 +597,90 @@ impl Lengthable for i32 { } } +use num_traits::cast::{cast, NumCast}; +/// `FixedPoint5` has the 5 least-significant bits for the fractional +/// part, upper for integer part: https://wiki.vg/Data_types#Fixed-point_numbers +#[derive(Clone, Copy)] +pub struct FixedPoint5(T); + +impl Serializable for FixedPoint5 { + fn read_from(buf: &mut R) -> Result { + Ok(Self(Serializable::read_from(buf)?)) + } + + fn write_to(&self, buf: &mut W) -> Result<(), Error> { + self.0.write_to(buf) + } +} + +impl default::Default for FixedPoint5 { + fn default() -> Self { + Self(T::default()) + } +} + +impl convert::From for FixedPoint5 { + fn from(x: f64) -> Self { + let n: T = cast(x * 32.0).unwrap(); + FixedPoint5::(n) + } +} + +impl convert::From> for f64 { + fn from(x: FixedPoint5) -> Self { + let f: f64 = cast(x.0).unwrap(); + f / 32.0 + } +} + +impl fmt::Debug for FixedPoint5 where T: fmt::Display, f64: convert::From, T: NumCast + Copy { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let x: f64 = (*self).into(); + write!(f, "FixedPoint5(#{} = {}f)", self.0, x) + } +} + +/// `FixedPoint12` is like `FixedPoint5` but the fractional part is 12-bit +#[derive(Clone, Copy)] +pub struct FixedPoint12(T); + +impl Serializable for FixedPoint12 { + fn read_from(buf: &mut R) -> Result { + Ok(Self(Serializable::read_from(buf)?)) + } + + fn write_to(&self, buf: &mut W) -> Result<(), Error> { + self.0.write_to(buf) + } +} + +impl default::Default for FixedPoint12 { + fn default() -> Self { + Self(T::default()) + } +} + +impl convert::From for FixedPoint12 { + fn from(x: f64) -> Self { + let n: T = cast(x * 32.0 * 128.0).unwrap(); + FixedPoint12::(n) + } +} + +impl convert::From> for f64 { + fn from(x: FixedPoint12) -> Self { + let f: f64 = cast(x.0).unwrap(); + f / (32.0 * 128.0) + } +} + +impl fmt::Debug for FixedPoint12 where T: fmt::Display, f64: convert::From, T: NumCast + Copy { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let x: f64 = (*self).into(); + write!(f, "FixedPoint12(#{} = {}f)", self.0, x) + } +} + /// `VarInt` have a variable size (between 1 and 5 bytes) when encoded based /// on the size of the number #[derive(Clone, Copy)] diff --git a/protocol/src/protocol/packet.rs b/protocol/src/protocol/packet.rs index 6e78020..21b0615 100644 --- a/protocol/src/protocol/packet.rs +++ b/protocol/src/protocol/packet.rs @@ -495,9 +495,9 @@ state_packets!( field entity_id: VarInt =, field uuid: UUID =, field ty: u8 =, - field x: i32 =, - field y: i32 =, - field z: i32 =, + field x: FixedPoint5 =, + field y: FixedPoint5 =, + field z: FixedPoint5 =, field pitch: i8 =, field yaw: i8 =, field data: i32 =, @@ -508,9 +508,9 @@ state_packets!( packet SpawnObject_i32_NoUUID { field entity_id: VarInt =, field ty: u8 =, - field x: i32 =, - field y: i32 =, - field z: i32 =, + field x: FixedPoint5 =, + field y: FixedPoint5 =, + field z: FixedPoint5 =, field pitch: i8 =, field yaw: i8 =, field data: i32 =, @@ -530,9 +530,9 @@ state_packets!( } packet SpawnExperienceOrb_i32 { field entity_id: VarInt =, - field x: i32 =, - field y: i32 =, - field z: i32 =, + field x: FixedPoint5 =, + field y: FixedPoint5 =, + field z: FixedPoint5 =, field count: i16 =, } /// SpawnGlobalEntity spawns an entity which is visible from anywhere in the @@ -547,9 +547,9 @@ state_packets!( packet SpawnGlobalEntity_i32 { field entity_id: VarInt =, field ty: u8 =, - field x: i32 =, - field y: i32 =, - field z: i32 =, + field x: FixedPoint5 =, + field y: FixedPoint5 =, + field z: FixedPoint5 =, } /// SpawnMob is used to spawn a living entity into the world when it is in /// range of the client. @@ -587,9 +587,9 @@ state_packets!( field entity_id: VarInt =, field uuid: UUID =, field ty: u8 =, - field x: i32 =, - field y: i32 =, - field z: i32 =, + field x: FixedPoint5 =, + field y: FixedPoint5 =, + field z: FixedPoint5 =, field yaw: i8 =, field pitch: i8 =, field head_pitch: i8 =, @@ -601,9 +601,9 @@ state_packets!( packet SpawnMob_u8_i32_NoUUID { field entity_id: VarInt =, field ty: u8 =, - field x: i32 =, - field y: i32 =, - field z: i32 =, + field x: FixedPoint5 =, + field y: FixedPoint5 =, + field z: FixedPoint5 =, field yaw: i8 =, field pitch: i8 =, field head_pitch: i8 =, @@ -651,9 +651,9 @@ state_packets!( packet SpawnPlayer_i32 { field entity_id: VarInt =, field uuid: UUID =, - field x: i32 =, - field y: i32 =, - field z: i32 =, + field x: FixedPoint5 =, + field y: FixedPoint5 =, + field z: FixedPoint5 =, field yaw: i8 =, field pitch: i8 =, field metadata: types::Metadata =, @@ -661,9 +661,9 @@ state_packets!( packet SpawnPlayer_i32_HeldItem { field entity_id: VarInt =, field uuid: UUID =, - field x: i32 =, - field y: i32 =, - field z: i32 =, + field x: FixedPoint5 =, + field y: FixedPoint5 =, + field z: FixedPoint5 =, field yaw: i8 =, field pitch: i8 =, field current_item: u16 =, @@ -674,9 +674,9 @@ state_packets!( field uuid: String =, field name: String =, field properties: LenPrefixed =, - field x: i32 =, - field y: i32 =, - field z: i32 =, + field x: FixedPoint5 =, + field y: FixedPoint5 =, + field z: FixedPoint5 =, field yaw: i8 =, field pitch: i8 =, field current_item: u16 =, @@ -1159,48 +1159,48 @@ state_packets!( /// EntityMove moves the entity with the id by the offsets provided. packet EntityMove_i16 { field entity_id: VarInt =, - field delta_x: i16 =, - field delta_y: i16 =, - field delta_z: i16 =, + field delta_x: FixedPoint12 =, + field delta_y: FixedPoint12 =, + field delta_z: FixedPoint12 =, field on_ground: bool =, } packet EntityMove_i8 { field entity_id: VarInt =, - field delta_x: i8 =, - field delta_y: i8 =, - field delta_z: i8 =, + field delta_x: FixedPoint5 =, + field delta_y: FixedPoint5 =, + field delta_z: FixedPoint5 =, field on_ground: bool =, } packet EntityMove_i8_i32_NoGround { field entity_id: i32 =, - field delta_x: i8 =, - field delta_y: i8 =, - field delta_z: i8 =, + field delta_x: FixedPoint5 =, + field delta_y: FixedPoint5 =, + field delta_z: FixedPoint5 =, } /// EntityLookAndMove is a combination of EntityMove and EntityLook. packet EntityLookAndMove_i16 { field entity_id: VarInt =, - field delta_x: i16 =, - field delta_y: i16 =, - field delta_z: i16 =, + field delta_x: FixedPoint12 =, + field delta_y: FixedPoint12 =, + field delta_z: FixedPoint12 =, field yaw: i8 =, field pitch: i8 =, field on_ground: bool =, } packet EntityLookAndMove_i8 { field entity_id: VarInt =, - field delta_x: i8 =, - field delta_y: i8 =, - field delta_z: i8 =, + field delta_x: FixedPoint5 =, + field delta_y: FixedPoint5 =, + field delta_z: FixedPoint5 =, field yaw: i8 =, field pitch: i8 =, field on_ground: bool =, } packet EntityLookAndMove_i8_i32_NoGround { field entity_id: i32 =, - field delta_x: i8 =, - field delta_y: i8 =, - field delta_z: i8 =, + field delta_x: FixedPoint5 =, + field delta_y: FixedPoint5 =, + field delta_z: FixedPoint5 =, field yaw: i8 =, field pitch: i8 =, } @@ -1677,18 +1677,18 @@ state_packets!( } packet EntityTeleport_i32 { field entity_id: VarInt =, - field x: i32 =, - field y: i32 =, - field z: i32 =, + field x: FixedPoint5 =, + field y: FixedPoint5 =, + field z: FixedPoint5 =, field yaw: i8 =, field pitch: i8 =, field on_ground: bool =, } packet EntityTeleport_i32_i32_NoGround { field entity_id: i32 =, - field x: i32 =, - field y: i32 =, - field z: i32 =, + field x: FixedPoint5 =, + field y: FixedPoint5 =, + field z: FixedPoint5 =, field yaw: i8 =, field pitch: i8 =, }