Skip to content

Commit

Permalink
Add Serverbound Movement Packets
Browse files Browse the repository at this point in the history
- SPlayerPosition
- SPlayerPositionRotation
- SPlayerRotation
  • Loading branch information
Snowiiii committed Aug 4, 2024
1 parent 0597722 commit 42bc84b
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 22 deletions.
6 changes: 4 additions & 2 deletions pumpkin-protocol/src/client/play/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ pub enum PlayerAction {
},
InitializeChat(u8),
UpdateGameMode(u8),
UpdateListed(u8),
UpdateListed {
listed: bool,
},
UpdateLatency(u8),
UpdateDisplayName(u8),
}
Expand Down Expand Up @@ -68,7 +70,7 @@ impl<'a> ClientPacket for CPlayerInfoUpdate<'a> {
}
PlayerAction::InitializeChat(_) => todo!(),
PlayerAction::UpdateGameMode(_) => todo!(),
PlayerAction::UpdateListed(_) => todo!(),
PlayerAction::UpdateListed { listed } => p.put_bool(*listed),
PlayerAction::UpdateLatency(_) => todo!(),
PlayerAction::UpdateDisplayName(_) => todo!(),
}
Expand Down
1 change: 0 additions & 1 deletion pumpkin-protocol/src/packet_decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ impl PacketDecoder {
.0;

data.advance(data.len() - r.len());
dbg!(packet_id);
Ok(Some(RawPacket {
len: packet_len,
id: packet_id,
Expand Down
62 changes: 62 additions & 0 deletions pumpkin-protocol/src/server/play/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,65 @@ impl ServerPacket for SConfirmTeleport {
}
}
}

pub struct SPlayerPosition {
pub x: f64,
pub feet_y: f64,
pub z: f64,
pub ground: bool,
}

impl ServerPacket for SPlayerPosition {
const PACKET_ID: VarInt = 0x1A;

fn read(bytebuf: &mut crate::bytebuf::ByteBuffer) -> Self {
Self {
x: bytebuf.get_f64(),
feet_y: bytebuf.get_f64(),
z: bytebuf.get_f64(),
ground: bytebuf.get_bool(),
}
}
}

pub struct SPlayerPositionRotation {
pub x: f64,
pub feet_y: f64,
pub z: f64,
pub yaw: f32,
pub pitch: f32,
pub ground: bool,
}

impl ServerPacket for SPlayerPositionRotation {
const PACKET_ID: VarInt = 0x1B;

fn read(bytebuf: &mut crate::bytebuf::ByteBuffer) -> Self {
Self {
x: bytebuf.get_f64(),
feet_y: bytebuf.get_f64(),
z: bytebuf.get_f64(),
yaw: bytebuf.get_f32(),
pitch: bytebuf.get_f32(),
ground: bytebuf.get_bool(),
}
}
}

pub struct SPlayerRotation {
pub yaw: f32,
pub pitch: f32,
pub ground: bool,
}

impl ServerPacket for SPlayerRotation {
const PACKET_ID: VarInt = 0x1C;

fn read(bytebuf: &mut crate::bytebuf::ByteBuffer) -> Self {
Self {
yaw: bytebuf.get_f32(),
pitch: bytebuf.get_f32(),
ground: bytebuf.get_bool(),
}
}
}
2 changes: 0 additions & 2 deletions pumpkin/src/client/client_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,6 @@ impl ClientPacketProcessor for Client {
}

fn handle_status_request(&mut self, server: &mut Server, _status_request: SStatusRequest) {
dbg!("sending status");

self.send_packet(CStatusResponse::new(&server.status_response_json))
.unwrap_or_else(|e| self.kick(&e.to_string()));
}
Expand Down
27 changes: 22 additions & 5 deletions pumpkin/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use pumpkin_protocol::{
config::{SAcknowledgeFinishConfig, SClientInformation, SKnownPacks, SPluginMessage},
handshake::SHandShake,
login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart},
play::SConfirmTeleport,
play::{SConfirmTeleport, SPlayerPosition, SPlayerPositionRotation, SPlayerRotation},
status::{SPingRequest, SStatusRequest},
},
text::Text,
Expand Down Expand Up @@ -109,10 +109,13 @@ impl Client {
Ok(())
}

pub fn is_player(&self) -> bool {
self.player.is_some()
}

/// Im many cases we want to kick the Client when an Packet Error occours, But especially in the Client state we will not try to kick when not important packets
/// e.g Postion, Rotation... has not been send
pub fn send_packet<P: ClientPacket>(&mut self, packet: P) -> Result<(), PacketError> {
dbg!("sending packet");
self.enc.append_packet(packet)?;
self.connection
.write_all(&self.enc.take())
Expand All @@ -121,10 +124,16 @@ impl Client {
}

pub fn teleport(&mut self, x: f64, y: f64, z: f64, yaw: f32, pitch: f32) {
assert!(self.player.is_some());
assert!(self.is_player());
// todo
let id = 0;
self.player.as_mut().unwrap().awaiting_teleport = Some(0);
let player = self.player.as_mut().unwrap();
player.x = x;
player.y = y;
player.z = z;
player.yaw = yaw;
player.pitch = pitch;
player.awaiting_teleport = Some(id);
self.send_packet(CSyncPlayerPostion::new(x, y, z, yaw, pitch, 0, id))
.unwrap_or_else(|e| self.kick(&e.to_string()));
}
Expand All @@ -140,7 +149,6 @@ impl Client {

/// Handles an incoming decoded Packet
pub fn handle_packet(&mut self, server: &mut Server, packet: &mut RawPacket) {
dbg!("Handling packet");
let bytebuf = &mut packet.bytebuf;
match self.connection_state {
pumpkin_protocol::ConnectionState::HandShake => match packet.id {
Expand Down Expand Up @@ -216,6 +224,15 @@ impl Client {
SConfirmTeleport::PACKET_ID => {
self.handle_confirm_teleport(server, SConfirmTeleport::read(bytebuf))
}
SPlayerPosition::PACKET_ID => {
self.handle_position(server, SPlayerPosition::read(bytebuf))
}
SPlayerPositionRotation::PACKET_ID => {
self.handle_position_rotation(server, SPlayerPositionRotation::read(bytebuf))
}
SPlayerRotation::PACKET_ID => {
self.handle_rotation(server, SPlayerRotation::read(bytebuf))
}
_ => log::error!("Failed to handle player packet id {}", packet.id),
}
}
Expand Down
54 changes: 53 additions & 1 deletion pumpkin/src/client/player_packet.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use pumpkin_protocol::server::play::SConfirmTeleport;
use pumpkin_protocol::server::play::{
SConfirmTeleport, SPlayerPosition, SPlayerPositionRotation, SPlayerRotation,
};

use crate::server::Server;

Expand All @@ -7,6 +9,15 @@ use super::Client;
// implement player packets
pub trait PlayerPacketProcessor {
fn handle_confirm_teleport(&mut self, server: &mut Server, confirm_teleport: SConfirmTeleport);

fn handle_position(&mut self, server: &mut Server, position: SPlayerPosition);

fn handle_position_rotation(
&mut self,
server: &mut Server,
position_rotation: SPlayerPositionRotation,
);
fn handle_rotation(&mut self, server: &mut Server, rotation: SPlayerRotation);
}

impl PlayerPacketProcessor for Client {
Expand All @@ -26,4 +37,45 @@ impl PlayerPacketProcessor for Client {
self.kick("Send Teleport confirm, but we did not teleport")
}
}

fn handle_position(&mut self, _server: &mut Server, position: SPlayerPosition) {
if position.x.is_nan() || position.feet_y.is_nan() || position.z.is_nan() {
self.kick("Invalid movement");
}
let player = self.player.as_mut().unwrap();
player.x = position.x;
player.y = position.feet_y;
player.z = position.z;
}

fn handle_position_rotation(
&mut self,
_server: &mut Server,
position_rotation: SPlayerPositionRotation,
) {
if position_rotation.x.is_nan()
|| position_rotation.feet_y.is_nan()
|| position_rotation.z.is_nan()
{
self.kick("Invalid movement");
}
if !position_rotation.yaw.is_finite() || !position_rotation.pitch.is_finite() {
self.kick("Invalid rotation");
}
let player = self.player.as_mut().unwrap();
player.x = position_rotation.x;
player.y = position_rotation.feet_y;
player.z = position_rotation.z;
player.yaw = position_rotation.yaw;
player.pitch = position_rotation.pitch;
}

fn handle_rotation(&mut self, _server: &mut Server, rotation: SPlayerRotation) {
if !rotation.yaw.is_finite() || !rotation.pitch.is_finite() {
self.kick("Invalid rotation");
}
let player = self.player.as_mut().unwrap();
player.yaw = rotation.yaw;
player.pitch = rotation.pitch;
}
}
14 changes: 14 additions & 0 deletions pumpkin/src/entity/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ use super::{Entity, EntityId};

pub struct Player {
pub entity: Entity,
pub x: f64,
pub y: f64,
pub z: f64,
pub yaw: f32,
pub pitch: f32,

// Client side value, Should be not trusted
pub on_ground: bool,

// Current awaiting teleport id, None if did not teleport
pub awaiting_teleport: Option<VarInt>,
Expand All @@ -13,6 +21,12 @@ impl Player {
pub fn new(entity: Entity) -> Self {
Self {
entity,
x: 0.0,
y: 0.0,
z: 0.0,
yaw: 0.0,
pitch: 0.0,
on_ground: false,
awaiting_teleport: None,
}
}
Expand Down
19 changes: 14 additions & 5 deletions pumpkin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub mod util;

#[cfg(not(target_os = "wasi"))]
fn main() -> io::Result<()> {
use std::{collections::HashMap, rc::Rc};
use std::{cell::RefCell, collections::HashMap, rc::Rc};

use client::Client;
use configuration::AdvancedConfiguration;
Expand Down Expand Up @@ -51,7 +51,7 @@ fn main() -> io::Result<()> {
// Unique token for each incoming connection.
let mut unique_token = Token(SERVER.0 + 1);

let mut connections: HashMap<Token, Client> = HashMap::new();
let mut connections: HashMap<Token, Rc<RefCell<Client>>> = HashMap::new();

log::info!("You now can connect to the server");

Expand Down Expand Up @@ -94,21 +94,30 @@ fn main() -> io::Result<()> {
token,
Interest::READABLE.add(Interest::WRITABLE),
)?;

connections.insert(token, Client::new(Rc::new(token), connection, addr));
let rc_token = Rc::new(token);
let client = Rc::new(RefCell::new(Client::new(
Rc::clone(&rc_token),
connection,
addr,
)));
server.add_client(rc_token, Rc::clone(&client));
connections.insert(token, client);
},

token => {
// Maybe received an event for a TCP connection.
let done = if let Some(client) = connections.get_mut(&token) {
let mut client = client.borrow_mut();
client.poll(&mut server, event);
client.closed
} else {
// Sporadic events happen, we can safely ignore them.
false
};
if done {
if let Some(mut client) = connections.remove(&token) {
if let Some(client) = connections.remove(&token) {
let mut client = client.borrow_mut();
server.remove_client(&token);
poll.registry().deregister(&mut client.connection)?;
}
}
Expand Down
Loading

0 comments on commit 42bc84b

Please sign in to comment.