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),
|
InitializeChat(u8),
|
||||||
UpdateGameMode(u8),
|
UpdateGameMode(u8),
|
||||||
UpdateListed(u8),
|
UpdateListed {
|
||||||
|
listed: bool,
|
||||||
|
},
|
||||||
UpdateLatency(u8),
|
UpdateLatency(u8),
|
||||||
UpdateDisplayName(u8),
|
UpdateDisplayName(u8),
|
||||||
}
|
}
|
||||||
@ -68,7 +70,7 @@ impl<'a> ClientPacket for CPlayerInfoUpdate<'a> {
|
|||||||
}
|
}
|
||||||
PlayerAction::InitializeChat(_) => todo!(),
|
PlayerAction::InitializeChat(_) => todo!(),
|
||||||
PlayerAction::UpdateGameMode(_) => todo!(),
|
PlayerAction::UpdateGameMode(_) => todo!(),
|
||||||
PlayerAction::UpdateListed(_) => todo!(),
|
PlayerAction::UpdateListed { listed } => p.put_bool(*listed),
|
||||||
PlayerAction::UpdateLatency(_) => todo!(),
|
PlayerAction::UpdateLatency(_) => todo!(),
|
||||||
PlayerAction::UpdateDisplayName(_) => todo!(),
|
PlayerAction::UpdateDisplayName(_) => todo!(),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,7 +49,6 @@ impl PacketDecoder {
|
|||||||
.0;
|
.0;
|
||||||
|
|
||||||
data.advance(data.len() - r.len());
|
data.advance(data.len() - r.len());
|
||||||
dbg!(packet_id);
|
|
||||||
Ok(Some(RawPacket {
|
Ok(Some(RawPacket {
|
||||||
len: packet_len,
|
len: packet_len,
|
||||||
id: packet_id,
|
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) {
|
fn handle_status_request(&mut self, server: &mut Server, _status_request: SStatusRequest) {
|
||||||
dbg!("sending status");
|
|
||||||
|
|
||||||
self.send_packet(CStatusResponse::new(&server.status_response_json))
|
self.send_packet(CStatusResponse::new(&server.status_response_json))
|
||||||
.unwrap_or_else(|e| self.kick(&e.to_string()));
|
.unwrap_or_else(|e| self.kick(&e.to_string()));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,7 @@ use pumpkin_protocol::{
|
|||||||
config::{SAcknowledgeFinishConfig, SClientInformation, SKnownPacks, SPluginMessage},
|
config::{SAcknowledgeFinishConfig, SClientInformation, SKnownPacks, SPluginMessage},
|
||||||
handshake::SHandShake,
|
handshake::SHandShake,
|
||||||
login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart},
|
login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart},
|
||||||
play::SConfirmTeleport,
|
play::{SConfirmTeleport, SPlayerPosition, SPlayerPositionRotation, SPlayerRotation},
|
||||||
status::{SPingRequest, SStatusRequest},
|
status::{SPingRequest, SStatusRequest},
|
||||||
},
|
},
|
||||||
text::Text,
|
text::Text,
|
||||||
@ -109,10 +109,13 @@ impl Client {
|
|||||||
Ok(())
|
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
|
/// 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
|
/// e.g Postion, Rotation... has not been send
|
||||||
pub fn send_packet<P: ClientPacket>(&mut self, packet: P) -> Result<(), PacketError> {
|
pub fn send_packet<P: ClientPacket>(&mut self, packet: P) -> Result<(), PacketError> {
|
||||||
dbg!("sending packet");
|
|
||||||
self.enc.append_packet(packet)?;
|
self.enc.append_packet(packet)?;
|
||||||
self.connection
|
self.connection
|
||||||
.write_all(&self.enc.take())
|
.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) {
|
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
|
// todo
|
||||||
let id = 0;
|
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))
|
self.send_packet(CSyncPlayerPostion::new(x, y, z, yaw, pitch, 0, id))
|
||||||
.unwrap_or_else(|e| self.kick(&e.to_string()));
|
.unwrap_or_else(|e| self.kick(&e.to_string()));
|
||||||
}
|
}
|
||||||
@ -140,7 +149,6 @@ impl Client {
|
|||||||
|
|
||||||
/// Handles an incoming decoded Packet
|
/// Handles an incoming decoded Packet
|
||||||
pub fn handle_packet(&mut self, server: &mut Server, packet: &mut RawPacket) {
|
pub fn handle_packet(&mut self, server: &mut Server, packet: &mut RawPacket) {
|
||||||
dbg!("Handling packet");
|
|
||||||
let bytebuf = &mut packet.bytebuf;
|
let bytebuf = &mut packet.bytebuf;
|
||||||
match self.connection_state {
|
match self.connection_state {
|
||||||
pumpkin_protocol::ConnectionState::HandShake => match packet.id {
|
pumpkin_protocol::ConnectionState::HandShake => match packet.id {
|
||||||
@ -216,6 +224,15 @@ impl Client {
|
|||||||
SConfirmTeleport::PACKET_ID => {
|
SConfirmTeleport::PACKET_ID => {
|
||||||
self.handle_confirm_teleport(server, SConfirmTeleport::read(bytebuf))
|
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),
|
_ => 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;
|
use crate::server::Server;
|
||||||
|
|
||||||
@ -7,6 +9,15 @@ use super::Client;
|
|||||||
// implement player packets
|
// implement player packets
|
||||||
pub trait PlayerPacketProcessor {
|
pub trait PlayerPacketProcessor {
|
||||||
fn handle_confirm_teleport(&mut self, server: &mut Server, confirm_teleport: SConfirmTeleport);
|
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 {
|
impl PlayerPacketProcessor for Client {
|
||||||
@ -26,4 +37,45 @@ impl PlayerPacketProcessor for Client {
|
|||||||
self.kick("Send Teleport confirm, but we did not teleport")
|
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 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
|
||||||
|
pub on_ground: bool,
|
||||||
|
|
||||||
// Current awaiting teleport id, None if did not teleport
|
// Current awaiting teleport id, None if did not teleport
|
||||||
pub awaiting_teleport: Option<VarInt>,
|
pub awaiting_teleport: Option<VarInt>,
|
||||||
@ -13,6 +21,12 @@ impl Player {
|
|||||||
pub fn new(entity: Entity) -> Self {
|
pub fn new(entity: Entity) -> Self {
|
||||||
Self {
|
Self {
|
||||||
entity,
|
entity,
|
||||||
|
x: 0.0,
|
||||||
|
y: 0.0,
|
||||||
|
z: 0.0,
|
||||||
|
yaw: 0.0,
|
||||||
|
pitch: 0.0,
|
||||||
|
on_ground: false,
|
||||||
awaiting_teleport: None,
|
awaiting_teleport: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ pub mod util;
|
|||||||
|
|
||||||
#[cfg(not(target_os = "wasi"))]
|
#[cfg(not(target_os = "wasi"))]
|
||||||
fn main() -> io::Result<()> {
|
fn main() -> io::Result<()> {
|
||||||
use std::{collections::HashMap, rc::Rc};
|
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
||||||
|
|
||||||
use client::Client;
|
use client::Client;
|
||||||
use configuration::AdvancedConfiguration;
|
use configuration::AdvancedConfiguration;
|
||||||
@ -51,7 +51,7 @@ fn main() -> io::Result<()> {
|
|||||||
// Unique token for each incoming connection.
|
// Unique token for each incoming connection.
|
||||||
let mut unique_token = Token(SERVER.0 + 1);
|
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");
|
log::info!("You now can connect to the server");
|
||||||
|
|
||||||
@ -94,13 +94,20 @@ fn main() -> io::Result<()> {
|
|||||||
token,
|
token,
|
||||||
Interest::READABLE.add(Interest::WRITABLE),
|
Interest::READABLE.add(Interest::WRITABLE),
|
||||||
)?;
|
)?;
|
||||||
|
let rc_token = Rc::new(token);
|
||||||
connections.insert(token, Client::new(Rc::new(token), connection, addr));
|
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 => {
|
token => {
|
||||||
// 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();
|
||||||
client.poll(&mut server, event);
|
client.poll(&mut server, event);
|
||||||
client.closed
|
client.closed
|
||||||
} else {
|
} else {
|
||||||
@ -108,7 +115,9 @@ fn main() -> io::Result<()> {
|
|||||||
false
|
false
|
||||||
};
|
};
|
||||||
if done {
|
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)?;
|
poll.registry().deregister(&mut client.connection)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,19 @@
|
|||||||
use std::{
|
use std::{
|
||||||
|
cell::RefCell,
|
||||||
|
collections::HashMap,
|
||||||
io::Cursor,
|
io::Cursor,
|
||||||
|
rc::Rc,
|
||||||
sync::atomic::{AtomicI32, Ordering},
|
sync::atomic::{AtomicI32, Ordering},
|
||||||
};
|
};
|
||||||
|
|
||||||
use base64::{engine::general_purpose, Engine};
|
use base64::{engine::general_purpose, Engine};
|
||||||
use mio::{event::Event, Poll};
|
use mio::{event::Event, Poll, Token};
|
||||||
use pumpkin_protocol::{
|
use pumpkin_protocol::{
|
||||||
client::{
|
client::{
|
||||||
config::CPluginMessage,
|
config::CPluginMessage,
|
||||||
play::{CChunkDataUpdateLight, CGameEvent, CLogin, CPlayerInfoUpdate, PlayerAction},
|
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 pumpkin_world::chunk::TestChunk;
|
||||||
use rsa::{rand_core::OsRng, traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey};
|
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
|
/// 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 cached_server_brand: Vec<u8>,
|
||||||
|
|
||||||
|
pub current_clients: HashMap<Rc<Token>, Rc<RefCell<Client>>>,
|
||||||
|
|
||||||
// todo replace with HashMap <World, Player>
|
// todo replace with HashMap <World, Player>
|
||||||
entity_id: AtomicI32, // todo: place this into every world
|
entity_id: AtomicI32, // todo: place this into every world
|
||||||
pub base_config: BasicConfiguration,
|
pub base_config: BasicConfiguration,
|
||||||
@ -83,6 +88,7 @@ impl Server {
|
|||||||
status_response,
|
status_response,
|
||||||
status_response_json,
|
status_response_json,
|
||||||
public_key_der,
|
public_key_der,
|
||||||
|
current_clients: HashMap::new(),
|
||||||
base_config: config.0,
|
base_config: config.0,
|
||||||
auth_client,
|
auth_client,
|
||||||
advanced_config: config.1,
|
advanced_config: config.1,
|
||||||
@ -95,8 +101,17 @@ impl Server {
|
|||||||
client.poll(self, event)
|
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
|
// 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
|
||||||
dbg!("spawning player");
|
dbg!("spawning player");
|
||||||
let entity_id = self.new_entity_id();
|
let entity_id = self.new_entity_id();
|
||||||
let player = Player::new(Entity { entity_id });
|
let player = Player::new(Entity { entity_id });
|
||||||
@ -108,16 +123,16 @@ impl Server {
|
|||||||
self.base_config.hardcore,
|
self.base_config.hardcore,
|
||||||
vec!["minecraft:overworld".into()],
|
vec!["minecraft:overworld".into()],
|
||||||
self.base_config.max_players as VarInt,
|
self.base_config.max_players as VarInt,
|
||||||
8, // view distance todo
|
self.base_config.view_distances as VarInt, // view distance todo
|
||||||
8, // sim view dinstance todo
|
self.base_config.simulation_distance as VarInt, // sim view dinstance todo
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
0,
|
0,
|
||||||
"minecraft:overworld".into(),
|
"minecraft:overworld".into(),
|
||||||
0, // seed
|
0, // seed
|
||||||
GameMode::Spectator.to_byte() as u8,
|
GameMode::Survival.to_byte() as u8,
|
||||||
GameMode::Spectator.to_byte(),
|
GameMode::Survival.to_byte(),
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false, // deth loc
|
false, // deth loc
|
||||||
@ -130,6 +145,8 @@ impl Server {
|
|||||||
// teleport
|
// teleport
|
||||||
client.teleport(10.0, 500.0, 10.0, 10.0, 10.0);
|
client.teleport(10.0, 500.0, 10.0, 10.0, 10.0);
|
||||||
let gameprofile = client.gameprofile.as_ref().unwrap();
|
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
|
client
|
||||||
.send_packet(CPlayerInfoUpdate::new(
|
.send_packet(CPlayerInfoUpdate::new(
|
||||||
0x01,
|
0x01,
|
||||||
@ -142,6 +159,7 @@ impl Server {
|
|||||||
}],
|
}],
|
||||||
))
|
))
|
||||||
.unwrap_or_else(|e| client.kick(&e.to_string()));
|
.unwrap_or_else(|e| client.kick(&e.to_string()));
|
||||||
|
// TODO: Now we send this to all other client
|
||||||
|
|
||||||
// Start waiting for level chunks
|
// Start waiting for level chunks
|
||||||
client
|
client
|
||||||
@ -151,6 +169,22 @@ impl Server {
|
|||||||
// Server::spawn_test_chunk(client);
|
// 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
|
// todo: do this in a world
|
||||||
fn _spawn_test_chunk(client: &mut Client) {
|
fn _spawn_test_chunk(client: &mut Client) {
|
||||||
let test_chunk = TestChunk::new();
|
let test_chunk = TestChunk::new();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user