Add Serverbound Movement Packets
- SPlayerPosition - SPlayerPositionRotation - SPlayerRotation
This commit is contained in:
parent
05977223e3
commit
42bc84b23c
@ -35,7 +35,9 @@ pub enum PlayerAction {
|
||||
},
|
||||
InitializeChat(u8),
|
||||
UpdateGameMode(u8),
|
||||
UpdateListed(u8),
|
||||
UpdateListed {
|
||||
listed: bool,
|
||||
},
|
||||
UpdateLatency(u8),
|
||||
UpdateDisplayName(u8),
|
||||
}
|
||||
@ -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!(),
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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()));
|
||||
}
|
||||
|
||||
@ -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,
|
||||
@ -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())
|
||||
@ -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()));
|
||||
}
|
||||
@ -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 {
|
||||
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
use pumpkin_protocol::server::play::SConfirmTeleport;
|
||||
use pumpkin_protocol::server::play::{
|
||||
SConfirmTeleport, SPlayerPosition, SPlayerPositionRotation, SPlayerRotation,
|
||||
};
|
||||
|
||||
use crate::server::Server;
|
||||
|
||||
@ -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 {
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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>,
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
@ -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");
|
||||
|
||||
@ -94,13 +94,20 @@ 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 {
|
||||
@ -108,7 +115,9 @@ fn main() -> io::Result<()> {
|
||||
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)?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,16 +1,19 @@
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
collections::HashMap,
|
||||
io::Cursor,
|
||||
rc::Rc,
|
||||
sync::atomic::{AtomicI32, Ordering},
|
||||
};
|
||||
|
||||
use base64::{engine::general_purpose, Engine};
|
||||
use mio::{event::Event, Poll};
|
||||
use mio::{event::Event, Poll, Token};
|
||||
use pumpkin_protocol::{
|
||||
client::{
|
||||
config::CPluginMessage,
|
||||
play::{CChunkDataUpdateLight, CGameEvent, CLogin, CPlayerInfoUpdate, PlayerAction},
|
||||
},
|
||||
BitSet, PacketError, Players, Sample, StatusResponse, VarInt, VarInt32, Version,
|
||||
BitSet, ClientPacket, PacketError, Players, Sample, StatusResponse, VarInt, VarInt32, Version,
|
||||
};
|
||||
use pumpkin_world::chunk::TestChunk;
|
||||
use rsa::{rand_core::OsRng, traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey};
|
||||
@ -41,6 +44,8 @@ pub struct Server {
|
||||
/// Cache the Server brand buffer so we don't have to rebuild them every time a player joins
|
||||
pub cached_server_brand: Vec<u8>,
|
||||
|
||||
pub current_clients: HashMap<Rc<Token>, Rc<RefCell<Client>>>,
|
||||
|
||||
// todo replace with HashMap <World, Player>
|
||||
entity_id: AtomicI32, // todo: place this into every world
|
||||
pub base_config: BasicConfiguration,
|
||||
@ -83,6 +88,7 @@ impl Server {
|
||||
status_response,
|
||||
status_response_json,
|
||||
public_key_der,
|
||||
current_clients: HashMap::new(),
|
||||
base_config: config.0,
|
||||
auth_client,
|
||||
advanced_config: config.1,
|
||||
@ -95,8 +101,17 @@ impl Server {
|
||||
client.poll(self, event)
|
||||
}
|
||||
|
||||
pub fn add_client(&mut self, token: Rc<Token>, client: Rc<RefCell<Client>>) {
|
||||
self.current_clients.insert(token, client);
|
||||
}
|
||||
|
||||
pub fn remove_client(&mut self, token: &Token) {
|
||||
self.current_clients.remove(token);
|
||||
}
|
||||
|
||||
// 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();
|
||||
let player = Player::new(Entity { entity_id });
|
||||
@ -108,16 +123,16 @@ impl Server {
|
||||
self.base_config.hardcore,
|
||||
vec!["minecraft:overworld".into()],
|
||||
self.base_config.max_players as VarInt,
|
||||
8, // view distance todo
|
||||
8, // sim view dinstance todo
|
||||
self.base_config.view_distances as VarInt, // view distance todo
|
||||
self.base_config.simulation_distance as VarInt, // sim view dinstance todo
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
"minecraft:overworld".into(),
|
||||
0, // seed
|
||||
GameMode::Spectator.to_byte() as u8,
|
||||
GameMode::Spectator.to_byte(),
|
||||
GameMode::Survival.to_byte() as u8,
|
||||
GameMode::Survival.to_byte(),
|
||||
false,
|
||||
false,
|
||||
false, // deth loc
|
||||
@ -130,6 +145,8 @@ impl Server {
|
||||
// teleport
|
||||
client.teleport(10.0, 500.0, 10.0, 10.0, 10.0);
|
||||
let gameprofile = client.gameprofile.as_ref().unwrap();
|
||||
// first send info update to our new player, So he can see his Skin
|
||||
// TODO: send more actions, (chat. list, ping)
|
||||
client
|
||||
.send_packet(CPlayerInfoUpdate::new(
|
||||
0x01,
|
||||
@ -142,6 +159,7 @@ impl Server {
|
||||
}],
|
||||
))
|
||||
.unwrap_or_else(|e| client.kick(&e.to_string()));
|
||||
// TODO: Now we send this to all other client
|
||||
|
||||
// Start waiting for level chunks
|
||||
client
|
||||
@ -151,6 +169,22 @@ impl Server {
|
||||
// Server::spawn_test_chunk(client);
|
||||
}
|
||||
|
||||
/// Sends a Packet to all Players
|
||||
fn broadcast_packet<P>(&mut self, packet: P) -> Result<(), PacketError>
|
||||
where
|
||||
P: ClientPacket,
|
||||
P: Clone,
|
||||
{
|
||||
for client in self.current_clients.values() {
|
||||
// Check if client is a player
|
||||
if client.borrow().is_player() {
|
||||
// we need to clone, Because we send a new packet to every client
|
||||
client.borrow_mut().send_packet(packet.clone())?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// todo: do this in a world
|
||||
fn _spawn_test_chunk(client: &mut Client) {
|
||||
let test_chunk = TestChunk::new();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user