diff --git a/Cargo.lock b/Cargo.lock index ef2c081..272be5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1822,6 +1822,7 @@ dependencies = [ "image 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.9.16 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index f10ffe7..ed46d1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ aes = "0.3.2" cfb8 = "0.3.2" rsa_public_encrypt_pkcs1 = "0.2.0" structopt = "0.2.14" +num-traits = "0.2.6" clipboard = { git = "https://github.com/aweinstock314/rust-clipboard", rev = "07d080be58a361a5bbdb548fafe9449843d968be" } # clippy = "*" diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 4ded3fc..bfdd683 100644 --- a/src/protocol/mod.rs +++ b/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/src/protocol/packet.rs b/src/protocol/packet.rs index 6e78020..21b0615 100644 --- a/src/protocol/packet.rs +++ b/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 =, } diff --git a/src/server/mod.rs b/src/server/mod.rs index 5a15346..5867ab0 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -857,12 +857,12 @@ impl Server { } fn on_entity_teleport_i32(&mut self, entity_telport: packet::play::clientbound::EntityTeleport_i32) { - self.on_entity_teleport(entity_telport.entity_id.0, entity_telport.x as f64, entity_telport.y as f64, entity_telport.z as f64, entity_telport.yaw as f64, entity_telport.pitch as f64, entity_telport.on_ground) + self.on_entity_teleport(entity_telport.entity_id.0, f64::from(entity_telport.x), f64::from(entity_telport.y), f64::from(entity_telport.z), entity_telport.yaw as f64, entity_telport.pitch as f64, entity_telport.on_ground) } fn on_entity_teleport_i32_i32_noground(&mut self, entity_telport: packet::play::clientbound::EntityTeleport_i32_i32_NoGround) { let on_ground = true; // TODO: how is this supposed to be set? (for 1.7) - self.on_entity_teleport(entity_telport.entity_id, entity_telport.x as f64, entity_telport.y as f64, entity_telport.z as f64, entity_telport.yaw as f64, entity_telport.pitch as f64, on_ground) + self.on_entity_teleport(entity_telport.entity_id, f64::from(entity_telport.x), f64::from(entity_telport.y), f64::from(entity_telport.z), entity_telport.yaw as f64, entity_telport.pitch as f64, on_ground) } @@ -880,24 +880,24 @@ impl Server { } fn on_entity_move_i16(&mut self, m: packet::play::clientbound::EntityMove_i16) { - self.on_entity_move(m.entity_id.0, m.delta_x as f64, m.delta_y as f64, m.delta_z as f64) + self.on_entity_move(m.entity_id.0, f64::from(m.delta_x), f64::from(m.delta_y), f64::from(m.delta_z)) } fn on_entity_move_i8(&mut self, m: packet::play::clientbound::EntityMove_i8) { - self.on_entity_move(m.entity_id.0, m.delta_x as f64, m.delta_y as f64, m.delta_z as f64) + self.on_entity_move(m.entity_id.0, f64::from(m.delta_x), f64::from(m.delta_y), f64::from(m.delta_z)) } fn on_entity_move_i8_i32_noground(&mut self, m: packet::play::clientbound::EntityMove_i8_i32_NoGround) { - self.on_entity_move(m.entity_id, m.delta_x as f64, m.delta_y as f64, m.delta_z as f64) + self.on_entity_move(m.entity_id, f64::from(m.delta_x), f64::from(m.delta_y), f64::from(m.delta_z)) } fn on_entity_move(&mut self, entity_id: i32, delta_x: f64, delta_y: f64, delta_z: f64) { if let Some(entity) = self.entity_map.get(&entity_id) { let position = self.entities.get_component_mut(*entity, self.target_position).unwrap(); - position.position.x += delta_x / (32.0 * 128.0); - position.position.y += delta_y / (32.0 * 128.0); - position.position.z += delta_z / (32.0 * 128.0); + position.position.x += delta_x; + position.position.y += delta_y; + position.position.z += delta_z; } } @@ -920,19 +920,19 @@ impl Server { fn on_entity_look_and_move_i16(&mut self, lookmove: packet::play::clientbound::EntityLookAndMove_i16) { self.on_entity_look_and_move(lookmove.entity_id.0, - lookmove.delta_x as f64, lookmove.delta_y as f64, lookmove.delta_z as f64, + f64::from(lookmove.delta_x), f64::from(lookmove.delta_y), f64::from(lookmove.delta_z), lookmove.yaw as f64, lookmove.pitch as f64) } fn on_entity_look_and_move_i8(&mut self, lookmove: packet::play::clientbound::EntityLookAndMove_i8) { self.on_entity_look_and_move(lookmove.entity_id.0, - lookmove.delta_x as f64, lookmove.delta_y as f64, lookmove.delta_z as f64, + f64::from(lookmove.delta_x), f64::from(lookmove.delta_y), f64::from(lookmove.delta_z), lookmove.yaw as f64, lookmove.pitch as f64) } fn on_entity_look_and_move_i8_i32_noground(&mut self, lookmove: packet::play::clientbound::EntityLookAndMove_i8_i32_NoGround) { self.on_entity_look_and_move(lookmove.entity_id, - lookmove.delta_x as f64, lookmove.delta_y as f64, lookmove.delta_z as f64, + f64::from(lookmove.delta_x), f64::from(lookmove.delta_y), f64::from(lookmove.delta_z), lookmove.yaw as f64, lookmove.pitch as f64) } @@ -941,9 +941,9 @@ impl Server { if let Some(entity) = self.entity_map.get(&entity_id) { let position = self.entities.get_component_mut(*entity, self.target_position).unwrap(); let rotation = self.entities.get_component_mut(*entity, self.target_rotation).unwrap(); - position.position.x += delta_x / (32.0 * 128.0); - position.position.y += delta_y / (32.0 * 128.0); - position.position.z += delta_z / (32.0 * 128.0); + position.position.x += delta_x; + position.position.y += delta_y; + position.position.z += delta_z; rotation.yaw = -(yaw / 256.0) * PI * 2.0; rotation.pitch = -(pitch / 256.0) * PI * 2.0; } @@ -954,15 +954,15 @@ impl Server { } fn on_player_spawn_i32(&mut self, spawn: packet::play::clientbound::SpawnPlayer_i32) { - self.on_player_spawn(spawn.entity_id.0, spawn.uuid, spawn.x as f64, spawn.y as f64, spawn.z as f64, spawn.yaw as f64, spawn.pitch as f64) + self.on_player_spawn(spawn.entity_id.0, spawn.uuid, f64::from(spawn.x), f64::from(spawn.y), f64::from(spawn.z), spawn.yaw as f64, spawn.pitch as f64) } fn on_player_spawn_i32_helditem(&mut self, spawn: packet::play::clientbound::SpawnPlayer_i32_HeldItem) { - self.on_player_spawn(spawn.entity_id.0, spawn.uuid, spawn.x as f64, spawn.y as f64, spawn.z as f64, spawn.yaw as f64, spawn.pitch as f64) + self.on_player_spawn(spawn.entity_id.0, spawn.uuid, f64::from(spawn.x), f64::from(spawn.y), f64::from(spawn.z), spawn.yaw as f64, spawn.pitch as f64) } fn on_player_spawn_i32_helditem_string(&mut self, spawn: packet::play::clientbound::SpawnPlayer_i32_HeldItem_String) { - self.on_player_spawn(spawn.entity_id.0, protocol::UUID::from_str(&spawn.uuid), spawn.x as f64, spawn.y as f64, spawn.z as f64, spawn.yaw as f64, spawn.pitch as f64) + self.on_player_spawn(spawn.entity_id.0, protocol::UUID::from_str(&spawn.uuid), f64::from(spawn.x), f64::from(spawn.y), f64::from(spawn.z), spawn.yaw as f64, spawn.pitch as f64) } fn on_player_spawn(&mut self, entity_id: i32, uuid: protocol::UUID, x: f64, y: f64, z: f64, pitch: f64, yaw: f64) {