Add Player movement
This commit is contained in:
parent
32569bafe5
commit
eb18873960
@ -50,7 +50,7 @@ Pumpkin is currently under heavy development.
|
||||
- [x] Player Skin
|
||||
- [x] Player Client brand
|
||||
- [x] Player Teleport
|
||||
- [ ] Player Movement
|
||||
- [x] Player Movement
|
||||
- [ ] Player Animation
|
||||
- [ ] Player Inventory
|
||||
- [ ] Player Attack
|
||||
|
||||
@ -7,6 +7,15 @@ pub type EntityId = i32;
|
||||
pub struct Entity {
|
||||
pub entity_id: EntityId,
|
||||
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 {
|
||||
@ -14,6 +23,15 @@ impl Entity {
|
||||
Self {
|
||||
entity_id,
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
20
pumpkin-protocol/src/client/play/c_head_rot.rs
Normal file
20
pumpkin-protocol/src/client/play/c_head_rot.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -21,6 +21,7 @@ pub struct CSpawnEntity {
|
||||
}
|
||||
|
||||
impl CSpawnEntity {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
entity_id: VarInt,
|
||||
entity_uuid: uuid::Uuid,
|
||||
|
||||
38
pumpkin-protocol/src/client/play/c_update_entitiy_pos_rot.rs
Normal file
38
pumpkin-protocol/src/client/play/c_update_entitiy_pos_rot.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
32
pumpkin-protocol/src/client/play/c_update_entity_pos.rs
Normal file
32
pumpkin-protocol/src/client/play/c_update_entity_pos.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
24
pumpkin-protocol/src/client/play/c_update_entity_rot.rs
Normal file
24
pumpkin-protocol/src/client/play/c_update_entity_rot.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
mod c_change_difficulty;
|
||||
mod c_chunk_data_update_light;
|
||||
mod c_game_event;
|
||||
mod c_head_rot;
|
||||
mod c_login;
|
||||
mod c_play_disconnect;
|
||||
mod c_player_abilities;
|
||||
@ -9,11 +10,15 @@ mod c_set_held_item;
|
||||
mod c_spawn_player;
|
||||
mod c_sync_player_position;
|
||||
mod c_system_chat_message;
|
||||
mod c_update_entitiy_pos_rot;
|
||||
mod c_update_entity_pos;
|
||||
mod c_update_entity_rot;
|
||||
mod player_action;
|
||||
|
||||
pub use c_change_difficulty::*;
|
||||
pub use c_chunk_data_update_light::*;
|
||||
pub use c_game_event::*;
|
||||
pub use c_head_rot::*;
|
||||
pub use c_login::*;
|
||||
pub use c_play_disconnect::*;
|
||||
pub use c_player_abilities::*;
|
||||
@ -22,4 +27,7 @@ pub use c_set_held_item::*;
|
||||
pub use c_spawn_player::*;
|
||||
pub use c_sync_player_position::*;
|
||||
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::*;
|
||||
|
||||
@ -138,11 +138,15 @@ impl Client {
|
||||
// todo
|
||||
let id = 0;
|
||||
let player = self.player.as_mut().unwrap();
|
||||
player.x = x;
|
||||
player.y = y;
|
||||
player.z = z;
|
||||
player.yaw = yaw;
|
||||
player.pitch = pitch;
|
||||
let entity = &mut player.entity;
|
||||
entity.x = x;
|
||||
entity.y = y;
|
||||
entity.z = z;
|
||||
entity.lastx = x;
|
||||
entity.lasty = y;
|
||||
entity.lastz = z;
|
||||
entity.yaw = yaw;
|
||||
entity.pitch = pitch;
|
||||
player.awaiting_teleport = Some(id.into());
|
||||
self.send_packet(CSyncPlayerPostion::new(x, y, z, yaw, pitch, 0, id.into()));
|
||||
}
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
use pumpkin_protocol::server::play::{
|
||||
use pumpkin_protocol::{
|
||||
client::play::{CHeadRot, CUpdateEntityPos, CUpdateEntityPosRot, CUpdateEntityRot},
|
||||
server::play::{
|
||||
SChatCommand, SConfirmTeleport, SPlayerCommand, SPlayerPosition, SPlayerPositionRotation,
|
||||
SPlayerRotation,
|
||||
},
|
||||
};
|
||||
|
||||
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() {
|
||||
self.kick("Invalid movement");
|
||||
}
|
||||
let player = self.player.as_mut().unwrap();
|
||||
player.x = position.x;
|
||||
player.y = position.feet_y;
|
||||
player.z = position.z;
|
||||
let entity = &mut player.entity;
|
||||
entity.lastx = entity.x;
|
||||
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(
|
||||
&mut self,
|
||||
_server: &mut Server,
|
||||
server: &mut Server,
|
||||
position_rotation: SPlayerPositionRotation,
|
||||
) {
|
||||
if position_rotation.x.is_nan()
|
||||
@ -54,23 +80,61 @@ impl Client {
|
||||
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;
|
||||
let entity = &mut player.entity;
|
||||
|
||||
entity.x = position_rotation.x;
|
||||
entity.y = position_rotation.feet_y;
|
||||
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() {
|
||||
self.kick("Invalid rotation");
|
||||
}
|
||||
let player = self.player.as_mut().unwrap();
|
||||
player.yaw = rotation.yaw;
|
||||
player.pitch = rotation.pitch;
|
||||
let entity = &mut player.entity;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -7,11 +7,6 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
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,
|
||||
@ -26,15 +21,7 @@ pub struct Player {
|
||||
impl Player {
|
||||
pub fn new(entity_id: EntityId) -> Self {
|
||||
Self {
|
||||
entity: Entity {
|
||||
entity_id,
|
||||
entity_type: EntityType::Player,
|
||||
},
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0,
|
||||
yaw: 0.0,
|
||||
pitch: 0.0,
|
||||
entity: Entity::new(entity_id, EntityType::Player),
|
||||
on_ground: false,
|
||||
awaiting_teleport: None,
|
||||
sneaking: false,
|
||||
|
||||
@ -9,7 +9,6 @@ use configuration::AdvancedConfiguration;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
rc::Rc,
|
||||
sync::{Arc, Mutex},
|
||||
thread,
|
||||
};
|
||||
|
||||
@ -65,10 +64,10 @@ fn main() -> io::Result<()> {
|
||||
|
||||
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,
|
||||
advanced_configuration,
|
||||
))));
|
||||
));
|
||||
log::info!("Started Server took {}ms", time.elapsed().as_millis());
|
||||
log::info!("You now can connect to the server");
|
||||
|
||||
@ -128,8 +127,6 @@ fn main() -> io::Result<()> {
|
||||
addr,
|
||||
)));
|
||||
server
|
||||
.lock()
|
||||
.unwrap()
|
||||
.add_client(rc_token, Rc::clone(&client));
|
||||
connections.insert(token, client);
|
||||
},
|
||||
@ -138,7 +135,7 @@ fn main() -> io::Result<()> {
|
||||
// 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.lock().unwrap(), event);
|
||||
client.poll(&mut server, event);
|
||||
client.closed
|
||||
} else {
|
||||
// Sporadic events happen, we can safely ignore them.
|
||||
@ -147,7 +144,7 @@ fn main() -> io::Result<()> {
|
||||
if done {
|
||||
if let Some(client) = connections.remove(&token) {
|
||||
let mut client = client.borrow_mut();
|
||||
server.lock().unwrap().remove_client(&token);
|
||||
server.remove_client(&token);
|
||||
poll.registry().deregister(&mut client.connection)?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,8 +18,7 @@ use pumpkin_protocol::{
|
||||
CSpawnEntity, PlayerAction,
|
||||
},
|
||||
},
|
||||
BitSet, ClientPacket, Players, Sample, StatusResponse, VarInt,
|
||||
Version, CURRENT_MC_PROTOCOL,
|
||||
BitSet, ClientPacket, Players, Sample, StatusResponse, VarInt, Version, CURRENT_MC_PROTOCOL,
|
||||
};
|
||||
use pumpkin_world::chunk::TestChunk;
|
||||
use rsa::{rand_core::OsRng, traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey};
|
||||
@ -117,8 +116,8 @@ impl Server {
|
||||
// todo: do this in a world
|
||||
pub fn spawn_player(&mut self, client: &mut Client) {
|
||||
// This code follows the vanilla packet order
|
||||
dbg!("spawning player");
|
||||
let entity_id = self.new_entity_id();
|
||||
log::debug!("spawning player, entity id {}", entity_id);
|
||||
let player = Player::new(entity_id);
|
||||
client.player = Some(player);
|
||||
|
||||
@ -234,16 +233,17 @@ impl Server {
|
||||
for (_, existing_client) in self.current_clients.iter().filter(|c| c.0 != &token) {
|
||||
let existing_client = existing_client.borrow();
|
||||
if let Some(player) = &existing_client.player {
|
||||
let entity = &player.entity;
|
||||
let gameprofile = existing_client.gameprofile.as_ref().unwrap();
|
||||
client.send_packet(CSpawnEntity::new(
|
||||
player.entity_id().into(),
|
||||
gameprofile.id,
|
||||
EntityType::Player.to_i32().unwrap().into(),
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
0,
|
||||
0,
|
||||
entity.x,
|
||||
entity.y,
|
||||
entity.z,
|
||||
entity.yaw as u8,
|
||||
entity.pitch as u8,
|
||||
0,
|
||||
0.into(),
|
||||
0,
|
||||
@ -257,7 +257,7 @@ impl Server {
|
||||
}
|
||||
|
||||
/// 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
|
||||
P: ClientPacket,
|
||||
P: Clone,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user