Use Entity teleport Packet instead of Player

Should make fixing https://github.com/Snowiiii/Pumpkin/issues/363 easier
This commit is contained in:
Snowiiii 2024-12-07 15:40:50 +01:00
parent a04b23f633
commit b2f627d517
12 changed files with 113 additions and 90 deletions

View File

@ -50,7 +50,7 @@ thiserror = "2"
num-traits = "0.2" num-traits = "0.2"
num-derive = "0.4" num-derive = "0.4"
bytes = "1.8" bytes = "1.9"
# Concurrency/Parallelism and Synchronization # Concurrency/Parallelism and Synchronization
rayon = "1.10.0" rayon = "1.10.0"

View File

@ -18,8 +18,7 @@ log.workspace = true
tokio.workspace = true tokio.workspace = true
num-traits.workspace = true num-traits.workspace = true
num-derive.workspace = true num-derive.workspace = true
bytes.workspace = true
bytes = "1.8"
# encryption # encryption
aes = "0.8.4" aes = "0.8.4"

View File

@ -4,20 +4,16 @@ use pumpkin_macros::client_packet;
use crate::{ClientPacket, PositionFlag, VarInt}; use crate::{ClientPacket, PositionFlag, VarInt};
#[client_packet("play:player_position")] #[client_packet("play:player_position")]
pub struct CSyncPlayerPosition<'a> { pub struct CPlayerPosition<'a> {
teleport_id: VarInt, teleport_id: VarInt,
x: f64, position: Vector3<f64>,
y: f64, delta: Vector3<f64>,
z: f64,
delta_x: f64,
delta_y: f64,
delta_z: f64,
yaw: f32, yaw: f32,
pitch: f32, pitch: f32,
releatives: &'a [PositionFlag], releatives: &'a [PositionFlag],
} }
impl<'a> CSyncPlayerPosition<'a> { impl<'a> CPlayerPosition<'a> {
pub fn new( pub fn new(
teleport_id: VarInt, teleport_id: VarInt,
position: Vector3<f64>, position: Vector3<f64>,
@ -28,12 +24,8 @@ impl<'a> CSyncPlayerPosition<'a> {
) -> Self { ) -> Self {
Self { Self {
teleport_id, teleport_id,
x: position.x, position,
y: position.y, delta,
z: position.z,
delta_x: delta.x,
delta_y: delta.y,
delta_z: delta.z,
yaw, yaw,
pitch, pitch,
releatives, 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) { fn write(&self, bytebuf: &mut crate::bytebuf::ByteBuffer) {
bytebuf.put_var_int(&self.teleport_id); bytebuf.put_var_int(&self.teleport_id);
bytebuf.put_f64(self.x); bytebuf.put_f64(self.position.x);
bytebuf.put_f64(self.y); bytebuf.put_f64(self.position.y);
bytebuf.put_f64(self.z); bytebuf.put_f64(self.position.z);
bytebuf.put_f64(self.delta_x); bytebuf.put_f64(self.delta.x);
bytebuf.put_f64(self.delta_y); bytebuf.put_f64(self.delta.y);
bytebuf.put_f64(self.delta_z); bytebuf.put_f64(self.delta.z);
bytebuf.put_f32(self.yaw); bytebuf.put_f32(self.yaw);
bytebuf.put_f32(self.pitch); bytebuf.put_f32(self.pitch);
// not sure about that // not sure about that

View File

@ -1,38 +1,54 @@
use pumpkin_core::math::vector3::Vector3;
use pumpkin_macros::client_packet; use pumpkin_macros::client_packet;
use serde::Serialize;
use crate::VarInt; use crate::{ClientPacket, PositionFlag, VarInt};
#[derive(Serialize)]
#[client_packet("play:teleport_entity")] #[client_packet("play:teleport_entity")]
pub struct CTeleportEntitiy { pub struct CTeleportEntitiy<'a> {
entity_id: VarInt, entity_id: VarInt,
x: f64, position: Vector3<f64>,
y: f64, delta: Vector3<f64>,
z: f64, yaw: f32,
yaw: u8, pitch: f32,
pitch: u8, releatives: &'a [PositionFlag],
on_ground: bool, on_ground: bool,
} }
impl CTeleportEntitiy { impl<'a> CTeleportEntitiy<'a> {
pub fn new( pub fn new(
entity_id: VarInt, entity_id: VarInt,
x: f64, position: Vector3<f64>,
y: f64, delta: Vector3<f64>,
z: f64, yaw: f32,
yaw: u8, pitch: f32,
pitch: u8, releatives: &'a [PositionFlag],
on_ground: bool, on_ground: bool,
) -> Self { ) -> Self {
Self { Self {
entity_id, entity_id,
x, position,
y, delta,
z,
yaw, yaw,
pitch, pitch,
releatives,
on_ground, 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);
}
}

View File

@ -34,6 +34,7 @@ mod c_play_disconnect;
mod c_player_abilities; mod c_player_abilities;
mod c_player_chat_message; mod c_player_chat_message;
mod c_player_info_update; mod c_player_info_update;
mod c_player_position;
mod c_player_remove; mod c_player_remove;
mod c_remove_entities; mod c_remove_entities;
mod c_reset_score; mod c_reset_score;
@ -55,7 +56,6 @@ mod c_sound_effect;
mod c_spawn_entity; mod c_spawn_entity;
mod c_store_cookie; mod c_store_cookie;
mod c_subtitle; mod c_subtitle;
mod c_sync_player_position;
mod c_system_chat_message; mod c_system_chat_message;
mod c_teleport_entity; mod c_teleport_entity;
mod c_transfer; mod c_transfer;
@ -104,6 +104,7 @@ pub use c_play_disconnect::*;
pub use c_player_abilities::*; pub use c_player_abilities::*;
pub use c_player_chat_message::*; pub use c_player_chat_message::*;
pub use c_player_info_update::*; pub use c_player_info_update::*;
pub use c_player_position::*;
pub use c_player_remove::*; pub use c_player_remove::*;
pub use c_remove_entities::*; pub use c_remove_entities::*;
pub use c_reset_score::*; pub use c_reset_score::*;
@ -125,7 +126,6 @@ pub use c_sound_effect::*;
pub use c_spawn_entity::*; pub use c_spawn_entity::*;
pub use c_store_cookie::*; pub use c_store_cookie::*;
pub use c_subtitle::*; pub use c_subtitle::*;
pub use c_sync_player_position::*;
pub use c_system_chat_message::*; pub use c_system_chat_message::*;
pub use c_teleport_entity::*; pub use c_teleport_entity::*;
pub use c_transfer::*; pub use c_transfer::*;

View File

@ -37,7 +37,7 @@ parking_lot.workspace = true
serde.workspace = true serde.workspace = true
serde_json.workspace = true serde_json.workspace = true
bytes = "1.8" bytes.workspace = true
rand = "0.8.5" rand = "0.8.5"

View File

@ -92,8 +92,7 @@ impl Player {
if let Some((id, position)) = awaiting_teleport.as_ref() { if let Some((id, position)) = awaiting_teleport.as_ref() {
if id == &confirm_teleport.teleport_id { 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 // 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 self.living_entity.set_pos(*position);
.set_pos(position.x, position.y, position.z);
*awaiting_teleport = None; *awaiting_teleport = None;
} else { } else {
@ -115,25 +114,28 @@ impl Player {
pos.clamp(-2.0E7, 2.0E7) pos.clamp(-2.0E7, 2.0E7)
} }
pub async fn handle_position(self: &Arc<Self>, position: SPlayerPosition) { pub async fn handle_position(self: &Arc<Self>, position_packet: SPlayerPosition) {
if position.x.is_nan() || position.feet_y.is_nan() || position.z.is_nan() { if position_packet.x.is_nan()
|| position_packet.feet_y.is_nan()
|| position_packet.z.is_nan()
{
self.kick(TextComponent::text("Invalid movement")).await; self.kick(TextComponent::text("Invalid movement")).await;
return; return;
} }
let position = Vector3::new(
let entity = &self.living_entity.entity; Self::clamp_horizontal(position_packet.x),
self.living_entity.set_pos( Self::clamp_vertical(position_packet.feet_y),
Self::clamp_horizontal(position.x), Self::clamp_horizontal(position_packet.z),
Self::clamp_vertical(position.feet_y),
Self::clamp_horizontal(position.z),
); );
let entity = &self.living_entity.entity;
self.living_entity.set_pos(position);
let pos = entity.pos.load(); let pos = entity.pos.load();
let last_pos = self.living_entity.last_pos.load(); let last_pos = self.living_entity.last_pos.load();
entity entity
.on_ground .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 entity_id = entity.entity_id;
let Vector3 { x, y, z } = pos; let Vector3 { x, y, z } = pos;
@ -161,7 +163,7 @@ impl Player {
x.mul_add(4096.0, -(last_x * 4096.0)) as i16, x.mul_add(4096.0, -(last_x * 4096.0)) as i16,
y.mul_add(4096.0, -(last_y * 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, z.mul_add(4096.0, -(last_z * 4096.0)) as i16,
position.ground, position_packet.ground,
), ),
) )
.await; .await;
@ -184,13 +186,13 @@ impl Player {
self.kick(TextComponent::text("Invalid rotation")).await; self.kick(TextComponent::text("Invalid rotation")).await;
return; return;
} }
let position = Vector3::new(
let entity = &self.living_entity.entity;
self.living_entity.set_pos(
Self::clamp_horizontal(position_rotation.x), Self::clamp_horizontal(position_rotation.x),
Self::clamp_vertical(position_rotation.feet_y), Self::clamp_vertical(position_rotation.feet_y),
Self::clamp_horizontal(position_rotation.z), Self::clamp_horizontal(position_rotation.z),
); );
let entity = &self.living_entity.entity;
self.living_entity.set_pos(position);
let pos = entity.pos.load(); let pos = entity.pos.load();
let last_pos = self.living_entity.last_pos.load(); let last_pos = self.living_entity.last_pos.load();

View File

@ -68,7 +68,7 @@ impl CommandExecutor for TpEntitiesToEntityExecutor {
for target in targets { for target in targets {
let yaw = target.living_entity.entity.yaw.load(); let yaw = target.living_entity.entity.yaw.load();
let pitch = target.living_entity.entity.pitch.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(()) Ok(())
@ -93,7 +93,7 @@ impl CommandExecutor for TpEntitiesToPosFacingPosExecutor {
let (yaw, pitch) = yaw_pitch_facing_position(&pos, &facing_pos); let (yaw, pitch) = yaw_pitch_facing_position(&pos, &facing_pos);
for target in targets { for target in targets {
target.teleport(pos, yaw, pitch).await; target.living_entity.entity.teleport(pos, yaw, pitch).await;
} }
Ok(()) Ok(())
@ -120,7 +120,7 @@ impl CommandExecutor for TpEntitiesToPosFacingEntityExecutor {
let (yaw, pitch) = yaw_pitch_facing_position(&pos, &facing_entity.pos.load()); let (yaw, pitch) = yaw_pitch_facing_position(&pos, &facing_entity.pos.load());
for target in targets { for target in targets {
target.teleport(pos, yaw, pitch).await; target.living_entity.entity.teleport(pos, yaw, pitch).await;
} }
Ok(()) Ok(())
@ -144,7 +144,7 @@ impl CommandExecutor for TpEntitiesToPosWithRotationExecutor {
let (yaw, pitch) = RotationArgumentConsumer::find_arg(args, ARG_ROTATION)?; let (yaw, pitch) = RotationArgumentConsumer::find_arg(args, ARG_ROTATION)?;
for target in targets { for target in targets {
target.teleport(pos, yaw, pitch).await; target.living_entity.entity.teleport(pos, yaw, pitch).await;
} }
Ok(()) Ok(())
@ -168,7 +168,7 @@ impl CommandExecutor for TpEntitiesToPosExecutor {
for target in targets { for target in targets {
let yaw = target.living_entity.entity.yaw.load(); let yaw = target.living_entity.entity.yaw.load();
let pitch = target.living_entity.entity.pitch.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(()) Ok(())
@ -192,7 +192,7 @@ impl CommandExecutor for TpSelfToEntityExecutor {
CommandSender::Player(player) => { CommandSender::Player(player) => {
let yaw = player.living_entity.entity.yaw.load(); let yaw = player.living_entity.entity.yaw.load();
let pitch = player.living_entity.entity.pitch.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 sender
@ -222,7 +222,7 @@ impl CommandExecutor for TpSelfToPosExecutor {
let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?; let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
let yaw = player.living_entity.entity.yaw.load(); let yaw = player.living_entity.entity.yaw.load();
let pitch = player.living_entity.entity.pitch.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 sender

View File

@ -68,9 +68,9 @@ impl<C: Container> LivingEntity<C> {
} }
} }
pub fn set_pos(&self, x: f64, y: f64, z: f64) { pub fn set_pos(&self, position: Vector3<f64>) {
self.last_pos.store(self.entity.pos.load()); 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) { pub async fn set_health(&self, health: f32) {

View File

@ -11,7 +11,7 @@ use pumpkin_core::math::{
}; };
use pumpkin_entity::{entity_type::EntityType, pose::EntityPose, EntityId}; use pumpkin_entity::{entity_type::EntityType, pose::EntityPose, EntityId};
use pumpkin_protocol::{ use pumpkin_protocol::{
client::play::{CSetEntityMetadata, Metadata}, client::play::{CSetEntityMetadata, CTeleportEntitiy, Metadata},
VarInt, VarInt,
}; };
@ -95,12 +95,10 @@ impl Entity {
/// Updates the entity's position, block position, and chunk position. /// 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. /// 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, new_position: Vector3<f64>) {
pub fn set_pos(&self, x: f64, y: f64, z: f64) {
let pos = self.pos.load(); let pos = self.pos.load();
if pos.x != x || pos.y != y || pos.z != z { if pos != new_position {
self.pos.store(Vector3::new(x, y, z)); self.pos.store(new_position);
self.bounding_box.store(BoundingBox::new_from_pos( self.bounding_box.store(BoundingBox::new_from_pos(
pos.x, pos.x,
pos.y, pos.y,
@ -108,9 +106,9 @@ impl Entity {
&self.bounding_box_size.load(), &self.bounding_box_size.load(),
)); ));
let floor_x = x.floor() as i32; let floor_x = new_position.x.floor() as i32;
let floor_y = y.floor() as i32; let floor_y = new_position.y.floor() as i32;
let floor_z = z.floor() as i32; let floor_z = new_position.z.floor() as i32;
let block_pos = self.block_pos.load(); let block_pos = self.block_pos.load();
let block_pos_vec = block_pos.0; let block_pos_vec = block_pos.0;
@ -134,6 +132,23 @@ impl Entity {
} }
} }
pub async fn teleport(&self, position: Vector3<f64>, 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 /// Sets the Entity yaw & pitch Rotation
pub fn set_rotation(&self, yaw: f32, pitch: f32) { pub fn set_rotation(&self, yaw: f32, pitch: f32) {
// TODO // TODO

View File

@ -27,7 +27,7 @@ use pumpkin_protocol::{
bytebuf::packet_id::Packet, bytebuf::packet_id::Packet,
client::play::{ client::play::{
CCombatDeath, CEntityStatus, CGameEvent, CHurtAnimation, CKeepAlive, CPlayDisconnect, CCombatDeath, CEntityStatus, CGameEvent, CHurtAnimation, CKeepAlive, CPlayDisconnect,
CPlayerAbilities, CPlayerInfoUpdate, CSetHealth, CSyncPlayerPosition, CSystemChatMessage, CPlayerAbilities, CPlayerInfoUpdate, CPlayerPosition, CSetHealth, CSystemChatMessage,
GameEvent, PlayerAction, GameEvent, PlayerAction,
}, },
server::play::{ server::play::{
@ -396,30 +396,29 @@ impl Player {
self.permission_lvl self.permission_lvl
} }
/// yaw and pitch in degrees /// Yaw and Pitch in degrees
pub async fn teleport(&self, position: Vector3<f64>, yaw: f32, pitch: f32) { /// 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<f64>, yaw: f32, pitch: f32) {
// this is the ultra special magic code used to create the teleport id // this is the ultra special magic code used to create the teleport id
// This returns the old value // This returns the old value
// This operation wraps around on overflow.
let i = self let i = self
.teleport_id_count .teleport_id_count
.fetch_add(1, std::sync::atomic::Ordering::Relaxed); .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; let teleport_id = i + 1;
self.living_entity self.living_entity.set_pos(position);
.set_pos(position.x, position.y, position.z);
let entity = &self.living_entity.entity; let entity = &self.living_entity.entity;
entity.set_rotation(yaw, pitch); entity.set_rotation(yaw, pitch);
*self.awaiting_teleport.lock().await = Some((teleport_id.into(), position)); *self.awaiting_teleport.lock().await = Some((teleport_id.into(), position));
self.client self.client
.send_packet(&CSyncPlayerPosition::new( .send_packet(&CPlayerPosition::new(
teleport_id.into(), teleport_id.into(),
position, position,
Vector3::new(0.0, 0.0, 0.0), Vector3::new(0.0, 0.0, 0.0),
yaw, yaw,
pitch, pitch,
// TODO
&[], &[],
)) ))
.await; .await;

View File

@ -270,7 +270,7 @@ impl World {
position.y = f64::from(top + 1); position.y = f64::from(top + 1);
log::debug!("Sending player teleport to {}", player.gameprofile.name); 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); player.living_entity.last_pos.store(position);
@ -457,7 +457,7 @@ impl World {
position.y = f64::from(top + 1); position.y = f64::from(top + 1);
log::debug!("Sending player teleport to {}", player.gameprofile.name); 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); player.living_entity.last_pos.store(position);