From e02f05825f3a5f77d3886dba8985c80106b6f901 Mon Sep 17 00:00:00 2001 From: Snowiiii Date: Sat, 7 Dec 2024 16:20:49 +0100 Subject: [PATCH] Add Deserialize and Serialize for Vector3 --- pumpkin-core/Cargo.toml | 1 + pumpkin-core/src/math/vector3.rs | 107 ++++++++++++++++++ .../src/client/play/c_damage_event.rs | 5 +- .../src/client/play/c_entity_velocity.rs | 2 +- .../src/client/play/c_particle.rs | 26 ++--- .../src/client/play/c_update_entity_pos.rs | 17 +-- .../client/play/c_update_entity_pos_rot.rs | 13 +-- .../src/server/play/s_interact.rs | 13 ++- .../src/server/play/s_player_position.rs | 5 +- .../server/play/s_player_position_rotation.rs | 5 +- .../src/server/play/s_use_item_on.rs | 6 +- pumpkin/src/client/combat.rs | 14 +-- pumpkin/src/client/player_packet.rs | 70 ++++++------ 13 files changed, 179 insertions(+), 105 deletions(-) diff --git a/pumpkin-core/Cargo.toml b/pumpkin-core/Cargo.toml index 84248ab3e..c56368a99 100644 --- a/pumpkin-core/Cargo.toml +++ b/pumpkin-core/Cargo.toml @@ -6,6 +6,7 @@ edition.workspace = true [dependencies] pumpkin-nbt = { path = "../pumpkin-nbt" } serde.workspace = true +bytes.workspace = true uuid.workspace = true num-traits.workspace = true num-derive.workspace = true diff --git a/pumpkin-core/src/math/vector3.rs b/pumpkin-core/src/math/vector3.rs index 1f2bf0032..53d87826a 100644 --- a/pumpkin-core/src/math/vector3.rs +++ b/pumpkin-core/src/math/vector3.rs @@ -1,3 +1,4 @@ +use bytes::BufMut; use std::ops::{Add, Div, Mul, Sub}; use num_traits::Float; @@ -117,8 +118,114 @@ pub trait Math: + Sized { } +impl Math for i16 {} impl Math for f64 {} impl Math for f32 {} impl Math for i32 {} impl Math for i64 {} impl Math for u8 {} + +impl<'de> serde::Deserialize<'de> for Vector3 { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + struct Vector3Visitor; + + impl<'de> serde::de::Visitor<'de> for Vector3Visitor { + type Value = Vector3; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a valid Vector<32>") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: serde::de::SeqAccess<'de>, + { + if let Some(x) = seq.next_element::()? { + if let Some(y) = seq.next_element::()? { + if let Some(z) = seq.next_element::()? { + return Ok(Vector3::new(x, y, z)); + } + } + } + Err(serde::de::Error::custom("Failed to read Vector")) + } + } + + deserializer.deserialize_seq(Vector3Visitor) + } +} + +impl<'de> serde::Deserialize<'de> for Vector3 { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + struct Vector3Visitor; + + impl<'de> serde::de::Visitor<'de> for Vector3Visitor { + type Value = Vector3; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a valid Vector") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: serde::de::SeqAccess<'de>, + { + if let Some(x) = seq.next_element::()? { + if let Some(y) = seq.next_element::()? { + if let Some(z) = seq.next_element::()? { + return Ok(Vector3::new(x, y, z)); + } + } + } + Err(serde::de::Error::custom("Failed to read Vector")) + } + } + + deserializer.deserialize_seq(Vector3Visitor) + } +} + +impl serde::Serialize for Vector3 { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut buf = Vec::new(); + buf.put_f32(self.x); + buf.put_f32(self.y); + buf.put_f32(self.z); + serializer.serialize_bytes(&buf) + } +} + +impl serde::Serialize for Vector3 { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut buf = Vec::new(); + buf.put_f64(self.x); + buf.put_f64(self.y); + buf.put_f64(self.z); + serializer.serialize_bytes(&buf) + } +} + +impl serde::Serialize for Vector3 { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut buf = Vec::new(); + buf.put_i16(self.x); + buf.put_i16(self.y); + buf.put_i16(self.z); + serializer.serialize_bytes(&buf) + } +} diff --git a/pumpkin-protocol/src/client/play/c_damage_event.rs b/pumpkin-protocol/src/client/play/c_damage_event.rs index ab1042678..4d2d04eaf 100644 --- a/pumpkin-protocol/src/client/play/c_damage_event.rs +++ b/pumpkin-protocol/src/client/play/c_damage_event.rs @@ -1,3 +1,4 @@ +use pumpkin_core::math::vector3::Vector3; use pumpkin_macros::client_packet; use serde::Serialize; @@ -10,7 +11,7 @@ pub struct CDamageEvent { source_type_id: VarInt, source_cause_id: VarInt, source_direct_id: VarInt, - source_position: Option<(f64, f64, f64)>, + source_position: Option>, } impl CDamageEvent { @@ -19,7 +20,7 @@ impl CDamageEvent { source_type_id: VarInt, source_cause_id: Option, source_direct_id: Option, - source_position: Option<(f64, f64, f64)>, + source_position: Option>, ) -> Self { Self { entity_id, diff --git a/pumpkin-protocol/src/client/play/c_entity_velocity.rs b/pumpkin-protocol/src/client/play/c_entity_velocity.rs index e73989b6c..63c543501 100644 --- a/pumpkin-protocol/src/client/play/c_entity_velocity.rs +++ b/pumpkin-protocol/src/client/play/c_entity_velocity.rs @@ -13,7 +13,7 @@ pub struct CEntityVelocity<'a> { } impl<'a> CEntityVelocity<'a> { - pub fn new(entity_id: &'a VarInt, velocity_x: f32, velocity_y: f32, velocity_z: f32) -> Self { + pub fn new(entity_id: &'a VarInt, velocity_x: f64, velocity_y: f64, velocity_z: f64) -> Self { Self { entity_id, velocity_x: (velocity_x.clamp(-3.9, 3.9) * 8000.0) as i16, diff --git a/pumpkin-protocol/src/client/play/c_particle.rs b/pumpkin-protocol/src/client/play/c_particle.rs index 0110df8c2..45cc14340 100644 --- a/pumpkin-protocol/src/client/play/c_particle.rs +++ b/pumpkin-protocol/src/client/play/c_particle.rs @@ -1,3 +1,4 @@ +use pumpkin_core::math::vector3::Vector3; use pumpkin_macros::client_packet; use serde::Serialize; @@ -8,12 +9,8 @@ use crate::VarInt; pub struct CParticle<'a> { /// If true, particle distance increases from 256 to 65536. long_distance: bool, - x: f64, - y: f64, - z: f64, - offset_x: f32, - offset_y: f32, - offset_z: f32, + position: Vector3, + offset: Vector3, max_speed: f32, particle_count: i32, pariticle_id: VarInt, @@ -21,15 +18,10 @@ pub struct CParticle<'a> { } impl<'a> CParticle<'a> { - #[expect(clippy::too_many_arguments)] pub fn new( long_distance: bool, - x: f64, - y: f64, - z: f64, - offset_x: f32, - offset_y: f32, - offset_z: f32, + position: Vector3, + offset: Vector3, max_speed: f32, particle_count: i32, pariticle_id: VarInt, @@ -37,12 +29,8 @@ impl<'a> CParticle<'a> { ) -> Self { Self { long_distance, - x, - y, - z, - offset_x, - offset_y, - offset_z, + position, + offset, max_speed, particle_count, pariticle_id, diff --git a/pumpkin-protocol/src/client/play/c_update_entity_pos.rs b/pumpkin-protocol/src/client/play/c_update_entity_pos.rs index bb0eab806..b94e92530 100644 --- a/pumpkin-protocol/src/client/play/c_update_entity_pos.rs +++ b/pumpkin-protocol/src/client/play/c_update_entity_pos.rs @@ -1,3 +1,4 @@ +use pumpkin_core::math::vector3::Vector3; use pumpkin_macros::client_packet; use serde::Serialize; @@ -7,25 +8,15 @@ use crate::VarInt; #[client_packet("play:move_entity_pos")] pub struct CUpdateEntityPos { entity_id: VarInt, - delta_x: i16, - delta_y: i16, - delta_z: i16, + delta: Vector3, on_ground: bool, } impl CUpdateEntityPos { - pub fn new( - entity_id: VarInt, - delta_x: i16, - delta_y: i16, - delta_z: i16, - on_ground: bool, - ) -> Self { + pub fn new(entity_id: VarInt, delta: Vector3, on_ground: bool) -> Self { Self { entity_id, - delta_x, - delta_y, - delta_z, + delta, on_ground, } } diff --git a/pumpkin-protocol/src/client/play/c_update_entity_pos_rot.rs b/pumpkin-protocol/src/client/play/c_update_entity_pos_rot.rs index ecc14b681..c15b0237a 100644 --- a/pumpkin-protocol/src/client/play/c_update_entity_pos_rot.rs +++ b/pumpkin-protocol/src/client/play/c_update_entity_pos_rot.rs @@ -1,3 +1,4 @@ +use pumpkin_core::math::vector3::Vector3; use pumpkin_macros::client_packet; use serde::Serialize; @@ -7,9 +8,7 @@ use crate::VarInt; #[client_packet("play:move_entity_pos_rot")] pub struct CUpdateEntityPosRot { entity_id: VarInt, - delta_x: i16, - delta_y: i16, - delta_z: i16, + delta: Vector3, yaw: u8, pitch: u8, on_ground: bool, @@ -18,18 +17,14 @@ pub struct CUpdateEntityPosRot { impl CUpdateEntityPosRot { pub fn new( entity_id: VarInt, - delta_x: i16, - delta_y: i16, - delta_z: i16, + delta: Vector3, yaw: u8, pitch: u8, on_ground: bool, ) -> Self { Self { entity_id, - delta_x, - delta_y, - delta_z, + delta, yaw, pitch, on_ground, diff --git a/pumpkin-protocol/src/server/play/s_interact.rs b/pumpkin-protocol/src/server/play/s_interact.rs index 9a1a5d7b5..f283f0487 100644 --- a/pumpkin-protocol/src/server/play/s_interact.rs +++ b/pumpkin-protocol/src/server/play/s_interact.rs @@ -1,5 +1,6 @@ use num_derive::FromPrimitive; use num_traits::FromPrimitive; +use pumpkin_core::math::vector3::Vector3; use pumpkin_macros::server_packet; use crate::{bytebuf::DeserializerError, ServerPacket, VarInt}; @@ -8,7 +9,7 @@ use crate::{bytebuf::DeserializerError, ServerPacket, VarInt}; pub struct SInteract { pub entity_id: VarInt, pub typ: VarInt, - pub target_position: Option<(f32, f32, f32)>, + pub target_position: Option>, pub hand: Option, pub sneaking: bool, } @@ -23,12 +24,14 @@ impl ServerPacket for SInteract { let action = ActionType::from_i32(typ.0).ok_or(DeserializerError::Message( "invalid action type".to_string(), ))?; - let target_position: Option<(f32, f32, f32)> = match action { + let target_position: Option> = match action { ActionType::Interact => None, ActionType::Attack => None, - ActionType::InteractAt => { - Some((bytebuf.get_f32()?, bytebuf.get_f32()?, bytebuf.get_f32()?)) - } + ActionType::InteractAt => Some(Vector3::new( + bytebuf.get_f32()?, + bytebuf.get_f32()?, + bytebuf.get_f32()?, + )), }; let hand = match action { ActionType::Interact => Some(bytebuf.get_var_int()?), diff --git a/pumpkin-protocol/src/server/play/s_player_position.rs b/pumpkin-protocol/src/server/play/s_player_position.rs index 729b406be..ea0b6a74b 100644 --- a/pumpkin-protocol/src/server/play/s_player_position.rs +++ b/pumpkin-protocol/src/server/play/s_player_position.rs @@ -1,10 +1,9 @@ +use pumpkin_core::math::vector3::Vector3; use pumpkin_macros::server_packet; #[derive(serde::Deserialize)] #[server_packet("play:move_player_pos")] pub struct SPlayerPosition { - pub x: f64, - pub feet_y: f64, - pub z: f64, + pub position: Vector3, pub ground: bool, } diff --git a/pumpkin-protocol/src/server/play/s_player_position_rotation.rs b/pumpkin-protocol/src/server/play/s_player_position_rotation.rs index a97a68ed5..0b4453558 100644 --- a/pumpkin-protocol/src/server/play/s_player_position_rotation.rs +++ b/pumpkin-protocol/src/server/play/s_player_position_rotation.rs @@ -1,11 +1,10 @@ +use pumpkin_core::math::vector3::Vector3; use pumpkin_macros::server_packet; #[derive(serde::Deserialize)] #[server_packet("play:move_player_pos_rot")] pub struct SPlayerPositionRotation { - pub x: f64, - pub feet_y: f64, - pub z: f64, + pub position: Vector3, pub yaw: f32, pub pitch: f32, pub ground: bool, diff --git a/pumpkin-protocol/src/server/play/s_use_item_on.rs b/pumpkin-protocol/src/server/play/s_use_item_on.rs index 3e16d282c..6ad28fb65 100644 --- a/pumpkin-protocol/src/server/play/s_use_item_on.rs +++ b/pumpkin-protocol/src/server/play/s_use_item_on.rs @@ -1,4 +1,4 @@ -use pumpkin_core::math::position::WorldPosition; +use pumpkin_core::math::{position::WorldPosition, vector3::Vector3}; use pumpkin_macros::server_packet; use serde::Deserialize; @@ -10,9 +10,7 @@ pub struct SUseItemOn { pub hand: VarInt, pub location: WorldPosition, pub face: VarInt, - pub cursor_pos_x: f32, - pub cursor_pos_y: f32, - pub cursor_pos_z: f32, + pub cursor_pos: Vector3, pub inside_block: bool, pub is_against_world_border: bool, pub sequence: VarInt, diff --git a/pumpkin/src/client/combat.rs b/pumpkin/src/client/combat.rs index 73cea5f9e..8b5b0ed10 100644 --- a/pumpkin/src/client/combat.rs +++ b/pumpkin/src/client/combat.rs @@ -80,9 +80,9 @@ pub async fn handle_knockback( let packet = &CEntityVelocity::new( &entity_id, - victim_velocity.x as f32, - victim_velocity.y as f32, - victim_velocity.z as f32, + victim_velocity.x, + victim_velocity.y, + victim_velocity.z, ); let velocity = attacker_entity.velocity.load(); attacker_entity @@ -105,12 +105,8 @@ pub async fn spawn_sweep_particle(attacker_entity: &Entity, world: &World, pos: world .broadcast_packet_all(&CParticle::new( false, - pos.x + d, - body_y, - pos.z + e, - 0.0, - 0.0, - 0.0, + Vector3::new(pos.x + d, body_y, pos.z + e), + Vector3::new(0.0, 0.0, 0.0), 0.0, 0, VarInt(i32::from(particle!("sweep_attack"))), // sweep diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 706b7fe2b..1dd55bf0f 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -114,18 +114,17 @@ impl Player { pos.clamp(-2.0E7, 2.0E7) } - pub async fn handle_position(self: &Arc, position_packet: SPlayerPosition) { - if position_packet.x.is_nan() - || position_packet.feet_y.is_nan() - || position_packet.z.is_nan() - { + pub async fn handle_position(self: &Arc, packet: SPlayerPosition) { + // y = feet Y + let position = packet.position; + if position.x.is_nan() || position.y.is_nan() || position.z.is_nan() { self.kick(TextComponent::text("Invalid movement")).await; return; } let position = Vector3::new( - Self::clamp_horizontal(position_packet.x), - Self::clamp_vertical(position_packet.feet_y), - Self::clamp_horizontal(position_packet.z), + Self::clamp_horizontal(position.x), + Self::clamp_vertical(position.y), + Self::clamp_horizontal(position.z), ); let entity = &self.living_entity.entity; self.living_entity.set_pos(position); @@ -135,11 +134,10 @@ impl Player { entity .on_ground - .store(position_packet.ground, std::sync::atomic::Ordering::Relaxed); + .store(packet.ground, std::sync::atomic::Ordering::Relaxed); let entity_id = entity.entity_id; let Vector3 { x, y, z } = pos; - let (last_x, last_y, last_z) = (last_pos.x, last_pos.y, last_pos.z); let world = &entity.world; // let delta = Vector3::new(x - lastx, y - lasty, z - lastz); @@ -160,36 +158,34 @@ impl Player { &[self.gameprofile.id], &CUpdateEntityPos::new( entity_id.into(), - x.mul_add(4096.0, -(last_x * 4096.0)) as i16, - y.mul_add(4096.0, -(last_y * 4096.0)) as i16, - z.mul_add(4096.0, -(last_z * 4096.0)) as i16, - position_packet.ground, + Vector3::new( + x.mul_add(4096.0, -(last_pos.x * 4096.0)) as i16, + y.mul_add(4096.0, -(last_pos.y * 4096.0)) as i16, + z.mul_add(4096.0, -(last_pos.z * 4096.0)) as i16, + ), + packet.ground, ), ) .await; player_chunker::update_position(self).await; } - pub async fn handle_position_rotation( - self: &Arc, - position_rotation: SPlayerPositionRotation, - ) { - if position_rotation.x.is_nan() - || position_rotation.feet_y.is_nan() - || position_rotation.z.is_nan() - { + pub async fn handle_position_rotation(self: &Arc, packet: SPlayerPositionRotation) { + // y = feet Y + let position = packet.position; + if position.x.is_nan() || position.y.is_nan() || position.z.is_nan() { self.kick(TextComponent::text("Invalid movement")).await; return; } - if position_rotation.yaw.is_infinite() || position_rotation.pitch.is_infinite() { + if packet.yaw.is_infinite() || packet.pitch.is_infinite() { self.kick(TextComponent::text("Invalid rotation")).await; return; } let position = Vector3::new( - Self::clamp_horizontal(position_rotation.x), - Self::clamp_vertical(position_rotation.feet_y), - Self::clamp_horizontal(position_rotation.z), + Self::clamp_horizontal(position.x), + Self::clamp_vertical(position.y), + Self::clamp_horizontal(position.z), ); let entity = &self.living_entity.entity; self.living_entity.set_pos(position); @@ -197,19 +193,17 @@ impl Player { let pos = entity.pos.load(); let last_pos = self.living_entity.last_pos.load(); - entity.on_ground.store( - position_rotation.ground, - std::sync::atomic::Ordering::Relaxed, - ); + entity + .on_ground + .store(packet.ground, std::sync::atomic::Ordering::Relaxed); entity.set_rotation( - wrap_degrees(position_rotation.yaw) % 360.0, - wrap_degrees(position_rotation.pitch).clamp(-90.0, 90.0) % 360.0, + wrap_degrees(packet.yaw) % 360.0, + wrap_degrees(packet.pitch).clamp(-90.0, 90.0) % 360.0, ); let entity_id = entity.entity_id; let Vector3 { x, y, z } = pos; - let (last_x, last_y, last_z) = (last_pos.x, last_pos.y, last_pos.z); let yaw = modulus(entity.yaw.load() * 256.0 / 360.0, 256.0); let pitch = modulus(entity.pitch.load() * 256.0 / 360.0, 256.0); @@ -235,12 +229,14 @@ impl Player { &[self.gameprofile.id], &CUpdateEntityPosRot::new( entity_id.into(), - x.mul_add(4096.0, -(last_x * 4096.0)) as i16, - y.mul_add(4096.0, -(last_y * 4096.0)) as i16, - z.mul_add(4096.0, -(last_z * 4096.0)) as i16, + Vector3::new( + x.mul_add(4096.0, -(last_pos.x * 4096.0)) as i16, + y.mul_add(4096.0, -(last_pos.y * 4096.0)) as i16, + z.mul_add(4096.0, -(last_pos.z * 4096.0)) as i16, + ), yaw as u8, pitch as u8, - position_rotation.ground, + packet.ground, ), ) .await;