diff --git a/Cargo.lock b/Cargo.lock index 25d080c6b..55ce38c49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1164,6 +1164,7 @@ dependencies = [ "num-bigint", "num-derive", "num-traits", + "pumpkin-entity", "pumpkin-protocol", "pumpkin-registry", "pumpkin-world", @@ -1180,6 +1181,14 @@ dependencies = [ "uuid", ] +[[package]] +name = "pumpkin-entity" +version = "0.1.0" +dependencies = [ + "num-derive", + "num-traits", +] + [[package]] name = "pumpkin-macros" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index c2a5b77d0..7ce9d72cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = [ "pumpkin-macros/", "pumpkin-protocol/", "pumpkin-registry/", "pumpkin-world", "pumpkin/" ] +members = [ "pumpkin-entity", "pumpkin-macros/", "pumpkin-protocol/", "pumpkin-registry/", "pumpkin-world", "pumpkin/" ] [workspace.package] version = "0.1.0" diff --git a/pumpkin-entity/Cargo.toml b/pumpkin-entity/Cargo.toml new file mode 100644 index 000000000..6e73e97cc --- /dev/null +++ b/pumpkin-entity/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "pumpkin-entity" +version.workspace = true +edition.workspace = true + +[dependencies] +num-traits = "0.2" +num-derive = "0.4" \ No newline at end of file diff --git a/pumpkin-entity/src/entity_type.rs b/pumpkin-entity/src/entity_type.rs new file mode 100644 index 000000000..4062e73a8 --- /dev/null +++ b/pumpkin-entity/src/entity_type.rs @@ -0,0 +1,8 @@ +use num_derive::ToPrimitive; + +// todo +#[derive(ToPrimitive, Clone)] +pub enum EntityType { + Zombie = 124, + Player = 128, +} diff --git a/pumpkin-entity/src/lib.rs b/pumpkin-entity/src/lib.rs new file mode 100644 index 000000000..743414bdb --- /dev/null +++ b/pumpkin-entity/src/lib.rs @@ -0,0 +1,19 @@ +use entity_type::EntityType; + +pub mod entity_type; + +pub type EntityId = i32; + +pub struct Entity { + pub entity_id: EntityId, + pub entity_type: EntityType, +} + +impl Entity { + pub fn new(entity_id: EntityId, entity_type: EntityType) -> Self { + Self { + entity_id, + entity_type, + } + } +} diff --git a/pumpkin-protocol/src/bytebuf/mod.rs b/pumpkin-protocol/src/bytebuf/mod.rs index e4f6ea6b4..86d49df2e 100644 --- a/pumpkin-protocol/src/bytebuf/mod.rs +++ b/pumpkin-protocol/src/bytebuf/mod.rs @@ -1,4 +1,4 @@ -use crate::{BitSet, VarInt, VarLong}; +use crate::{BitSet, VarInt, VarLongType}; use bytes::{Buf, BufMut, BytesMut}; use core::str; use std::io::{self, Error, ErrorKind}; @@ -44,10 +44,10 @@ impl ByteBuffer { } } - value + VarInt(value) } - pub fn get_var_long(&mut self) -> VarLong { + pub fn get_var_long(&mut self) -> VarLongType { let mut value: i64 = 0; let mut position: i64 = 0; @@ -75,7 +75,7 @@ impl ByteBuffer { } pub fn get_string_len(&mut self, max_size: usize) -> Result { - let size = self.get_var_int(); + let size = self.get_var_int().0; if size as usize > max_size { return Err(Error::new( ErrorKind::InvalidData, @@ -121,7 +121,7 @@ impl ByteBuffer { } pub fn put_string(&mut self, val: &str) { - self.put_var_int(val.len() as VarInt); + self.put_var_int(&val.len().into()); self.buffer.put(val.as_bytes()); } @@ -131,8 +131,8 @@ impl ByteBuffer { } } - pub fn put_var_int(&mut self, value: VarInt) { - let mut val = value; + pub fn put_var_int(&mut self, value: &VarInt) { + let mut val = value.0; for _ in 0..5 { let mut b: u8 = val as u8 & 0b01111111; val >>= 7; @@ -147,7 +147,7 @@ impl ByteBuffer { } pub fn put_bit_set(&mut self, set: &BitSet) { - self.put_var_int(set.0); + self.put_var_int(&set.0); for b in &set.1 { self.put_i64(*b); } @@ -173,7 +173,7 @@ impl ByteBuffer { } pub fn get_list(&mut self, val: impl Fn(&mut Self) -> T) -> Vec { - let len = self.get_var_int().try_into().unwrap(); + let len = self.get_var_int().0 as usize; let mut list = Vec::with_capacity(len); for _ in 0..len { list.push(val(self)); @@ -182,14 +182,14 @@ impl ByteBuffer { } /// Writes a list to the buffer. pub fn put_list(&mut self, list: &[T], write: impl Fn(&mut Self, &T)) { - self.put_var_int(list.len().try_into().unwrap()); + self.put_var_int(&list.len().into()); for v in list { write(self, v); } } pub fn put_varint_arr(&mut self, v: &[i32]) { - self.put_list(v, |p, &v| p.put_var_int(v)) + self.put_list(v, |p, &v| p.put_var_int(&v.into())) } /* pub fn get_nbt(&mut self) -> Option { diff --git a/pumpkin-protocol/src/bytebuf/packet_id.rs b/pumpkin-protocol/src/bytebuf/packet_id.rs index f12b1b378..e335eed9b 100644 --- a/pumpkin-protocol/src/bytebuf/packet_id.rs +++ b/pumpkin-protocol/src/bytebuf/packet_id.rs @@ -1,10 +1,10 @@ use serde::{Serialize, Serializer}; -use crate::{ClientPacket, VarInt, VarInt32}; +use crate::{ClientPacket, VarInt, VarIntType}; use super::{serializer, ByteBuffer}; -impl Serialize for VarInt32 { +impl Serialize for VarInt { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -27,7 +27,7 @@ impl Serialize for VarInt32 { } pub trait Packet { - const PACKET_ID: VarInt; + const PACKET_ID: VarIntType; } impl

ClientPacket for P diff --git a/pumpkin-protocol/src/client/login/c_encryption_request.rs b/pumpkin-protocol/src/client/login/c_encryption_request.rs index 41bbad1b2..7636ca377 100644 --- a/pumpkin-protocol/src/client/login/c_encryption_request.rs +++ b/pumpkin-protocol/src/client/login/c_encryption_request.rs @@ -1,6 +1,6 @@ use pumpkin_macros::packet; -use crate::{bytebuf::ByteBuffer, ClientPacket, VarInt}; +use crate::{bytebuf::ByteBuffer, ClientPacket, VarIntType}; #[packet(0x01)] pub struct CEncryptionRequest<'a> { @@ -29,9 +29,9 @@ impl<'a> CEncryptionRequest<'a> { impl<'a> ClientPacket for CEncryptionRequest<'a> { fn write(&self, bytebuf: &mut ByteBuffer) { bytebuf.put_string(self.server_id); - bytebuf.put_var_int(self.public_key.len() as VarInt); + bytebuf.put_var_int(&(self.public_key.len() as VarIntType).into()); bytebuf.put_slice(self.public_key); - bytebuf.put_var_int(self.verify_token.len() as VarInt); + bytebuf.put_var_int(&(self.verify_token.len() as VarIntType).into()); bytebuf.put_slice(self.verify_token); bytebuf.put_bool(self.should_authenticate); } diff --git a/pumpkin-protocol/src/client/login/c_set_compression.rs b/pumpkin-protocol/src/client/login/c_set_compression.rs index 1eff9dc38..e0c53b94c 100644 --- a/pumpkin-protocol/src/client/login/c_set_compression.rs +++ b/pumpkin-protocol/src/client/login/c_set_compression.rs @@ -1,16 +1,16 @@ use pumpkin_macros::packet; use serde::Serialize; -use crate::VarInt32; +use crate::VarInt; #[derive(Serialize)] #[packet(0x03)] pub struct CSetCompression { - threshold: VarInt32, + threshold: VarInt, } impl CSetCompression { - pub fn new(threshold: VarInt32) -> Self { + pub fn new(threshold: VarInt) -> Self { Self { threshold } } } diff --git a/pumpkin-protocol/src/client/play/c_chunk_data_update_light.rs b/pumpkin-protocol/src/client/play/c_chunk_data_update_light.rs index c9063a047..fb954c145 100644 --- a/pumpkin-protocol/src/client/play/c_chunk_data_update_light.rs +++ b/pumpkin-protocol/src/client/play/c_chunk_data_update_light.rs @@ -1,6 +1,6 @@ use pumpkin_macros::packet; -use crate::{bytebuf::ByteBuffer, BitSet, ClientPacket, VarInt}; +use crate::{bytebuf::ByteBuffer, BitSet, ClientPacket, VarInt, VarIntType}; #[packet(0x27)] pub struct CChunkDataUpdateLight { @@ -50,23 +50,23 @@ impl ClientPacket for CChunkDataUpdateLight { bytebuf.put_i32(self.chunk_x); bytebuf.put_i32(self.chunk_y); bytebuf.put_slice(&self.heightmaps); - bytebuf.put_var_int(self.data.len() as VarInt); + bytebuf.put_var_int(&(self.data.len() as VarIntType).into()); bytebuf.put_slice(&self.data); bytebuf.put_list::(&self.block_entites, |p, v| { p.put_u8(v.packed_xz); p.put_i16(v.y); - p.put_var_int(v.typee); + p.put_var_int(&v.typee); p.put_slice(&v.data); }); bytebuf.put_bit_set(&self.sky_light_mask); bytebuf.put_bit_set(&self.block_light_mask); bytebuf.put_bit_set(&self.empty_sky_light_mask); bytebuf.put_list::(&self.sky_lights, |p, v| { - p.put_var_int(v.array.len() as VarInt); + p.put_var_int(&(v.array.len() as VarIntType).into()); p.put_slice(&v.array); }); bytebuf.put_list::(&self.block_lights, |p, v| { - p.put_var_int(v.array.len() as VarInt); + p.put_var_int(&(v.array.len() as VarIntType).into()); p.put_slice(&v.array); }); } diff --git a/pumpkin-protocol/src/client/play/c_login.rs b/pumpkin-protocol/src/client/play/c_login.rs index ce7b4763c..0cb8fe79e 100644 --- a/pumpkin-protocol/src/client/play/c_login.rs +++ b/pumpkin-protocol/src/client/play/c_login.rs @@ -83,13 +83,13 @@ impl ClientPacket for CLogin { bytebuf.put_i32(self.entity_id); bytebuf.put_bool(self.is_hardcore); bytebuf.put_list(&self.dimension_names, |buf, v| buf.put_string(v)); - bytebuf.put_var_int(self.max_players); - bytebuf.put_var_int(self.view_distance); - bytebuf.put_var_int(self.simulated_distance); + bytebuf.put_var_int(&self.max_players); + bytebuf.put_var_int(&self.view_distance); + bytebuf.put_var_int(&self.simulated_distance); bytebuf.put_bool(self.reduced_debug_info); bytebuf.put_bool(self.enabled_respawn_screen); bytebuf.put_bool(self.limited_crafting); - bytebuf.put_var_int(self.dimension_type); + bytebuf.put_var_int(&self.dimension_type); bytebuf.put_string(&self.dimension_name); bytebuf.put_i64(self.hashed_seed); bytebuf.put_u8(self.game_mode); @@ -101,7 +101,7 @@ impl ClientPacket for CLogin { bytebuf.put_string(self.death_dimension_name.as_ref().unwrap()); bytebuf.put_i64(self.death_loc.unwrap()); } - bytebuf.put_var_int(self.portal_cooldown); + bytebuf.put_var_int(&self.portal_cooldown); bytebuf.put_bool(self.enforce_secure_chat); } } diff --git a/pumpkin-protocol/src/client/play/c_player_info_update.rs b/pumpkin-protocol/src/client/play/c_player_info_update.rs index f3ad678a7..23028c855 100644 --- a/pumpkin-protocol/src/client/play/c_player_info_update.rs +++ b/pumpkin-protocol/src/client/play/c_player_info_update.rs @@ -4,15 +4,16 @@ use crate::{bytebuf::ByteBuffer, ClientPacket, Property}; use super::PlayerAction; +#[derive(Clone)] #[packet(0x3E)] pub struct CPlayerInfoUpdate<'a> { pub actions: i8, - pub players: &'a [Player<'a>], + pub players: &'a [Player], } -pub struct Player<'a> { +pub struct Player { pub uuid: uuid::Uuid, - pub actions: &'a [PlayerAction], + pub actions: Vec, } impl<'a> CPlayerInfoUpdate<'a> { @@ -26,7 +27,7 @@ impl<'a> ClientPacket for CPlayerInfoUpdate<'a> { bytebuf.put_i8(self.actions); bytebuf.put_list::(self.players, |p, v| { p.put_uuid(v.uuid); - for action in v.actions { + for action in &v.actions { match action { PlayerAction::AddPlayer { name, properties } => { p.put_string(name); diff --git a/pumpkin-protocol/src/client/play/c_spawn_player.rs b/pumpkin-protocol/src/client/play/c_spawn_player.rs new file mode 100644 index 000000000..17c7d43f1 --- /dev/null +++ b/pumpkin-protocol/src/client/play/c_spawn_player.rs @@ -0,0 +1,73 @@ +use pumpkin_macros::packet; + +use crate::{ClientPacket, VarInt}; + +#[derive(Clone)] +#[packet(0x01)] +pub struct CSpawnEntity { + entity_id: VarInt, + entity_uuid: uuid::Uuid, + typ: VarInt, + x: f64, + y: f64, + z: f64, + pitch: u8, // angle + yaw: u8, // angle + head_yaw: u8, // angle + data: VarInt, + velocity_x: i16, + velocity_y: i16, + velocity_z: i16, +} + +impl CSpawnEntity { + pub fn new( + entity_id: VarInt, + entity_uuid: uuid::Uuid, + typ: VarInt, + x: f64, + y: f64, + z: f64, + pitch: u8, // angle + yaw: u8, // angle + head_yaw: u8, // angle + data: VarInt, + velocity_x: i16, + velocity_y: i16, + velocity_z: i16, + ) -> Self { + Self { + entity_id, + entity_uuid, + typ, + x, + y, + z, + pitch, + yaw, + head_yaw, + data, + velocity_x, + velocity_y, + velocity_z, + } + } +} + +impl ClientPacket for CSpawnEntity { + fn write(&self, bytebuf: &mut crate::bytebuf::ByteBuffer) { + bytebuf.put_var_int(&self.entity_id); + bytebuf.put_uuid(self.entity_uuid); + bytebuf.put_var_int(&self.typ); + bytebuf.put_f64(self.x); + bytebuf.put_f64(self.y); + bytebuf.put_f64(self.z); + bytebuf.put_u8(self.pitch); + bytebuf.put_u8(self.yaw); + bytebuf.put_u8(self.head_yaw); + bytebuf.put_var_int(&self.data); + bytebuf.put_i16(self.velocity_x); + bytebuf.put_i16(self.velocity_y); + bytebuf.put_i16(self.velocity_z); + } +} diff --git a/pumpkin-protocol/src/client/play/c_sync_player_position.rs b/pumpkin-protocol/src/client/play/c_sync_player_position.rs index 341f6999e..056214281 100644 --- a/pumpkin-protocol/src/client/play/c_sync_player_position.rs +++ b/pumpkin-protocol/src/client/play/c_sync_player_position.rs @@ -1,7 +1,7 @@ use pumpkin_macros::packet; use serde::Serialize; -use crate::VarInt32; +use crate::VarInt; #[derive(Serialize)] #[packet(0x40)] @@ -12,7 +12,7 @@ pub struct CSyncPlayerPostion { yaw: f32, pitch: f32, flags: i8, - teleport_id: VarInt32, + teleport_id: VarInt, } impl CSyncPlayerPostion { @@ -23,7 +23,7 @@ impl CSyncPlayerPostion { yaw: f32, pitch: f32, flags: i8, - teleport_id: VarInt32, + teleport_id: VarInt, ) -> Self { Self { x, diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index 8e68eb329..addc0590b 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -6,6 +6,7 @@ mod c_play_disconnect; mod c_player_abilities; mod c_player_info_update; mod c_set_held_item; +mod c_spawn_player; mod c_sync_player_position; mod c_system_chat_message; mod player_action; @@ -18,6 +19,7 @@ pub use c_play_disconnect::*; pub use c_player_abilities::*; pub use c_player_info_update::*; pub use c_set_held_item::*; +pub use c_spawn_player::*; pub use c_sync_player_position::*; pub use c_system_chat_message::*; pub use player_action::*; diff --git a/pumpkin-protocol/src/lib.rs b/pumpkin-protocol/src/lib.rs index 6ff4893a1..2cbbe3ce0 100644 --- a/pumpkin-protocol/src/lib.rs +++ b/pumpkin-protocol/src/lib.rs @@ -19,14 +19,15 @@ pub const MAX_PACKET_SIZE: i32 = 2097152; /// usally uses a namespace like "minecraft:thing" pub type Identifier = String; -pub type VarInt = i32; -pub type VarLong = i64; +pub type VarIntType = i32; +pub type VarLongType = i64; pub struct BitSet(pub VarInt, pub Vec); -pub struct VarInt32(pub i32); +#[derive(Debug, Clone, PartialEq)] +pub struct VarInt(pub VarIntType); -impl VarInt32 { +impl VarInt { /// The maximum number of bytes a `VarInt` could occupy when read from and /// written to the Minecraft protocol. pub const MAX_SIZE: usize = 5; @@ -83,16 +84,40 @@ impl VarInt32 { let byte = r.get_u8(); val |= (i32::from(byte) & 0b01111111) << (i * 7); if byte & 0b10000000 == 0 { - return Ok(VarInt32(val)); + return Ok(VarInt(val)); } } Err(VarIntDecodeError::TooLarge) } } -impl From for VarInt32 { +impl From for VarInt { fn from(value: i32) -> Self { - VarInt32(value) + VarInt(value) + } +} + +impl From for VarInt { + fn from(value: u32) -> Self { + VarInt(value as i32) + } +} + +impl From for VarInt { + fn from(value: u8) -> Self { + VarInt(value as i32) + } +} + +impl From for VarInt { + fn from(value: usize) -> Self { + VarInt(value as i32) + } +} + +impl From for i32 { + fn from(value: VarInt) -> Self { + value.0 } } @@ -134,6 +159,7 @@ pub enum ConnectionState { impl From for ConnectionState { fn from(value: VarInt) -> Self { + let value = value.0; match value { 1 => Self::Status, 2 => Self::Login, @@ -147,7 +173,6 @@ impl From for ConnectionState { } pub struct RawPacket { - pub len: VarInt, pub id: VarInt, pub bytebuf: ByteBuffer, } diff --git a/pumpkin-protocol/src/packet_decoder.rs b/pumpkin-protocol/src/packet_decoder.rs index 5d59ab81b..c53a7be08 100644 --- a/pumpkin-protocol/src/packet_decoder.rs +++ b/pumpkin-protocol/src/packet_decoder.rs @@ -2,7 +2,7 @@ use aes::cipher::{generic_array::GenericArray, BlockDecryptMut, BlockSizeUser, K use bytes::{Buf, BytesMut}; use crate::{ - bytebuf::ByteBuffer, PacketError, RawPacket, VarInt32, VarIntDecodeError, MAX_PACKET_SIZE, + bytebuf::ByteBuffer, PacketError, RawPacket, VarInt, VarIntDecodeError, MAX_PACKET_SIZE, }; type Cipher = cfb8::Decryptor; @@ -19,7 +19,7 @@ impl PacketDecoder { pub fn decode(&mut self) -> Result, PacketError> { let mut r = &self.buf[..]; - let packet_len = match VarInt32::decode_partial(&mut r) { + let packet_len = match VarInt::decode_partial(&mut r) { Ok(len) => len, Err(VarIntDecodeError::Incomplete) => return Ok(None), Err(VarIntDecodeError::TooLarge) => Err(PacketError::MailformedLength)?, @@ -34,7 +34,7 @@ impl PacketDecoder { return Ok(None); } - let packet_len_len = VarInt32(packet_len).written_size(); + let packet_len_len = VarInt(packet_len).written_size(); let mut data; @@ -44,13 +44,10 @@ impl PacketDecoder { data = self.buf.split_to(packet_len as usize); r = &data[..]; - let packet_id = VarInt32::decode(&mut r) - .map_err(|_| PacketError::DecodeID)? - .0; + let packet_id = VarInt::decode(&mut r).map_err(|_| PacketError::DecodeID)?; data.advance(data.len() - r.len()); Ok(Some(RawPacket { - len: packet_len, id: packet_id, bytebuf: ByteBuffer::new(data), })) diff --git a/pumpkin-protocol/src/packet_encoder.rs b/pumpkin-protocol/src/packet_encoder.rs index bd0831c0f..53f2116ab 100644 --- a/pumpkin-protocol/src/packet_encoder.rs +++ b/pumpkin-protocol/src/packet_encoder.rs @@ -3,7 +3,7 @@ use std::io::Write; use aes::cipher::{generic_array::GenericArray, BlockEncryptMut, BlockSizeUser, KeyIvInit}; use bytes::{BufMut, BytesMut}; -use crate::{bytebuf::ByteBuffer, ClientPacket, PacketError, VarInt32, MAX_PACKET_SIZE}; +use crate::{bytebuf::ByteBuffer, ClientPacket, PacketError, VarInt, MAX_PACKET_SIZE}; type Cipher = cfb8::Encryptor; @@ -22,7 +22,7 @@ impl PacketEncoder { let mut writer = (&mut self.buf).writer(); let mut packet_buf = ByteBuffer::empty(); - VarInt32(P::PACKET_ID) + VarInt(P::PACKET_ID) .encode(&mut writer) .map_err(|_| PacketError::EncodeID)?; packet.write(&mut packet_buf); @@ -41,14 +41,14 @@ impl PacketEncoder { Err(PacketError::TooLong)? } - let packet_len_size = VarInt32(packet_len as i32).written_size(); + let packet_len_size = VarInt(packet_len as i32).written_size(); self.buf.put_bytes(0, packet_len_size); self.buf .copy_within(start_len..start_len + data_len, start_len + packet_len_size); let front = &mut self.buf[start_len..]; - VarInt32(packet_len as i32) + VarInt(packet_len as i32) .encode(front) .map_err(|_| PacketError::EncodeID)?; Ok(()) diff --git a/pumpkin-protocol/src/server/config/mod.rs b/pumpkin-protocol/src/server/config/mod.rs index 2ee53ecd4..59806c86a 100644 --- a/pumpkin-protocol/src/server/config/mod.rs +++ b/pumpkin-protocol/src/server/config/mod.rs @@ -12,7 +12,7 @@ pub struct SClientInformation { } impl ServerPacket for SClientInformation { - const PACKET_ID: VarInt = 0x00; + const PACKET_ID: VarInt = VarInt(0x00); fn read(bytebuf: &mut ByteBuffer) -> Self { Self { @@ -34,7 +34,7 @@ pub struct SPluginMessage { } impl ServerPacket for SPluginMessage { - const PACKET_ID: VarInt = 0x02; + const PACKET_ID: VarInt = VarInt(0x02); fn read(bytebuf: &mut ByteBuffer) -> Self { Self { @@ -47,7 +47,7 @@ impl ServerPacket for SPluginMessage { pub struct SAcknowledgeFinishConfig {} impl ServerPacket for SAcknowledgeFinishConfig { - const PACKET_ID: VarInt = 0x03; + const PACKET_ID: VarInt = VarInt(0x03); fn read(_bytebuf: &mut ByteBuffer) -> Self { Self {} @@ -60,7 +60,7 @@ pub struct SKnownPacks { } impl ServerPacket for SKnownPacks { - const PACKET_ID: VarInt = 0x07; + const PACKET_ID: VarInt = VarInt(0x07); fn read(bytebuf: &mut ByteBuffer) -> Self { Self { diff --git a/pumpkin-protocol/src/server/handshake/mod.rs b/pumpkin-protocol/src/server/handshake/mod.rs index 9ffbc2d77..9894ac9fd 100644 --- a/pumpkin-protocol/src/server/handshake/mod.rs +++ b/pumpkin-protocol/src/server/handshake/mod.rs @@ -8,7 +8,7 @@ pub struct SHandShake { } impl ServerPacket for SHandShake { - const PACKET_ID: VarInt = 0x00; + const PACKET_ID: VarInt = VarInt(0x00); fn read(bytebuf: &mut ByteBuffer) -> Self { Self { diff --git a/pumpkin-protocol/src/server/login/mod.rs b/pumpkin-protocol/src/server/login/mod.rs index 8e73b5542..36862cedf 100644 --- a/pumpkin-protocol/src/server/login/mod.rs +++ b/pumpkin-protocol/src/server/login/mod.rs @@ -6,7 +6,7 @@ pub struct SLoginStart { } impl ServerPacket for SLoginStart { - const PACKET_ID: VarInt = 0x00; + const PACKET_ID: VarInt = VarInt(0x00); fn read(bytebuf: &mut ByteBuffer) -> Self { Self { @@ -24,13 +24,13 @@ pub struct SEncryptionResponse { } impl ServerPacket for SEncryptionResponse { - const PACKET_ID: VarInt = 0x01; + const PACKET_ID: VarInt = VarInt(0x01); fn read(bytebuf: &mut ByteBuffer) -> Self { let shared_secret_length = bytebuf.get_var_int(); - let shared_secret = bytebuf.copy_to_bytes(shared_secret_length as usize); + let shared_secret = bytebuf.copy_to_bytes(shared_secret_length.0 as usize); let verify_token_length = bytebuf.get_var_int(); - let verify_token = bytebuf.copy_to_bytes(shared_secret_length as usize); + let verify_token = bytebuf.copy_to_bytes(shared_secret_length.0 as usize); Self { shared_secret_length, shared_secret: shared_secret.to_vec(), @@ -47,7 +47,7 @@ pub struct SLoginPluginResponse<'a> { } impl<'a> ServerPacket for SLoginPluginResponse<'a> { - const PACKET_ID: VarInt = 0x02; + const PACKET_ID: VarInt = VarInt(0x02); fn read(bytebuf: &mut ByteBuffer) -> Self { Self { @@ -64,7 +64,7 @@ pub struct SLoginAcknowledged { } impl ServerPacket for SLoginAcknowledged { - const PACKET_ID: VarInt = 0x03; + const PACKET_ID: VarInt = VarInt(0x03); fn read(_bytebuf: &mut ByteBuffer) -> Self { Self {} diff --git a/pumpkin-protocol/src/server/play/mod.rs b/pumpkin-protocol/src/server/play/mod.rs index e0acfe4e4..62782c7cd 100644 --- a/pumpkin-protocol/src/server/play/mod.rs +++ b/pumpkin-protocol/src/server/play/mod.rs @@ -8,7 +8,7 @@ pub struct SConfirmTeleport { } impl ServerPacket for SConfirmTeleport { - const PACKET_ID: VarInt = 0x00; + const PACKET_ID: VarInt = VarInt(0x00); fn read(bytebuf: &mut crate::bytebuf::ByteBuffer) -> Self { Self { @@ -22,7 +22,7 @@ pub struct SChatCommand { } impl ServerPacket for SChatCommand { - const PACKET_ID: VarInt = 0x04; + const PACKET_ID: VarInt = VarInt(0x04); fn read(bytebuf: &mut crate::bytebuf::ByteBuffer) -> Self { Self { @@ -39,7 +39,7 @@ pub struct SPlayerPosition { } impl ServerPacket for SPlayerPosition { - const PACKET_ID: VarInt = 0x1A; + const PACKET_ID: VarInt = VarInt(0x1A); fn read(bytebuf: &mut crate::bytebuf::ByteBuffer) -> Self { Self { @@ -69,12 +69,12 @@ pub enum Action { } impl ServerPacket for SPlayerCommand { - const PACKET_ID: VarInt = 0x25; + const PACKET_ID: VarInt = VarInt(0x25); fn read(bytebuf: &mut crate::bytebuf::ByteBuffer) -> Self { Self { entitiy_id: bytebuf.get_var_int(), - action: Action::from_i32(bytebuf.get_var_int()).unwrap(), + action: Action::from_i32(bytebuf.get_var_int().into()).unwrap(), jump_boost: bytebuf.get_var_int(), } } @@ -90,7 +90,7 @@ pub struct SPlayerPositionRotation { } impl ServerPacket for SPlayerPositionRotation { - const PACKET_ID: VarInt = 0x1B; + const PACKET_ID: VarInt = VarInt(0x1B); fn read(bytebuf: &mut crate::bytebuf::ByteBuffer) -> Self { Self { @@ -111,7 +111,7 @@ pub struct SPlayerRotation { } impl ServerPacket for SPlayerRotation { - const PACKET_ID: VarInt = 0x1C; + const PACKET_ID: VarInt = VarInt(0x1C); fn read(bytebuf: &mut crate::bytebuf::ByteBuffer) -> Self { Self { diff --git a/pumpkin-protocol/src/server/status/mod.rs b/pumpkin-protocol/src/server/status/mod.rs index da6548ca7..a9f7f7987 100644 --- a/pumpkin-protocol/src/server/status/mod.rs +++ b/pumpkin-protocol/src/server/status/mod.rs @@ -5,7 +5,7 @@ pub struct SStatusRequest { } impl ServerPacket for SStatusRequest { - const PACKET_ID: VarInt = 0x00; + const PACKET_ID: VarInt = VarInt(0x00); fn read(_bytebuf: &mut ByteBuffer) -> Self { Self {} @@ -17,7 +17,7 @@ pub struct SPingRequest { } impl ServerPacket for SPingRequest { - const PACKET_ID: VarInt = 0x01; + const PACKET_ID: VarInt = VarInt(0x01); fn read(bytebuf: &mut ByteBuffer) -> Self { Self { diff --git a/pumpkin/Cargo.toml b/pumpkin/Cargo.toml index c5fb4fd64..3f9fe1c1a 100644 --- a/pumpkin/Cargo.toml +++ b/pumpkin/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] pumpkin-world = { path = "../pumpkin-world"} +pumpkin-entity = { path = "../pumpkin-entity"} pumpkin-protocol = { path = "../pumpkin-protocol"} pumpkin-registry = { path = "../pumpkin-registry"} diff --git a/pumpkin/src/client/client_packet.rs b/pumpkin/src/client/client_packet.rs index 351adaae8..3e44cbce3 100644 --- a/pumpkin/src/client/client_packet.rs +++ b/pumpkin/src/client/client_packet.rs @@ -35,14 +35,12 @@ impl Client { } pub fn handle_status_request(&mut self, server: &mut Server, _status_request: SStatusRequest) { - self.send_packet(CStatusResponse::new(&server.status_response_json)) - .unwrap_or_else(|e| self.kick(&e.to_string())); + self.send_packet(CStatusResponse::new(&server.status_response_json)); } pub fn handle_ping_request(&mut self, _server: &mut Server, ping_request: SPingRequest) { dbg!("ping"); - self.send_packet(CPingResponse::new(ping_request.payload)) - .unwrap_or_else(|e| self.kick(&e.to_string())); + self.send_packet(CPingResponse::new(ping_request.payload)); self.close(); } @@ -64,8 +62,7 @@ impl Client { &verify_token, server.base_config.online_mode, // TODO ); - self.send_packet(packet) - .unwrap_or_else(|e| self.kick(&e.to_string())); + self.send_packet(packet); } pub fn handle_encryption_response( @@ -101,8 +98,7 @@ impl Client { if let Some(profile) = self.gameprofile.as_ref().cloned() { let packet = CLoginSuccess::new(profile.id, profile.name, &profile.properties, false); - self.send_packet(packet) - .unwrap_or_else(|e| self.kick(&e.to_string())); + self.send_packet(packet); } else { self.kick("game profile is none"); } @@ -121,16 +117,13 @@ impl Client { _login_acknowledged: SLoginAcknowledged, ) { self.connection_state = ConnectionState::Config; - server - .send_brand(self) - .unwrap_or_else(|e| self.kick(&e.to_string())); + server.send_brand(self); // known data packs self.send_packet(CKnownPacks::new(&[KnownPack { namespace: "minecraft", id: "core", version: "1.21", - }])) - .unwrap_or_else(|e| self.kick(&e.to_string())); + }])); dbg!("login achnowlaged"); } pub fn handle_client_information( @@ -141,10 +134,10 @@ impl Client { self.config = Some(PlayerConfig { locale: client_information.locale, view_distance: client_information.view_distance, - chat_mode: ChatMode::from_i32(client_information.chat_mode).unwrap(), + chat_mode: ChatMode::from_i32(client_information.chat_mode.into()).unwrap(), chat_colors: client_information.chat_colors, skin_parts: client_information.skin_parts, - main_hand: Hand::from_i32(client_information.main_hand).unwrap(), + main_hand: Hand::from_i32(client_information.main_hand.into()).unwrap(), text_filtering: client_information.text_filtering, server_listing: client_information.server_listing, }); @@ -167,14 +160,12 @@ impl Client { self.send_packet(CRegistryData::new( ®istry.registry_id, ®istry.registry_entries, - )) - .unwrap_or_else(|e| self.kick(&e.to_string())); + )); } // We are done with configuring dbg!("finish config"); - self.send_packet(CFinishConfig::new()) - .unwrap_or_else(|e| self.kick(&e.to_string())); + self.send_packet(CFinishConfig::new()); } pub fn handle_config_acknowledged( diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index 19b18d3c8..69598feab 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -114,9 +114,18 @@ impl Client { self.player.is_some() } - /// Im many cases we want to kick the Client when an Packet Error occours, But especially in the Client state we will not try to kick when not important packets - /// e.g Postion, Rotation... has not been send - pub fn send_packet(&mut self, packet: P) -> Result<(), PacketError> { + /// Send a Clientbound Packet to the Client + pub fn send_packet(&mut self, packet: P) { + self.enc + .append_packet(packet) + .unwrap_or_else(|e| self.kick(&e.to_string())); + self.connection + .write_all(&self.enc.take()) + .map_err(|_| PacketError::ConnectionWrite) + .unwrap_or_else(|e| self.kick(&e.to_string())); + } + + pub fn try_send_packet(&mut self, packet: P) -> Result<(), PacketError> { self.enc.append_packet(packet)?; self.connection .write_all(&self.enc.take()) @@ -134,14 +143,12 @@ impl Client { player.z = z; player.yaw = yaw; player.pitch = pitch; - player.awaiting_teleport = Some(id); - self.send_packet(CSyncPlayerPostion::new(x, y, z, yaw, pitch, 0, id.into())) - .unwrap_or_else(|e| self.kick(&e.to_string())); + player.awaiting_teleport = Some(id.into()); + self.send_packet(CSyncPlayerPostion::new(x, y, z, yaw, pitch, 0, id.into())); } pub fn set_gamemode(&mut self, gamemode: GameMode) { - self.send_packet(CGameEvent::new(3, gamemode.to_f32().unwrap())) - .unwrap_or_else(|e| self.kick(&e.to_string())); + self.send_packet(CGameEvent::new(3, gamemode.to_f32().unwrap())); } pub fn process_packets(&mut self, server: &mut Server) { @@ -161,7 +168,7 @@ impl Client { SHandShake::PACKET_ID => self.handle_handshake(server, SHandShake::read(bytebuf)), _ => log::error!( "Failed to handle packet id {} while in Handshake state", - packet.id + packet.id.0 ), }, pumpkin_protocol::ConnectionState::Status => match packet.id { @@ -173,7 +180,7 @@ impl Client { } _ => log::error!( "Failed to handle packet id {} while in Status state", - packet.id + packet.id.0 ), }, pumpkin_protocol::ConnectionState::Login => match packet.id { @@ -191,7 +198,7 @@ impl Client { } _ => log::error!( "Failed to handle packet id {} while in Login state", - packet.id + packet.id.0 ), }, pumpkin_protocol::ConnectionState::Config => match packet.id { @@ -209,7 +216,7 @@ impl Client { } _ => log::error!( "Failed to handle packet id {} while in Config state", - packet.id + packet.id.0 ), }, pumpkin_protocol::ConnectionState::Play => { @@ -245,7 +252,7 @@ impl Client { SPlayerCommand::PACKET_ID => { self.handle_player_command(server, SPlayerCommand::read(bytebuf)) } - _ => log::error!("Failed to handle player packet id {}", packet.id), + _ => log::error!("Failed to handle player packet id {}", packet.id.0), } } @@ -296,9 +303,8 @@ impl Client { } } - pub fn send_message(&mut self, text: TextComponent) { - self.send_packet(CSystemChatMessge::new(text, false)) - .unwrap_or_else(|e| self.kick(&e.to_string())); + pub fn send_system_message(&mut self, text: TextComponent) { + self.send_packet(CSystemChatMessge::new(text, false)); } /// Kicks the Client with a reason depending on the connection state @@ -306,17 +312,17 @@ impl Client { dbg!(reason); match self.connection_state { ConnectionState::Login => { - self.send_packet(CLoginDisconnect::new( + self.try_send_packet(CLoginDisconnect::new( &serde_json::to_string_pretty(&reason).unwrap(), )) .unwrap_or_else(|_| self.close()); } ConnectionState::Config => { - self.send_packet(CConfigDisconnect::new(reason)) + self.try_send_packet(CConfigDisconnect::new(reason)) .unwrap_or_else(|_| self.close()); } ConnectionState::Play => { - self.send_packet(CPlayDisconnect::new(TextComponent { + self.try_send_packet(CPlayDisconnect::new(TextComponent { text: reason.to_string(), })) .unwrap_or_else(|_| self.close()); diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 423be04cb..a90fd6f85 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -18,7 +18,7 @@ impl Client { confirm_teleport: SConfirmTeleport, ) { let player = self.player.as_mut().unwrap(); - if let Some(id) = player.awaiting_teleport { + if let Some(id) = player.awaiting_teleport.clone() { if id == confirm_teleport.teleport_id { } else { log::warn!("Teleport id does not match, Weird but okay"); @@ -71,13 +71,13 @@ impl Client { } pub fn handle_chat_command(&mut self, server: &mut Server, command: SChatCommand) { - handle_command(&mut CommandSender::Player(self), command.command, server); + handle_command(&mut CommandSender::Player(self), command.command); } pub fn handle_player_command(&mut self, _server: &mut Server, command: SPlayerCommand) { let player = self.player.as_mut().unwrap(); - if command.entitiy_id != player.entity.entity_id { + if command.entitiy_id != player.entity.entity_id.into() { return; } diff --git a/pumpkin/src/commands/gamemode.rs b/pumpkin/src/commands/gamemode.rs index 00b10e1eb..5cc26b34e 100644 --- a/pumpkin/src/commands/gamemode.rs +++ b/pumpkin/src/commands/gamemode.rs @@ -13,17 +13,13 @@ impl<'a> Command<'a> for GamemodeCommand { const DESCRIPTION: &'a str = "Changes the gamemode for a Player"; - fn on_execute( - sender: &mut super::CommandSender<'a>, - command: String, - _server: &mut crate::server::Server, - ) { + fn on_execute(sender: &mut super::CommandSender<'a>, command: String) { let player = sender.as_mut_player().unwrap(); let args: Vec<&str> = command.split_whitespace().collect(); if args.len() != 2 { // todo red - player.send_message("Usage: /gamemode ".into()); + player.send_system_message("Usage: /gamemode ".into()); return; } @@ -31,11 +27,11 @@ impl<'a> Command<'a> for GamemodeCommand { match mode_str.parse() { Ok(mode) => { player.set_gamemode(mode); - player.send_message(format!("Set own game mode to {mode_str}").into()); + player.send_system_message(format!("Set own game mode to {mode_str}").into()); } Err(_) => { // todo red - player.send_message("Invalid gamemode".into()); + player.send_system_message("Invalid gamemode".into()); } } } diff --git a/pumpkin/src/commands/mod.rs b/pumpkin/src/commands/mod.rs index 47caa966e..9c97c0f2a 100644 --- a/pumpkin/src/commands/mod.rs +++ b/pumpkin/src/commands/mod.rs @@ -2,7 +2,7 @@ use gamemode::GamemodeCommand; use pumpkin::PumpkinCommand; use pumpkin_protocol::text::TextComponent; -use crate::{client::Client, server::Server}; +use crate::client::Client; mod gamemode; mod pumpkin; @@ -13,7 +13,7 @@ pub trait Command<'a> { const NAME: &'a str; const DESCRIPTION: &'a str; - fn on_execute(sender: &mut CommandSender<'a>, command: String, server: &mut Server); + fn on_execute(sender: &mut CommandSender<'a>, command: String); /// Specifies wether the Command Sender has to be a Player fn player_required() -> bool { @@ -31,7 +31,7 @@ impl<'a> CommandSender<'a> { match self { // todo: add color and stuff to console CommandSender::Console => log::info!("{}", text.text), - CommandSender::Player(c) => c.send_message(text), + CommandSender::Player(c) => c.send_system_message(text), } } @@ -55,15 +55,15 @@ impl<'a> CommandSender<'a> { } } } -pub fn handle_command(sender: &mut CommandSender, command: String, server: &mut Server) { +pub fn handle_command(sender: &mut CommandSender, command: String) { let command = command.to_lowercase(); // an ugly mess i know if command.starts_with(PumpkinCommand::NAME) { - PumpkinCommand::on_execute(sender, command, server); + PumpkinCommand::on_execute(sender, command); return; } if command.starts_with(GamemodeCommand::NAME) { - GamemodeCommand::on_execute(sender, command, server); + GamemodeCommand::on_execute(sender, command); return; } // todo: red color diff --git a/pumpkin/src/commands/pumpkin.rs b/pumpkin/src/commands/pumpkin.rs index d743c4c83..69d560192 100644 --- a/pumpkin/src/commands/pumpkin.rs +++ b/pumpkin/src/commands/pumpkin.rs @@ -17,11 +17,7 @@ impl<'a> Command<'a> for PumpkinCommand { const DESCRIPTION: &'a str = "Displays information about Pumpkin"; - fn on_execute( - sender: &mut super::CommandSender<'a>, - _command: String, - _server: &mut crate::server::Server, - ) { + fn on_execute(sender: &mut super::CommandSender<'a>, _command: String) { let version = env!("CARGO_PKG_VERSION"); let description = env!("CARGO_PKG_DESCRIPTION"); sender.send_message(TextComponent::from(format!("Pumpkin {version}, {description} (Minecraft {CURRENT_MC_VERSION}, Protocol {CURRENT_MC_PROTOCOL})"))) diff --git a/pumpkin/src/entity/mod.rs b/pumpkin/src/entity/mod.rs index 1255ab620..f28d7c205 100644 --- a/pumpkin/src/entity/mod.rs +++ b/pumpkin/src/entity/mod.rs @@ -1,13 +1 @@ pub mod player; - -pub type EntityId = i32; - -pub struct Entity { - pub entity_id: EntityId, -} - -impl Entity { - pub fn new(entity_id: EntityId) -> Self { - Self { entity_id } - } -} diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index ccded9cd0..8f66a2a23 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -1,11 +1,10 @@ use std::str::FromStr; use num_derive::{FromPrimitive, ToPrimitive}; +use pumpkin_entity::{entity_type::EntityType, Entity, EntityId}; use pumpkin_protocol::VarInt; use serde::{Deserialize, Serialize}; -use super::{Entity, EntityId}; - pub struct Player { pub entity: Entity, pub x: f64, @@ -25,9 +24,12 @@ pub struct Player { } impl Player { - pub fn new(entity: Entity) -> Self { + pub fn new(entity_id: EntityId) -> Self { Self { - entity, + entity: Entity { + entity_id, + entity_type: EntityType::Player, + }, x: 0.0, y: 0.0, z: 0.0, diff --git a/pumpkin/src/main.rs b/pumpkin/src/main.rs index 9a8012e22..811368548 100644 --- a/pumpkin/src/main.rs +++ b/pumpkin/src/main.rs @@ -29,7 +29,7 @@ pub mod util; #[cfg(not(target_os = "wasi"))] fn main() -> io::Result<()> { - use std::time::Instant; + use std::{cell::RefCell, time::Instant}; let time = Instant::now(); let basic_config = BasicConfiguration::load("configuration.toml"); @@ -63,7 +63,7 @@ fn main() -> io::Result<()> { let use_console = advanced_configuration.commands.use_console; - let mut connections: HashMap = HashMap::new(); + let mut connections: HashMap>> = HashMap::new(); let server = Arc::new(Mutex::new(Server::new(( basic_config, @@ -73,7 +73,6 @@ fn main() -> io::Result<()> { log::info!("You now can connect to the server"); if use_console { - let server_clone = server.clone(); thread::spawn(move || { let stdin = std::io::stdin(); loop { @@ -81,11 +80,7 @@ fn main() -> io::Result<()> { stdin .read_line(&mut out) .expect("Failed to read console line"); - handle_command( - &mut commands::CommandSender::Console, - out, - &mut server_clone.lock().unwrap(), - ); + handle_command(&mut commands::CommandSender::Console, out); } }); } @@ -127,14 +122,22 @@ fn main() -> io::Result<()> { Interest::READABLE.add(Interest::WRITABLE), )?; let rc_token = Rc::new(token); - let client = Client::new(Rc::clone(&rc_token), connection, addr); - // server.add_client(rc_token, Rc::clone(&client)); + let client = Rc::new(RefCell::new(Client::new( + Rc::clone(&rc_token), + connection, + addr, + ))); + server + .lock() + .unwrap() + .add_client(rc_token, Rc::clone(&client)); connections.insert(token, client); }, token => { // Maybe received an event for a TCP connection. let done = if let Some(client) = connections.get_mut(&token) { + let mut client = client.borrow_mut(); client.poll(&mut server.lock().unwrap(), event); client.closed } else { @@ -142,8 +145,9 @@ fn main() -> io::Result<()> { false }; if done { - if let Some(mut client) = connections.remove(&token) { - // server.remove_client(&token); + if let Some(client) = connections.remove(&token) { + let mut client = client.borrow_mut(); + server.lock().unwrap().remove_client(&token); poll.registry().deregister(&mut client.connection)?; } } diff --git a/pumpkin/src/server.rs b/pumpkin/src/server.rs index ecdf9401e..88797d6fb 100644 --- a/pumpkin/src/server.rs +++ b/pumpkin/src/server.rs @@ -1,5 +1,6 @@ use std::{ cell::RefCell, + collections::HashMap, io::Cursor, rc::Rc, sync::atomic::{AtomicI32, Ordering}, @@ -8,13 +9,17 @@ use std::{ use base64::{engine::general_purpose, Engine}; use mio::{event::Event, Poll, Token}; use num_traits::ToPrimitive; +use pumpkin_entity::{entity_type::EntityType, EntityId}; use pumpkin_protocol::{ client::{ config::CPluginMessage, - play::{CChunkDataUpdateLight, CGameEvent, CLogin, CPlayerInfoUpdate, PlayerAction}, + play::{ + CChunkDataUpdateLight, CGameEvent, CLogin, CPlayerAbilities, CPlayerInfoUpdate, + CSpawnEntity, PlayerAction, + }, }, - BitSet, ClientPacket, PacketError, Players, Sample, StatusResponse, VarInt, VarInt32, Version, - CURRENT_MC_PROTOCOL, + BitSet, ClientPacket, Players, Sample, StatusResponse, VarInt, + Version, CURRENT_MC_PROTOCOL, }; use pumpkin_world::chunk::TestChunk; use rsa::{rand_core::OsRng, traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey}; @@ -23,10 +28,7 @@ use serde::{Deserialize, Serialize}; use crate::{ client::Client, configuration::{AdvancedConfiguration, BasicConfiguration}, - entity::{ - player::{GameMode, Player}, - Entity, EntityId, - }, + entity::player::{GameMode, Player}, }; pub const CURRENT_MC_VERSION: &str = "1.21"; @@ -47,7 +49,7 @@ pub struct Server { /// Cache the Server brand buffer so we don't have to rebuild them every time a player joins pub cached_server_brand: Vec, - // pub current_clients: HashMap, Rc>>, + pub current_clients: HashMap, Rc>>, // todo replace with HashMap entity_id: AtomicI32, // todo: place this into every world @@ -90,7 +92,7 @@ impl Server { status_response, status_response_json, public_key_der, - // current_clients: HashMap::new(), + current_clients: HashMap::new(), base_config: config.0, auth_client, advanced_config: config.1, @@ -103,114 +105,188 @@ impl Server { client.poll(self, event) } - pub fn add_client(&mut self, _token: Rc, _client: Rc>) { - // self.current_clients.insert(token, client); + pub fn add_client(&mut self, token: Rc, client: Rc>) { + self.current_clients.insert(token, client); } - pub fn remove_client(&mut self, _token: &Token) { - // self.current_clients.remove(token); + pub fn remove_client(&mut self, token: &Token) { + self.current_clients.remove(token); } + // here is where the magic happens // todo: do this in a world pub fn spawn_player(&mut self, client: &mut Client) { // This code follows the vanilla packet order dbg!("spawning player"); let entity_id = self.new_entity_id(); - let player = Player::new(Entity { entity_id }); + let player = Player::new(entity_id); client.player = Some(player); - client - .send_packet(CLogin::new( - entity_id, - self.base_config.hardcore, - vec!["minecraft:overworld".into()], - self.base_config.max_players as VarInt, - self.base_config.view_distance as VarInt, // view distance todo - self.base_config.simulation_distance as VarInt, // sim view dinstance todo - false, - false, - false, - 0, - "minecraft:overworld".into(), - 0, // seed - match self.base_config.default_gamemode { - GameMode::Undefined => GameMode::Survival, - game_mode => game_mode, - } - .to_u8() - .unwrap(), - self.base_config.default_gamemode.to_i8().unwrap(), - false, - false, - false, // deth loc - None, - None, - 0, - false, - )) - .unwrap_or_else(|e| client.kick(&e.to_string())); + // login packet for our new player + client.send_packet(CLogin::new( + entity_id, + self.base_config.hardcore, + vec!["minecraft:overworld".into()], + self.base_config.max_players.into(), + self.base_config.view_distance.into(), // view distance todo + self.base_config.simulation_distance.into(), // sim view dinstance todo + false, + false, + false, + 0.into(), + "minecraft:overworld".into(), + 0, // seed + match self.base_config.default_gamemode { + GameMode::Undefined => GameMode::Survival, + game_mode => game_mode, + } + .to_u8() + .unwrap(), + self.base_config.default_gamemode.to_i8().unwrap(), + false, + false, + false, // deth loc + None, + None, + 0.into(), + false, + )); + // player abilities + client.send_packet(CPlayerAbilities::new(0x02, 00.2, 0.1)); + // teleport - client.teleport(10.0, 500.0, 10.0, 10.0, 10.0); + let x = 10.0; + let y = 500.0; + let z = 10.0; + client.teleport(x, y, z, 10.0, 10.0); let gameprofile = client.gameprofile.as_ref().unwrap(); // first send info update to our new player, So he can see his Skin // TODO: send more actions, (chat. list, ping) - client - .send_packet(CPlayerInfoUpdate::new( + client.send_packet(CPlayerInfoUpdate::new( + 0x01, + &[pumpkin_protocol::client::play::Player { + uuid: gameprofile.id, + actions: vec![PlayerAction::AddPlayer { + name: gameprofile.name.clone(), + properties: gameprofile.properties.clone(), + }], + }], + )); + let gameprofile = client.gameprofile.as_ref().unwrap(); + // send his info to everyone else + self.broadcast_packet( + client, + CPlayerInfoUpdate::new( 0x01, &[pumpkin_protocol::client::play::Player { uuid: gameprofile.id, - actions: &[PlayerAction::AddPlayer { + actions: vec![PlayerAction::AddPlayer { name: gameprofile.name.clone(), properties: gameprofile.properties.clone(), }], }], - )) - .unwrap_or_else(|e| client.kick(&e.to_string())); - // TODO: Now we send this to all other client + ), + ); + + // here we send all the infos of already joined players + let mut entries = Vec::new(); + for (_, client) in self.current_clients.iter().filter(|c| c.0 != &client.token) { + let client = client.borrow(); + if client.is_player() { + let gameprofile = client.gameprofile.as_ref().unwrap(); + entries.push(pumpkin_protocol::client::play::Player { + uuid: gameprofile.id, + actions: vec![PlayerAction::AddPlayer { + name: gameprofile.name.clone(), + properties: gameprofile.properties.clone(), + }], + }) + } + } + client.send_packet(CPlayerInfoUpdate::new(0x01, &entries)); // Start waiting for level chunks - client - .send_packet(CGameEvent::new(13, 0.0)) - .unwrap_or_else(|e| client.kick(&e.to_string())); + client.send_packet(CGameEvent::new(13, 0.0)); + + let gameprofile = client.gameprofile.as_ref().unwrap(); + + // spawn player for every client + self.broadcast_packet( + client, + CSpawnEntity::new( + entity_id.into(), + gameprofile.id, + EntityType::Player.to_i32().unwrap().into(), + x, + y, + z, + 0, + 0, + 0, + 0.into(), + 0, + 0, + 0, + ), + ); + // spawn players for our client + let token = client.token.clone(); + for (_, existing_client) in self.current_clients.iter().filter(|c| c.0 != &token) { + let existing_client = existing_client.borrow(); + if let Some(player) = &existing_client.player { + let gameprofile = existing_client.gameprofile.as_ref().unwrap(); + client.send_packet(CSpawnEntity::new( + player.entity_id().into(), + gameprofile.id, + EntityType::Player.to_i32().unwrap().into(), + x, + y, + z, + 0, + 0, + 0, + 0.into(), + 0, + 0, + 0, + )) + } + } // Server::spawn_test_chunk(client); } /// Sends a Packet to all Players - fn _broadcast_packet

(&mut self, _packet: P) -> Result<(), PacketError> + fn broadcast_packet

(&mut self, from: &Client, packet: P) where P: ClientPacket, P: Clone, { - /* for client in self.current_clients.values() { + for (_, client) in self.current_clients.iter().filter(|c| c.0 != &from.token) { // Check if client is a player - if client.borrow().is_player() { + let mut client = client.borrow_mut(); + if client.is_player() { // we need to clone, Because we send a new packet to every client - client.borrow_mut().send_packet(packet.clone())?; + client.send_packet(packet.clone()); } } - - */ - Ok(()) } // todo: do this in a world fn _spawn_test_chunk(client: &mut Client) { let test_chunk = TestChunk::new(); - client - .send_packet(CChunkDataUpdateLight::new( - 10, - 10, - test_chunk.heightmap, - Vec::new(), - Vec::new(), - BitSet(0, Vec::new()), - BitSet(0, Vec::new()), - BitSet(0, Vec::new()), - Vec::new(), - Vec::new(), - )) - .unwrap_or_else(|e| client.kick(&e.to_string())) + client.send_packet(CChunkDataUpdateLight::new( + 10, + 10, + test_chunk.heightmap, + Vec::new(), + Vec::new(), + BitSet(0.into(), Vec::new()), + BitSet(0.into(), Vec::new()), + BitSet(0.into(), Vec::new()), + Vec::new(), + Vec::new(), + )); } // move to world @@ -221,17 +297,17 @@ impl Server { pub fn build_brand() -> Vec { let brand = "Pumpkin"; let mut buf = vec![]; - let _ = VarInt32(brand.len() as i32).encode(&mut buf); + let _ = VarInt(brand.len() as i32).encode(&mut buf); buf.extend_from_slice(brand.as_bytes()); buf } - pub fn send_brand(&self, client: &mut Client) -> Result<(), PacketError> { + pub fn send_brand(&self, client: &mut Client) { // send server brand client.send_packet(CPluginMessage::new( "minecraft:brand", &self.cached_server_brand, - )) + )); } pub fn build_response(config: &BasicConfiguration) -> StatusResponse {