fix crash on join

This commit is contained in:
Snowiiii 2024-07-30 21:49:34 +02:00
parent 090599b412
commit 37cac21899
17 changed files with 541 additions and 115 deletions

14
configuration.toml Normal file
View File

@ -0,0 +1,14 @@
server_address = "127.0.0.1"
server_port = 25565
seed = ""
max_plyers = -1
view_distances = 10
simulation_distance = 10
resource_pack = ""
resource_pack_sha1 = ""
default_difficulty = "Normal"
allow_nether = true
hardcore = false
online_mode = true
spawn_protection = 16
motd = "A Blazing fast Pumpkin Server!"

2
features.toml Normal file
View File

@ -0,0 +1,2 @@
liquid_physics = true
encryption = true

View File

@ -1,79 +1,90 @@
use crate::protocol::{ use crate::{
client::{ protocol::{
config::CFinishConfig, client::{
login::{CEncryptionRequest, CLoginSuccess}, config::CFinishConfig,
status::{CPingResponse, CStatusResponse}, login::{CEncryptionRequest, CLoginSuccess},
status::{CPingResponse, CStatusResponse},
},
server::{
config::{SAcknowledgeFinishConfig, SClientInformation},
handshake::SHandShake,
login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart},
status::{SPingRequest, SStatusRequest},
},
ConnectionState,
}, },
server::{ server::Server,
config::{SAcknowledgeFinishConfig, SClientInformation},
handshake::SHandShake,
login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart},
status::{SPingRequest, SStatusRequest},
},
ConnectionState,
}; };
use super::{Client, PlayerConfig}; use super::{Client, PlayerConfig};
pub trait ClientPacketProcessor { pub trait ClientPacketProcessor {
// Handshake // Handshake
fn handle_handshake(&mut self, handshake: SHandShake); fn handle_handshake(&mut self, server: &mut Server, handshake: SHandShake);
// Status // Status
fn handle_status_request(&mut self, status_request: SStatusRequest); fn handle_status_request(&mut self, server: &mut Server, status_request: SStatusRequest);
fn handle_ping_request(&mut self, ping_request: SPingRequest); fn handle_ping_request(&mut self, server: &mut Server, ping_request: SPingRequest);
// Login // Login
fn handle_login_start(&mut self, login_start: SLoginStart); fn handle_login_start(&mut self, server: &mut Server, login_start: SLoginStart);
fn handle_encryption_response(&mut self, encryption_response: SEncryptionResponse); fn handle_encryption_response(
fn handle_plugin_response(&mut self, plugin_response: SLoginPluginResponse); &mut self,
fn handle_login_acknowledged(&mut self, login_acknowledged: SLoginAcknowledged); server: &mut Server,
encryption_response: SEncryptionResponse,
);
fn handle_plugin_response(
&mut self,
server: &mut Server,
plugin_response: SLoginPluginResponse,
);
fn handle_login_acknowledged(
&mut self,
server: &mut Server,
login_acknowledged: SLoginAcknowledged,
);
// Config // Config
fn handle_client_information(&mut self, client_information: SClientInformation); fn handle_client_information(
fn handle_config_acknowledged(&mut self, config_acknowledged: SAcknowledgeFinishConfig); &mut self,
server: &mut Server,
client_information: SClientInformation,
);
fn handle_config_acknowledged(
&mut self,
server: &mut Server,
config_acknowledged: SAcknowledgeFinishConfig,
);
} }
impl ClientPacketProcessor for Client { impl ClientPacketProcessor for Client {
fn handle_handshake(&mut self, handshake: SHandShake) { fn handle_handshake(&mut self, _server: &mut Server, handshake: SHandShake) {
// TODO set protocol version and check protocol version // TODO set protocol version and check protocol version
self.connection_state = handshake.next_state; self.connection_state = handshake.next_state;
dbg!("handshake"); dbg!("handshake");
} }
fn handle_status_request(&mut self, _status_request: SStatusRequest) { fn handle_status_request(&mut self, server: &mut Server, _status_request: SStatusRequest) {
dbg!("sending status"); dbg!("sending status");
dbg!("test first"); let response = serde_json::to_string(&server.status_response).unwrap();
let guard = self.server.try_lock().unwrap();
dbg!("test");
let response = serde_json::to_string(&guard.status_response).unwrap();
drop(guard);
self.send_packet(CStatusResponse::new(response)); self.send_packet(CStatusResponse::new(response));
} }
fn handle_ping_request(&mut self, ping_request: SPingRequest) { fn handle_ping_request(&mut self, _server: &mut Server, ping_request: SPingRequest) {
dbg!("ping"); dbg!("ping");
self.send_packet(CPingResponse::new(ping_request.payload)); self.send_packet(CPingResponse::new(ping_request.payload));
self.close(); self.close();
} }
fn handle_login_start(&mut self, login_start: SLoginStart) { fn handle_login_start(&mut self, server: &mut Server, login_start: SLoginStart) {
dbg!("login start"); dbg!("login start");
self.name = Some(login_start.name); self.name = Some(login_start.name);
self.uuid = Some(login_start.uuid); self.uuid = Some(login_start.uuid);
let verify_token: [u8; 4] = rand::random(); let verify_token: [u8; 4] = rand::random();
let public_key_der = self let public_key_der = &server.public_key_der;
.server
.to_owned()
.lock()
.unwrap()
.public_key_der
.clone(); // todo do not clone
let packet = CEncryptionRequest::new( let packet = CEncryptionRequest::new(
"".into(), "".into(),
public_key_der.len() as i32, public_key_der.len() as i32,
&public_key_der, public_key_der,
verify_token.len() as i32, verify_token.len() as i32,
&verify_token, &verify_token,
false, // TODO false, // TODO
@ -81,27 +92,45 @@ impl ClientPacketProcessor for Client {
self.send_packet(packet); self.send_packet(packet);
} }
fn handle_encryption_response(&mut self, encryption_response: SEncryptionResponse) { fn handle_encryption_response(
&mut self,
server: &mut Server,
encryption_response: SEncryptionResponse,
) {
dbg!("encryption response"); dbg!("encryption response");
// should be impossible // should be impossible
if self.uuid.is_none() || self.name.is_none() { if self.uuid.is_none() || self.name.is_none() {
self.kick("UUID or Name is none".into()); self.kick("UUID or Name is none".into());
return; return;
} }
self.enable_encryption(encryption_response.shared_secret) self.enable_encryption(server, encryption_response.shared_secret)
.unwrap(); .unwrap();
let packet = CLoginSuccess::new(self.uuid.unwrap(), self.name.clone().unwrap(), 0, false); let packet = CLoginSuccess::new(self.uuid.unwrap(), self.name.clone().unwrap(), 0, false);
self.send_packet(packet); self.send_packet(packet);
} }
fn handle_plugin_response(&mut self, plugin_response: SLoginPluginResponse) {} fn handle_plugin_response(
&mut self,
_server: &mut Server,
_plugin_response: SLoginPluginResponse,
) {
}
fn handle_login_acknowledged(&mut self, login_acknowledged: SLoginAcknowledged) { fn handle_login_acknowledged(
&mut self,
_server: &mut Server,
login_acknowledged: SLoginAcknowledged,
) {
let _ = login_acknowledged;
self.connection_state = ConnectionState::Config; self.connection_state = ConnectionState::Config;
dbg!("login achnowlaged"); dbg!("login achnowlaged");
} }
fn handle_client_information(&mut self, client_information: SClientInformation) { fn handle_client_information(
&mut self,
_server: &mut Server,
client_information: SClientInformation,
) {
self.config = Some(PlayerConfig { self.config = Some(PlayerConfig {
locale: client_information.locale, locale: client_information.locale,
view_distance: client_information.view_distance, view_distance: client_information.view_distance,
@ -116,10 +145,14 @@ impl ClientPacketProcessor for Client {
self.send_packet(CFinishConfig::new()); self.send_packet(CFinishConfig::new());
} }
fn handle_config_acknowledged(&mut self, config_acknowledged: SAcknowledgeFinishConfig) { fn handle_config_acknowledged(
&mut self,
server: &mut Server,
config_acknowledged: SAcknowledgeFinishConfig,
) {
dbg!("config acknowledged"); dbg!("config acknowledged");
self.connection_state = ConnectionState::Play; self.connection_state = ConnectionState::Play;
// generate a player // generate a player
self.server.lock().unwrap().spawn_player(&self.token); server.spawn_player(self);
} }
} }

View File

@ -2,11 +2,10 @@ use std::{
collections::VecDeque, collections::VecDeque,
io::{self, Write}, io::{self, Write},
rc::Rc, rc::Rc,
sync::{Arc, Mutex},
}; };
use crate::{ use crate::{
entity::player::{ChatMode, Hand}, entity::player::{ChatMode, Hand, Player},
protocol::{ protocol::{
client::{config::CConfigDisconnect, login::CLoginDisconnect}, client::{config::CConfigDisconnect, login::CLoginDisconnect},
server::{ server::{
@ -49,11 +48,12 @@ pub struct PlayerConfig {
} }
pub struct Client { pub struct Client {
pub player: Option<Player>,
pub name: Option<String>, pub name: Option<String>,
pub uuid: Option<uuid::Uuid>, pub uuid: Option<uuid::Uuid>,
pub config: Option<PlayerConfig>, pub config: Option<PlayerConfig>,
pub server: Arc<Mutex<Server>>,
pub connection_state: ConnectionState, pub connection_state: ConnectionState,
pub encrytion: bool, pub encrytion: bool,
pub closed: bool, pub closed: bool,
@ -65,13 +65,13 @@ pub struct Client {
} }
impl Client { impl Client {
pub fn new(server: Arc<Mutex<Server>>, token: Rc<Token>, connection: TcpStream) -> Self { pub fn new(token: Rc<Token>, connection: TcpStream) -> Self {
Self { Self {
name: None, name: None,
uuid: None, uuid: None,
config: None, config: None,
server,
token, token,
player: None,
connection_state: ConnectionState::HandShake, connection_state: ConnectionState::HandShake,
connection, connection,
enc: PacketEncoder::default(), enc: PacketEncoder::default(),
@ -86,12 +86,13 @@ impl Client {
self.client_packets_queue.push_back(packet); self.client_packets_queue.push_back(packet);
} }
pub fn enable_encryption(&mut self, shared_secret: Vec<u8>) -> anyhow::Result<()> { pub fn enable_encryption(
&mut self,
server: &mut Server,
shared_secret: Vec<u8>,
) -> anyhow::Result<()> {
self.encrytion = true; self.encrytion = true;
let shared_secret = self let shared_secret = server
.server
.lock()
.unwrap()
.private_key .private_key
.decrypt(Pkcs1v15Encrypt, &shared_secret) .decrypt(Pkcs1v15Encrypt, &shared_secret)
.context("failed to decrypt shared secret")?; .context("failed to decrypt shared secret")?;
@ -110,21 +111,21 @@ impl Client {
self.connection.write_all(&self.enc.take()).unwrap(); self.connection.write_all(&self.enc.take()).unwrap();
} }
pub fn procress_packets(&mut self) { pub fn process_packets(&mut self, server: &mut Server) {
let mut i = 0; let mut i = 0;
while i < self.client_packets_queue.len() { while i < self.client_packets_queue.len() {
let mut packet = self.client_packets_queue.remove(i).unwrap(); let mut packet = self.client_packets_queue.remove(i).unwrap();
self.handle_packet(&mut packet); self.handle_packet(server, &mut packet);
i += 1; i += 1;
} }
} }
pub fn handle_packet(&mut self, packet: &mut RawPacket) { pub fn handle_packet(&mut self, server: &mut Server, packet: &mut RawPacket) {
dbg!("Handling packet"); dbg!("Handling packet");
let bytebuf = &mut packet.bytebuf; let bytebuf = &mut packet.bytebuf;
match self.connection_state { match self.connection_state {
crate::protocol::ConnectionState::HandShake => match packet.id { crate::protocol::ConnectionState::HandShake => match packet.id {
SHandShake::PACKET_ID => self.handle_handshake(SHandShake::read(bytebuf)), SHandShake::PACKET_ID => self.handle_handshake(server, SHandShake::read(bytebuf)),
_ => log::error!( _ => log::error!(
"Failed to handle packet id {} while in Handshake state", "Failed to handle packet id {} while in Handshake state",
packet.id packet.id
@ -132,24 +133,28 @@ impl Client {
}, },
crate::protocol::ConnectionState::Status => match packet.id { crate::protocol::ConnectionState::Status => match packet.id {
SStatusRequest::PACKET_ID => { SStatusRequest::PACKET_ID => {
self.handle_status_request(SStatusRequest::read(bytebuf)) self.handle_status_request(server, SStatusRequest::read(bytebuf))
}
SPingRequest::PACKET_ID => {
self.handle_ping_request(server, SPingRequest::read(bytebuf))
} }
SPingRequest::PACKET_ID => self.handle_ping_request(SPingRequest::read(bytebuf)),
_ => log::error!( _ => log::error!(
"Failed to handle packet id {} while in Status state", "Failed to handle packet id {} while in Status state",
packet.id packet.id
), ),
}, },
crate::protocol::ConnectionState::Login => match packet.id { crate::protocol::ConnectionState::Login => match packet.id {
SLoginStart::PACKET_ID => self.handle_login_start(SLoginStart::read(bytebuf)), SLoginStart::PACKET_ID => {
self.handle_login_start(server, SLoginStart::read(bytebuf))
}
SEncryptionResponse::PACKET_ID => { SEncryptionResponse::PACKET_ID => {
self.handle_encryption_response(SEncryptionResponse::read(bytebuf)) self.handle_encryption_response(server, SEncryptionResponse::read(bytebuf))
} }
SLoginPluginResponse::PACKET_ID => { SLoginPluginResponse::PACKET_ID => {
self.handle_plugin_response(SLoginPluginResponse::read(bytebuf)) self.handle_plugin_response(server, SLoginPluginResponse::read(bytebuf))
} }
SLoginAcknowledged::PACKET_ID => { SLoginAcknowledged::PACKET_ID => {
self.handle_login_acknowledged(SLoginAcknowledged::read(bytebuf)) self.handle_login_acknowledged(server, SLoginAcknowledged::read(bytebuf))
} }
_ => log::error!( _ => log::error!(
"Failed to handle packet id {} while in Login state", "Failed to handle packet id {} while in Login state",
@ -158,10 +163,10 @@ impl Client {
}, },
crate::protocol::ConnectionState::Config => match packet.id { crate::protocol::ConnectionState::Config => match packet.id {
SClientInformation::PACKET_ID => { SClientInformation::PACKET_ID => {
self.handle_client_information(SClientInformation::read(bytebuf)) self.handle_client_information(server, SClientInformation::read(bytebuf))
} }
SAcknowledgeFinishConfig::PACKET_ID => { SAcknowledgeFinishConfig::PACKET_ID => {
self.handle_config_acknowledged(SAcknowledgeFinishConfig::read(bytebuf)) self.handle_config_acknowledged(server, SAcknowledgeFinishConfig::read(bytebuf))
} }
_ => log::error!( _ => log::error!(
"Failed to handle packet id {} while in Config state", "Failed to handle packet id {} while in Config state",
@ -173,7 +178,7 @@ impl Client {
} }
/// Returns `true` if the connection is done. /// Returns `true` if the connection is done.
pub fn poll(&mut self, _registry: &Registry, event: &Event) -> anyhow::Result<()> { pub fn poll(&mut self, server: &mut Server, event: &Event) -> anyhow::Result<bool> {
if event.is_readable() { if event.is_readable() {
let mut received_data = vec![0; 4096]; let mut received_data = vec![0; 4096];
let mut bytes_read = 0; let mut bytes_read = 0;
@ -206,12 +211,12 @@ impl Client {
self.dec.queue_slice(&received_data[..bytes_read]); self.dec.queue_slice(&received_data[..bytes_read]);
if let Some(packet) = self.dec.decode()? { if let Some(packet) = self.dec.decode()? {
self.add_packet(packet); self.add_packet(packet);
self.procress_packets(); self.process_packets(server);
} }
self.dec.clear(); self.dec.clear();
} }
} }
Ok(()) Ok(self.closed)
} }
pub fn kick(&mut self, reason: String) { pub fn kick(&mut self, reason: String) {

View File

@ -3,7 +3,6 @@ use std::io::Write;
use aes::cipher::{generic_array::GenericArray, BlockEncryptMut, BlockSizeUser, KeyIvInit}; use aes::cipher::{generic_array::GenericArray, BlockEncryptMut, BlockSizeUser, KeyIvInit};
use anyhow::{ensure, Context}; use anyhow::{ensure, Context};
use bytes::{BufMut, BytesMut}; use bytes::{BufMut, BytesMut};
use rsa::pkcs8::der::Encode;
use crate::{ use crate::{
client::MAX_PACKET_SIZE, client::MAX_PACKET_SIZE,

View File

@ -1,3 +1,5 @@
use std::rc::Rc;
use crate::{ use crate::{
client::Client, client::Client,
protocol::{ClientPacket, RawPacket, VarInt}, protocol::{ClientPacket, RawPacket, VarInt},
@ -7,24 +9,16 @@ use super::{Entity, EntityId};
pub struct Player { pub struct Player {
pub entity: Entity, pub entity: Entity,
// All networking stuff
pub client: Client,
} }
impl Player { impl Player {
pub fn new(entity: Entity, client: Client) -> Self { pub fn new(entity: Entity) -> Self {
Self { entity, client } Self { entity }
} }
pub fn entity_id(&self) -> EntityId { pub fn entity_id(&self) -> EntityId {
self.entity.entity_id self.entity.entity_id
} }
pub fn handle_packet(&mut self, _packet: &mut RawPacket) {}
pub fn send_packet<P: ClientPacket>(&mut self, packet: P) {
self.client.send_packet(packet);
}
} }
pub enum Hand { pub enum Hand {

View File

@ -17,9 +17,13 @@ pub mod entity;
pub mod protocol; pub mod protocol;
pub mod server; pub mod server;
pub mod util; pub mod util;
pub mod world;
#[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 client::Client;
use configuration::AdvancedConfiguration; use configuration::AdvancedConfiguration;
let basic_config = BasicConfiguration::load("configuration.toml"); let basic_config = BasicConfiguration::load("configuration.toml");
@ -44,9 +48,11 @@ 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();
log::info!("You now can connect to the server"); log::info!("You now can connect to the server");
let server = Arc::new(Mutex::new(Server::new())); let mut server = Server::new();
loop { loop {
if let Err(err) = poll.poll(&mut events, None) { if let Err(err) = poll.poll(&mut events, None) {
@ -86,26 +92,20 @@ fn main() -> io::Result<()> {
Interest::READABLE.add(Interest::WRITABLE), Interest::READABLE.add(Interest::WRITABLE),
)?; )?;
let rc_server = Arc::clone(&server); connections.insert(token, Client::new(Rc::new(token), connection));
let mut guard = server.try_lock().unwrap();
guard.new_client(rc_server, connection, token);
}, },
token => { token => {
// Maybe received an event for a TCP connection. // Maybe received an event for a TCP connection.
let done = if let Some(client) = let done = if let Some(client) = connections.get_mut(&token) {
server.try_lock().unwrap().connections.get_mut(&token) client.poll(&mut server, event).unwrap();
{
client.poll(poll.registry(), event).unwrap();
client.closed client.closed
} else { } else {
// Sporadic events happen, we can safely ignore them. // Sporadic events happen, we can safely ignore them.
false false
}; };
if done { if done {
if let Some(mut client) = if let Some(mut client) = connections.remove(&token) {
server.try_lock().unwrap().connections.remove(&token)
{
poll.registry().deregister(&mut client.connection)?; poll.registry().deregister(&mut client.connection)?;
} }
} }

View File

@ -1,4 +1,4 @@
use crate::protocol::{VarInt, VarLong}; use crate::protocol::{nbt::NBT, VarInt, VarLong};
use super::{Endian, CONTINUE_BIT, SEGMENT_BITS}; use super::{Endian, CONTINUE_BIT, SEGMENT_BITS};
use byteorder::{BigEndian, ByteOrder, LittleEndian}; use byteorder::{BigEndian, ByteOrder, LittleEndian};
@ -618,6 +618,15 @@ impl ByteBuffer {
read_number!(self, read_f64, 8) read_number!(self, read_f64, 8)
} }
pub fn read_nbt(&mut self) -> Result<NBT> {
match NBT::deserialize_buf(self) {
Ok(v) => Ok(v),
Err(err) => {
return Err(Error::new(ErrorKind::InvalidData, "Failed read nbt"));
}
}
}
/// Read a string. /// Read a string.
/// ///
/// _Note_: First it reads a 32 bits value representing the size, then 'size' raw bytes /// _Note_: First it reads a 32 bits value representing the size, then 'size' raw bytes

View File

@ -1,4 +1,26 @@
use crate::protocol::ClientPacket; use crate::protocol::{nbt::NBT, ClientPacket, VarInt};
pub struct CRegistryData {
registry_id: String,
entry_count: VarInt,
entries: NBT,
}
struct Entry {
entry_id: String,
has_data: bool,
data: NBT,
}
impl ClientPacket for CRegistryData {
const PACKET_ID: VarInt = 0x07;
fn write(&self, bytebuf: &mut crate::protocol::bytebuf::buffer::ByteBuffer) {
bytebuf.write_string(&self.registry_id);
bytebuf.write_var_int(self.entry_count);
// bytebuf.write_array(self.entries);
}
}
pub struct CCookieRequest { pub struct CCookieRequest {
// TODO // TODO
@ -30,6 +52,12 @@ impl ClientPacket for CConfigDisconnect {
pub struct CFinishConfig {} pub struct CFinishConfig {}
impl Default for CFinishConfig {
fn default() -> Self {
Self::new()
}
}
impl CFinishConfig { impl CFinishConfig {
pub fn new() -> Self { pub fn new() -> Self {
Self {} Self {}

View File

@ -29,6 +29,7 @@ pub struct CLogin {
} }
impl CLogin { impl CLogin {
#[allow(clippy::too_many_arguments)]
pub fn new( pub fn new(
entity_id: i32, entity_id: i32,
is_hardcore: bool, is_hardcore: bool,

View File

@ -6,6 +6,8 @@ use byteorder::ReadBytesExt;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub mod bytebuf; pub mod bytebuf;
pub mod nbt;
mod registry;
pub mod client; pub mod client;
pub mod server; pub mod server;

View File

@ -0,0 +1,105 @@
use std::{collections::HashMap, error::Error, fmt, string::FromUtf8Error};
use crate::protocol::bytebuf::buffer::ByteBuffer;
use super::{Tag, NBT};
#[derive(Debug)]
pub enum ParseError {
InvalidType(u8),
InvalidString(FromUtf8Error),
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidType(ty) => write!(f, "invalid tag type: {}", ty),
Self::InvalidString(e) => write!(f, "invalid string: {}", e),
}
}
}
impl Error for ParseError {}
impl NBT {
/// Deserializes the given byte array as nbt data.
pub fn deserialize(buf: Vec<u8>) -> Result<Self, ParseError> {
Self::deserialize_buf(&mut ByteBuffer::from_vec(buf))
}
/// Deserializes the given buffer as nbt data. This will continue reading
/// where this buffer is currently placed, and will advance the reader to be
/// right after the nbt data. If this function returns an error, then the
/// buffer will be in an undefined state (it will still be safe, but there are
/// no guarantees as too how far ahead the buffer will have been advanced).
pub fn deserialize_buf(buf: &mut ByteBuffer) -> Result<Self, ParseError> {
let ty = buf.read_u8().unwrap();
let len = buf.read_u16().unwrap();
let name = String::from_utf8(buf.read_bytes(len as usize).unwrap()).unwrap();
Ok(NBT::new(&name, Tag::deserialize(ty, buf)?))
}
}
impl Tag {
fn deserialize(ty: u8, buf: &mut ByteBuffer) -> Result<Self, ParseError> {
match ty {
0 => Ok(Self::End),
1 => Ok(Self::Byte(buf.read_i8().unwrap())),
2 => Ok(Self::Short(buf.read_i16().unwrap())),
3 => Ok(Self::Int(buf.read_i32().unwrap())),
4 => Ok(Self::Long(buf.read_i64().unwrap())),
5 => Ok(Self::Float(buf.read_f32().unwrap())),
6 => Ok(Self::Double(buf.read_f64().unwrap())),
7 => {
let len = buf.read_i32().unwrap();
Ok(Self::ByteArr(buf.read_bytes(len as usize).unwrap()))
}
8 => {
let len = buf.read_u16().unwrap();
match String::from_utf8(buf.read_bytes(len as usize).unwrap()) {
Ok(v) => Ok(Self::String(v)),
Err(e) => Err(ParseError::InvalidString(e)),
}
}
9 => {
let inner_ty = buf.read_u8().unwrap();
let len = buf.read_i32().unwrap();
let mut inner = Vec::with_capacity(len as usize);
for _ in 0..len {
inner.push(Tag::deserialize(inner_ty, buf)?);
}
Ok(Self::List(inner))
}
10 => {
let mut inner = HashMap::new();
loop {
let ty = buf.read_u8().unwrap();
if ty == Self::End.ty() {
break;
}
let len = buf.read_u16().unwrap();
let name = String::from_utf8(buf.read_bytes(len as usize).unwrap()).unwrap();
let tag = Tag::deserialize(ty, buf)?;
inner.insert(name, tag);
}
Ok(Self::Compound(inner))
}
11 => {
let len = buf.read_i32().unwrap();
let mut inner = Vec::with_capacity(len as usize);
for _ in 0..len {
inner.push(buf.read_i32().unwrap());
}
Ok(Self::IntArray(inner))
}
12 => {
let len = buf.read_i32().unwrap();
let mut inner = Vec::with_capacity(len as usize);
for _ in 0..len {
inner.push(buf.read_i64().unwrap());
}
Ok(Self::LongArray(inner))
}
_ => Err(ParseError::InvalidType(ty)),
}
}
}

View File

@ -0,0 +1,115 @@
use std::collections::HashMap;
mod deserialize;
mod serialize;
#[derive(Debug, Clone, PartialEq)]
pub struct NBT {
tag: Tag,
name: String,
}
/// This is a single tag. It does not contain a name, but has the actual data
/// for any of the nbt tags.
#[derive(Debug, Clone, PartialEq)]
pub enum Tag {
End,
Byte(i8),
Short(i16),
Int(i32),
Long(i64),
Float(f32),
Double(f64),
ByteArr(Vec<u8>),
String(String),
List(Vec<Tag>), // All elements must be the same type, and un-named.
Compound(HashMap<String, Tag>), // Types can be any kind, and are named. Order is not defined.
IntArray(Vec<i32>),
LongArray(Vec<i64>),
}
impl NBT {
/// Creates a new nbt tag. The tag value can be anything.
///
/// # Panics
/// This will panic if the tag is a list, and the values within that list
/// contain multiple types. This is a limitation with the nbt data format:
/// lists can only contain one type of data.
pub fn new(name: &str, tag: Tag) -> Self {
if let Tag::List(inner) = &tag {
if let Some(v) = inner.get(0) {
let ty = v.ty();
for v in inner {
if v.ty() != ty {
panic!("the given list contains multiple types: {:?}", inner);
}
}
}
}
NBT {
tag,
name: name.into(),
}
}
/// Creates an empty nbt tag.
pub fn empty(name: &str) -> Self {
NBT {
tag: Tag::End,
name: name.into(),
}
}
/// Appends the given element to the list. This will panic if self is not a
/// list, or if tag does not match the type of the existing elements.
pub fn list_add(&mut self, tag: Tag) {
if let Tag::List(inner) = &mut self.tag {
if let Some(v) = inner.get(0) {
if tag.ty() != v.ty() {
panic!(
"cannot add different types to list. current: {:?}, new: {:?}",
inner, tag
);
} else {
inner.push(tag);
}
} else {
// No elements yet, so we add this no matter what type it is.
inner.push(tag);
}
} else {
panic!("called list_add on non-list type: {:?}", self);
}
}
/// Appends the given element to the compound. This will panic if self is not
/// a compound tag.
pub fn compound_add(&mut self, name: String, value: Tag) {
if let Tag::Compound(inner) = &mut self.tag {
inner.insert(name, value);
} else {
panic!("called compound_add on non-compound type: {:?}", self);
}
}
/// If this is a compound tag, this returns the inner data of the tag.
/// Otherwise, this panics.
pub fn compound(&self) -> &HashMap<String, Tag> {
if let Tag::Compound(inner) = &self.tag {
&inner
} else {
panic!("called compound on non-compound type: {:?}", self);
}
}
}
impl Tag {
/// A simpler way to construct compound tags inline.
pub fn compound(value: &[(&str, Tag)]) -> Self {
let mut inner = HashMap::new();
for (name, tag) in value {
inner.insert(name.to_string(), tag.clone());
}
Self::Compound(inner)
}
}

View File

@ -0,0 +1,91 @@
use crate::protocol::bytebuf::buffer::ByteBuffer;
use super::{Tag, NBT};
impl NBT {
pub fn serialize(&self) -> Vec<u8> {
let mut out = ByteBuffer::new();
out.write_u8(self.tag.ty());
out.write_u16(self.name.len() as u16);
out.write_bytes(self.name.as_bytes());
out.write_bytes(&self.tag.serialize());
out.into_vec()
}
}
impl Tag {
/// Returns the type of the tag.
pub fn ty(&self) -> u8 {
match self {
Self::End => 0,
Self::Byte(_) => 1,
Self::Short(_) => 2,
Self::Int(_) => 3,
Self::Long(_) => 4,
Self::Float(_) => 5,
Self::Double(_) => 6,
Self::ByteArr(_) => 7,
Self::String(_) => 8,
Self::List(_) => 9,
Self::Compound(_) => 10,
Self::IntArray(_) => 11,
Self::LongArray(_) => 12,
}
}
fn serialize(&self) -> Vec<u8> {
let mut out = ByteBuffer::new();
match self {
Self::End => (),
Self::Byte(v) => out.write_i8(*v),
Self::Short(v) => out.write_i16(*v),
Self::Int(v) => out.write_i32(*v),
Self::Long(v) => out.write_i64(*v),
Self::Float(v) => out.write_f32(*v),
Self::Double(v) => out.write_f64(*v),
Self::ByteArr(v) => {
out.write_i32(v.len() as i32);
out.write_bytes(v);
}
Self::String(v) => {
out.write_u16(v.len() as u16);
out.write_bytes(v.as_bytes());
}
Self::List(v) => {
out.write_u8(v.get(0).unwrap_or(&Self::End).ty());
out.write_i32(v.len() as i32);
for tag in v {
out.write_bytes(&tag.serialize());
}
}
Self::Compound(v) => {
for (name, tag) in v {
// Each element in the HashMap is essentially a NBT, but we store it in a
// separated form, so we have a manual implementation of serialize() here.
out.write_u8(tag.ty());
if tag.ty() == Self::End.ty() {
// End tags don't have a name, so we stop early.
break;
}
out.write_u16(name.len() as u16);
out.write_bytes(name.as_bytes());
out.write_bytes(&tag.serialize());
}
out.write_u8(Self::End.ty());
}
Self::IntArray(v) => {
out.write_i32(v.len() as i32);
for elem in v {
out.write_i32(*elem);
}
}
Self::LongArray(v) => {
out.write_i32(v.len() as i32);
for elem in v {
out.write_i64(*elem);
}
}
}
out.into_vec()
}
}

View File

View File

@ -1,15 +1,13 @@
use std::{ use std::{
borrow::BorrowMut,
collections::HashMap, collections::HashMap,
io::Cursor, io::Cursor,
rc::Rc, rc::Rc,
sync::{ sync::atomic::{AtomicI32, Ordering},
atomic::{AtomicI32, Ordering},
Arc, Mutex,
},
}; };
use base64::{engine::general_purpose, Engine}; use base64::{engine::general_purpose, Engine};
use mio::{net::TcpStream, Token}; use mio::{event::Event, net::TcpStream, Poll, Token};
use rsa::{rand_core::OsRng, traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey}; use rsa::{rand_core::OsRng, traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -20,6 +18,7 @@ use crate::{
Entity, EntityId, Entity, EntityId,
}, },
protocol::{client::play::CLogin, Players, Sample, StatusResponse, VarInt, Version}, protocol::{client::play::CLogin, Players, Sample, StatusResponse, VarInt, Version},
world::World,
}; };
pub struct Server { pub struct Server {
@ -33,12 +32,12 @@ pub struct Server {
pub max_players: u32, pub max_players: u32,
pub world: World,
pub status_response: StatusResponse, pub status_response: StatusResponse,
pub connections: HashMap<Token, 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 players: Vec<Player>,
pub difficulty: Difficulty, pub difficulty: Difficulty,
} }
@ -65,6 +64,7 @@ impl Server {
Self { Self {
// 0 is invalid // 0 is invalid
entity_id: 2.into(), entity_id: 2.into(),
world: World::new(),
online_mode: true, online_mode: true,
encryption: true, encryption: true,
compression_threshold: None, // 256 compression_threshold: None, // 256
@ -73,23 +73,29 @@ impl Server {
max_players, max_players,
status_response, status_response,
public_key_der, public_key_der,
connections: HashMap::new(),
players: Vec::new(),
difficulty: Difficulty::Normal, difficulty: Difficulty::Normal,
} }
} }
pub fn new_client(&mut self, rc: Arc<Mutex<Server>>, connection: TcpStream, token: Token) { // Returns Tokens to remove
self.connections pub fn poll(
.insert(token, Client::new(rc, Rc::new(token), connection)); &mut self,
client: &mut Client,
poll: &Poll,
event: &Event,
) -> anyhow::Result<bool> {
// todo, Poll players in every world
client.poll(self, event)
} }
//CLIENT KOMMT in den Player
pub fn spawn_player(&mut self, token: &Token) { pub fn spawn_player(&mut self, client: &mut Client) {
let mut player = Player { let player = Player {
entity: Entity::new(self.new_entity_id()), entity: Entity {
client: self.connections.remove(token).unwrap(), entity_id: self.new_entity_id(),
},
}; };
player.send_packet(CLogin::new(
client.send_packet(CLogin::new(
player.entity_id(), player.entity_id(),
self.difficulty == Difficulty::Hard, self.difficulty == Difficulty::Hard,
1, 1,
@ -114,7 +120,7 @@ impl Server {
false, false,
)); ));
self.players.push(player); client.player = Some(player);
} }
// move to world // move to world

22
pumpkin/src/world.rs Normal file
View File

@ -0,0 +1,22 @@
use mio::Token;
use crate::{
entity::{
player::{GameMode, Player},
Entity,
},
protocol::{client::play::CLogin, VarInt},
server::Difficulty,
};
pub struct World {
pub players: Vec<Player>,
}
impl World {
pub fn new() -> Self {
Self {
players: Vec::new(),
}
}
}