diff --git a/configuration.toml b/configuration.toml new file mode 100644 index 000000000..0cf04ee10 --- /dev/null +++ b/configuration.toml @@ -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!" diff --git a/features.toml b/features.toml new file mode 100644 index 000000000..65150ccd9 --- /dev/null +++ b/features.toml @@ -0,0 +1,2 @@ +liquid_physics = true +encryption = true diff --git a/pumpkin/src/client/client_packet.rs b/pumpkin/src/client/client_packet.rs index cc687845c..2ed1d8de3 100644 --- a/pumpkin/src/client/client_packet.rs +++ b/pumpkin/src/client/client_packet.rs @@ -1,79 +1,90 @@ -use crate::protocol::{ - client::{ - config::CFinishConfig, - login::{CEncryptionRequest, CLoginSuccess}, - status::{CPingResponse, CStatusResponse}, +use crate::{ + protocol::{ + client::{ + config::CFinishConfig, + login::{CEncryptionRequest, CLoginSuccess}, + status::{CPingResponse, CStatusResponse}, + }, + server::{ + config::{SAcknowledgeFinishConfig, SClientInformation}, + handshake::SHandShake, + login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart}, + status::{SPingRequest, SStatusRequest}, + }, + ConnectionState, }, - server::{ - config::{SAcknowledgeFinishConfig, SClientInformation}, - handshake::SHandShake, - login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart}, - status::{SPingRequest, SStatusRequest}, - }, - ConnectionState, + server::Server, }; use super::{Client, PlayerConfig}; pub trait ClientPacketProcessor { // Handshake - fn handle_handshake(&mut self, handshake: SHandShake); + fn handle_handshake(&mut self, server: &mut Server, handshake: SHandShake); // Status - fn handle_status_request(&mut self, status_request: SStatusRequest); - fn handle_ping_request(&mut self, ping_request: SPingRequest); + fn handle_status_request(&mut self, server: &mut Server, status_request: SStatusRequest); + fn handle_ping_request(&mut self, server: &mut Server, ping_request: SPingRequest); // Login - fn handle_login_start(&mut self, login_start: SLoginStart); - fn handle_encryption_response(&mut self, encryption_response: SEncryptionResponse); - fn handle_plugin_response(&mut self, plugin_response: SLoginPluginResponse); - fn handle_login_acknowledged(&mut self, login_acknowledged: SLoginAcknowledged); + fn handle_login_start(&mut self, server: &mut Server, login_start: SLoginStart); + fn handle_encryption_response( + &mut self, + 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 - fn handle_client_information(&mut self, client_information: SClientInformation); - fn handle_config_acknowledged(&mut self, config_acknowledged: SAcknowledgeFinishConfig); + fn handle_client_information( + &mut self, + server: &mut Server, + client_information: SClientInformation, + ); + fn handle_config_acknowledged( + &mut self, + server: &mut Server, + config_acknowledged: SAcknowledgeFinishConfig, + ); } 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 self.connection_state = handshake.next_state; 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!("test first"); - - let guard = self.server.try_lock().unwrap(); - dbg!("test"); - - let response = serde_json::to_string(&guard.status_response).unwrap(); - drop(guard); + let response = serde_json::to_string(&server.status_response).unwrap(); 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"); self.send_packet(CPingResponse::new(ping_request.payload)); 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"); self.name = Some(login_start.name); self.uuid = Some(login_start.uuid); let verify_token: [u8; 4] = rand::random(); - let public_key_der = self - .server - .to_owned() - .lock() - .unwrap() - .public_key_der - .clone(); // todo do not clone + let public_key_der = &server.public_key_der; let packet = CEncryptionRequest::new( "".into(), public_key_der.len() as i32, - &public_key_der, + public_key_der, verify_token.len() as i32, &verify_token, false, // TODO @@ -81,27 +92,45 @@ impl ClientPacketProcessor for Client { 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"); // should be impossible if self.uuid.is_none() || self.name.is_none() { self.kick("UUID or Name is none".into()); return; } - self.enable_encryption(encryption_response.shared_secret) + self.enable_encryption(server, encryption_response.shared_secret) .unwrap(); let packet = CLoginSuccess::new(self.uuid.unwrap(), self.name.clone().unwrap(), 0, false); 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; 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 { locale: client_information.locale, view_distance: client_information.view_distance, @@ -116,10 +145,14 @@ impl ClientPacketProcessor for Client { 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"); self.connection_state = ConnectionState::Play; // generate a player - self.server.lock().unwrap().spawn_player(&self.token); + server.spawn_player(self); } } diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index bafd8e910..9cd2f82c5 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -2,11 +2,10 @@ use std::{ collections::VecDeque, io::{self, Write}, rc::Rc, - sync::{Arc, Mutex}, }; use crate::{ - entity::player::{ChatMode, Hand}, + entity::player::{ChatMode, Hand, Player}, protocol::{ client::{config::CConfigDisconnect, login::CLoginDisconnect}, server::{ @@ -49,11 +48,12 @@ pub struct PlayerConfig { } pub struct Client { + pub player: Option, + pub name: Option, pub uuid: Option, pub config: Option, - pub server: Arc>, pub connection_state: ConnectionState, pub encrytion: bool, pub closed: bool, @@ -65,13 +65,13 @@ pub struct Client { } impl Client { - pub fn new(server: Arc>, token: Rc, connection: TcpStream) -> Self { + pub fn new(token: Rc, connection: TcpStream) -> Self { Self { name: None, uuid: None, config: None, - server, token, + player: None, connection_state: ConnectionState::HandShake, connection, enc: PacketEncoder::default(), @@ -86,12 +86,13 @@ impl Client { self.client_packets_queue.push_back(packet); } - pub fn enable_encryption(&mut self, shared_secret: Vec) -> anyhow::Result<()> { + pub fn enable_encryption( + &mut self, + server: &mut Server, + shared_secret: Vec, + ) -> anyhow::Result<()> { self.encrytion = true; - let shared_secret = self - .server - .lock() - .unwrap() + let shared_secret = server .private_key .decrypt(Pkcs1v15Encrypt, &shared_secret) .context("failed to decrypt shared secret")?; @@ -110,21 +111,21 @@ impl Client { 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; while i < self.client_packets_queue.len() { let mut packet = self.client_packets_queue.remove(i).unwrap(); - self.handle_packet(&mut packet); + self.handle_packet(server, &mut packet); 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"); let bytebuf = &mut packet.bytebuf; match self.connection_state { 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!( "Failed to handle packet id {} while in Handshake state", packet.id @@ -132,24 +133,28 @@ impl Client { }, crate::protocol::ConnectionState::Status => match 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!( "Failed to handle packet id {} while in Status state", 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 => { - self.handle_encryption_response(SEncryptionResponse::read(bytebuf)) + self.handle_encryption_response(server, SEncryptionResponse::read(bytebuf)) } SLoginPluginResponse::PACKET_ID => { - self.handle_plugin_response(SLoginPluginResponse::read(bytebuf)) + self.handle_plugin_response(server, SLoginPluginResponse::read(bytebuf)) } SLoginAcknowledged::PACKET_ID => { - self.handle_login_acknowledged(SLoginAcknowledged::read(bytebuf)) + self.handle_login_acknowledged(server, SLoginAcknowledged::read(bytebuf)) } _ => log::error!( "Failed to handle packet id {} while in Login state", @@ -158,10 +163,10 @@ impl Client { }, crate::protocol::ConnectionState::Config => match packet.id { SClientInformation::PACKET_ID => { - self.handle_client_information(SClientInformation::read(bytebuf)) + self.handle_client_information(server, SClientInformation::read(bytebuf)) } SAcknowledgeFinishConfig::PACKET_ID => { - self.handle_config_acknowledged(SAcknowledgeFinishConfig::read(bytebuf)) + self.handle_config_acknowledged(server, SAcknowledgeFinishConfig::read(bytebuf)) } _ => log::error!( "Failed to handle packet id {} while in Config state", @@ -173,7 +178,7 @@ impl Client { } /// 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 { if event.is_readable() { let mut received_data = vec![0; 4096]; let mut bytes_read = 0; @@ -206,12 +211,12 @@ impl Client { self.dec.queue_slice(&received_data[..bytes_read]); if let Some(packet) = self.dec.decode()? { self.add_packet(packet); - self.procress_packets(); + self.process_packets(server); } self.dec.clear(); } } - Ok(()) + Ok(self.closed) } pub fn kick(&mut self, reason: String) { diff --git a/pumpkin/src/client/packet_encoder.rs b/pumpkin/src/client/packet_encoder.rs index a50136b8e..74821b4e0 100644 --- a/pumpkin/src/client/packet_encoder.rs +++ b/pumpkin/src/client/packet_encoder.rs @@ -3,7 +3,6 @@ use std::io::Write; use aes::cipher::{generic_array::GenericArray, BlockEncryptMut, BlockSizeUser, KeyIvInit}; use anyhow::{ensure, Context}; use bytes::{BufMut, BytesMut}; -use rsa::pkcs8::der::Encode; use crate::{ client::MAX_PACKET_SIZE, diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index d55cf4200..31f98d1f0 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -1,3 +1,5 @@ +use std::rc::Rc; + use crate::{ client::Client, protocol::{ClientPacket, RawPacket, VarInt}, @@ -7,24 +9,16 @@ use super::{Entity, EntityId}; pub struct Player { pub entity: Entity, - // All networking stuff - pub client: Client, } impl Player { - pub fn new(entity: Entity, client: Client) -> Self { - Self { entity, client } + pub fn new(entity: Entity) -> Self { + Self { entity } } pub fn entity_id(&self) -> EntityId { self.entity.entity_id } - - pub fn handle_packet(&mut self, _packet: &mut RawPacket) {} - - pub fn send_packet(&mut self, packet: P) { - self.client.send_packet(packet); - } } pub enum Hand { diff --git a/pumpkin/src/main.rs b/pumpkin/src/main.rs index 12c2c42da..94aeaf8e4 100644 --- a/pumpkin/src/main.rs +++ b/pumpkin/src/main.rs @@ -17,9 +17,13 @@ pub mod entity; pub mod protocol; pub mod server; pub mod util; +pub mod world; #[cfg(not(target_os = "wasi"))] fn main() -> io::Result<()> { + use std::{collections::HashMap, rc::Rc}; + + use client::Client; use configuration::AdvancedConfiguration; let basic_config = BasicConfiguration::load("configuration.toml"); @@ -44,9 +48,11 @@ fn main() -> io::Result<()> { // Unique token for each incoming connection. let mut unique_token = Token(SERVER.0 + 1); + let mut connections: HashMap = HashMap::new(); + log::info!("You now can connect to the server"); - let server = Arc::new(Mutex::new(Server::new())); + let mut server = Server::new(); loop { if let Err(err) = poll.poll(&mut events, None) { @@ -86,26 +92,20 @@ fn main() -> io::Result<()> { Interest::READABLE.add(Interest::WRITABLE), )?; - let rc_server = Arc::clone(&server); - let mut guard = server.try_lock().unwrap(); - guard.new_client(rc_server, connection, token); + connections.insert(token, Client::new(Rc::new(token), connection)); }, token => { // Maybe received an event for a TCP connection. - let done = if let Some(client) = - server.try_lock().unwrap().connections.get_mut(&token) - { - client.poll(poll.registry(), event).unwrap(); + let done = if let Some(client) = connections.get_mut(&token) { + client.poll(&mut server, event).unwrap(); client.closed } else { // Sporadic events happen, we can safely ignore them. false }; if done { - if let Some(mut client) = - server.try_lock().unwrap().connections.remove(&token) - { + if let Some(mut client) = connections.remove(&token) { poll.registry().deregister(&mut client.connection)?; } } diff --git a/pumpkin/src/protocol/bytebuf/buffer.rs b/pumpkin/src/protocol/bytebuf/buffer.rs index 91570b905..bfd3708c7 100644 --- a/pumpkin/src/protocol/bytebuf/buffer.rs +++ b/pumpkin/src/protocol/bytebuf/buffer.rs @@ -1,4 +1,4 @@ -use crate::protocol::{VarInt, VarLong}; +use crate::protocol::{nbt::NBT, VarInt, VarLong}; use super::{Endian, CONTINUE_BIT, SEGMENT_BITS}; use byteorder::{BigEndian, ByteOrder, LittleEndian}; @@ -618,6 +618,15 @@ impl ByteBuffer { read_number!(self, read_f64, 8) } + pub fn read_nbt(&mut self) -> Result { + match NBT::deserialize_buf(self) { + Ok(v) => Ok(v), + Err(err) => { + return Err(Error::new(ErrorKind::InvalidData, "Failed read nbt")); + } + } + } + /// Read a string. /// /// _Note_: First it reads a 32 bits value representing the size, then 'size' raw bytes diff --git a/pumpkin/src/protocol/client/config/mod.rs b/pumpkin/src/protocol/client/config/mod.rs index f79ef36b3..23d847f94 100644 --- a/pumpkin/src/protocol/client/config/mod.rs +++ b/pumpkin/src/protocol/client/config/mod.rs @@ -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 { // TODO @@ -30,6 +52,12 @@ impl ClientPacket for CConfigDisconnect { pub struct CFinishConfig {} +impl Default for CFinishConfig { + fn default() -> Self { + Self::new() + } +} + impl CFinishConfig { pub fn new() -> Self { Self {} diff --git a/pumpkin/src/protocol/client/play/mod.rs b/pumpkin/src/protocol/client/play/mod.rs index 19583aa16..0f6eb665e 100644 --- a/pumpkin/src/protocol/client/play/mod.rs +++ b/pumpkin/src/protocol/client/play/mod.rs @@ -29,6 +29,7 @@ pub struct CLogin { } impl CLogin { + #[allow(clippy::too_many_arguments)] pub fn new( entity_id: i32, is_hardcore: bool, diff --git a/pumpkin/src/protocol/mod.rs b/pumpkin/src/protocol/mod.rs index d2ea9e71f..f26d50d13 100644 --- a/pumpkin/src/protocol/mod.rs +++ b/pumpkin/src/protocol/mod.rs @@ -6,6 +6,8 @@ use byteorder::ReadBytesExt; use serde::{Deserialize, Serialize}; pub mod bytebuf; +pub mod nbt; +mod registry; pub mod client; pub mod server; diff --git a/pumpkin/src/protocol/nbt/deserialize.rs b/pumpkin/src/protocol/nbt/deserialize.rs new file mode 100644 index 000000000..601a82986 --- /dev/null +++ b/pumpkin/src/protocol/nbt/deserialize.rs @@ -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) -> Result { + 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 { + 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 { + 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)), + } + } +} diff --git a/pumpkin/src/protocol/nbt/mod.rs b/pumpkin/src/protocol/nbt/mod.rs new file mode 100644 index 000000000..4a07e910b --- /dev/null +++ b/pumpkin/src/protocol/nbt/mod.rs @@ -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), + String(String), + List(Vec), // All elements must be the same type, and un-named. + Compound(HashMap), // Types can be any kind, and are named. Order is not defined. + IntArray(Vec), + LongArray(Vec), +} + +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 { + 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) + } +} diff --git a/pumpkin/src/protocol/nbt/serialize.rs b/pumpkin/src/protocol/nbt/serialize.rs new file mode 100644 index 000000000..b55d44f2f --- /dev/null +++ b/pumpkin/src/protocol/nbt/serialize.rs @@ -0,0 +1,91 @@ +use crate::protocol::bytebuf::buffer::ByteBuffer; + +use super::{Tag, NBT}; + +impl NBT { + pub fn serialize(&self) -> Vec { + 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 { + 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() + } +} diff --git a/pumpkin/src/protocol/registry/mod.rs b/pumpkin/src/protocol/registry/mod.rs new file mode 100644 index 000000000..e69de29bb diff --git a/pumpkin/src/server.rs b/pumpkin/src/server.rs index 7ada4fc85..4f4c43ef1 100644 --- a/pumpkin/src/server.rs +++ b/pumpkin/src/server.rs @@ -1,15 +1,13 @@ use std::{ + borrow::BorrowMut, collections::HashMap, io::Cursor, rc::Rc, - sync::{ - atomic::{AtomicI32, Ordering}, - Arc, Mutex, - }, + sync::atomic::{AtomicI32, Ordering}, }; 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 serde::{Deserialize, Serialize}; @@ -20,6 +18,7 @@ use crate::{ Entity, EntityId, }, protocol::{client::play::CLogin, Players, Sample, StatusResponse, VarInt, Version}, + world::World, }; pub struct Server { @@ -33,12 +32,12 @@ pub struct Server { pub max_players: u32, + pub world: World, + pub status_response: StatusResponse, - pub connections: HashMap, // todo replace with HashMap entity_id: AtomicI32, // todo: place this into every world - pub players: Vec, pub difficulty: Difficulty, } @@ -65,6 +64,7 @@ impl Server { Self { // 0 is invalid entity_id: 2.into(), + world: World::new(), online_mode: true, encryption: true, compression_threshold: None, // 256 @@ -73,23 +73,29 @@ impl Server { max_players, status_response, public_key_der, - connections: HashMap::new(), - players: Vec::new(), difficulty: Difficulty::Normal, } } - pub fn new_client(&mut self, rc: Arc>, connection: TcpStream, token: Token) { - self.connections - .insert(token, Client::new(rc, Rc::new(token), connection)); + // Returns Tokens to remove + pub fn poll( + &mut self, + client: &mut Client, + poll: &Poll, + event: &Event, + ) -> anyhow::Result { + // todo, Poll players in every world + client.poll(self, event) } - - pub fn spawn_player(&mut self, token: &Token) { - let mut player = Player { - entity: Entity::new(self.new_entity_id()), - client: self.connections.remove(token).unwrap(), + //CLIENT KOMMT in den Player + pub fn spawn_player(&mut self, client: &mut Client) { + let player = Player { + entity: Entity { + entity_id: self.new_entity_id(), + }, }; - player.send_packet(CLogin::new( + + client.send_packet(CLogin::new( player.entity_id(), self.difficulty == Difficulty::Hard, 1, @@ -114,7 +120,7 @@ impl Server { false, )); - self.players.push(player); + client.player = Some(player); } // move to world diff --git a/pumpkin/src/world.rs b/pumpkin/src/world.rs new file mode 100644 index 000000000..7fb7085ba --- /dev/null +++ b/pumpkin/src/world.rs @@ -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, +} + +impl World { + pub fn new() -> Self { + Self { + players: Vec::new(), + } + } +}