diff --git a/Cargo.toml b/Cargo.toml index 8ad56ae1a..ae9ee6f2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ thiserror = "2" num-traits = "0.2" num-derive = "0.4" -bytes = "1.8" +bytes = "1.9" # Concurrency/Parallelism and Synchronization rayon = "1.10.0" diff --git a/pumpkin-protocol/Cargo.toml b/pumpkin-protocol/Cargo.toml index 12112220f..b2a4c7803 100644 --- a/pumpkin-protocol/Cargo.toml +++ b/pumpkin-protocol/Cargo.toml @@ -18,8 +18,7 @@ log.workspace = true tokio.workspace = true num-traits.workspace = true num-derive.workspace = true - -bytes = "1.8" +bytes.workspace = true # encryption aes = "0.8.4" diff --git a/pumpkin-protocol/src/client/play/c_sync_player_position.rs b/pumpkin-protocol/src/client/play/c_player_position.rs similarity index 59% rename from pumpkin-protocol/src/client/play/c_sync_player_position.rs rename to pumpkin-protocol/src/client/play/c_player_position.rs index 5e163df7a..0a99a9e09 100644 --- a/pumpkin-protocol/src/client/play/c_sync_player_position.rs +++ b/pumpkin-protocol/src/client/play/c_player_position.rs @@ -4,20 +4,16 @@ use pumpkin_macros::client_packet; use crate::{ClientPacket, PositionFlag, VarInt}; #[client_packet("play:player_position")] -pub struct CSyncPlayerPosition<'a> { +pub struct CPlayerPosition<'a> { teleport_id: VarInt, - x: f64, - y: f64, - z: f64, - delta_x: f64, - delta_y: f64, - delta_z: f64, + position: Vector3, + delta: Vector3, yaw: f32, pitch: f32, releatives: &'a [PositionFlag], } -impl<'a> CSyncPlayerPosition<'a> { +impl<'a> CPlayerPosition<'a> { pub fn new( teleport_id: VarInt, position: Vector3, @@ -28,12 +24,8 @@ impl<'a> CSyncPlayerPosition<'a> { ) -> Self { Self { teleport_id, - x: position.x, - y: position.y, - z: position.z, - delta_x: delta.x, - delta_y: delta.y, - delta_z: delta.z, + position, + delta, yaw, pitch, releatives, @@ -41,15 +33,15 @@ impl<'a> CSyncPlayerPosition<'a> { } } -impl ClientPacket for CSyncPlayerPosition<'_> { +impl ClientPacket for CPlayerPosition<'_> { fn write(&self, bytebuf: &mut crate::bytebuf::ByteBuffer) { bytebuf.put_var_int(&self.teleport_id); - bytebuf.put_f64(self.x); - bytebuf.put_f64(self.y); - bytebuf.put_f64(self.z); - bytebuf.put_f64(self.delta_x); - bytebuf.put_f64(self.delta_y); - bytebuf.put_f64(self.delta_z); + bytebuf.put_f64(self.position.x); + bytebuf.put_f64(self.position.y); + bytebuf.put_f64(self.position.z); + bytebuf.put_f64(self.delta.x); + bytebuf.put_f64(self.delta.y); + bytebuf.put_f64(self.delta.z); bytebuf.put_f32(self.yaw); bytebuf.put_f32(self.pitch); // not sure about that diff --git a/pumpkin-protocol/src/client/play/c_teleport_entity.rs b/pumpkin-protocol/src/client/play/c_teleport_entity.rs index 10d90c5c0..4327ed658 100644 --- a/pumpkin-protocol/src/client/play/c_teleport_entity.rs +++ b/pumpkin-protocol/src/client/play/c_teleport_entity.rs @@ -1,38 +1,54 @@ +use pumpkin_core::math::vector3::Vector3; use pumpkin_macros::client_packet; -use serde::Serialize; -use crate::VarInt; +use crate::{ClientPacket, PositionFlag, VarInt}; -#[derive(Serialize)] #[client_packet("play:teleport_entity")] -pub struct CTeleportEntitiy { +pub struct CTeleportEntitiy<'a> { entity_id: VarInt, - x: f64, - y: f64, - z: f64, - yaw: u8, - pitch: u8, + position: Vector3, + delta: Vector3, + yaw: f32, + pitch: f32, + releatives: &'a [PositionFlag], on_ground: bool, } -impl CTeleportEntitiy { +impl<'a> CTeleportEntitiy<'a> { pub fn new( entity_id: VarInt, - x: f64, - y: f64, - z: f64, - yaw: u8, - pitch: u8, + position: Vector3, + delta: Vector3, + yaw: f32, + pitch: f32, + releatives: &'a [PositionFlag], on_ground: bool, ) -> Self { Self { entity_id, - x, - y, - z, + position, + delta, yaw, pitch, + releatives, on_ground, } } } + +impl ClientPacket for CTeleportEntitiy<'_> { + fn write(&self, bytebuf: &mut crate::bytebuf::ByteBuffer) { + bytebuf.put_var_int(&self.entity_id); + bytebuf.put_f64(self.position.x); + bytebuf.put_f64(self.position.y); + bytebuf.put_f64(self.position.z); + bytebuf.put_f64(self.delta.x); + bytebuf.put_f64(self.delta.y); + bytebuf.put_f64(self.delta.z); + bytebuf.put_f32(self.yaw); + bytebuf.put_f32(self.pitch); + // not sure about that + bytebuf.put_i32(PositionFlag::get_bitfield(self.releatives)); + bytebuf.put_bool(self.on_ground); + } +} diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index 6d8289fc5..79f7e3ea3 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -34,6 +34,7 @@ mod c_play_disconnect; mod c_player_abilities; mod c_player_chat_message; mod c_player_info_update; +mod c_player_position; mod c_player_remove; mod c_remove_entities; mod c_reset_score; @@ -55,7 +56,6 @@ mod c_sound_effect; mod c_spawn_entity; mod c_store_cookie; mod c_subtitle; -mod c_sync_player_position; mod c_system_chat_message; mod c_teleport_entity; mod c_transfer; @@ -104,6 +104,7 @@ pub use c_play_disconnect::*; pub use c_player_abilities::*; pub use c_player_chat_message::*; pub use c_player_info_update::*; +pub use c_player_position::*; pub use c_player_remove::*; pub use c_remove_entities::*; pub use c_reset_score::*; @@ -125,7 +126,6 @@ pub use c_sound_effect::*; pub use c_spawn_entity::*; pub use c_store_cookie::*; pub use c_subtitle::*; -pub use c_sync_player_position::*; pub use c_system_chat_message::*; pub use c_teleport_entity::*; pub use c_transfer::*; diff --git a/pumpkin/Cargo.toml b/pumpkin/Cargo.toml index 0025889ec..476258e2b 100644 --- a/pumpkin/Cargo.toml +++ b/pumpkin/Cargo.toml @@ -37,7 +37,7 @@ parking_lot.workspace = true serde.workspace = true serde_json.workspace = true -bytes = "1.8" +bytes.workspace = true rand = "0.8.5" diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 89bcbda23..706b7fe2b 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -92,8 +92,7 @@ impl Player { if let Some((id, position)) = awaiting_teleport.as_ref() { if id == &confirm_teleport.teleport_id { // we should set the pos now to that we requested in the teleport packet, Is may fixed issues when the client sended position packets while being teleported - self.living_entity - .set_pos(position.x, position.y, position.z); + self.living_entity.set_pos(*position); *awaiting_teleport = None; } else { @@ -115,25 +114,28 @@ impl Player { pos.clamp(-2.0E7, 2.0E7) } - pub async fn handle_position(self: &Arc, position: SPlayerPosition) { - if position.x.is_nan() || position.feet_y.is_nan() || position.z.is_nan() { + 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() + { self.kick(TextComponent::text("Invalid movement")).await; return; } - - let entity = &self.living_entity.entity; - self.living_entity.set_pos( - Self::clamp_horizontal(position.x), - Self::clamp_vertical(position.feet_y), - Self::clamp_horizontal(position.z), + let position = Vector3::new( + Self::clamp_horizontal(position_packet.x), + Self::clamp_vertical(position_packet.feet_y), + Self::clamp_horizontal(position_packet.z), ); + let entity = &self.living_entity.entity; + self.living_entity.set_pos(position); let pos = entity.pos.load(); let last_pos = self.living_entity.last_pos.load(); entity .on_ground - .store(position.ground, std::sync::atomic::Ordering::Relaxed); + .store(position_packet.ground, std::sync::atomic::Ordering::Relaxed); let entity_id = entity.entity_id; let Vector3 { x, y, z } = pos; @@ -161,7 +163,7 @@ impl Player { 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.ground, + position_packet.ground, ), ) .await; @@ -184,13 +186,13 @@ impl Player { self.kick(TextComponent::text("Invalid rotation")).await; return; } - - let entity = &self.living_entity.entity; - self.living_entity.set_pos( + let position = Vector3::new( Self::clamp_horizontal(position_rotation.x), Self::clamp_vertical(position_rotation.feet_y), Self::clamp_horizontal(position_rotation.z), ); + let entity = &self.living_entity.entity; + self.living_entity.set_pos(position); let pos = entity.pos.load(); let last_pos = self.living_entity.last_pos.load(); diff --git a/pumpkin/src/command/commands/cmd_teleport.rs b/pumpkin/src/command/commands/cmd_teleport.rs index fc368db16..3bc4cf08d 100644 --- a/pumpkin/src/command/commands/cmd_teleport.rs +++ b/pumpkin/src/command/commands/cmd_teleport.rs @@ -68,7 +68,7 @@ impl CommandExecutor for TpEntitiesToEntityExecutor { for target in targets { let yaw = target.living_entity.entity.yaw.load(); let pitch = target.living_entity.entity.pitch.load(); - target.teleport(pos, yaw, pitch).await; + target.living_entity.entity.teleport(pos, yaw, pitch).await; } Ok(()) @@ -93,7 +93,7 @@ impl CommandExecutor for TpEntitiesToPosFacingPosExecutor { let (yaw, pitch) = yaw_pitch_facing_position(&pos, &facing_pos); for target in targets { - target.teleport(pos, yaw, pitch).await; + target.living_entity.entity.teleport(pos, yaw, pitch).await; } Ok(()) @@ -120,7 +120,7 @@ impl CommandExecutor for TpEntitiesToPosFacingEntityExecutor { let (yaw, pitch) = yaw_pitch_facing_position(&pos, &facing_entity.pos.load()); for target in targets { - target.teleport(pos, yaw, pitch).await; + target.living_entity.entity.teleport(pos, yaw, pitch).await; } Ok(()) @@ -144,7 +144,7 @@ impl CommandExecutor for TpEntitiesToPosWithRotationExecutor { let (yaw, pitch) = RotationArgumentConsumer::find_arg(args, ARG_ROTATION)?; for target in targets { - target.teleport(pos, yaw, pitch).await; + target.living_entity.entity.teleport(pos, yaw, pitch).await; } Ok(()) @@ -168,7 +168,7 @@ impl CommandExecutor for TpEntitiesToPosExecutor { for target in targets { let yaw = target.living_entity.entity.yaw.load(); let pitch = target.living_entity.entity.pitch.load(); - target.teleport(pos, yaw, pitch).await; + target.living_entity.entity.teleport(pos, yaw, pitch).await; } Ok(()) @@ -192,7 +192,7 @@ impl CommandExecutor for TpSelfToEntityExecutor { CommandSender::Player(player) => { let yaw = player.living_entity.entity.yaw.load(); let pitch = player.living_entity.entity.pitch.load(); - player.teleport(pos, yaw, pitch).await; + player.living_entity.entity.teleport(pos, yaw, pitch).await; } _ => { sender @@ -222,7 +222,7 @@ impl CommandExecutor for TpSelfToPosExecutor { let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?; let yaw = player.living_entity.entity.yaw.load(); let pitch = player.living_entity.entity.pitch.load(); - player.teleport(pos, yaw, pitch).await; + player.living_entity.entity.teleport(pos, yaw, pitch).await; } _ => { sender diff --git a/pumpkin/src/entity/living.rs b/pumpkin/src/entity/living.rs index ba2c2aab6..e116ef43b 100644 --- a/pumpkin/src/entity/living.rs +++ b/pumpkin/src/entity/living.rs @@ -68,9 +68,9 @@ impl LivingEntity { } } - pub fn set_pos(&self, x: f64, y: f64, z: f64) { + pub fn set_pos(&self, position: Vector3) { self.last_pos.store(self.entity.pos.load()); - self.entity.set_pos(x, y, z); + self.entity.set_pos(position); } pub async fn set_health(&self, health: f32) { diff --git a/pumpkin/src/entity/mod.rs b/pumpkin/src/entity/mod.rs index 1f55ec91c..9be5e8aab 100644 --- a/pumpkin/src/entity/mod.rs +++ b/pumpkin/src/entity/mod.rs @@ -11,7 +11,7 @@ use pumpkin_core::math::{ }; use pumpkin_entity::{entity_type::EntityType, pose::EntityPose, EntityId}; use pumpkin_protocol::{ - client::play::{CSetEntityMetadata, Metadata}, + client::play::{CSetEntityMetadata, CTeleportEntitiy, Metadata}, VarInt, }; @@ -95,12 +95,10 @@ impl Entity { /// Updates the entity's position, block position, and chunk position. /// /// This function calculates the new position, block position, and chunk position based on the provided coordinates. If any of these values change, the corresponding fields are updated. - #[expect(clippy::float_cmp)] - pub fn set_pos(&self, x: f64, y: f64, z: f64) { + pub fn set_pos(&self, new_position: Vector3) { let pos = self.pos.load(); - if pos.x != x || pos.y != y || pos.z != z { - self.pos.store(Vector3::new(x, y, z)); - + if pos != new_position { + self.pos.store(new_position); self.bounding_box.store(BoundingBox::new_from_pos( pos.x, pos.y, @@ -108,9 +106,9 @@ impl Entity { &self.bounding_box_size.load(), )); - let floor_x = x.floor() as i32; - let floor_y = y.floor() as i32; - let floor_z = z.floor() as i32; + let floor_x = new_position.x.floor() as i32; + let floor_y = new_position.y.floor() as i32; + let floor_z = new_position.z.floor() as i32; let block_pos = self.block_pos.load(); let block_pos_vec = block_pos.0; @@ -134,6 +132,23 @@ impl Entity { } } + pub async fn teleport(&self, position: Vector3, yaw: f32, pitch: f32) { + self.world + .broadcast_packet_all(&CTeleportEntitiy::new( + self.entity_id.into(), + position, + Vector3::new(0.0, 0.0, 0.0), + yaw, + pitch, + // TODO + &[], + self.on_ground.load(std::sync::atomic::Ordering::SeqCst), + )) + .await; + self.set_pos(position); + self.set_rotation(yaw, pitch); + } + /// Sets the Entity yaw & pitch Rotation pub fn set_rotation(&self, yaw: f32, pitch: f32) { // TODO diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index ea5b8dc95..bfa1d5956 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -27,7 +27,7 @@ use pumpkin_protocol::{ bytebuf::packet_id::Packet, client::play::{ CCombatDeath, CEntityStatus, CGameEvent, CHurtAnimation, CKeepAlive, CPlayDisconnect, - CPlayerAbilities, CPlayerInfoUpdate, CSetHealth, CSyncPlayerPosition, CSystemChatMessage, + CPlayerAbilities, CPlayerInfoUpdate, CPlayerPosition, CSetHealth, CSystemChatMessage, GameEvent, PlayerAction, }, server::play::{ @@ -396,30 +396,29 @@ impl Player { self.permission_lvl } - /// yaw and pitch in degrees - pub async fn teleport(&self, position: Vector3, yaw: f32, pitch: f32) { + /// Yaw and Pitch in degrees + /// Rarly used, For example when waking up player from bed or first time spawn. Otherwise entity teleport is used + /// Player should respond with the `SConfirmTeleport` packet + pub async fn request_teleport(&self, position: Vector3, yaw: f32, pitch: f32) { // this is the ultra special magic code used to create the teleport id // This returns the old value + // This operation wraps around on overflow. let i = self .teleport_id_count .fetch_add(1, std::sync::atomic::Ordering::Relaxed); - if i + 2 == i32::MAX { - self.teleport_id_count - .store(0, std::sync::atomic::Ordering::Relaxed); - } let teleport_id = i + 1; - self.living_entity - .set_pos(position.x, position.y, position.z); + self.living_entity.set_pos(position); let entity = &self.living_entity.entity; entity.set_rotation(yaw, pitch); *self.awaiting_teleport.lock().await = Some((teleport_id.into(), position)); self.client - .send_packet(&CSyncPlayerPosition::new( + .send_packet(&CPlayerPosition::new( teleport_id.into(), position, Vector3::new(0.0, 0.0, 0.0), yaw, pitch, + // TODO &[], )) .await; diff --git a/pumpkin/src/world/mod.rs b/pumpkin/src/world/mod.rs index 3b0db3de6..4edd8c3cb 100644 --- a/pumpkin/src/world/mod.rs +++ b/pumpkin/src/world/mod.rs @@ -270,7 +270,7 @@ impl World { position.y = f64::from(top + 1); log::debug!("Sending player teleport to {}", player.gameprofile.name); - player.teleport(position, yaw, pitch).await; + player.request_teleport(position, yaw, pitch).await; player.living_entity.last_pos.store(position); @@ -457,7 +457,7 @@ impl World { position.y = f64::from(top + 1); log::debug!("Sending player teleport to {}", player.gameprofile.name); - player.teleport(position, yaw, pitch).await; + player.request_teleport(position, yaw, pitch).await; player.living_entity.last_pos.store(position);