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::{
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);
}
}

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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 {

View File

@@ -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)?;
}
}

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 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

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 {
// 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 {}

View File

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

View File

@@ -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;

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::{
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
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(),
}
}
}