diff --git a/src/command.rs b/src/command.rs index 0b9050a..ddfa17b 100644 --- a/src/command.rs +++ b/src/command.rs @@ -1,7 +1,10 @@ use half::f16; use crate::{ - packet::{server::ServerPacket, ExtBitmask, STRING_LENGTH}, + packet::{ + server::{ServerPacket, TeleportBehavior}, + ExtBitmask, STRING_LENGTH, + }, player::PlayerType, server::{ config::{ConfigCoordinatesWithOrientation, ServerProtectionMode}, @@ -595,21 +598,41 @@ impl<'m> Command<'m> { }; if let Some(player) = data.players.iter_mut().find(|p| p.username == username) { + let yaw = yaw.unwrap_or(player.yaw); + let pitch = pitch.unwrap_or(player.pitch); player.x = x; player.y = y; player.z = z; + player.yaw = yaw; + player.pitch = pitch; let packet = ServerPacket::SetPositionOrientation { player_id: player.id, x, y, z, - yaw: yaw.unwrap_or(player.yaw), - pitch: pitch.unwrap_or(player.pitch), + yaw, + pitch, + }; + let ext_packet = ServerPacket::ExtEntityTeleport { + entity_id: player.id, + teleport_behavior: TeleportBehavior::UsePosition + | TeleportBehavior::UseOrientation + | TeleportBehavior::ModeInterpolated, + x, + y, + z, + yaw, + pitch, }; let id = player.id; for player in &mut data.players { - let mut packet = packet.clone(); + let mut packet = + if player.extensions.contains(ExtBitmask::ExtEntityTeleport) { + ext_packet.clone() + } else { + packet.clone() + }; if player.id == id { packet.set_player_id(-1); player.packets_to_send.push(ServerPacket::Message { diff --git a/src/packet.rs b/src/packet.rs index c57474b..e1de20b 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -208,6 +208,9 @@ impl ExtBitmask { Self::InventoryOrder => { ExtInfo::new("InventoryOrder".to_string(), 1, Self::InventoryOrder) } + Self::ExtEntityTeleport => { + ExtInfo::new("ExtEntityTeleport".to_string(), 1, Self::ExtEntityTeleport) + } _ => return None, }) } diff --git a/src/packet/server.rs b/src/packet/server.rs index 0e55bad..2c8c260 100644 --- a/src/packet/server.rs +++ b/src/packet/server.rs @@ -111,6 +111,15 @@ pub enum ServerPacket { EnvWeatherType { weather_type: WeatherType }, /// packet to set a block's position in the client's inventory SetInventoryOrder { order: u8, block: u8 }, + ExtEntityTeleport { + entity_id: i8, + teleport_behavior: TeleportBehavior, + x: f16, + y: f16, + z: f16, + yaw: u8, + pitch: u8, + }, } impl ServerPacket { @@ -139,6 +148,7 @@ impl ServerPacket { Self::HoldThis { .. } => 0x14, Self::EnvWeatherType { .. } => 0x1f, Self::SetInventoryOrder { .. } => 0x2c, + Self::ExtEntityTeleport { .. } => 0x36, } } @@ -262,6 +272,22 @@ impl ServerPacket { } => writer.write_u8(*block).write_bool(*prevent_change), Self::EnvWeatherType { weather_type } => writer.write_u8(weather_type.into()), Self::SetInventoryOrder { order, block } => writer.write_u8(*order).write_u8(*block), + Self::ExtEntityTeleport { + entity_id, + teleport_behavior, + x, + y, + z, + yaw, + pitch, + } => writer + .write_i8(*entity_id) + .write_u8(teleport_behavior.bits()) + .write_f16(*x) + .write_f16(*y) + .write_f16(*z) + .write_u8(*yaw) + .write_u8(*pitch), } } @@ -275,6 +301,7 @@ impl ServerPacket { Self::UpdateOrientation { player_id, .. } => *player_id, Self::DespawnPlayer { player_id, .. } => *player_id, Self::Message { player_id, .. } => *player_id, + Self::ExtEntityTeleport { entity_id, .. } => *entity_id, _ => return None, }) } @@ -289,6 +316,7 @@ impl ServerPacket { Self::UpdateOrientation { player_id, .. } => *player_id = new_player_id, Self::DespawnPlayer { player_id, .. } => *player_id = new_player_id, Self::Message { player_id, .. } => *player_id = new_player_id, + Self::ExtEntityTeleport { entity_id, .. } => *entity_id = new_player_id, _ => {} } } @@ -301,3 +329,15 @@ impl ServerPacket { ) } } + +/// bitmask for ExtEntityTeleport's teleport behavior +#[bitmask_enum::bitmask(u8)] +pub enum TeleportBehavior { + UsePosition = 0b00000001, + ModeInstant = 0, + ModeInterpolated = 0b00000010, + ModeRelativeInterpolated = 0b00000100, + ModeRelativeSeamless = 0b00000110, + UseOrientation = 0b00010000, + InterpolateOrientation = 0b00100000, +}