mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
fix crash on join
This commit is contained in:
14
configuration.toml
Normal file
14
configuration.toml
Normal 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
2
features.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
liquid_physics = true
|
||||
encryption = true
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Player>,
|
||||
|
||||
pub name: Option<String>,
|
||||
pub uuid: Option<uuid::Uuid>,
|
||||
pub config: Option<PlayerConfig>,
|
||||
|
||||
pub server: Arc<Mutex<Server>>,
|
||||
pub connection_state: ConnectionState,
|
||||
pub encrytion: bool,
|
||||
pub closed: bool,
|
||||
@@ -65,13 +65,13 @@ pub struct 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 {
|
||||
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<u8>) -> anyhow::Result<()> {
|
||||
pub fn enable_encryption(
|
||||
&mut self,
|
||||
server: &mut Server,
|
||||
shared_secret: Vec<u8>,
|
||||
) -> 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<bool> {
|
||||
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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<P: ClientPacket>(&mut self, packet: P) {
|
||||
self.client.send_packet(packet);
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Hand {
|
||||
|
||||
@@ -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<Token, Client> = 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)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<NBT> {
|
||||
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
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -29,6 +29,7 @@ pub struct CLogin {
|
||||
}
|
||||
|
||||
impl CLogin {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
entity_id: i32,
|
||||
is_hardcore: bool,
|
||||
|
||||
@@ -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;
|
||||
|
||||
105
pumpkin/src/protocol/nbt/deserialize.rs
Normal file
105
pumpkin/src/protocol/nbt/deserialize.rs
Normal 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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
115
pumpkin/src/protocol/nbt/mod.rs
Normal file
115
pumpkin/src/protocol/nbt/mod.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
91
pumpkin/src/protocol/nbt/serialize.rs
Normal file
91
pumpkin/src/protocol/nbt/serialize.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
0
pumpkin/src/protocol/registry/mod.rs
Normal file
0
pumpkin/src/protocol/registry/mod.rs
Normal file
@@ -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<Token, Client>,
|
||||
|
||||
// todo replace with HashMap <World, Player>
|
||||
entity_id: AtomicI32, // todo: place this into every world
|
||||
pub players: Vec<Player>,
|
||||
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<Mutex<Server>>, 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<bool> {
|
||||
// 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
|
||||
|
||||
22
pumpkin/src/world.rs
Normal file
22
pumpkin/src/world.rs
Normal 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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user