Add Player movement

This commit is contained in:
Snowiiii 2024-08-06 18:10:03 +02:00
parent 32569bafe5
commit eb18873960
13 changed files with 246 additions and 53 deletions

View File

@ -50,7 +50,7 @@ Pumpkin is currently under heavy development.
- [x] Player Skin - [x] Player Skin
- [x] Player Client brand - [x] Player Client brand
- [x] Player Teleport - [x] Player Teleport
- [ ] Player Movement - [x] Player Movement
- [ ] Player Animation - [ ] Player Animation
- [ ] Player Inventory - [ ] Player Inventory
- [ ] Player Attack - [ ] Player Attack

View File

@ -7,6 +7,15 @@ pub type EntityId = i32;
pub struct Entity { pub struct Entity {
pub entity_id: EntityId, pub entity_id: EntityId,
pub entity_type: EntityType, pub entity_type: EntityType,
pub x: f64,
pub y: f64,
pub z: f64,
pub lastx: f64,
pub lasty: f64,
pub lastz: f64,
pub yaw: f32,
pub head_yaw: f32,
pub pitch: f32,
} }
impl Entity { impl Entity {
@ -14,6 +23,15 @@ impl Entity {
Self { Self {
entity_id, entity_id,
entity_type, entity_type,
x: 0.0,
y: 0.0,
z: 0.0,
lastx: 0.0,
lasty: 0.0,
lastz: 0.0,
yaw: 0.0,
head_yaw: 0.0,
pitch: 0.0,
} }
} }
} }

View File

@ -0,0 +1,20 @@
use pumpkin_macros::packet;
use serde::Serialize;
use crate::VarInt;
#[derive(Serialize, Clone)]
#[packet(0x48)]
pub struct CHeadRot {
entity_id: VarInt,
head_yaw: u8,
}
impl CHeadRot {
pub fn new(entity_id: VarInt, head_yaw: u8) -> Self {
Self {
entity_id,
head_yaw,
}
}
}

View File

@ -21,6 +21,7 @@ pub struct CSpawnEntity {
} }
impl CSpawnEntity { impl CSpawnEntity {
#[allow(clippy::too_many_arguments)]
pub fn new( pub fn new(
entity_id: VarInt, entity_id: VarInt,
entity_uuid: uuid::Uuid, entity_uuid: uuid::Uuid,

View File

@ -0,0 +1,38 @@
use pumpkin_macros::packet;
use serde::Serialize;
use crate::VarInt;
#[derive(Serialize, Clone)]
#[packet(0x2F)]
pub struct CUpdateEntityPosRot {
entity_id: VarInt,
delta_x: i16,
delta_y: i16,
delta_z: i16,
yaw: u8,
pitch: u8,
on_ground: bool,
}
impl CUpdateEntityPosRot {
pub fn new(
entity_id: VarInt,
delta_x: i16,
delta_y: i16,
delta_z: i16,
yaw: u8,
pitch: u8,
on_ground: bool,
) -> Self {
Self {
entity_id,
delta_x,
delta_y,
delta_z,
yaw,
pitch,
on_ground,
}
}
}

View File

@ -0,0 +1,32 @@
use pumpkin_macros::packet;
use serde::Serialize;
use crate::VarInt;
#[derive(Serialize, Clone)]
#[packet(0x2E)]
pub struct CUpdateEntityPos {
entity_id: VarInt,
delta_x: i16,
delta_y: i16,
delta_z: i16,
on_ground: bool,
}
impl CUpdateEntityPos {
pub fn new(
entity_id: VarInt,
delta_x: i16,
delta_y: i16,
delta_z: i16,
on_ground: bool,
) -> Self {
Self {
entity_id,
delta_x,
delta_y,
delta_z,
on_ground,
}
}
}

View File

@ -0,0 +1,24 @@
use pumpkin_macros::packet;
use serde::Serialize;
use crate::VarInt;
#[derive(Serialize, Clone)]
#[packet(0x30)]
pub struct CUpdateEntityRot {
entity_id: VarInt,
yaw: u8,
pitch: u8,
on_ground: bool,
}
impl CUpdateEntityRot {
pub fn new(entity_id: VarInt, yaw: u8, pitch: u8, on_ground: bool) -> Self {
Self {
entity_id,
yaw,
pitch,
on_ground,
}
}
}

View File

@ -1,6 +1,7 @@
mod c_change_difficulty; mod c_change_difficulty;
mod c_chunk_data_update_light; mod c_chunk_data_update_light;
mod c_game_event; mod c_game_event;
mod c_head_rot;
mod c_login; mod c_login;
mod c_play_disconnect; mod c_play_disconnect;
mod c_player_abilities; mod c_player_abilities;
@ -9,11 +10,15 @@ mod c_set_held_item;
mod c_spawn_player; mod c_spawn_player;
mod c_sync_player_position; mod c_sync_player_position;
mod c_system_chat_message; mod c_system_chat_message;
mod c_update_entitiy_pos_rot;
mod c_update_entity_pos;
mod c_update_entity_rot;
mod player_action; mod player_action;
pub use c_change_difficulty::*; pub use c_change_difficulty::*;
pub use c_chunk_data_update_light::*; pub use c_chunk_data_update_light::*;
pub use c_game_event::*; pub use c_game_event::*;
pub use c_head_rot::*;
pub use c_login::*; pub use c_login::*;
pub use c_play_disconnect::*; pub use c_play_disconnect::*;
pub use c_player_abilities::*; pub use c_player_abilities::*;
@ -22,4 +27,7 @@ pub use c_set_held_item::*;
pub use c_spawn_player::*; pub use c_spawn_player::*;
pub use c_sync_player_position::*; pub use c_sync_player_position::*;
pub use c_system_chat_message::*; pub use c_system_chat_message::*;
pub use c_update_entitiy_pos_rot::*;
pub use c_update_entity_pos::*;
pub use c_update_entity_rot::*;
pub use player_action::*; pub use player_action::*;

View File

@ -138,11 +138,15 @@ impl Client {
// todo // todo
let id = 0; let id = 0;
let player = self.player.as_mut().unwrap(); let player = self.player.as_mut().unwrap();
player.x = x; let entity = &mut player.entity;
player.y = y; entity.x = x;
player.z = z; entity.y = y;
player.yaw = yaw; entity.z = z;
player.pitch = pitch; entity.lastx = x;
entity.lasty = y;
entity.lastz = z;
entity.yaw = yaw;
entity.pitch = pitch;
player.awaiting_teleport = Some(id.into()); player.awaiting_teleport = Some(id.into());
self.send_packet(CSyncPlayerPostion::new(x, y, z, yaw, pitch, 0, id.into())); self.send_packet(CSyncPlayerPostion::new(x, y, z, yaw, pitch, 0, id.into()));
} }

View File

@ -1,6 +1,9 @@
use pumpkin_protocol::server::play::{ use pumpkin_protocol::{
SChatCommand, SConfirmTeleport, SPlayerCommand, SPlayerPosition, SPlayerPositionRotation, client::play::{CHeadRot, CUpdateEntityPos, CUpdateEntityPosRot, CUpdateEntityRot},
SPlayerRotation, server::play::{
SChatCommand, SConfirmTeleport, SPlayerCommand, SPlayerPosition, SPlayerPositionRotation,
SPlayerRotation,
},
}; };
use crate::{ use crate::{
@ -29,19 +32,42 @@ impl Client {
} }
} }
pub fn handle_position(&mut self, _server: &mut Server, position: SPlayerPosition) { pub fn handle_position(&mut self, server: &mut Server, position: SPlayerPosition) {
if position.x.is_nan() || position.feet_y.is_nan() || position.z.is_nan() { if position.x.is_nan() || position.feet_y.is_nan() || position.z.is_nan() {
self.kick("Invalid movement"); self.kick("Invalid movement");
} }
let player = self.player.as_mut().unwrap(); let player = self.player.as_mut().unwrap();
player.x = position.x; let entity = &mut player.entity;
player.y = position.feet_y; entity.lastx = entity.x;
player.z = position.z; entity.lasty = entity.y;
entity.lastz = entity.z;
entity.x = position.x;
entity.y = position.feet_y;
entity.z = position.z;
// todo: teleport when moving > 8 block
// send new position to all other players
let on_ground = player.on_ground;
let entity_id = entity.entity_id;
let (x, lastx) = (entity.x, entity.lastx);
let (y, lasty) = (entity.y, entity.lasty);
let (z, lastz) = (entity.z, entity.lastz);
server.broadcast_packet(
self,
CUpdateEntityPos::new(
entity_id.into(),
(x * 4096.0 - lastx * 4096.0) as i16,
(y * 4096.0 - lasty * 4096.0) as i16,
(z * 4096.0 - lastz * 4096.0) as i16,
on_ground,
),
);
} }
pub fn handle_position_rotation( pub fn handle_position_rotation(
&mut self, &mut self,
_server: &mut Server, server: &mut Server,
position_rotation: SPlayerPositionRotation, position_rotation: SPlayerPositionRotation,
) { ) {
if position_rotation.x.is_nan() if position_rotation.x.is_nan()
@ -54,23 +80,61 @@ impl Client {
self.kick("Invalid rotation"); self.kick("Invalid rotation");
} }
let player = self.player.as_mut().unwrap(); let player = self.player.as_mut().unwrap();
player.x = position_rotation.x; let entity = &mut player.entity;
player.y = position_rotation.feet_y;
player.z = position_rotation.z; entity.x = position_rotation.x;
player.yaw = position_rotation.yaw; entity.y = position_rotation.feet_y;
player.pitch = position_rotation.pitch; entity.z = position_rotation.z;
entity.yaw = position_rotation.yaw % 360.0;
entity.pitch = position_rotation.pitch.clamp(-90.0, 90.0) % 360.0;
// send new position to all other players
let on_ground = player.on_ground;
let entity_id = entity.entity_id;
let (x, lastx) = (entity.x, entity.lastx);
let (y, lasty) = (entity.y, entity.lasty);
let (z, lastz) = (entity.z, entity.lastz);
let yaw = (entity.yaw * 256.0 / 360.0).floor();
let pitch = (entity.pitch * 256.0 / 360.0).floor();
let head_yaw = (entity.head_yaw * 256.0 / 360.0).floor();
server.broadcast_packet(
self,
CUpdateEntityPosRot::new(
entity_id.into(),
(x * 4096.0 - lastx * 4096.0) as i16,
(y * 4096.0 - lasty * 4096.0) as i16,
(z * 4096.0 - lastz * 4096.0) as i16,
yaw as u8,
pitch as u8,
on_ground,
),
);
server.broadcast_packet(self, CHeadRot::new(entity_id.into(), head_yaw as u8));
} }
pub fn handle_rotation(&mut self, _server: &mut Server, rotation: SPlayerRotation) { pub fn handle_rotation(&mut self, server: &mut Server, rotation: SPlayerRotation) {
if !rotation.yaw.is_finite() || !rotation.pitch.is_finite() { if !rotation.yaw.is_finite() || !rotation.pitch.is_finite() {
self.kick("Invalid rotation"); self.kick("Invalid rotation");
} }
let player = self.player.as_mut().unwrap(); let player = self.player.as_mut().unwrap();
player.yaw = rotation.yaw; let entity = &mut player.entity;
player.pitch = rotation.pitch; entity.yaw = rotation.yaw % 360.0;
entity.pitch = rotation.pitch.clamp(-90.0, 90.0) % 360.0;
// send new position to all other players
let on_ground = player.on_ground;
let entity_id = entity.entity_id;
let yaw = entity.yaw;
let pitch = entity.pitch;
server.broadcast_packet(
self,
CUpdateEntityRot::new(entity_id.into(), yaw as u8, pitch as u8, on_ground),
);
server.broadcast_packet(self, CHeadRot::new(entity_id.into(), yaw as u8));
} }
pub fn handle_chat_command(&mut self, server: &mut Server, command: SChatCommand) { pub fn handle_chat_command(&mut self, _server: &mut Server, command: SChatCommand) {
handle_command(&mut CommandSender::Player(self), command.command); handle_command(&mut CommandSender::Player(self), command.command);
} }

View File

@ -7,11 +7,6 @@ use serde::{Deserialize, Serialize};
pub struct Player { pub struct Player {
pub entity: Entity, 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 // Client side value, Should be not trusted
pub on_ground: bool, pub on_ground: bool,
@ -26,15 +21,7 @@ pub struct Player {
impl Player { impl Player {
pub fn new(entity_id: EntityId) -> Self { pub fn new(entity_id: EntityId) -> Self {
Self { Self {
entity: Entity { entity: Entity::new(entity_id, EntityType::Player),
entity_id,
entity_type: EntityType::Player,
},
x: 0.0,
y: 0.0,
z: 0.0,
yaw: 0.0,
pitch: 0.0,
on_ground: false, on_ground: false,
awaiting_teleport: None, awaiting_teleport: None,
sneaking: false, sneaking: false,

View File

@ -9,7 +9,6 @@ use configuration::AdvancedConfiguration;
use std::{ use std::{
collections::HashMap, collections::HashMap,
rc::Rc, rc::Rc,
sync::{Arc, Mutex},
thread, thread,
}; };
@ -65,10 +64,10 @@ fn main() -> io::Result<()> {
let mut connections: HashMap<Token, Rc<RefCell<Client>>> = HashMap::new(); let mut connections: HashMap<Token, Rc<RefCell<Client>>> = HashMap::new();
let server = Arc::new(Mutex::new(Server::new(( let mut server = Server::new((
basic_config, basic_config,
advanced_configuration, advanced_configuration,
)))); ));
log::info!("Started Server took {}ms", time.elapsed().as_millis()); log::info!("Started Server took {}ms", time.elapsed().as_millis());
log::info!("You now can connect to the server"); log::info!("You now can connect to the server");
@ -128,8 +127,6 @@ fn main() -> io::Result<()> {
addr, addr,
))); )));
server server
.lock()
.unwrap()
.add_client(rc_token, Rc::clone(&client)); .add_client(rc_token, Rc::clone(&client));
connections.insert(token, client); connections.insert(token, client);
}, },
@ -138,7 +135,7 @@ fn main() -> io::Result<()> {
// Maybe received an event for a TCP connection. // Maybe received an event for a TCP connection.
let done = if let Some(client) = connections.get_mut(&token) { let done = if let Some(client) = connections.get_mut(&token) {
let mut client = client.borrow_mut(); let mut client = client.borrow_mut();
client.poll(&mut server.lock().unwrap(), event); client.poll(&mut server, event);
client.closed client.closed
} else { } else {
// Sporadic events happen, we can safely ignore them. // Sporadic events happen, we can safely ignore them.
@ -147,7 +144,7 @@ fn main() -> io::Result<()> {
if done { if done {
if let Some(client) = connections.remove(&token) { if let Some(client) = connections.remove(&token) {
let mut client = client.borrow_mut(); let mut client = client.borrow_mut();
server.lock().unwrap().remove_client(&token); server.remove_client(&token);
poll.registry().deregister(&mut client.connection)?; poll.registry().deregister(&mut client.connection)?;
} }
} }

View File

@ -18,8 +18,7 @@ use pumpkin_protocol::{
CSpawnEntity, PlayerAction, CSpawnEntity, PlayerAction,
}, },
}, },
BitSet, ClientPacket, Players, Sample, StatusResponse, VarInt, BitSet, ClientPacket, Players, Sample, StatusResponse, VarInt, Version, CURRENT_MC_PROTOCOL,
Version, CURRENT_MC_PROTOCOL,
}; };
use pumpkin_world::chunk::TestChunk; use pumpkin_world::chunk::TestChunk;
use rsa::{rand_core::OsRng, traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey}; use rsa::{rand_core::OsRng, traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey};
@ -117,8 +116,8 @@ impl Server {
// todo: do this in a world // todo: do this in a world
pub fn spawn_player(&mut self, client: &mut Client) { pub fn spawn_player(&mut self, client: &mut Client) {
// This code follows the vanilla packet order // This code follows the vanilla packet order
dbg!("spawning player");
let entity_id = self.new_entity_id(); let entity_id = self.new_entity_id();
log::debug!("spawning player, entity id {}", entity_id);
let player = Player::new(entity_id); let player = Player::new(entity_id);
client.player = Some(player); client.player = Some(player);
@ -234,16 +233,17 @@ impl Server {
for (_, existing_client) in self.current_clients.iter().filter(|c| c.0 != &token) { for (_, existing_client) in self.current_clients.iter().filter(|c| c.0 != &token) {
let existing_client = existing_client.borrow(); let existing_client = existing_client.borrow();
if let Some(player) = &existing_client.player { if let Some(player) = &existing_client.player {
let entity = &player.entity;
let gameprofile = existing_client.gameprofile.as_ref().unwrap(); let gameprofile = existing_client.gameprofile.as_ref().unwrap();
client.send_packet(CSpawnEntity::new( client.send_packet(CSpawnEntity::new(
player.entity_id().into(), player.entity_id().into(),
gameprofile.id, gameprofile.id,
EntityType::Player.to_i32().unwrap().into(), EntityType::Player.to_i32().unwrap().into(),
x, entity.x,
y, entity.y,
z, entity.z,
0, entity.yaw as u8,
0, entity.pitch as u8,
0, 0,
0.into(), 0.into(),
0, 0,
@ -257,7 +257,7 @@ impl Server {
} }
/// Sends a Packet to all Players /// Sends a Packet to all Players
fn broadcast_packet<P>(&mut self, from: &Client, packet: P) pub fn broadcast_packet<P>(&mut self, from: &Client, packet: P)
where where
P: ClientPacket, P: ClientPacket,
P: Clone, P: Clone,