From 55e8cd696ebad8f45cff389a4e808719cf9f0671 Mon Sep 17 00:00:00 2001 From: kralverde <80051564+kralverde@users.noreply.github.com> Date: Sat, 21 Dec 2024 06:54:23 -0500 Subject: [PATCH 1/6] Remove optimizations for dev builds (#404) --- Cargo.toml | 2 -- pumpkin-world/src/level.rs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0c92812e..7122a354 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,8 +16,6 @@ members = [ version = "0.1.0" edition = "2021" -[profile.dev.package."*"] -opt-level = 3 [profile.dev] opt-level = 1 diff --git a/pumpkin-world/src/level.rs b/pumpkin-world/src/level.rs index 2a6a9571..e0b8ac12 100644 --- a/pumpkin-world/src/level.rs +++ b/pumpkin-world/src/level.rs @@ -72,7 +72,7 @@ impl Level { } } else { let seed = get_or_create_seed(); - let world_gen = get_world_gen(seed).into(); // TODO Read Seed from config. + let world_gen = get_world_gen(seed).into(); Self { seed, world_gen, From 0633197b628aeb861d386e32971b10b1d5c43ed1 Mon Sep 17 00:00:00 2001 From: Alexander Medvedev Date: Sat, 21 Dec 2024 17:03:52 +0100 Subject: [PATCH 2/6] pumpkin-protocol: added codecs --- pumpkin-protocol/src/bytebuf/deserializer.rs | 24 +-- pumpkin-protocol/src/bytebuf/mod.rs | 91 ++++++----- pumpkin-protocol/src/bytebuf/packet_id.rs | 14 +- pumpkin-protocol/src/bytebuf/serializer.rs | 44 ++--- .../src/client/config/c_cookie_request.rs | 2 +- .../src/client/config/c_known_packs.rs | 4 +- .../src/client/config/c_registry_data.rs | 23 ++- .../src/client/config/c_store_cookie.rs | 2 +- .../src/client/login/c_cookie_request.rs | 3 +- .../src/client/login/c_login_success.rs | 4 +- .../src/client/play/c_boss_event.rs | 4 +- .../src/client/play/c_chunk_data.rs | 12 +- .../src/client/play/c_command_suggestions.rs | 4 +- .../src/client/play/c_commands.rs | 24 +-- .../src/client/play/c_cookie_request.rs | 3 +- .../src/client/play/c_entity_sound_effect.rs | 6 +- .../client/play/c_initialize_world_border.rs | 2 +- pumpkin-protocol/src/client/play/c_login.rs | 14 +- .../src/client/play/c_player_chat_message.rs | 10 +- .../src/client/play/c_player_info_update.rs | 4 +- .../src/client/play/c_player_position.rs | 4 +- pumpkin-protocol/src/client/play/c_respawn.rs | 14 +- .../src/client/play/c_set_border_lerp_size.rs | 2 +- .../src/client/play/c_sound_effect.rs | 6 +- .../src/client/play/c_store_cookie.rs | 2 +- .../src/client/play/c_teleport_entity.rs | 4 +- .../src/client/play/c_update_objectives.rs | 4 +- pumpkin-protocol/src/lib.rs | 34 +--- pumpkin-protocol/src/packet_decoder.rs | 9 +- pumpkin-protocol/src/packet_encoder.rs | 7 +- .../src/server/config/s_cookie_response.rs | 9 +- .../src/server/config/s_plugin_message.rs | 11 +- pumpkin-protocol/src/server/handshake/mod.rs | 4 +- .../src/server/login/s_cookie_response.rs | 9 +- .../src/server/login/s_encryption_response.rs | 4 +- .../src/server/login/s_login_start.rs | 4 +- .../src/server/login/s_plugin_response.rs | 6 +- .../src/server/play/s_chat_message.rs | 4 +- .../src/server/play/s_cookie_response.rs | 9 +- .../src/server/play/s_interact.rs | 4 +- .../src/server/play/s_player_command.rs | 4 +- pumpkin-protocol/src/var_int.rs | 151 ----------------- pumpkin-protocol/src/var_long.rs | 152 ------------------ pumpkin-registry/src/banner_pattern.rs | 3 +- pumpkin-registry/src/biome.rs | 2 +- pumpkin-registry/src/lib.rs | 72 ++++----- pumpkin-registry/src/paint.rs | 3 +- pumpkin-registry/src/trim_pattern.rs | 3 +- pumpkin-world/src/item/item_registry.rs | 11 +- pumpkin/src/client/client_packet.rs | 17 +- pumpkin/src/client/combat.rs | 3 +- pumpkin/src/client/container.rs | 2 +- pumpkin/src/client/mod.rs | 14 +- pumpkin/src/client/player_packet.rs | 4 +- pumpkin/src/command/commands/cmd_transfer.rs | 2 +- pumpkin/src/entity/mod.rs | 2 +- pumpkin/src/entity/player.rs | 11 +- pumpkin/src/server/connection_cache.rs | 3 +- pumpkin/src/server/mod.rs | 2 - pumpkin/src/world/mod.rs | 10 +- pumpkin/src/world/scoreboard.rs | 3 +- 61 files changed, 307 insertions(+), 611 deletions(-) delete mode 100644 pumpkin-protocol/src/var_int.rs delete mode 100644 pumpkin-protocol/src/var_long.rs diff --git a/pumpkin-protocol/src/bytebuf/deserializer.rs b/pumpkin-protocol/src/bytebuf/deserializer.rs index 3b999e96..c7f574c3 100644 --- a/pumpkin-protocol/src/bytebuf/deserializer.rs +++ b/pumpkin-protocol/src/bytebuf/deserializer.rs @@ -1,11 +1,11 @@ use std::fmt::Display; use super::{ByteBuf, ReadingError}; -use bytes::Bytes; +use bytes::Buf; use serde::de::{self, DeserializeSeed, SeqAccess}; -pub struct Deserializer<'a> { - inner: &'a mut Bytes, +pub struct Deserializer<'a, B: Buf> { + inner: &'a mut B, } impl de::Error for ReadingError { @@ -14,13 +14,13 @@ impl de::Error for ReadingError { } } -impl<'a> Deserializer<'a> { - pub fn new(buf: &'a mut Bytes) -> Self { +impl<'a, B: Buf> Deserializer<'a, B> { + pub fn new(buf: &'a mut B) -> Self { Self { inner: buf } } } -impl<'de> de::Deserializer<'de> for Deserializer<'_> { +impl<'de, B: Buf> de::Deserializer<'de> for Deserializer<'_, B> { type Error = ReadingError; fn deserialize_any(self, _visitor: V) -> Result @@ -184,11 +184,11 @@ impl<'de> de::Deserializer<'de> for Deserializer<'_> { where V: de::Visitor<'de>, { - struct Access<'a, 'b> { - deserializer: &'a mut Deserializer<'b>, + struct Access<'a, 'b, B: Buf> { + deserializer: &'a mut Deserializer<'b, B>, } - impl<'de, 'a, 'b: 'a> SeqAccess<'de> for Access<'a, 'b> { + impl<'de, 'a, 'b: 'a, B: Buf> SeqAccess<'de> for Access<'a, 'b, B> { type Error = ReadingError; fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> @@ -216,12 +216,12 @@ impl<'de> de::Deserializer<'de> for Deserializer<'_> { where V: de::Visitor<'de>, { - struct Access<'a, 'b> { - deserializer: &'a mut Deserializer<'b>, + struct Access<'a, 'b, B: Buf> { + deserializer: &'a mut Deserializer<'b, B>, len: usize, } - impl<'de, 'a, 'b: 'a> SeqAccess<'de> for Access<'a, 'b> { + impl<'de, 'a, 'b: 'a, B: Buf> SeqAccess<'de> for Access<'a, 'b, B> { type Error = ReadingError; fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> diff --git a/pumpkin-protocol/src/bytebuf/mod.rs b/pumpkin-protocol/src/bytebuf/mod.rs index 94e57f52..b1ee75ae 100644 --- a/pumpkin-protocol/src/bytebuf/mod.rs +++ b/pumpkin-protocol/src/bytebuf/mod.rs @@ -1,6 +1,12 @@ use core::str; -use crate::{BitSet, FixedBitSet, VarInt, VarLong}; +use crate::{ + codec::{ + bit_set::BitSet, identifier::Identifier, var_int::VarInt, var_long::VarLong, Codec, + DecodeError, + }, + FixedBitSet, +}; use bytes::{Buf, BufMut}; mod deserializer; @@ -54,9 +60,11 @@ pub trait ByteBuf: Buf { fn try_get_var_long(&mut self) -> Result; + fn try_get_identifer(&mut self) -> Result; + fn try_get_string(&mut self) -> Result; - fn try_get_string_len(&mut self, max_size: u32) -> Result; + fn try_get_string_len(&mut self, max_size: usize) -> Result; /// Reads a boolean. If true, the closure is called, and the returned value is /// wrapped in Some. Otherwise, this returns None. @@ -181,12 +189,8 @@ impl ByteBuf for T { match VarInt::decode(self) { Ok(var_int) => Ok(var_int), Err(error) => match error { - crate::VarIntDecodeError::Incomplete => { - Err(ReadingError::Incomplete("varint".to_string())) - } - crate::VarIntDecodeError::TooLarge => { - Err(ReadingError::TooLarge("varint".to_string())) - } + DecodeError::Incomplete => Err(ReadingError::Incomplete("varint".to_string())), + DecodeError::TooLarge => Err(ReadingError::TooLarge("varint".to_string())), }, } } @@ -194,28 +198,24 @@ impl ByteBuf for T { match VarLong::decode(self) { Ok(var_long) => Ok(var_long), Err(error) => match error { - crate::VarLongDecodeError::Incomplete => { - Err(ReadingError::Incomplete("varint".to_string())) - } - crate::VarLongDecodeError::TooLarge => { - Err(ReadingError::TooLarge("varlong".to_string())) - } + DecodeError::Incomplete => Err(ReadingError::Incomplete("varint".to_string())), + DecodeError::TooLarge => Err(ReadingError::TooLarge("varlong".to_string())), }, } } fn try_get_string(&mut self) -> Result { - self.try_get_string_len(i16::MAX as u32) + self.try_get_string_len(i16::MAX as usize) } - fn try_get_string_len(&mut self, max_size: u32) -> Result { + fn try_get_string_len(&mut self, max_size: usize) -> Result { let size = self.try_get_var_int()?.0; - if size as u32 > max_size { + if size as usize > max_size { return Err(ReadingError::TooLarge("string".to_string())); } let data = self.try_copy_to_bytes(size as usize)?; - if data.len() as u32 > max_size { + if data.len() > max_size { return Err(ReadingError::TooLarge("string".to_string())); } match str::from_utf8(&data) { @@ -256,6 +256,16 @@ impl ByteBuf for T { fn try_get_fixed_bitset(&mut self, bits: usize) -> Result { self.try_copy_to_bytes(bits.div_ceil(8)) } + + fn try_get_identifer(&mut self) -> Result { + match Identifier::decode(self) { + Ok(identifer) => Ok(identifer), + Err(error) => match error { + DecodeError::Incomplete => Err(ReadingError::Incomplete("identifer".to_string())), + DecodeError::TooLarge => Err(ReadingError::TooLarge("identifer".to_string())), + }, + } + } } pub trait ByteBufMut { @@ -265,7 +275,7 @@ pub trait ByteBufMut { fn put_string(&mut self, val: &str); - fn put_string_len(&mut self, val: &str, max_size: u32); + fn put_string_len(&mut self, val: &str, max_size: usize); fn put_string_array(&mut self, array: &[String]); @@ -277,6 +287,8 @@ pub trait ByteBufMut { fn put_list(&mut self, list: &[G], write: impl Fn(&mut Self, &G)); + fn put_identifier(&mut self, val: &Identifier); + fn put_var_int(&mut self, value: &VarInt); fn put_varint_arr(&mut self, v: &[i32]); @@ -299,11 +311,11 @@ impl ByteBufMut for T { } fn put_string(&mut self, val: &str) { - self.put_string_len(val, i16::MAX as u32); + self.put_string_len(val, i16::MAX as usize); } - fn put_string_len(&mut self, val: &str, max_size: u32) { - if val.len() as u32 > max_size { + fn put_string_len(&mut self, val: &str, max_size: usize) { + if val.len() > max_size { // Should be panic?, I mean its our fault panic!("String is too big"); } @@ -317,15 +329,12 @@ impl ByteBufMut for T { } } - fn put_var_int(&mut self, value: &VarInt) { - value.encode(self); + fn put_var_int(&mut self, var_int: &VarInt) { + var_int.encode(self); } - fn put_bit_set(&mut self, set: &BitSet) { - self.put_var_int(&set.0); - for b in set.1 { - self.put_i64(*b); - } + fn put_bit_set(&mut self, bit_set: &BitSet) { + bit_set.encode(self); } fn put_option(&mut self, val: &Option, write: impl FnOnce(&mut Self, &G)) { @@ -345,6 +354,10 @@ impl ByteBufMut for T { fn put_varint_arr(&mut self, v: &[i32]) { self.put_list(v, |p, &v| p.put_var_int(&v.into())) } + + fn put_identifier(&mut self, val: &Identifier) { + val.encode(self); + } } #[cfg(test)] @@ -364,14 +377,12 @@ mod test { bar: i32, } let foo = Foo { bar: 69 }; - let mut serializer = serializer::Serializer::new(BytesMut::new()); + let mut bytes = BytesMut::new(); + let mut serializer = serializer::Serializer::new(&mut bytes); foo.serialize(&mut serializer).unwrap(); - let serialized: BytesMut = serializer.into(); - let deserialized: Foo = Foo::deserialize(deserializer::Deserializer::new( - &mut Bytes::from(serialized), - )) - .unwrap(); + let deserialized: Foo = + Foo::deserialize(deserializer::Deserializer::new(&mut Bytes::from(bytes))).unwrap(); assert_eq!(foo, deserialized); } @@ -383,14 +394,12 @@ mod test { bar: VarInt, } let foo = Foo { bar: 69.into() }; - let mut serializer = serializer::Serializer::new(BytesMut::new()); + let mut bytes = BytesMut::new(); + let mut serializer = serializer::Serializer::new(&mut bytes); foo.serialize(&mut serializer).unwrap(); - let serialized: BytesMut = serializer.into(); - let deserialized: Foo = Foo::deserialize(deserializer::Deserializer::new( - &mut Bytes::from(serialized), - )) - .unwrap(); + let deserialized: Foo = + Foo::deserialize(deserializer::Deserializer::new(&mut Bytes::from(bytes))).unwrap(); assert_eq!(foo, deserialized); } diff --git a/pumpkin-protocol/src/bytebuf/packet_id.rs b/pumpkin-protocol/src/bytebuf/packet_id.rs index 95c8a18e..6534033e 100644 --- a/pumpkin-protocol/src/bytebuf/packet_id.rs +++ b/pumpkin-protocol/src/bytebuf/packet_id.rs @@ -1,7 +1,7 @@ -use bytes::{BufMut, Bytes, BytesMut}; +use bytes::{Buf, BufMut}; use serde::{de::DeserializeOwned, Serialize}; -use crate::{ClientPacket, ServerPacket, VarIntType}; +use crate::{codec::var_int::VarIntType, ClientPacket, ServerPacket}; use super::{deserializer, serializer, ReadingError}; @@ -13,14 +13,10 @@ impl

ClientPacket for P where P: Packet + Serialize, { - fn write(&self, bytebuf: &mut BytesMut) { - let mut serializer = serializer::Serializer::new(BytesMut::new()); + fn write(&self, bytebuf: &mut impl BufMut) { + let mut serializer = serializer::Serializer::new(bytebuf); self.serialize(&mut serializer) .expect("Could not serialize packet"); - // We write the packet in an empty bytebuffer and then put it into our current one. - // In the future we may do packet batching thats the reason i don't let every packet create a new bytebuffer and use - // an existing instead - bytebuf.put(serializer.output); } } @@ -28,7 +24,7 @@ impl

ServerPacket for P where P: Packet + DeserializeOwned, { - fn read(bytebuf: &mut Bytes) -> Result { + fn read(bytebuf: &mut impl Buf) -> Result { let deserializer = deserializer::Deserializer::new(bytebuf); P::deserialize(deserializer) } diff --git a/pumpkin-protocol/src/bytebuf/serializer.rs b/pumpkin-protocol/src/bytebuf/serializer.rs index cace3c6a..5682aa7b 100644 --- a/pumpkin-protocol/src/bytebuf/serializer.rs +++ b/pumpkin-protocol/src/bytebuf/serializer.rs @@ -1,6 +1,6 @@ use std::fmt::Display; -use bytes::{BufMut, BytesMut}; +use bytes::BufMut; use serde::{ ser::{self}, Serialize, @@ -9,34 +9,16 @@ use thiserror::Error; use super::ByteBufMut; -pub struct Serializer { - pub output: BytesMut, +pub struct Serializer { + pub output: B, } -impl Serializer { - pub fn new(buf: BytesMut) -> Self { +impl Serializer { + pub fn new(buf: B) -> Self { Self { output: buf } } } -impl From for BytesMut { - fn from(val: Serializer) -> Self { - val.output - } -} - -impl AsRef for Serializer { - fn as_ref(&self) -> &BytesMut { - &self.output - } -} - -impl AsMut for Serializer { - fn as_mut(&mut self) -> &mut BytesMut { - &mut self.output - } -} - #[derive(Debug, Error)] pub enum SerializerError { #[error("serializer error {0}")] @@ -57,7 +39,7 @@ impl ser::Error for SerializerError { // Structs are ignored // Iterables' values are written in order, but NO information (e.g. size) about the // iterable itself is written (list sizes should be a separate field) -impl ser::Serializer for &mut Serializer { +impl ser::Serializer for &mut Serializer { type Ok = (); type Error = SerializerError; @@ -227,7 +209,7 @@ impl ser::Serializer for &mut Serializer { } } -impl ser::SerializeSeq for &mut Serializer { +impl ser::SerializeSeq for &mut Serializer { // Must match the `Ok` type of the serializer. type Ok = (); // Must match the `Error` type of the serializer. @@ -247,7 +229,7 @@ impl ser::SerializeSeq for &mut Serializer { } } -impl ser::SerializeTuple for &mut Serializer { +impl ser::SerializeTuple for &mut Serializer { type Ok = (); type Error = SerializerError; @@ -264,7 +246,7 @@ impl ser::SerializeTuple for &mut Serializer { } // Same thing but for tuple structs. -impl ser::SerializeTupleStruct for &mut Serializer { +impl ser::SerializeTupleStruct for &mut Serializer { type Ok = (); type Error = SerializerError; @@ -289,7 +271,7 @@ impl ser::SerializeTupleStruct for &mut Serializer { // // So the `end` method in this impl is responsible for closing both the `]` and // the `}`. -impl ser::SerializeTupleVariant for &mut Serializer { +impl ser::SerializeTupleVariant for &mut Serializer { type Ok = (); type Error = SerializerError; @@ -313,7 +295,7 @@ impl ser::SerializeTupleVariant for &mut Serializer { // `serialize_entry` method allows serializers to optimize for the case where // key and value are both available simultaneously. In JSON it doesn't make a // difference so the default behavior for `serialize_entry` is fine. -impl ser::SerializeMap for &mut Serializer { +impl ser::SerializeMap for &mut Serializer { type Ok = (); type Error = SerializerError; @@ -349,7 +331,7 @@ impl ser::SerializeMap for &mut Serializer { // Structs are like maps in which the keys are constrained to be compile-time // constant strings. -impl ser::SerializeStruct for &mut Serializer { +impl ser::SerializeStruct for &mut Serializer { type Ok = (); type Error = SerializerError; @@ -372,7 +354,7 @@ impl ser::SerializeStruct for &mut Serializer { // Similar to `SerializeTupleVariant`, here the `end` method is responsible for // closing both of the curly braces opened by `serialize_struct_variant`. -impl ser::SerializeStructVariant for &mut Serializer { +impl ser::SerializeStructVariant for &mut Serializer { type Ok = (); type Error = SerializerError; diff --git a/pumpkin-protocol/src/client/config/c_cookie_request.rs b/pumpkin-protocol/src/client/config/c_cookie_request.rs index 08bdcedb..71fb9aca 100644 --- a/pumpkin-protocol/src/client/config/c_cookie_request.rs +++ b/pumpkin-protocol/src/client/config/c_cookie_request.rs @@ -1,6 +1,6 @@ use pumpkin_macros::client_packet; -use crate::Identifier; +use crate::codec::identifier::Identifier; #[derive(serde::Serialize)] #[client_packet("config:cookie_request")] diff --git a/pumpkin-protocol/src/client/config/c_known_packs.rs b/pumpkin-protocol/src/client/config/c_known_packs.rs index 467143e2..7622b93e 100644 --- a/pumpkin-protocol/src/client/config/c_known_packs.rs +++ b/pumpkin-protocol/src/client/config/c_known_packs.rs @@ -1,4 +1,4 @@ -use bytes::BytesMut; +use bytes::BufMut; use pumpkin_macros::client_packet; use crate::{bytebuf::ByteBufMut, ClientPacket, KnownPack}; @@ -15,7 +15,7 @@ impl<'a> CKnownPacks<'a> { } impl ClientPacket for CKnownPacks<'_> { - fn write(&self, bytebuf: &mut BytesMut) { + fn write(&self, bytebuf: &mut impl BufMut) { bytebuf.put_list::(self.known_packs, |p, v| { p.put_string(v.namespace); p.put_string(v.id); diff --git a/pumpkin-protocol/src/client/config/c_registry_data.rs b/pumpkin-protocol/src/client/config/c_registry_data.rs index 001769d5..5a04e682 100644 --- a/pumpkin-protocol/src/client/config/c_registry_data.rs +++ b/pumpkin-protocol/src/client/config/c_registry_data.rs @@ -1,16 +1,16 @@ use bytes::{BufMut, BytesMut}; use pumpkin_macros::client_packet; -use crate::{bytebuf::ByteBufMut, ClientPacket}; +use crate::{bytebuf::ByteBufMut, codec::identifier::Identifier, ClientPacket}; #[client_packet("config:registry_data")] pub struct CRegistryData<'a> { - registry_id: &'a str, - entries: &'a [RegistryEntry<'a>], + registry_id: &'a Identifier, + entries: &'a [RegistryEntry], } impl<'a> CRegistryData<'a> { - pub fn new(registry_id: &'a str, entries: &'a [RegistryEntry]) -> Self { + pub fn new(registry_id: &'a Identifier, entries: &'a [RegistryEntry]) -> Self { Self { registry_id, entries, @@ -18,18 +18,17 @@ impl<'a> CRegistryData<'a> { } } -pub struct RegistryEntry<'a> { - pub entry_id: &'a str, - pub data: BytesMut, +pub struct RegistryEntry { + pub entry_id: Identifier, + pub data: Option, } impl ClientPacket for CRegistryData<'_> { - fn write(&self, bytebuf: &mut BytesMut) { - bytebuf.put_string(self.registry_id); + fn write(&self, bytebuf: &mut impl BufMut) { + bytebuf.put_identifier(self.registry_id); bytebuf.put_list::(self.entries, |p, v| { - p.put_string(v.entry_id); - p.put_bool(!v.data.is_empty()); - p.put_slice(&v.data); + p.put_identifier(&v.entry_id); + p.put_option(&v.data, |p, v| p.put_slice(v)); }); } } diff --git a/pumpkin-protocol/src/client/config/c_store_cookie.rs b/pumpkin-protocol/src/client/config/c_store_cookie.rs index 511bdd0d..0334df2d 100644 --- a/pumpkin-protocol/src/client/config/c_store_cookie.rs +++ b/pumpkin-protocol/src/client/config/c_store_cookie.rs @@ -1,4 +1,4 @@ -use crate::{Identifier, VarInt}; +use crate::{codec::identifier::Identifier, VarInt}; use pumpkin_macros::client_packet; #[derive(serde::Serialize)] diff --git a/pumpkin-protocol/src/client/login/c_cookie_request.rs b/pumpkin-protocol/src/client/login/c_cookie_request.rs index df592625..e1749fac 100644 --- a/pumpkin-protocol/src/client/login/c_cookie_request.rs +++ b/pumpkin-protocol/src/client/login/c_cookie_request.rs @@ -1,7 +1,8 @@ -use crate::Identifier; use pumpkin_macros::client_packet; use serde::Serialize; +use crate::codec::identifier::Identifier; + #[derive(Serialize)] #[client_packet("login:cookie_request")] /// Requests a cookie that was previously stored. diff --git a/pumpkin-protocol/src/client/login/c_login_success.rs b/pumpkin-protocol/src/client/login/c_login_success.rs index 8c6f311a..290ca4c2 100644 --- a/pumpkin-protocol/src/client/login/c_login_success.rs +++ b/pumpkin-protocol/src/client/login/c_login_success.rs @@ -1,4 +1,4 @@ -use bytes::BytesMut; +use bytes::BufMut; use pumpkin_macros::client_packet; use crate::{bytebuf::ByteBufMut, ClientPacket, Property}; @@ -21,7 +21,7 @@ impl<'a> CLoginSuccess<'a> { } impl ClientPacket for CLoginSuccess<'_> { - fn write(&self, bytebuf: &mut BytesMut) { + fn write(&self, bytebuf: &mut impl BufMut) { bytebuf.put_uuid(self.uuid); bytebuf.put_string(self.username); bytebuf.put_list::(self.properties, |p, v| { diff --git a/pumpkin-protocol/src/client/play/c_boss_event.rs b/pumpkin-protocol/src/client/play/c_boss_event.rs index 449f18e1..e5b2292d 100644 --- a/pumpkin-protocol/src/client/play/c_boss_event.rs +++ b/pumpkin-protocol/src/client/play/c_boss_event.rs @@ -1,7 +1,7 @@ use crate::bytebuf::ByteBufMut; use crate::client::play::bossevent_action::BosseventAction; use crate::{ClientPacket, VarInt}; -use bytes::{BufMut, BytesMut}; +use bytes::BufMut; use pumpkin_macros::client_packet; #[client_packet("play:boss_event")] @@ -17,7 +17,7 @@ impl<'a> CBossEvent<'a> { } impl ClientPacket for CBossEvent<'_> { - fn write(&self, bytebuf: &mut BytesMut) { + fn write(&self, bytebuf: &mut impl BufMut) { bytebuf.put_uuid(&self.uuid); let action = &self.action; match action { diff --git a/pumpkin-protocol/src/client/play/c_chunk_data.rs b/pumpkin-protocol/src/client/play/c_chunk_data.rs index f655c00c..1356508f 100644 --- a/pumpkin-protocol/src/client/play/c_chunk_data.rs +++ b/pumpkin-protocol/src/client/play/c_chunk_data.rs @@ -1,4 +1,4 @@ -use crate::{bytebuf::ByteBufMut, BitSet, ClientPacket, VarInt}; +use crate::{bytebuf::ByteBufMut, codec::bit_set::BitSet, ClientPacket, VarInt}; use bytes::{BufMut, BytesMut}; use pumpkin_macros::client_packet; @@ -8,7 +8,7 @@ use pumpkin_world::{chunk::ChunkData, DIRECT_PALETTE_BITS}; pub struct CChunkData<'a>(pub &'a ChunkData); impl ClientPacket for CChunkData<'_> { - fn write(&self, buf: &mut BytesMut) { + fn write(&self, buf: &mut impl BufMut) { // Chunk X buf.put_i32(self.0.position.x); // Chunk Z @@ -113,13 +113,13 @@ impl ClientPacket for CChunkData<'_> { // Sky Light Mask // All of the chunks, this is not optimal and uses way more data than needed but will be // overhauled with full lighting system. - buf.put_bit_set(&BitSet(VarInt(1), &[0b01111111111111111111111110])); + buf.put_bit_set(&BitSet(VarInt(1), vec![0b01111111111111111111111110])); // Block Light Mask - buf.put_bit_set(&BitSet(VarInt(1), &[0])); + buf.put_bit_set(&BitSet(VarInt(1), vec![0])); // Empty Sky Light Mask - buf.put_bit_set(&BitSet(VarInt(1), &[0b0])); + buf.put_bit_set(&BitSet(VarInt(1), vec![0b0])); // Empty Block Light Mask - buf.put_bit_set(&BitSet(VarInt(1), &[0])); + buf.put_bit_set(&BitSet(VarInt(1), vec![0])); buf.put_var_int(&VarInt(self.0.blocks.subchunks_len() as i32)); self.0.blocks.iter_subchunks().for_each(|chunk| { diff --git a/pumpkin-protocol/src/client/play/c_command_suggestions.rs b/pumpkin-protocol/src/client/play/c_command_suggestions.rs index d3592ce3..25ae6683 100644 --- a/pumpkin-protocol/src/client/play/c_command_suggestions.rs +++ b/pumpkin-protocol/src/client/play/c_command_suggestions.rs @@ -1,4 +1,4 @@ -use bytes::{BufMut, BytesMut}; +use bytes::BufMut; use pumpkin_core::text::TextComponent; use pumpkin_macros::client_packet; @@ -29,7 +29,7 @@ impl<'a> CCommandSuggestions<'a> { } impl ClientPacket for CCommandSuggestions<'_> { - fn write(&self, bytebuf: &mut BytesMut) { + fn write(&self, bytebuf: &mut impl BufMut) { bytebuf.put_var_int(&self.id); bytebuf.put_var_int(&self.start); bytebuf.put_var_int(&self.length); diff --git a/pumpkin-protocol/src/client/play/c_commands.rs b/pumpkin-protocol/src/client/play/c_commands.rs index d3b54d6f..264a5133 100644 --- a/pumpkin-protocol/src/client/play/c_commands.rs +++ b/pumpkin-protocol/src/client/play/c_commands.rs @@ -1,4 +1,4 @@ -use bytes::{BufMut, BytesMut}; +use bytes::BufMut; use pumpkin_macros::client_packet; use crate::{bytebuf::ByteBufMut, ClientPacket, VarInt}; @@ -19,7 +19,7 @@ impl<'a> CCommands<'a> { } impl ClientPacket for CCommands<'_> { - fn write(&self, bytebuf: &mut BytesMut) { + fn write(&self, bytebuf: &mut impl BufMut) { bytebuf.put_list(&self.nodes, |bytebuf, node: &ProtoNode| { node.write_to(bytebuf) }); @@ -52,7 +52,7 @@ impl ProtoNode<'_> { const FLAG_HAS_REDIRECT: u8 = 8; const FLAG_HAS_SUGGESTION_TYPE: u8 = 16; - pub fn write_to(&self, bytebuf: &mut BytesMut) { + pub fn write_to(&self, bytebuf: &mut impl BufMut) { // flags let flags = match self.node_type { ProtoNodeType::Root => 0, @@ -188,7 +188,7 @@ impl ProtoCmdArgParser<'_> { pub const SCORE_HOLDER_FLAG_ALLOW_MULTIPLE: u8 = 1; - pub fn write_to_buffer(&self, bytebuf: &mut BytesMut) { + pub fn write_to_buffer(&self, bytebuf: &mut impl BufMut) { match self { Self::Bool => bytebuf.put_var_int(&0.into()), Self::Float { min, max } => Self::write_number_arg(&1.into(), *min, *max, bytebuf), @@ -270,7 +270,7 @@ impl ProtoCmdArgParser<'_> { id: &VarInt, min: Option, max: Option, - bytebuf: &mut BytesMut, + bytebuf: &mut impl BufMut, ) { let mut flags: u8 = 0; if min.is_some() { @@ -291,13 +291,13 @@ impl ProtoCmdArgParser<'_> { } } - fn write_with_flags(id: &VarInt, flags: u8, bytebuf: &mut BytesMut) { + fn write_with_flags(id: &VarInt, flags: u8, bytebuf: &mut impl BufMut) { bytebuf.put_var_int(id); bytebuf.put_u8(flags); } - fn write_with_identifier(id: &VarInt, extra_identifier: &str, bytebuf: &mut BytesMut) { + fn write_with_identifier(id: &VarInt, extra_identifier: &str, bytebuf: &mut impl BufMut) { bytebuf.put_var_int(id); bytebuf.put_string(extra_identifier); @@ -313,29 +313,29 @@ pub enum StringProtoArgBehavior { } trait NumberCmdArg { - fn write(self, bytebuf: &mut BytesMut); + fn write(self, bytebuf: &mut impl BufMut); } impl NumberCmdArg for f32 { - fn write(self, bytebuf: &mut BytesMut) { + fn write(self, bytebuf: &mut impl BufMut) { bytebuf.put_f32(self); } } impl NumberCmdArg for f64 { - fn write(self, bytebuf: &mut BytesMut) { + fn write(self, bytebuf: &mut impl BufMut) { bytebuf.put_f64(self); } } impl NumberCmdArg for i32 { - fn write(self, bytebuf: &mut BytesMut) { + fn write(self, bytebuf: &mut impl BufMut) { bytebuf.put_i32(self); } } impl NumberCmdArg for i64 { - fn write(self, bytebuf: &mut BytesMut) { + fn write(self, bytebuf: &mut impl BufMut) { bytebuf.put_i64(self); } } diff --git a/pumpkin-protocol/src/client/play/c_cookie_request.rs b/pumpkin-protocol/src/client/play/c_cookie_request.rs index 58d49494..9b569cc0 100644 --- a/pumpkin-protocol/src/client/play/c_cookie_request.rs +++ b/pumpkin-protocol/src/client/play/c_cookie_request.rs @@ -1,7 +1,8 @@ -use crate::Identifier; use pumpkin_macros::client_packet; use serde::Serialize; +use crate::codec::identifier::Identifier; + #[derive(Serialize)] #[client_packet("play:cookie_request")] /// Requests a cookie that was previously stored. diff --git a/pumpkin-protocol/src/client/play/c_entity_sound_effect.rs b/pumpkin-protocol/src/client/play/c_entity_sound_effect.rs index 37848de8..27de764f 100644 --- a/pumpkin-protocol/src/client/play/c_entity_sound_effect.rs +++ b/pumpkin-protocol/src/client/play/c_entity_sound_effect.rs @@ -1,4 +1,4 @@ -use bytes::{BufMut, BytesMut}; +use bytes::BufMut; use pumpkin_macros::client_packet; use crate::{bytebuf::ByteBufMut, ClientPacket, IDOrSoundEvent, SoundCategory, SoundEvent, VarInt}; @@ -39,11 +39,11 @@ impl CEntitySoundEffect { } impl ClientPacket for CEntitySoundEffect { - fn write(&self, bytebuf: &mut BytesMut) { + fn write(&self, bytebuf: &mut impl BufMut) { bytebuf.put_var_int(&self.sound_event.id); if self.sound_event.id.0 == 0 { if let Some(test) = &self.sound_event.sound_event { - bytebuf.put_string(&test.sound_name); + bytebuf.put_identifier(&test.sound_name); bytebuf.put_option(&test.range, |p, v| { p.put_f32(*v); diff --git a/pumpkin-protocol/src/client/play/c_initialize_world_border.rs b/pumpkin-protocol/src/client/play/c_initialize_world_border.rs index f4d6663a..f2ab72f6 100644 --- a/pumpkin-protocol/src/client/play/c_initialize_world_border.rs +++ b/pumpkin-protocol/src/client/play/c_initialize_world_border.rs @@ -1,7 +1,7 @@ use pumpkin_macros::client_packet; use serde::Serialize; -use crate::{VarInt, VarLong}; +use crate::{codec::var_long::VarLong, VarInt}; #[derive(Serialize)] #[client_packet("play:initialize_border")] diff --git a/pumpkin-protocol/src/client/play/c_login.rs b/pumpkin-protocol/src/client/play/c_login.rs index 12a594f8..ec6e23bb 100644 --- a/pumpkin-protocol/src/client/play/c_login.rs +++ b/pumpkin-protocol/src/client/play/c_login.rs @@ -3,7 +3,7 @@ use pumpkin_core::math::position::WorldPosition; use pumpkin_macros::client_packet; use serde::Serialize; -use crate::VarInt; +use crate::{codec::identifier::Identifier, VarInt}; #[derive(Serialize)] #[client_packet("play:login")] @@ -11,7 +11,7 @@ pub struct CLogin<'a> { entity_id: i32, is_hardcore: bool, dimension_count: VarInt, - dimension_names: &'a [&'a str], + dimension_names: &'a [Identifier], max_players: VarInt, view_distance: VarInt, simulated_distance: VarInt, @@ -20,13 +20,13 @@ pub struct CLogin<'a> { limited_crafting: bool, // Spawn Info dimension_type: VarInt, - dimension_name: &'a str, + dimension_name: Identifier, hashed_seed: i64, game_mode: u8, previous_gamemode: i8, debug: bool, is_flat: bool, - death_dimension_name: Option<(&'a str, WorldPosition)>, + death_dimension_name: Option<(Identifier, WorldPosition)>, portal_cooldown: VarInt, sealevel: VarInt, enforce_secure_chat: bool, @@ -37,7 +37,7 @@ impl<'a> CLogin<'a> { pub fn new( entity_id: i32, is_hardcore: bool, - dimension_names: &'a [&'a str], + dimension_names: &'a [Identifier], max_players: VarInt, view_distance: VarInt, simulated_distance: VarInt, @@ -45,13 +45,13 @@ impl<'a> CLogin<'a> { enabled_respawn_screen: bool, limited_crafting: bool, dimension_type: VarInt, - dimension_name: &'a str, + dimension_name: Identifier, hashed_seed: i64, game_mode: u8, previous_gamemode: i8, debug: bool, is_flat: bool, - death_dimension_name: Option<(&'a str, WorldPosition)>, + death_dimension_name: Option<(Identifier, WorldPosition)>, portal_cooldown: VarInt, sealevel: VarInt, enforce_secure_chat: bool, diff --git a/pumpkin-protocol/src/client/play/c_player_chat_message.rs b/pumpkin-protocol/src/client/play/c_player_chat_message.rs index b774a2f2..0db6c3df 100644 --- a/pumpkin-protocol/src/client/play/c_player_chat_message.rs +++ b/pumpkin-protocol/src/client/play/c_player_chat_message.rs @@ -3,7 +3,7 @@ use pumpkin_core::text::TextComponent; use pumpkin_macros::client_packet; use serde::Serialize; -use crate::{BitSet, VarInt}; +use crate::{codec::bit_set::BitSet, VarInt}; #[derive(Serialize)] #[client_packet("play:player_chat")] @@ -18,7 +18,7 @@ pub struct CPlayerChatMessage<'a> { previous_messages_count: VarInt, previous_messages: &'a [PreviousMessage<'a>], // max 20 unsigned_content: Option>, - filter_type: FilterType<'a>, + filter_type: FilterType, chat_type: VarInt, sender_name: TextComponent<'a>, target_name: Option>, @@ -35,7 +35,7 @@ impl<'a> CPlayerChatMessage<'a> { salt: i64, previous_messages: &'a [PreviousMessage<'a>], unsigned_content: Option>, - filter_type: FilterType<'a>, + filter_type: FilterType, chat_type: VarInt, sender_name: TextComponent<'a>, target_name: Option>, @@ -66,11 +66,11 @@ pub struct PreviousMessage<'a> { #[derive(Serialize)] #[repr(i32)] -pub enum FilterType<'a> { +pub enum FilterType { /// Message is not filtered at all PassThrough = 0, /// Message is fully filtered FullyFiltered = 1, /// Only some characters in the message are filtered - PartiallyFiltered(BitSet<'a>) = 2, + PartiallyFiltered(BitSet) = 2, } 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 5626b387..72d912cb 100644 --- a/pumpkin-protocol/src/client/play/c_player_info_update.rs +++ b/pumpkin-protocol/src/client/play/c_player_info_update.rs @@ -1,4 +1,4 @@ -use bytes::{BufMut, BytesMut}; +use bytes::BufMut; use pumpkin_macros::client_packet; use crate::{bytebuf::ByteBufMut, ClientPacket, Property}; @@ -23,7 +23,7 @@ impl<'a> CPlayerInfoUpdate<'a> { } impl ClientPacket for CPlayerInfoUpdate<'_> { - fn write(&self, bytebuf: &mut BytesMut) { + fn write(&self, bytebuf: &mut impl BufMut) { bytebuf.put_i8(self.actions); bytebuf.put_list::(self.players, |p, v| { p.put_uuid(&v.uuid); diff --git a/pumpkin-protocol/src/client/play/c_player_position.rs b/pumpkin-protocol/src/client/play/c_player_position.rs index 96a6bc59..287c1b2f 100644 --- a/pumpkin-protocol/src/client/play/c_player_position.rs +++ b/pumpkin-protocol/src/client/play/c_player_position.rs @@ -1,4 +1,4 @@ -use bytes::{BufMut, BytesMut}; +use bytes::BufMut; use pumpkin_core::math::vector3::Vector3; use pumpkin_macros::client_packet; @@ -35,7 +35,7 @@ impl<'a> CPlayerPosition<'a> { } impl ClientPacket for CPlayerPosition<'_> { - fn write(&self, bytebuf: &mut BytesMut) { + fn write(&self, bytebuf: &mut impl BufMut) { bytebuf.put_var_int(&self.teleport_id); bytebuf.put_f64(self.position.x); bytebuf.put_f64(self.position.y); diff --git a/pumpkin-protocol/src/client/play/c_respawn.rs b/pumpkin-protocol/src/client/play/c_respawn.rs index b892d53e..9d68b059 100644 --- a/pumpkin-protocol/src/client/play/c_respawn.rs +++ b/pumpkin-protocol/src/client/play/c_respawn.rs @@ -2,35 +2,35 @@ use pumpkin_core::math::position::WorldPosition; use pumpkin_macros::client_packet; use serde::Serialize; -use crate::VarInt; +use crate::{codec::identifier::Identifier, VarInt}; #[derive(Serialize)] #[client_packet("play:respawn")] -pub struct CRespawn<'a> { +pub struct CRespawn { dimension_type: VarInt, - dimension_name: &'a str, + dimension_name: Identifier, hashed_seed: i64, game_mode: u8, previous_gamemode: i8, debug: bool, is_flat: bool, - death_dimension_name: Option<(&'a str, WorldPosition)>, + death_dimension_name: Option<(Identifier, WorldPosition)>, portal_cooldown: VarInt, sealevel: VarInt, data_kept: u8, } -impl<'a> CRespawn<'a> { +impl CRespawn { #[expect(clippy::too_many_arguments)] pub fn new( dimension_type: VarInt, - dimension_name: &'a str, + dimension_name: Identifier, hashed_seed: i64, game_mode: u8, previous_gamemode: i8, debug: bool, is_flat: bool, - death_dimension_name: Option<(&'a str, WorldPosition)>, + death_dimension_name: Option<(Identifier, WorldPosition)>, portal_cooldown: VarInt, sealevel: VarInt, data_kept: u8, diff --git a/pumpkin-protocol/src/client/play/c_set_border_lerp_size.rs b/pumpkin-protocol/src/client/play/c_set_border_lerp_size.rs index 0d15ab9b..5f8861a7 100644 --- a/pumpkin-protocol/src/client/play/c_set_border_lerp_size.rs +++ b/pumpkin-protocol/src/client/play/c_set_border_lerp_size.rs @@ -1,7 +1,7 @@ use pumpkin_macros::client_packet; use serde::Serialize; -use crate::VarLong; +use crate::codec::var_long::VarLong; #[derive(Serialize)] #[client_packet("play:set_border_lerp_size")] diff --git a/pumpkin-protocol/src/client/play/c_sound_effect.rs b/pumpkin-protocol/src/client/play/c_sound_effect.rs index d2f7f344..d34af971 100644 --- a/pumpkin-protocol/src/client/play/c_sound_effect.rs +++ b/pumpkin-protocol/src/client/play/c_sound_effect.rs @@ -1,4 +1,4 @@ -use bytes::{BufMut, BytesMut}; +use bytes::BufMut; use pumpkin_macros::client_packet; use crate::{bytebuf::ByteBufMut, ClientPacket, IDOrSoundEvent, SoundCategory, SoundEvent, VarInt}; @@ -45,11 +45,11 @@ impl CSoundEffect { } impl ClientPacket for CSoundEffect { - fn write(&self, bytebuf: &mut BytesMut) { + fn write(&self, bytebuf: &mut impl BufMut) { bytebuf.put_var_int(&self.sound_event.id); if self.sound_event.id.0 == 0 { if let Some(test) = &self.sound_event.sound_event { - bytebuf.put_string(&test.sound_name); + bytebuf.put_identifier(&test.sound_name); bytebuf.put_option(&test.range, |p, v| { p.put_f32(*v); diff --git a/pumpkin-protocol/src/client/play/c_store_cookie.rs b/pumpkin-protocol/src/client/play/c_store_cookie.rs index b9fc02ce..da715f22 100644 --- a/pumpkin-protocol/src/client/play/c_store_cookie.rs +++ b/pumpkin-protocol/src/client/play/c_store_cookie.rs @@ -1,4 +1,4 @@ -use crate::{Identifier, VarInt}; +use crate::{codec::identifier::Identifier, VarInt}; use pumpkin_macros::client_packet; use serde::Serialize; diff --git a/pumpkin-protocol/src/client/play/c_teleport_entity.rs b/pumpkin-protocol/src/client/play/c_teleport_entity.rs index 02029373..2ec00492 100644 --- a/pumpkin-protocol/src/client/play/c_teleport_entity.rs +++ b/pumpkin-protocol/src/client/play/c_teleport_entity.rs @@ -1,4 +1,4 @@ -use bytes::{BufMut, BytesMut}; +use bytes::BufMut; use pumpkin_core::math::vector3::Vector3; use pumpkin_macros::client_packet; @@ -38,7 +38,7 @@ impl<'a> CTeleportEntity<'a> { } impl ClientPacket for CTeleportEntity<'_> { - fn write(&self, bytebuf: &mut BytesMut) { + fn write(&self, bytebuf: &mut impl BufMut) { bytebuf.put_var_int(&self.entity_id); bytebuf.put_f64(self.position.x); bytebuf.put_f64(self.position.y); diff --git a/pumpkin-protocol/src/client/play/c_update_objectives.rs b/pumpkin-protocol/src/client/play/c_update_objectives.rs index 12fcefc3..41c45ff5 100644 --- a/pumpkin-protocol/src/client/play/c_update_objectives.rs +++ b/pumpkin-protocol/src/client/play/c_update_objectives.rs @@ -1,4 +1,4 @@ -use bytes::{BufMut, BytesMut}; +use bytes::BufMut; use pumpkin_core::text::TextComponent; use pumpkin_macros::client_packet; @@ -32,7 +32,7 @@ impl<'a> CUpdateObjectives<'a> { } impl ClientPacket for CUpdateObjectives<'_> { - fn write(&self, bytebuf: &mut BytesMut) { + fn write(&self, bytebuf: &mut impl BufMut) { bytebuf.put_string(self.objective_name); bytebuf.put_u8(self.mode); if self.mode == 0 || self.mode == 2 { diff --git a/pumpkin-protocol/src/lib.rs b/pumpkin-protocol/src/lib.rs index f5b5db46..85a5311e 100644 --- a/pumpkin-protocol/src/lib.rs +++ b/pumpkin-protocol/src/lib.rs @@ -1,48 +1,28 @@ use std::num::NonZeroU16; use bytebuf::{packet_id::Packet, ReadingError}; -use bytes::{Bytes, BytesMut}; +use bytes::{Buf, BufMut, Bytes}; +use codec::{identifier::Identifier, var_int::VarInt}; use pumpkin_core::text::{style::Style, TextComponent}; -use serde::{Deserialize, Serialize, Serializer}; +use serde::{Deserialize, Serialize}; pub mod bytebuf; pub mod client; +pub mod codec; pub mod packet_decoder; pub mod packet_encoder; pub mod query; pub mod server; pub mod slot; -mod var_int; -pub use var_int::*; - -mod var_long; -pub use var_long::*; - /// To current Minecraft protocol /// Don't forget to change this when porting pub const CURRENT_MC_PROTOCOL: NonZeroU16 = unsafe { NonZeroU16::new_unchecked(769) }; pub const MAX_PACKET_SIZE: i32 = 2097152; -/// usally uses a namespace like "minecraft:thing" -pub type Identifier = String; -pub type VarIntType = i32; -pub type VarLongType = i64; pub type FixedBitSet = bytes::Bytes; -pub struct BitSet<'a>(pub VarInt, pub &'a [i64]); - -impl Serialize for BitSet<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - // TODO: make this right - (&self.0, self.1).serialize(serializer) - } -} - #[derive(Debug, PartialEq, Clone, Copy)] pub enum ConnectionState { HandShake, @@ -89,7 +69,7 @@ pub struct IDOrSoundEvent { #[derive(Serialize)] pub struct SoundEvent { - pub sound_name: String, + pub sound_name: Identifier, pub range: Option, } @@ -99,11 +79,11 @@ pub struct RawPacket { } pub trait ClientPacket: Packet { - fn write(&self, bytebuf: &mut BytesMut); + fn write(&self, bytebuf: &mut impl BufMut); } pub trait ServerPacket: Packet + Sized { - fn read(bytebuf: &mut Bytes) -> Result; + fn read(bytebuf: &mut impl Buf) -> Result; } #[derive(Serialize)] diff --git a/pumpkin-protocol/src/packet_decoder.rs b/pumpkin-protocol/src/packet_decoder.rs index badd34b7..8c267f94 100644 --- a/pumpkin-protocol/src/packet_decoder.rs +++ b/pumpkin-protocol/src/packet_decoder.rs @@ -3,7 +3,10 @@ use bytes::{Buf, Bytes, BytesMut}; use libdeflater::{DecompressionError, Decompressor}; use thiserror::Error; -use crate::{RawPacket, VarInt, VarIntDecodeError, MAX_PACKET_SIZE}; +use crate::{ + codec::{Codec, DecodeError}, + RawPacket, VarInt, MAX_PACKET_SIZE, +}; type Cipher = cfb8::Decryptor; @@ -38,8 +41,8 @@ impl PacketDecoder { let packet_len = match VarInt::decode(&mut r) { Ok(len) => len, - Err(VarIntDecodeError::Incomplete) => return Ok(None), - Err(VarIntDecodeError::TooLarge) => Err(PacketDecodeError::MalformedLength)?, + Err(DecodeError::Incomplete) => return Ok(None), + Err(DecodeError::TooLarge) => Err(PacketDecodeError::MalformedLength)?, }; let packet_len = packet_len.0; diff --git a/pumpkin-protocol/src/packet_encoder.rs b/pumpkin-protocol/src/packet_encoder.rs index a329ee08..d8bea1b7 100644 --- a/pumpkin-protocol/src/packet_encoder.rs +++ b/pumpkin-protocol/src/packet_encoder.rs @@ -5,7 +5,7 @@ use thiserror::Error; use libdeflater::{CompressionLvl, Compressor}; -use crate::{ClientPacket, VarInt, MAX_PACKET_SIZE}; +use crate::{codec::Codec, ClientPacket, VarInt, MAX_PACKET_SIZE}; type Cipher = cfb8::Encryptor; @@ -221,9 +221,8 @@ pub enum PacketEncodeError { #[cfg(test)] mod tests { use super::*; - use crate::bytebuf::packet_id::Packet; use crate::client::status::CStatusResponse; - use crate::VarIntDecodeError; + use crate::{bytebuf::packet_id::Packet, codec::DecodeError}; use aes::Aes128; use cfb8::cipher::AsyncStreamCipher; use cfb8::Decryptor as Cfb8Decryptor; @@ -247,7 +246,7 @@ mod tests { } /// Helper function to decode a VarInt from bytes - fn decode_varint(buffer: &mut &[u8]) -> Result { + fn decode_varint(buffer: &mut &[u8]) -> Result { VarInt::decode(buffer).map(|varint| varint.0) } diff --git a/pumpkin-protocol/src/server/config/s_cookie_response.rs b/pumpkin-protocol/src/server/config/s_cookie_response.rs index ec3f4da0..0a2fc03d 100644 --- a/pumpkin-protocol/src/server/config/s_cookie_response.rs +++ b/pumpkin-protocol/src/server/config/s_cookie_response.rs @@ -1,10 +1,11 @@ -use bytes::Bytes; +use bytes::Buf; use pumpkin_macros::server_packet; use serde::de; use crate::{ bytebuf::{ByteBuf, ReadingError}, - Identifier, ServerPacket, VarInt, + codec::identifier::Identifier, + ServerPacket, VarInt, }; #[server_packet("config:cookie_response")] @@ -20,8 +21,8 @@ pub struct SCookieResponse { const MAX_PAYLOAD_SIZE: i32 = 5120; impl ServerPacket for SCookieResponse { - fn read(bytebuf: &mut Bytes) -> Result { - let key = bytebuf.try_get_string()?; + fn read(bytebuf: &mut impl Buf) -> Result { + let key = bytebuf.try_get_identifer()?; let has_payload = bytebuf.try_get_bool()?; if !has_payload { diff --git a/pumpkin-protocol/src/server/config/s_plugin_message.rs b/pumpkin-protocol/src/server/config/s_plugin_message.rs index 25918761..d9e0abae 100644 --- a/pumpkin-protocol/src/server/config/s_plugin_message.rs +++ b/pumpkin-protocol/src/server/config/s_plugin_message.rs @@ -1,9 +1,10 @@ -use bytes::Bytes; +use bytes::Buf; use pumpkin_macros::server_packet; use crate::{ bytebuf::{ByteBuf, ReadingError}, - Identifier, ServerPacket, + codec::identifier::Identifier, + ServerPacket, }; #[server_packet("config:custom_payload")] @@ -13,10 +14,10 @@ pub struct SPluginMessage { } impl ServerPacket for SPluginMessage { - fn read(bytebuf: &mut Bytes) -> Result { + fn read(bytebuf: &mut impl Buf) -> Result { Ok(Self { - channel: bytebuf.try_get_string()?, - data: bytebuf.split_to(bytebuf.len()), + channel: bytebuf.try_get_identifer()?, + data: bytebuf.try_copy_to_bytes(bytebuf.remaining())?, }) } } diff --git a/pumpkin-protocol/src/server/handshake/mod.rs b/pumpkin-protocol/src/server/handshake/mod.rs index 0e8a15ae..9436e569 100644 --- a/pumpkin-protocol/src/server/handshake/mod.rs +++ b/pumpkin-protocol/src/server/handshake/mod.rs @@ -1,4 +1,4 @@ -use bytes::Bytes; +use bytes::Buf; use pumpkin_macros::server_packet; use crate::{ @@ -15,7 +15,7 @@ pub struct SHandShake { } impl ServerPacket for SHandShake { - fn read(bytebuf: &mut Bytes) -> Result { + fn read(bytebuf: &mut impl Buf) -> Result { Ok(Self { protocol_version: bytebuf.try_get_var_int()?, server_address: bytebuf.try_get_string_len(255)?, diff --git a/pumpkin-protocol/src/server/login/s_cookie_response.rs b/pumpkin-protocol/src/server/login/s_cookie_response.rs index 833ae788..82ed37f0 100644 --- a/pumpkin-protocol/src/server/login/s_cookie_response.rs +++ b/pumpkin-protocol/src/server/login/s_cookie_response.rs @@ -1,8 +1,9 @@ use crate::{ bytebuf::{ByteBuf, ReadingError}, - Identifier, ServerPacket, VarInt, + codec::identifier::Identifier, + ServerPacket, VarInt, }; -use bytes::Bytes; +use bytes::Buf; use pumpkin_macros::server_packet; use serde::de; @@ -19,8 +20,8 @@ pub struct SCookieResponse { const MAX_PAYLOAD_SIZE: i32 = 5120; impl ServerPacket for SCookieResponse { - fn read(bytebuf: &mut Bytes) -> Result { - let key = bytebuf.try_get_string()?; + fn read(bytebuf: &mut impl Buf) -> Result { + let key = bytebuf.try_get_identifer()?; let has_payload = bytebuf.try_get_bool()?; if !has_payload { diff --git a/pumpkin-protocol/src/server/login/s_encryption_response.rs b/pumpkin-protocol/src/server/login/s_encryption_response.rs index 300ada9c..f094231d 100644 --- a/pumpkin-protocol/src/server/login/s_encryption_response.rs +++ b/pumpkin-protocol/src/server/login/s_encryption_response.rs @@ -1,4 +1,4 @@ -use bytes::Bytes; +use bytes::Buf; use pumpkin_macros::server_packet; use crate::{ @@ -15,7 +15,7 @@ pub struct SEncryptionResponse { } impl ServerPacket for SEncryptionResponse { - fn read(bytebuf: &mut Bytes) -> Result { + fn read(bytebuf: &mut impl Buf) -> Result { let shared_secret_length = bytebuf.try_get_var_int()?; let shared_secret = bytebuf.try_copy_to_bytes(shared_secret_length.0 as usize)?; let verify_token_length = bytebuf.try_get_var_int()?; diff --git a/pumpkin-protocol/src/server/login/s_login_start.rs b/pumpkin-protocol/src/server/login/s_login_start.rs index 44347dc7..88bda187 100644 --- a/pumpkin-protocol/src/server/login/s_login_start.rs +++ b/pumpkin-protocol/src/server/login/s_login_start.rs @@ -1,4 +1,4 @@ -use bytes::Bytes; +use bytes::Buf; use pumpkin_macros::server_packet; use crate::{ @@ -13,7 +13,7 @@ pub struct SLoginStart { } impl ServerPacket for SLoginStart { - fn read(bytebuf: &mut Bytes) -> Result { + fn read(bytebuf: &mut impl Buf) -> Result { Ok(Self { name: bytebuf.try_get_string_len(16)?, uuid: bytebuf.try_get_uuid()?, diff --git a/pumpkin-protocol/src/server/login/s_plugin_response.rs b/pumpkin-protocol/src/server/login/s_plugin_response.rs index d96b796e..dd92a1bb 100644 --- a/pumpkin-protocol/src/server/login/s_plugin_response.rs +++ b/pumpkin-protocol/src/server/login/s_plugin_response.rs @@ -2,7 +2,7 @@ use crate::{ bytebuf::{ByteBuf, ReadingError}, ServerPacket, VarInt, }; -use bytes::Bytes; +use bytes::{Buf, Bytes}; use pumpkin_macros::server_packet; #[server_packet("login:custom_query_answer")] @@ -12,10 +12,10 @@ pub struct SLoginPluginResponse { } impl ServerPacket for SLoginPluginResponse { - fn read(bytebuf: &mut Bytes) -> Result { + fn read(bytebuf: &mut impl Buf) -> Result { Ok(Self { message_id: bytebuf.try_get_var_int()?, - data: bytebuf.try_get_option(|v| Ok(v.split_to(v.len())))?, + data: bytebuf.try_get_option(|v| v.try_copy_to_bytes(v.remaining()))?, }) } } diff --git a/pumpkin-protocol/src/server/play/s_chat_message.rs b/pumpkin-protocol/src/server/play/s_chat_message.rs index 9fd65df3..c0049af2 100644 --- a/pumpkin-protocol/src/server/play/s_chat_message.rs +++ b/pumpkin-protocol/src/server/play/s_chat_message.rs @@ -1,4 +1,4 @@ -use bytes::Bytes; +use bytes::{Buf, Bytes}; use pumpkin_macros::server_packet; use crate::{ @@ -19,7 +19,7 @@ pub struct SChatMessage { // TODO impl ServerPacket for SChatMessage { - fn read(bytebuf: &mut Bytes) -> Result { + fn read(bytebuf: &mut impl Buf) -> Result { Ok(Self { message: bytebuf.try_get_string()?, timestamp: bytebuf.try_get_i64()?, diff --git a/pumpkin-protocol/src/server/play/s_cookie_response.rs b/pumpkin-protocol/src/server/play/s_cookie_response.rs index f3127fb4..7779d8ac 100644 --- a/pumpkin-protocol/src/server/play/s_cookie_response.rs +++ b/pumpkin-protocol/src/server/play/s_cookie_response.rs @@ -1,8 +1,9 @@ use crate::{ bytebuf::{ByteBuf, ReadingError}, - Identifier, ServerPacket, VarInt, + codec::identifier::Identifier, + ServerPacket, VarInt, }; -use bytes::Bytes; +use bytes::Buf; use pumpkin_macros::server_packet; use serde::de; @@ -19,8 +20,8 @@ pub struct SCookieResponse { const MAX_PAYLOAD_SIZE: i32 = 5120; impl ServerPacket for SCookieResponse { - fn read(bytebuf: &mut Bytes) -> Result { - let key = bytebuf.try_get_string()?; + fn read(bytebuf: &mut impl Buf) -> Result { + let key = bytebuf.try_get_identifer()?; let has_payload = bytebuf.try_get_bool()?; if !has_payload { diff --git a/pumpkin-protocol/src/server/play/s_interact.rs b/pumpkin-protocol/src/server/play/s_interact.rs index c7371502..a6a3844d 100644 --- a/pumpkin-protocol/src/server/play/s_interact.rs +++ b/pumpkin-protocol/src/server/play/s_interact.rs @@ -1,4 +1,4 @@ -use bytes::Bytes; +use bytes::Buf; use num_derive::FromPrimitive; use num_traits::FromPrimitive; use pumpkin_core::math::vector3::Vector3; @@ -20,7 +20,7 @@ pub struct SInteract { // Great job Mojang ;D impl ServerPacket for SInteract { - fn read(bytebuf: &mut Bytes) -> Result { + fn read(bytebuf: &mut impl Buf) -> Result { let entity_id = bytebuf.try_get_var_int()?; let typ = bytebuf.try_get_var_int()?; let action = ActionType::from_i32(typ.0) diff --git a/pumpkin-protocol/src/server/play/s_player_command.rs b/pumpkin-protocol/src/server/play/s_player_command.rs index 8b2c7055..6a9b65a4 100644 --- a/pumpkin-protocol/src/server/play/s_player_command.rs +++ b/pumpkin-protocol/src/server/play/s_player_command.rs @@ -1,4 +1,4 @@ -use bytes::Bytes; +use bytes::Buf; use num_derive::FromPrimitive; use pumpkin_macros::server_packet; @@ -27,7 +27,7 @@ pub enum Action { } impl ServerPacket for SPlayerCommand { - fn read(bytebuf: &mut Bytes) -> Result { + fn read(bytebuf: &mut impl Buf) -> Result { Ok(Self { entity_id: bytebuf.try_get_var_int()?, action: bytebuf.try_get_var_int()?, diff --git a/pumpkin-protocol/src/var_int.rs b/pumpkin-protocol/src/var_int.rs deleted file mode 100644 index 1401230a..00000000 --- a/pumpkin-protocol/src/var_int.rs +++ /dev/null @@ -1,151 +0,0 @@ -use std::num::NonZeroUsize; - -use bytes::{Buf, BufMut}; -use serde::{ - de::{SeqAccess, Visitor}, - Deserialize, Deserializer, Serialize, Serializer, -}; -use thiserror::Error; - -pub type VarIntType = i32; - -/** - * A variable-length integer type used by the Minecraft network protocol. - */ -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct VarInt(pub VarIntType); - -impl VarInt { - /// The maximum number of bytes a `VarInt` can occupy. - pub const MAX_SIZE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(5) }; - - /// Returns the exact number of bytes this varint will write when - /// [`Encode::encode`] is called, assuming no error occurs. - pub const fn written_size(self) -> usize { - match self.0 { - 0 => 1, - n => (31 - n.leading_zeros() as usize) / 7 + 1, - } - } - - pub fn encode(&self, w: &mut impl BufMut) { - let mut val = self.0; - for _ in 0..Self::MAX_SIZE.get() { - let b: u8 = val as u8 & 0b01111111; - val >>= 7; - w.put_u8(if val == 0 { b } else { b | 0b10000000 }); - if val == 0 { - break; - } - } - } - - pub fn decode(r: &mut impl Buf) -> Result { - let mut val = 0; - for i in 0..Self::MAX_SIZE.get() { - if !r.has_remaining() { - return Err(VarIntDecodeError::Incomplete); - } - let byte = r.get_u8(); - val |= (i32::from(byte) & 0x7F) << (i * 7); - if byte & 0x80 == 0 { - return Ok(VarInt(val)); - } - } - Err(VarIntDecodeError::TooLarge) - } -} - -impl From for VarInt { - fn from(value: i32) -> Self { - 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 - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug, Error)] -pub enum VarIntDecodeError { - #[error("Incomplete VarInt decode")] - Incomplete, - #[error("VarInt is too large")] - TooLarge, -} - -impl Serialize for VarInt { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut value = self.0 as u32; - let mut buf = Vec::new(); - - while value > 0x7F { - buf.put_u8(value as u8 | 0x80); - value >>= 7; - } - - buf.put_u8(value as u8); - - serializer.serialize_bytes(&buf) - } -} - -impl<'de> Deserialize<'de> for VarInt { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct VarIntVisitor; - - impl<'de> Visitor<'de> for VarIntVisitor { - type Value = VarInt; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("a valid VarInt encoded in a byte sequence") - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: SeqAccess<'de>, - { - let mut val = 0; - for i in 0..VarInt::MAX_SIZE.get() { - if let Some(byte) = seq.next_element::()? { - val |= (i32::from(byte) & 0b01111111) << (i * 7); - if byte & 0b10000000 == 0 { - return Ok(VarInt(val)); - } - } else { - break; - } - } - Err(serde::de::Error::custom("VarInt was too large")) - } - } - - deserializer.deserialize_seq(VarIntVisitor) - } -} diff --git a/pumpkin-protocol/src/var_long.rs b/pumpkin-protocol/src/var_long.rs deleted file mode 100644 index 72f5c11e..00000000 --- a/pumpkin-protocol/src/var_long.rs +++ /dev/null @@ -1,152 +0,0 @@ -use std::num::NonZeroUsize; - -use bytes::{Buf, BufMut}; -use serde::{ - de::{self, SeqAccess, Visitor}, - Deserialize, Deserializer, Serialize, Serializer, -}; -use thiserror::Error; - -pub type VarLongType = i64; - -/** - * A variable-length long type used by the Minecraft network protocol. - */ -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct VarLong(pub VarLongType); - -impl VarLong { - /// The maximum number of bytes a `VarLong` - pub const MAX_SIZE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(10) }; - - /// Returns the exact number of bytes this varlong will write when - /// [`Encode::encode`] is called, assuming no error occurs. - pub const fn written_size(self) -> usize { - match self.0 { - 0 => 1, - n => (31 - n.leading_zeros() as usize) / 7 + 1, - } - } - - pub fn encode(&self, w: &mut impl BufMut) { - let mut x = self.0; - for _ in 0..Self::MAX_SIZE.get() { - let byte = (x & 0x7F) as u8; - x >>= 7; - if x == 0 { - w.put_slice(&[byte]); - break; - } - w.put_slice(&[byte | 0x80]); - } - } - - pub fn decode(r: &mut impl Buf) -> Result { - let mut val = 0; - for i in 0..Self::MAX_SIZE.get() { - if !r.has_remaining() { - return Err(VarLongDecodeError::Incomplete); - } - let byte = r.get_u8(); - val |= (i64::from(byte) & 0b01111111) << (i * 7); - if byte & 0b10000000 == 0 { - return Ok(VarLong(val)); - } - } - Err(VarLongDecodeError::TooLarge) - } -} - -impl From for VarLong { - fn from(value: i64) -> Self { - VarLong(value) - } -} - -impl From for VarLong { - fn from(value: u32) -> Self { - VarLong(value as i64) - } -} - -impl From for VarLong { - fn from(value: u8) -> Self { - VarLong(value as i64) - } -} - -impl From for VarLong { - fn from(value: usize) -> Self { - VarLong(value as i64) - } -} - -impl From for i64 { - fn from(value: VarLong) -> Self { - value.0 - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug, Error)] -pub enum VarLongDecodeError { - #[error("incomplete VarLong decode")] - Incomplete, - #[error("VarLong is too large")] - TooLarge, -} - -impl Serialize for VarLong { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut value = self.0 as u64; - let mut buf = Vec::new(); - - while value > 0x7F { - buf.put_u8(value as u8 | 0x80); - value >>= 7; - } - - buf.put_u8(value as u8); - - serializer.serialize_bytes(&buf) - } -} - -impl<'de> Deserialize<'de> for VarLong { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct VarLongVisitor; - - impl<'de> Visitor<'de> for VarLongVisitor { - type Value = VarLong; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("a valid VarInt encoded in a byte sequence") - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: SeqAccess<'de>, - { - let mut val = 0; - for i in 0..VarLong::MAX_SIZE.get() { - if let Some(byte) = seq.next_element::()? { - val |= (i64::from(byte) & 0b01111111) << (i * 7); - if byte & 0b10000000 == 0 { - return Ok(VarLong(val)); - } - } else { - break; - } - } - Err(de::Error::custom("VarInt was too large")) - } - } - - deserializer.deserialize_seq(VarLongVisitor) - } -} diff --git a/pumpkin-registry/src/banner_pattern.rs b/pumpkin-registry/src/banner_pattern.rs index bac63fda..da631c33 100644 --- a/pumpkin-registry/src/banner_pattern.rs +++ b/pumpkin-registry/src/banner_pattern.rs @@ -1,7 +1,8 @@ +use pumpkin_protocol::codec::identifier::Identifier; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct BannerPattern { - asset_id: String, + asset_id: Identifier, translation_key: String, } diff --git a/pumpkin-registry/src/biome.rs b/pumpkin-registry/src/biome.rs index cbe03b41..e2d52253 100644 --- a/pumpkin-registry/src/biome.rs +++ b/pumpkin-registry/src/biome.rs @@ -1,4 +1,4 @@ -use pumpkin_protocol::VarInt; +use pumpkin_protocol::codec::var_int::VarInt; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/pumpkin-registry/src/lib.rs b/pumpkin-registry/src/lib.rs index 6960a183..80786b17 100644 --- a/pumpkin-registry/src/lib.rs +++ b/pumpkin-registry/src/lib.rs @@ -10,7 +10,7 @@ use indexmap::IndexMap; use instrument::Instrument; use jukebox_song::JukeboxSong; use paint::Painting; -use pumpkin_protocol::client::config::RegistryEntry; +use pumpkin_protocol::{client::config::RegistryEntry, codec::identifier::Identifier}; pub use recipe::{ flatten_3x3, IngredientSlot, IngredientType, Recipe, RecipeResult, RecipeType, RECIPES, }; @@ -41,8 +41,8 @@ pub static SYNCED_REGISTRIES: LazyLock = LazyLock::new(|| { }); pub struct Registry { - pub registry_id: String, - pub registry_entries: Vec>, + pub registry_id: Identifier, + pub registry_entries: Vec, } #[derive(Serialize, Deserialize)] @@ -78,12 +78,12 @@ struct DataPool { } impl DimensionType { - pub fn name(&self) -> &str { + pub fn name(&self) -> Identifier { match self { - Self::Overworld => "minecraft:overworld", - Self::OverworldCaves => "minecraft:overworld_caves", - Self::TheEnd => "minecraft:the_end", - Self::TheNether => "minecraft:the_nether", + Self::Overworld => Identifier::vanilla("overworld"), + Self::OverworldCaves => Identifier::vanilla("overworld_caves"), + Self::TheEnd => Identifier::vanilla("the_end"), + Self::TheNether => Identifier::vanilla("the_nether"), } } } @@ -94,12 +94,12 @@ impl Registry { .biome .iter() .map(|s| RegistryEntry { - entry_id: s.0, - data: pumpkin_nbt::serializer::to_bytes_unnamed(&s.1).unwrap(), + entry_id: Identifier::vanilla(s.0), + data: Some(pumpkin_nbt::serializer::to_bytes_unnamed(&s.1).unwrap()), }) .collect(); let biome = Registry { - registry_id: "minecraft:worldgen/biome".to_string(), + registry_id: Identifier::vanilla("worldgen/biome"), registry_entries, }; @@ -107,12 +107,12 @@ impl Registry { .chat_type .iter() .map(|s| RegistryEntry { - entry_id: s.0, - data: pumpkin_nbt::serializer::to_bytes_unnamed(&s.1).unwrap(), + entry_id: Identifier::vanilla(s.0), + data: Some(pumpkin_nbt::serializer::to_bytes_unnamed(&s.1).unwrap()), }) .collect(); let chat_type = Registry { - registry_id: "minecraft:chat_type".to_string(), + registry_id: Identifier::vanilla("chat_type"), registry_entries, }; @@ -120,7 +120,7 @@ impl Registry { // .trim_pattern // .iter() // .map(|s| RegistryEntry { - // entry_id: s.0, + // entry_id: Identifier::vanilla(s.0), // data: pumpkin_nbt::serializer::to_bytes_unnamed(&s.1).unwrap(), // }) // .collect(); @@ -133,7 +133,7 @@ impl Registry { // .trim_material // .iter() // .map(|s| RegistryEntry { - // entry_id: s.0, + // entry_id: Identifier::vanilla(s.0), // data: pumpkin_nbt::serializer::to_bytes_unnamed(&s.1).unwrap(), // }) // .collect(); @@ -148,13 +148,13 @@ impl Registry { .map(|s| { let variant = s.1.clone(); RegistryEntry { - entry_id: s.0, - data: pumpkin_nbt::serializer::to_bytes_unnamed(&variant).unwrap(), + entry_id: Identifier::vanilla(s.0), + data: Some(pumpkin_nbt::serializer::to_bytes_unnamed(&variant).unwrap()), } }) .collect(); let wolf_variant = Registry { - registry_id: "minecraft:wolf_variant".to_string(), + registry_id: Identifier::vanilla("wolf_variant"), registry_entries, }; @@ -162,12 +162,12 @@ impl Registry { .painting_variant .iter() .map(|s| RegistryEntry { - entry_id: s.0, - data: pumpkin_nbt::serializer::to_bytes_unnamed(&s.1).unwrap(), + entry_id: Identifier::vanilla(s.0), + data: Some(pumpkin_nbt::serializer::to_bytes_unnamed(&s.1).unwrap()), }) .collect(); let painting_variant = Registry { - registry_id: "minecraft:painting_variant".to_string(), + registry_id: Identifier::vanilla("painting_variant"), registry_entries, }; @@ -175,12 +175,12 @@ impl Registry { .dimension_type .iter() .map(|s| RegistryEntry { - entry_id: s.0, - data: pumpkin_nbt::serializer::to_bytes_unnamed(&s.1).unwrap(), + entry_id: Identifier::vanilla(s.0), + data: Some(pumpkin_nbt::serializer::to_bytes_unnamed(&s.1).unwrap()), }) .collect(); let dimension_type = Registry { - registry_id: "minecraft:dimension_type".to_string(), + registry_id: Identifier::vanilla("dimension_type"), registry_entries, }; @@ -188,12 +188,12 @@ impl Registry { .damage_type .iter() .map(|s| RegistryEntry { - entry_id: s.0, - data: pumpkin_nbt::serializer::to_bytes_unnamed(&s.1).unwrap(), + entry_id: Identifier::vanilla(s.0), + data: Some(pumpkin_nbt::serializer::to_bytes_unnamed(&s.1).unwrap()), }) .collect(); let damage_type = Registry { - registry_id: "minecraft:damage_type".to_string(), + registry_id: Identifier::vanilla("damage_type"), registry_entries, }; @@ -201,12 +201,12 @@ impl Registry { .banner_pattern .iter() .map(|s| RegistryEntry { - entry_id: s.0, - data: pumpkin_nbt::serializer::to_bytes_unnamed(&s.1).unwrap(), + entry_id: Identifier::vanilla(s.0), + data: Some(pumpkin_nbt::serializer::to_bytes_unnamed(&s.1).unwrap()), }) .collect(); let banner_pattern = Registry { - registry_id: "minecraft:banner_pattern".to_string(), + registry_id: Identifier::vanilla("banner_pattern"), registry_entries, }; @@ -215,7 +215,7 @@ impl Registry { // .enchantment // .iter() // .map(|s| RegistryEntry { - // entry_id: s.0, + // entry_id: Identifier::vanilla(s.0), // data: pumpkin_nbt::serializer::to_bytes_unnamed(&s.1).unwrap(), // }) // .collect(); @@ -228,12 +228,12 @@ impl Registry { .jukebox_song .iter() .map(|s| RegistryEntry { - entry_id: s.0, - data: pumpkin_nbt::serializer::to_bytes_unnamed(&s.1).unwrap(), + entry_id: Identifier::vanilla(s.0), + data: Some(pumpkin_nbt::serializer::to_bytes_unnamed(&s.1).unwrap()), }) .collect(); let jukebox_song = Registry { - registry_id: "minecraft:jukebox_song".to_string(), + registry_id: Identifier::vanilla("jukebox_song"), registry_entries, }; @@ -241,7 +241,7 @@ impl Registry { // .instrument // .iter() // .map(|s| RegistryEntry { - // entry_id: s.0, + // entry_id: Identifier::vanilla(s.0), // data: pumpkin_nbt::serializer::to_bytes_unnamed(&s.1).unwrap(), // }) // .collect(); diff --git a/pumpkin-registry/src/paint.rs b/pumpkin-registry/src/paint.rs index 9c383f6f..1217798e 100644 --- a/pumpkin-registry/src/paint.rs +++ b/pumpkin-registry/src/paint.rs @@ -1,8 +1,9 @@ +use pumpkin_protocol::codec::identifier::Identifier; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Painting { - asset_id: String, + asset_id: Identifier, // #[serde(skip_serializing_if = "Option::is_none")] // title: Option>, // #[serde(skip_serializing_if = "Option::is_none")] diff --git a/pumpkin-registry/src/trim_pattern.rs b/pumpkin-registry/src/trim_pattern.rs index 48746df1..62f07daa 100644 --- a/pumpkin-registry/src/trim_pattern.rs +++ b/pumpkin-registry/src/trim_pattern.rs @@ -1,8 +1,9 @@ +use pumpkin_protocol::codec::identifier::Identifier; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TrimPattern { - asset_id: String, + asset_id: Identifier, template_item: String, // description: TextComponent<'static>, decal: bool, diff --git a/pumpkin-world/src/item/item_registry.rs b/pumpkin-world/src/item/item_registry.rs index e446e362..e393acc1 100644 --- a/pumpkin-world/src/item/item_registry.rs +++ b/pumpkin-world/src/item/item_registry.rs @@ -57,6 +57,15 @@ pub struct Modifier { pub type_val: String, pub id: String, pub amount: f64, - pub operation: String, + pub operation: Operation, + // TODO: Make this an enum pub slot: String, } + +#[derive(Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum Operation { + AddValue, + AddMultipliedBase, + AddMultipliedTotal, +} diff --git a/pumpkin/src/client/client_packet.rs b/pumpkin/src/client/client_packet.rs index dfe913e1..76e0ce68 100644 --- a/pumpkin/src/client/client_packet.rs +++ b/pumpkin/src/client/client_packet.rs @@ -12,9 +12,12 @@ use core::str; use num_traits::FromPrimitive; use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG}; use pumpkin_core::text::TextComponent; -use pumpkin_protocol::client::config::{CServerLinks, Label, Link, LinkType}; use pumpkin_protocol::server::config::SCookieResponse as SCCookieResponse; use pumpkin_protocol::server::login::SCookieResponse as SLCookieResponse; +use pumpkin_protocol::{ + client::config::{CServerLinks, Label, Link, LinkType}, + codec::var_int::VarInt, +}; use pumpkin_protocol::{ client::{ config::{CConfigAddResourcePack, CFinishConfig, CKnownPacks, CRegistryData}, @@ -27,7 +30,7 @@ use pumpkin_protocol::{ login::{SEncryptionResponse, SLoginPluginResponse, SLoginStart}, status::SStatusPingRequest, }, - ConnectionState, KnownPack, VarInt, CURRENT_MC_PROTOCOL, + ConnectionState, KnownPack, CURRENT_MC_PROTOCOL, }; use std::{ num::{NonZeroI32, NonZeroU8}, @@ -318,7 +321,7 @@ impl Client { // TODO: allow plugins to access this log::debug!( "Received cookie_response[login]: key: \"{}\", has_payload: \"{}\", payload_length: \"{}\"", - packet.key, + packet.key.to_string(), packet.has_payload, packet.payload_length.unwrap_or(VarInt::from(0)).0 ); @@ -417,8 +420,10 @@ impl Client { pub async fn handle_plugin_message(&self, plugin_message: SPluginMessage) { log::debug!("Handling plugin message"); - if plugin_message.channel.starts_with("minecraft:brand") - || plugin_message.channel.starts_with("MC|Brand") + if plugin_message + .channel + .to_string() + .starts_with("minecraft:brand") { log::debug!("got a client brand"); match str::from_utf8(&plugin_message.data) { @@ -432,7 +437,7 @@ impl Client { // TODO: allow plugins to access this log::debug!( "Received cookie_response[config]: key: \"{}\", has_payload: \"{}\", payload_length: \"{}\"", - packet.key, + packet.key.to_string(), packet.has_payload, packet.payload_length.unwrap_or(VarInt::from(0)).0 ); diff --git a/pumpkin/src/client/combat.rs b/pumpkin/src/client/combat.rs index 8b5b0ed1..12cb0a90 100644 --- a/pumpkin/src/client/combat.rs +++ b/pumpkin/src/client/combat.rs @@ -4,7 +4,8 @@ use pumpkin_core::math::vector3::Vector3; use pumpkin_macros::{particle, sound}; use pumpkin_protocol::{ client::play::{CEntityVelocity, CParticle}, - SoundCategory, VarInt, + codec::var_int::VarInt, + SoundCategory, }; use pumpkin_world::item::ItemStack; diff --git a/pumpkin/src/client/container.rs b/pumpkin/src/client/container.rs index f171c116..42a4b23c 100644 --- a/pumpkin/src/client/container.rs +++ b/pumpkin/src/client/container.rs @@ -12,9 +12,9 @@ use pumpkin_inventory::{Container, WindowType}; use pumpkin_protocol::client::play::{ CCloseContainer, COpenScreen, CSetContainerContent, CSetContainerProperty, CSetContainerSlot, }; +use pumpkin_protocol::codec::var_int::VarInt; use pumpkin_protocol::server::play::SClickContainer; use pumpkin_protocol::slot::Slot; -use pumpkin_protocol::VarInt; use pumpkin_world::item::item_registry::Item; use pumpkin_world::item::ItemStack; use std::sync::Arc; diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index 1e3ce5e5..977dd6f6 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -296,8 +296,8 @@ impl Client { /// /// # Arguments /// - /// * `server`: A reference to the `Arc` instance. - pub async fn process_packets(&self, server: &Arc) { + /// * `server`: A reference to the `Server` instance. + pub async fn process_packets(&self, server: &Server) { let mut packet_queue = self.client_packets_queue.lock().await; while let Some(mut packet) = packet_queue.pop_front() { if self.closed.load(std::sync::atomic::Ordering::Relaxed) { @@ -330,7 +330,7 @@ impl Client { /// /// # Arguments /// - /// * `server`: A reference to the `Arc` instance. + /// * `server`: A reference to the `Server` instance. /// * `packet`: A mutable reference to the `RawPacket` to be processed. /// /// # Returns @@ -342,7 +342,7 @@ impl Client { /// Returns a `DeserializerError` if an error occurs during packet deserialization. pub async fn handle_packet( &self, - server: &Arc, + server: &Server, packet: &mut RawPacket, ) -> Result<(), ReadingError> { match self.connection_state.load() { @@ -386,7 +386,7 @@ impl Client { async fn handle_status_packet( &self, - server: &Arc, + server: &Server, packet: &mut RawPacket, ) -> Result<(), ReadingError> { log::debug!("Handling status group"); @@ -412,7 +412,7 @@ impl Client { async fn handle_login_packet( &self, - server: &Arc, + server: &Server, packet: &mut RawPacket, ) -> Result<(), ReadingError> { log::debug!("Handling login group for id"); @@ -448,7 +448,7 @@ impl Client { async fn handle_config_packet( &self, - server: &Arc, + server: &Server, packet: &mut RawPacket, ) -> Result<(), ReadingError> { log::debug!("Handling config group"); diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 920de697..a7b2b809 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -19,11 +19,11 @@ use pumpkin_core::{ GameMode, }; use pumpkin_inventory::{InventoryError, WindowType}; +use pumpkin_protocol::codec::var_int::VarInt; use pumpkin_protocol::server::play::SCookieResponse as SPCookieResponse; use pumpkin_protocol::{ client::play::CCommandSuggestions, server::play::{SCloseContainer, SCommandSuggestion, SKeepAlive, SSetPlayerGround, SUseItem}, - VarInt, }; use pumpkin_protocol::{ client::play::{ @@ -896,7 +896,7 @@ impl Player { // TODO: allow plugins to access this log::debug!( "Received cookie_response[play]: key: \"{}\", has_payload: \"{}\", payload_length: \"{}\"", - packet.key, + packet.key.to_string(), packet.has_payload, packet.payload_length.unwrap_or(VarInt::from(0)).0 ); diff --git a/pumpkin/src/command/commands/cmd_transfer.rs b/pumpkin/src/command/commands/cmd_transfer.rs index 1af9ae3c..7660b808 100644 --- a/pumpkin/src/command/commands/cmd_transfer.rs +++ b/pumpkin/src/command/commands/cmd_transfer.rs @@ -2,7 +2,7 @@ use async_trait::async_trait; use pumpkin_core::text::color::{Color, NamedColor}; use pumpkin_core::text::TextComponent; use pumpkin_protocol::client::play::CTransfer; -use pumpkin_protocol::VarInt; +use pumpkin_protocol::codec::var_int::VarInt; use crate::command::args::arg_bounded_num::BoundedNumArgumentConsumer; use crate::command::args::arg_players::PlayersArgumentConsumer; diff --git a/pumpkin/src/entity/mod.rs b/pumpkin/src/entity/mod.rs index 92544ccb..649144a7 100644 --- a/pumpkin/src/entity/mod.rs +++ b/pumpkin/src/entity/mod.rs @@ -12,7 +12,7 @@ use pumpkin_core::math::{ use pumpkin_entity::{entity_type::EntityType, pose::EntityPose, EntityId}; use pumpkin_protocol::{ client::play::{CSetEntityMetadata, CTeleportEntity, Metadata}, - VarInt, + codec::var_int::VarInt, }; use crate::world::World; diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index 31ef1131..9f0a8e07 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -24,7 +24,6 @@ use pumpkin_core::{ use pumpkin_entity::{entity_type::EntityType, EntityId}; use pumpkin_inventory::player::PlayerInventory; use pumpkin_macros::sound; -use pumpkin_protocol::client::play::CUpdateTime; use pumpkin_protocol::server::play::{ SCloseContainer, SCookieResponse as SPCookieResponse, SPlayPingRequest, }; @@ -41,15 +40,19 @@ use pumpkin_protocol::{ SPlayerCommand, SPlayerInput, SPlayerPosition, SPlayerPositionRotation, SPlayerRotation, SSetCreativeSlot, SSetHeldItem, SSetPlayerGround, SSwingArm, SUseItem, SUseItemOn, }, - RawPacket, ServerPacket, SoundCategory, VarInt, + RawPacket, ServerPacket, SoundCategory, }; +use pumpkin_protocol::{client::play::CUpdateTime, codec::var_int::VarInt}; use pumpkin_protocol::{ client::play::{CSetEntityMetadata, Metadata}, server::play::{SClickContainer, SKeepAlive}, }; use pumpkin_world::{ cylindrical_chunk_iterator::Cylindrical, - item::{item_registry::get_item_by_id, ItemStack}, + item::{ + item_registry::{get_item_by_id, Operation}, + ItemStack, + }, }; use tokio::sync::{Mutex, Notify}; @@ -257,7 +260,7 @@ impl Player { // TODO: this should be cached in memory if let Some(modifiers) = &item.components.attribute_modifiers { for item_mod in &modifiers.modifiers { - if item_mod.operation == "add_value" { + if item_mod.operation == Operation::AddValue { if item_mod.id == "minecraft:base_attack_damage" { add_damage = item_mod.amount; } diff --git a/pumpkin/src/server/connection_cache.rs b/pumpkin/src/server/connection_cache.rs index 4171ea13..618fdac3 100644 --- a/pumpkin/src/server/connection_cache.rs +++ b/pumpkin/src/server/connection_cache.rs @@ -10,7 +10,8 @@ use base64::{engine::general_purpose, Engine as _}; use pumpkin_config::{BasicConfiguration, BASIC_CONFIG}; use pumpkin_protocol::{ client::{config::CPluginMessage, status::CStatusResponse}, - Players, StatusResponse, VarInt, Version, CURRENT_MC_PROTOCOL, + codec::{var_int::VarInt, Codec}, + Players, StatusResponse, Version, CURRENT_MC_PROTOCOL, }; use super::CURRENT_MC_VERSION; diff --git a/pumpkin/src/server/mod.rs b/pumpkin/src/server/mod.rs index 36ae0dde..33dd0c27 100644 --- a/pumpkin/src/server/mod.rs +++ b/pumpkin/src/server/mod.rs @@ -71,8 +71,6 @@ impl Server { #[allow(clippy::new_without_default)] #[must_use] pub fn new() -> Self { - // TODO: only create when needed - let auth_client = BASIC_CONFIG.online_mode.then(|| { reqwest::Client::builder() .timeout(Duration::from_millis(5000)) diff --git a/pumpkin/src/world/mod.rs b/pumpkin/src/world/mod.rs index dcfab4b9..9380f1bb 100644 --- a/pumpkin/src/world/mod.rs +++ b/pumpkin/src/world/mod.rs @@ -15,7 +15,10 @@ use pumpkin_core::math::vector2::Vector2; use pumpkin_core::math::{position::WorldPosition, vector3::Vector3}; use pumpkin_core::text::{color::NamedColor, TextComponent}; use pumpkin_entity::{entity_type::EntityType, EntityId}; -use pumpkin_protocol::client::play::CLevelEvent; +use pumpkin_protocol::{ + client::play::CLevelEvent, + codec::{identifier::Identifier, var_int::VarInt}, +}; use pumpkin_protocol::{ client::play::{CBlockUpdate, CRespawn, CSoundEffect, CWorldEvent}, SoundCategory, @@ -25,7 +28,7 @@ use pumpkin_protocol::{ CChunkData, CGameEvent, CLogin, CPlayerInfoUpdate, CRemoveEntities, CRemovePlayerInfo, CSetEntityMetadata, CSpawnEntity, GameEvent, Metadata, PlayerAction, }, - ClientPacket, VarInt, + ClientPacket, }; use pumpkin_registry::DimensionType; use pumpkin_world::chunk::ChunkData; @@ -223,7 +226,8 @@ impl World { server: &Server, ) { let command_dispatcher = &server.command_dispatcher; - let dimensions: Vec<&str> = server.dimensions.iter().map(DimensionType::name).collect(); + let dimensions: Vec = + server.dimensions.iter().map(DimensionType::name).collect(); // This code follows the vanilla packet order let entity_id = player.entity_id(); diff --git a/pumpkin/src/world/scoreboard.rs b/pumpkin/src/world/scoreboard.rs index 61279eed..16a3e329 100644 --- a/pumpkin/src/world/scoreboard.rs +++ b/pumpkin/src/world/scoreboard.rs @@ -3,7 +3,8 @@ use std::collections::HashMap; use pumpkin_core::text::TextComponent; use pumpkin_protocol::{ client::play::{CDisplayObjective, CUpdateObjectives, CUpdateScore, RenderType}, - NumberFormat, VarInt, + codec::var_int::VarInt, + NumberFormat, }; use super::World; From fd667901cdeb16ace017bc5a584df4b14f083274 Mon Sep 17 00:00:00 2001 From: Alexander Medvedev Date: Sat, 21 Dec 2024 17:09:27 +0100 Subject: [PATCH 3/6] add codecs folder to git --- pumpkin-protocol/src/codec/bit_set.rs | 53 ++++++++ pumpkin-protocol/src/codec/identifier.rs | 101 +++++++++++++++ pumpkin-protocol/src/codec/mod.rs | 27 ++++ pumpkin-protocol/src/codec/var_int.rs | 157 ++++++++++++++++++++++ pumpkin-protocol/src/codec/var_long.rs | 158 +++++++++++++++++++++++ 5 files changed, 496 insertions(+) create mode 100644 pumpkin-protocol/src/codec/bit_set.rs create mode 100644 pumpkin-protocol/src/codec/identifier.rs create mode 100644 pumpkin-protocol/src/codec/mod.rs create mode 100644 pumpkin-protocol/src/codec/var_int.rs create mode 100644 pumpkin-protocol/src/codec/var_long.rs diff --git a/pumpkin-protocol/src/codec/bit_set.rs b/pumpkin-protocol/src/codec/bit_set.rs new file mode 100644 index 00000000..27aa329d --- /dev/null +++ b/pumpkin-protocol/src/codec/bit_set.rs @@ -0,0 +1,53 @@ +use std::num::NonZeroUsize; + +use bytes::{Buf, BufMut}; +use serde::{Serialize, Serializer}; + +use crate::bytebuf::ByteBuf; +use crate::bytebuf::ByteBufMut; + +use super::{var_int::VarInt, Codec, DecodeError}; + +pub struct BitSet(pub VarInt, pub Vec); + +impl Codec for BitSet { + /// The maximum size of the BitSet is `remaining / 8`. + const MAX_SIZE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(usize::MAX) }; + + fn written_size(&self) -> usize { + todo!() + } + + fn encode(&self, write: &mut impl BufMut) { + write.put_var_int(&self.0); + for b in &self.1 { + write.put_i64(*b); + } + } + + fn decode(read: &mut impl Buf) -> Result { + // read length + let length = read + .try_get_var_int() + .map_err(|_| DecodeError::Incomplete)?; + // vanilla uses remaining / 8 + if length.0 as usize >= read.remaining() / 8 { + return Err(DecodeError::TooLarge); + } + let mut array: Vec = Vec::with_capacity(size_of::() * length.0 as usize); + for _ in 0..length.0 { + let long = read.try_get_i64().map_err(|_| DecodeError::Incomplete)?; + array.push(long); + } + Ok(BitSet(length, array)) + } +} + +impl Serialize for BitSet { + fn serialize(&self, _serializer: S) -> Result + where + S: Serializer, + { + todo!() + } +} diff --git a/pumpkin-protocol/src/codec/identifier.rs b/pumpkin-protocol/src/codec/identifier.rs new file mode 100644 index 00000000..6be5675c --- /dev/null +++ b/pumpkin-protocol/src/codec/identifier.rs @@ -0,0 +1,101 @@ +use std::num::NonZeroUsize; + +use bytes::{Buf, BufMut}; +use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer}; + +use crate::bytebuf::{ByteBuf, ByteBufMut}; + +use super::{Codec, DecodeError}; + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Identifier { + pub namespace: String, + pub path: String, +} + +impl Identifier { + pub fn vanilla(path: &str) -> Self { + Self { + namespace: "minecraft".to_string(), + path: path.to_string(), + } + } +} +impl Codec for Identifier { + /// The maximum number of bytes a `Identifer` is the same as for a normal String. + const MAX_SIZE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(i16::MAX as usize) }; + + fn written_size(&self) -> usize { + todo!() + } + + fn encode(&self, write: &mut impl BufMut) { + write.put_string_len(&self.to_string(), Self::MAX_SIZE.get()); + } + + fn decode(read: &mut impl Buf) -> Result { + let identifer = read + .try_get_string_len(Self::MAX_SIZE.get()) + .map_err(|_| DecodeError::Incomplete)?; + match identifer.split_once(":") { + Some((namespace, path)) => Ok(Identifier { + namespace: namespace.to_string(), + path: path.to_string(), + }), + None => Err(DecodeError::Incomplete), + } + } +} + +impl Serialize for Identifier { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&self.to_string()) + } +} + +impl<'de> Deserialize<'de> for Identifier { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct IdentifierVisitor; + + impl Visitor<'_> for IdentifierVisitor { + type Value = Identifier; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a valid Identifier (namespace:path)") + } + + fn visit_string(self, v: String) -> Result + where + E: serde::de::Error, + { + self.visit_str(&v) + } + + fn visit_str(self, identifer: &str) -> Result + where + E: serde::de::Error, + { + match identifer.split_once(":") { + Some((namespace, path)) => Ok(Identifier { + namespace: namespace.to_string(), + path: path.to_string(), + }), + None => Err(serde::de::Error::custom("Identifier can't be split")), + } + } + } + deserializer.deserialize_str(IdentifierVisitor) + } +} + +impl std::fmt::Display for Identifier { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}:{}", self.namespace, self.path) + } +} diff --git a/pumpkin-protocol/src/codec/mod.rs b/pumpkin-protocol/src/codec/mod.rs new file mode 100644 index 00000000..3af01e21 --- /dev/null +++ b/pumpkin-protocol/src/codec/mod.rs @@ -0,0 +1,27 @@ +use std::num::NonZeroUsize; + +use bytes::{Buf, BufMut}; +use thiserror::Error; + +pub mod bit_set; +pub mod identifier; +pub mod var_int; +pub mod var_long; + +pub trait Codec { + const MAX_SIZE: NonZeroUsize; + + fn written_size(&self) -> usize; + + fn encode(&self, write: &mut impl BufMut); + + fn decode(read: &mut impl Buf) -> Result; +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Error)] +pub enum DecodeError { + #[error("Incomplete VarInt decode")] + Incomplete, + #[error("VarInt is too large")] + TooLarge, +} diff --git a/pumpkin-protocol/src/codec/var_int.rs b/pumpkin-protocol/src/codec/var_int.rs new file mode 100644 index 00000000..4f502687 --- /dev/null +++ b/pumpkin-protocol/src/codec/var_int.rs @@ -0,0 +1,157 @@ +use std::{num::NonZeroUsize, ops::Deref}; + +use super::{Codec, DecodeError}; +use bytes::{Buf, BufMut}; +use serde::{ + de::{SeqAccess, Visitor}, + Deserialize, Deserializer, Serialize, Serializer, +}; + +pub type VarIntType = i32; + +/** + * A variable-length integer type used by the Minecraft network protocol. + */ +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct VarInt(pub VarIntType); + +impl Codec for VarInt { + /// The maximum number of bytes a `VarInt` can occupy. + const MAX_SIZE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(5) }; + + /// Returns the exact number of bytes this varint will write when + /// [`Encode::encode`] is called, assuming no error occurs. + fn written_size(&self) -> usize { + match self.0 { + 0 => 1, + n => (31 - n.leading_zeros() as usize) / 7 + 1, + } + } + + fn encode(&self, write: &mut impl BufMut) { + let mut val = self.0; + for _ in 0..Self::MAX_SIZE.get() { + let b: u8 = val as u8 & 0b01111111; + val >>= 7; + write.put_u8(if val == 0 { b } else { b | 0b10000000 }); + if val == 0 { + break; + } + } + } + + fn decode(read: &mut impl Buf) -> Result { + let mut val = 0; + for i in 0..Self::MAX_SIZE.get() { + if !read.has_remaining() { + return Err(DecodeError::Incomplete); + } + let byte = read.get_u8(); + val |= (i32::from(byte) & 0x7F) << (i * 7); + if byte & 0x80 == 0 { + return Ok(VarInt(val)); + } + } + Err(DecodeError::TooLarge) + } +} + +impl From for VarInt { + fn from(value: i32) -> Self { + 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 + } +} + +impl AsRef for VarInt { + fn as_ref(&self) -> &i32 { + &self.0 + } +} + +impl Deref for VarInt { + type Target = i32; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Serialize for VarInt { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut value = self.0 as u32; + let mut buf = Vec::new(); + + while value > 0x7F { + buf.put_u8(value as u8 | 0x80); + value >>= 7; + } + + buf.put_u8(value as u8); + + serializer.serialize_bytes(&buf) + } +} + +impl<'de> Deserialize<'de> for VarInt { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct VarIntVisitor; + + impl<'de> Visitor<'de> for VarIntVisitor { + type Value = VarInt; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a valid VarInt encoded in a byte sequence") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let mut val = 0; + for i in 0..VarInt::MAX_SIZE.get() { + if let Some(byte) = seq.next_element::()? { + val |= (i32::from(byte) & 0b01111111) << (i * 7); + if byte & 0b10000000 == 0 { + return Ok(VarInt(val)); + } + } else { + break; + } + } + Err(serde::de::Error::custom("VarInt was too large")) + } + } + + deserializer.deserialize_seq(VarIntVisitor) + } +} diff --git a/pumpkin-protocol/src/codec/var_long.rs b/pumpkin-protocol/src/codec/var_long.rs new file mode 100644 index 00000000..ceb2c1c9 --- /dev/null +++ b/pumpkin-protocol/src/codec/var_long.rs @@ -0,0 +1,158 @@ +use std::{num::NonZeroUsize, ops::Deref}; + +use super::{Codec, DecodeError}; +use bytes::{Buf, BufMut}; +use serde::{ + de::{self, SeqAccess, Visitor}, + Deserialize, Deserializer, Serialize, Serializer, +}; + +pub type VarLongType = i64; + +/** + * A variable-length long type used by the Minecraft network protocol. + */ +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct VarLong(pub VarLongType); + +impl Codec for VarLong { + /// The maximum number of bytes a `VarLong` can occupy. + const MAX_SIZE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(10) }; + + /// Returns the exact number of bytes this varlong will write when + /// [`Encode::encode`] is called, assuming no error occurs. + fn written_size(&self) -> usize { + match self.0 { + 0 => 1, + n => (31 - n.leading_zeros() as usize) / 7 + 1, + } + } + + fn encode(&self, write: &mut impl BufMut) { + let mut x = self.0; + for _ in 0..Self::MAX_SIZE.get() { + let byte = (x & 0x7F) as u8; + x >>= 7; + if x == 0 { + write.put_slice(&[byte]); + break; + } + write.put_slice(&[byte | 0x80]); + } + } + + fn decode(read: &mut impl Buf) -> Result { + let mut val = 0; + for i in 0..Self::MAX_SIZE.get() { + if !read.has_remaining() { + return Err(DecodeError::Incomplete); + } + let byte = read.get_u8(); + val |= (i64::from(byte) & 0b01111111) << (i * 7); + if byte & 0b10000000 == 0 { + return Ok(VarLong(val)); + } + } + Err(DecodeError::TooLarge) + } +} + +impl From for VarLong { + fn from(value: i64) -> Self { + VarLong(value) + } +} + +impl From for VarLong { + fn from(value: u32) -> Self { + VarLong(value as i64) + } +} + +impl From for VarLong { + fn from(value: u8) -> Self { + VarLong(value as i64) + } +} + +impl From for VarLong { + fn from(value: usize) -> Self { + VarLong(value as i64) + } +} + +impl From for i64 { + fn from(value: VarLong) -> Self { + value.0 + } +} + +impl AsRef for VarLong { + fn as_ref(&self) -> &i64 { + &self.0 + } +} + +impl Deref for VarLong { + type Target = i64; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Serialize for VarLong { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut value = self.0 as u64; + let mut buf = Vec::new(); + + while value > 0x7F { + buf.put_u8(value as u8 | 0x80); + value >>= 7; + } + + buf.put_u8(value as u8); + + serializer.serialize_bytes(&buf) + } +} + +impl<'de> Deserialize<'de> for VarLong { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct VarLongVisitor; + + impl<'de> Visitor<'de> for VarLongVisitor { + type Value = VarLong; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a valid VarInt encoded in a byte sequence") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let mut val = 0; + for i in 0..VarLong::MAX_SIZE.get() { + if let Some(byte) = seq.next_element::()? { + val |= (i64::from(byte) & 0b01111111) << (i * 7); + if byte & 0b10000000 == 0 { + return Ok(VarLong(val)); + } + } else { + break; + } + } + Err(de::Error::custom("VarInt was too large")) + } + } + + deserializer.deserialize_seq(VarLongVisitor) + } +} From 3dae300f818af81d44eb64f9d688f110ce846fa3 Mon Sep 17 00:00:00 2001 From: Alexander Medvedev Date: Tue, 24 Dec 2024 00:56:19 +0100 Subject: [PATCH 4/6] Some refactors --- pumpkin-protocol/Cargo.toml | 7 + .../client/play/c_set_container_content.rs | 2 +- .../src/client/play/c_set_container_slot.rs | 2 +- pumpkin-protocol/src/codec/mod.rs | 1 + pumpkin-protocol/src/{ => codec}/slot.rs | 0 pumpkin-protocol/src/lib.rs | 4 +- pumpkin-protocol/src/packet_decoder.rs | 4 +- pumpkin-protocol/src/packet_encoder.rs | 4 +- .../src/server/config/s_cookie_response.rs | 4 +- .../src/server/login/s_cookie_response.rs | 4 +- .../src/server/play/s_click_container.rs | 2 +- .../src/server/play/s_set_creative_slot.rs | 2 +- .../aquifer_sampler.rs | 2 +- .../{world_gen => generation}/blender/mod.rs | 0 .../{world_gen => generation}/chunk_noise.rs | 6 +- .../generation_shapes.rs | 0 .../{world_gen => generation}/generator.rs | 2 +- .../generic_generator.rs | 0 .../{world_gen => generation}/height_limit.rs | 0 .../implementation/mod.rs | 0 .../implementation/overworld/biome/mod.rs | 0 .../implementation/overworld/biome/plains.rs | 2 +- .../implementation/overworld/mod.rs | 0 .../implementation/superflat.rs | 2 +- .../implementation/test.rs | 2 +- .../src/{world_gen => generation}/mod.rs | 0 .../{world_gen => generation}/noise/config.rs | 4 +- .../noise/density/basic.rs | 6 +- .../noise/density/blend.rs | 2 +- .../noise/density/component_functions.rs | 2 +- .../noise/density/end.rs | 2 +- .../noise/density/math.rs | 0 .../noise/density/mod.rs | 8 +- .../noise/density/noise.rs | 4 +- .../noise/density/offset.rs | 0 .../noise/density/spline.rs | 4 +- .../noise/density/terrain_helpers.rs | 6 +- .../noise/density/unary.rs | 0 .../noise/density/weird.rs | 0 .../{world_gen => generation}/noise/mod.rs | 0 .../{world_gen => generation}/noise/perlin.rs | 4 +- .../{world_gen => generation}/noise/router.rs | 6 +- .../noise/simplex.rs | 4 +- .../{world_gen => generation}/ore_sampler.rs | 0 .../{world_gen => generation}/positions.rs | 0 .../{world_gen => generation}/proto_chunk.rs | 2 +- .../src/{world_gen => generation}/seed.rs | 0 pumpkin-world/src/level.rs | 2 +- pumpkin-world/src/lib.rs | 6 +- pumpkin/src/entity/player.rs | 5 +- pumpkin/src/main.rs | 9 +- pumpkin/src/{client => net}/authentication.rs | 26 +-- pumpkin/src/{client => net}/combat.rs | 0 pumpkin/src/{client => net}/container.rs | 2 +- pumpkin/src/{ => net}/lan_broadcast.rs | 0 pumpkin/src/{client => net}/mod.rs | 56 +++-- pumpkin/src/net/packet/config.rs | 98 +++++++++ pumpkin/src/net/packet/handshake.rs | 29 +++ .../client_packet.rs => net/packet/login.rs} | 201 ++++-------------- pumpkin/src/net/packet/mod.rs | 9 + .../player_packet.rs => net/packet/play.rs} | 2 +- pumpkin/src/net/packet/status.rs | 18 ++ pumpkin/src/{ => net}/proxy/bungeecord.rs | 34 +-- pumpkin/src/{ => net}/proxy/mod.rs | 0 pumpkin/src/{ => net}/proxy/velocity.rs | 2 +- pumpkin/src/{ => net}/query.rs | 0 pumpkin/src/{ => net}/rcon/mod.rs | 1 - pumpkin/src/{ => net}/rcon/packet.rs | 0 pumpkin/src/server/connection_cache.rs | 2 + pumpkin/src/server/key_store.rs | 3 +- pumpkin/src/server/mod.rs | 4 +- pumpkin/src/world/worldborder.rs | 2 +- 72 files changed, 333 insertions(+), 284 deletions(-) rename pumpkin-protocol/src/{ => codec}/slot.rs (100%) rename pumpkin-world/src/{world_gen => generation}/aquifer_sampler.rs (99%) rename pumpkin-world/src/{world_gen => generation}/blender/mod.rs (100%) rename pumpkin-world/src/{world_gen => generation}/chunk_noise.rs (99%) rename pumpkin-world/src/{world_gen => generation}/generation_shapes.rs (100%) rename pumpkin-world/src/{world_gen => generation}/generator.rs (97%) rename pumpkin-world/src/{world_gen => generation}/generic_generator.rs (100%) rename pumpkin-world/src/{world_gen => generation}/height_limit.rs (100%) rename pumpkin-world/src/{world_gen => generation}/implementation/mod.rs (100%) rename pumpkin-world/src/{world_gen => generation}/implementation/overworld/biome/mod.rs (100%) rename pumpkin-world/src/{world_gen => generation}/implementation/overworld/biome/plains.rs (99%) rename pumpkin-world/src/{world_gen => generation}/implementation/overworld/mod.rs (100%) rename pumpkin-world/src/{world_gen => generation}/implementation/superflat.rs (98%) rename pumpkin-world/src/{world_gen => generation}/implementation/test.rs (99%) rename pumpkin-world/src/{world_gen => generation}/mod.rs (100%) rename pumpkin-world/src/{world_gen => generation}/noise/config.rs (99%) rename pumpkin-world/src/{world_gen => generation}/noise/density/basic.rs (99%) rename pumpkin-world/src/{world_gen => generation}/noise/density/blend.rs (99%) rename pumpkin-world/src/{world_gen => generation}/noise/density/component_functions.rs (99%) rename pumpkin-world/src/{world_gen => generation}/noise/density/end.rs (97%) rename pumpkin-world/src/{world_gen => generation}/noise/density/math.rs (100%) rename pumpkin-world/src/{world_gen => generation}/noise/density/mod.rs (99%) rename pumpkin-world/src/{world_gen => generation}/noise/density/noise.rs (99%) rename pumpkin-world/src/{world_gen => generation}/noise/density/offset.rs (100%) rename pumpkin-world/src/{world_gen => generation}/noise/density/spline.rs (99%) rename pumpkin-world/src/{world_gen => generation}/noise/density/terrain_helpers.rs (99%) rename pumpkin-world/src/{world_gen => generation}/noise/density/unary.rs (100%) rename pumpkin-world/src/{world_gen => generation}/noise/density/weird.rs (100%) rename pumpkin-world/src/{world_gen => generation}/noise/mod.rs (100%) rename pumpkin-world/src/{world_gen => generation}/noise/perlin.rs (99%) rename pumpkin-world/src/{world_gen => generation}/noise/router.rs (99%) rename pumpkin-world/src/{world_gen => generation}/noise/simplex.rs (99%) rename pumpkin-world/src/{world_gen => generation}/ore_sampler.rs (100%) rename pumpkin-world/src/{world_gen => generation}/positions.rs (100%) rename pumpkin-world/src/{world_gen => generation}/proto_chunk.rs (99%) rename pumpkin-world/src/{world_gen => generation}/seed.rs (100%) rename pumpkin/src/{client => net}/authentication.rs (85%) rename pumpkin/src/{client => net}/combat.rs (100%) rename pumpkin/src/{client => net}/container.rs (99%) rename pumpkin/src/{ => net}/lan_broadcast.rs (100%) rename pumpkin/src/{client => net}/mod.rs (94%) create mode 100644 pumpkin/src/net/packet/config.rs create mode 100644 pumpkin/src/net/packet/handshake.rs rename pumpkin/src/{client/client_packet.rs => net/packet/login.rs} (63%) create mode 100644 pumpkin/src/net/packet/mod.rs rename pumpkin/src/{client/player_packet.rs => net/packet/play.rs} (99%) create mode 100644 pumpkin/src/net/packet/status.rs rename pumpkin/src/{ => net}/proxy/bungeecord.rs (59%) rename pumpkin/src/{ => net}/proxy/mod.rs (100%) rename pumpkin/src/{ => net}/proxy/velocity.rs (98%) rename pumpkin/src/{ => net}/query.rs (100%) rename pumpkin/src/{ => net}/rcon/mod.rs (98%) rename pumpkin/src/{ => net}/rcon/packet.rs (100%) diff --git a/pumpkin-protocol/Cargo.toml b/pumpkin-protocol/Cargo.toml index 3e417ecb..674b290e 100644 --- a/pumpkin-protocol/Cargo.toml +++ b/pumpkin-protocol/Cargo.toml @@ -3,6 +3,13 @@ name = "pumpkin-protocol" version.workspace = true edition.workspace = true +[features] +default = ["packets", "query"] +packets = ["serverbound", "clientbound"] +serverbound = [] +clientbound = [] +query = [] + [dependencies] pumpkin-nbt = { path = "../pumpkin-nbt" } pumpkin-config = { path = "../pumpkin-config" } diff --git a/pumpkin-protocol/src/client/play/c_set_container_content.rs b/pumpkin-protocol/src/client/play/c_set_container_content.rs index 38e6b39a..275739f2 100644 --- a/pumpkin-protocol/src/client/play/c_set_container_content.rs +++ b/pumpkin-protocol/src/client/play/c_set_container_content.rs @@ -1,4 +1,4 @@ -use crate::slot::Slot; +use crate::codec::slot::Slot; use crate::VarInt; use pumpkin_macros::client_packet; diff --git a/pumpkin-protocol/src/client/play/c_set_container_slot.rs b/pumpkin-protocol/src/client/play/c_set_container_slot.rs index 19e6b484..e632da4e 100644 --- a/pumpkin-protocol/src/client/play/c_set_container_slot.rs +++ b/pumpkin-protocol/src/client/play/c_set_container_slot.rs @@ -1,4 +1,4 @@ -use crate::slot::Slot; +use crate::codec::slot::Slot; use crate::VarInt; use pumpkin_macros::client_packet; diff --git a/pumpkin-protocol/src/codec/mod.rs b/pumpkin-protocol/src/codec/mod.rs index 3af01e21..57af2e19 100644 --- a/pumpkin-protocol/src/codec/mod.rs +++ b/pumpkin-protocol/src/codec/mod.rs @@ -5,6 +5,7 @@ use thiserror::Error; pub mod bit_set; pub mod identifier; +pub mod slot; pub mod var_int; pub mod var_long; diff --git a/pumpkin-protocol/src/slot.rs b/pumpkin-protocol/src/codec/slot.rs similarity index 100% rename from pumpkin-protocol/src/slot.rs rename to pumpkin-protocol/src/codec/slot.rs diff --git a/pumpkin-protocol/src/lib.rs b/pumpkin-protocol/src/lib.rs index 85a5311e..c6156b94 100644 --- a/pumpkin-protocol/src/lib.rs +++ b/pumpkin-protocol/src/lib.rs @@ -7,13 +7,15 @@ use pumpkin_core::text::{style::Style, TextComponent}; use serde::{Deserialize, Serialize}; pub mod bytebuf; +#[cfg(feature = "clientbound")] pub mod client; pub mod codec; pub mod packet_decoder; pub mod packet_encoder; +#[cfg(feature = "query")] pub mod query; +#[cfg(feature = "serverbound")] pub mod server; -pub mod slot; /// To current Minecraft protocol /// Don't forget to change this when porting diff --git a/pumpkin-protocol/src/packet_decoder.rs b/pumpkin-protocol/src/packet_decoder.rs index 8c267f94..5059a2c5 100644 --- a/pumpkin-protocol/src/packet_decoder.rs +++ b/pumpkin-protocol/src/packet_decoder.rs @@ -16,8 +16,8 @@ type Cipher = cfb8::Decryptor; pub struct PacketDecoder { buf: BytesMut, decompress_buf: BytesMut, - compression: bool, cipher: Option, + compression: bool, decompressor: Decompressor, } @@ -28,8 +28,8 @@ impl Default for PacketDecoder { Self { buf: BytesMut::new(), decompress_buf: BytesMut::new(), - compression: false, cipher: None, + compression: false, decompressor: Decompressor::new(), } } diff --git a/pumpkin-protocol/src/packet_encoder.rs b/pumpkin-protocol/src/packet_encoder.rs index d8bea1b7..1636d56e 100644 --- a/pumpkin-protocol/src/packet_encoder.rs +++ b/pumpkin-protocol/src/packet_encoder.rs @@ -15,8 +15,8 @@ type Cipher = cfb8::Encryptor; pub struct PacketEncoder { buf: BytesMut, compress_buf: Vec, - compression_threshold: Option, cipher: Option, + compression_threshold: Option, compressor: Compressor, // Reuse the compressor for all packets } @@ -27,8 +27,8 @@ impl Default for PacketEncoder { Self { buf: BytesMut::with_capacity(1024), compress_buf: Vec::with_capacity(1024), - compression_threshold: None, cipher: None, + compression_threshold: None, compressor: Compressor::new(CompressionLvl::fastest()), // init compressor with fastest compression level } } diff --git a/pumpkin-protocol/src/server/config/s_cookie_response.rs b/pumpkin-protocol/src/server/config/s_cookie_response.rs index 0a2fc03d..b9e3a0a9 100644 --- a/pumpkin-protocol/src/server/config/s_cookie_response.rs +++ b/pumpkin-protocol/src/server/config/s_cookie_response.rs @@ -11,7 +11,7 @@ use crate::{ #[server_packet("config:cookie_response")] /// Response to a Cookie Request (configuration) from the server. /// The Notchian (vanilla) server only accepts responses of up to 5 kiB in size. -pub struct SCookieResponse { +pub struct SConfigCookieResponse { pub key: Identifier, pub has_payload: bool, pub payload_length: Option, @@ -20,7 +20,7 @@ pub struct SCookieResponse { const MAX_PAYLOAD_SIZE: i32 = 5120; -impl ServerPacket for SCookieResponse { +impl ServerPacket for SConfigCookieResponse { fn read(bytebuf: &mut impl Buf) -> Result { let key = bytebuf.try_get_identifer()?; let has_payload = bytebuf.try_get_bool()?; diff --git a/pumpkin-protocol/src/server/login/s_cookie_response.rs b/pumpkin-protocol/src/server/login/s_cookie_response.rs index 82ed37f0..5e498a1b 100644 --- a/pumpkin-protocol/src/server/login/s_cookie_response.rs +++ b/pumpkin-protocol/src/server/login/s_cookie_response.rs @@ -10,7 +10,7 @@ use serde::de; #[server_packet("login:cookie_response")] /// Response to a Cookie Request (login) from the server. /// The Notchian server only accepts responses of up to 5 kiB in size. -pub struct SCookieResponse { +pub struct SLoginCookieResponse { pub key: Identifier, pub has_payload: bool, pub payload_length: Option, @@ -19,7 +19,7 @@ pub struct SCookieResponse { const MAX_PAYLOAD_SIZE: i32 = 5120; -impl ServerPacket for SCookieResponse { +impl ServerPacket for SLoginCookieResponse { fn read(bytebuf: &mut impl Buf) -> Result { let key = bytebuf.try_get_identifer()?; let has_payload = bytebuf.try_get_bool()?; diff --git a/pumpkin-protocol/src/server/play/s_click_container.rs b/pumpkin-protocol/src/server/play/s_click_container.rs index b81e366c..6dcf4abd 100644 --- a/pumpkin-protocol/src/server/play/s_click_container.rs +++ b/pumpkin-protocol/src/server/play/s_click_container.rs @@ -1,4 +1,4 @@ -use crate::slot::Slot; +use crate::codec::slot::Slot; use crate::VarInt; use num_derive::FromPrimitive; use num_traits::FromPrimitive; diff --git a/pumpkin-protocol/src/server/play/s_set_creative_slot.rs b/pumpkin-protocol/src/server/play/s_set_creative_slot.rs index 0dff80b4..59835a43 100644 --- a/pumpkin-protocol/src/server/play/s_set_creative_slot.rs +++ b/pumpkin-protocol/src/server/play/s_set_creative_slot.rs @@ -1,6 +1,6 @@ use pumpkin_macros::server_packet; -use crate::slot::Slot; +use crate::codec::slot::Slot; #[derive(serde::Deserialize, Debug)] #[server_packet("play:set_creative_mode_slot")] diff --git a/pumpkin-world/src/world_gen/aquifer_sampler.rs b/pumpkin-world/src/generation/aquifer_sampler.rs similarity index 99% rename from pumpkin-world/src/world_gen/aquifer_sampler.rs rename to pumpkin-world/src/generation/aquifer_sampler.rs index ebe4d6ac..8dfb4646 100644 --- a/pumpkin-world/src/world_gen/aquifer_sampler.rs +++ b/pumpkin-world/src/generation/aquifer_sampler.rs @@ -661,7 +661,7 @@ mod test { use crate::{ block::BlockState, - world_gen::{ + generation::{ chunk_noise::{ BlockStateSampler, ChunkNoiseDensityFunctions, ChunkNoiseGenerator, ChunkNoiseState, LAVA_BLOCK, WATER_BLOCK, diff --git a/pumpkin-world/src/world_gen/blender/mod.rs b/pumpkin-world/src/generation/blender/mod.rs similarity index 100% rename from pumpkin-world/src/world_gen/blender/mod.rs rename to pumpkin-world/src/generation/blender/mod.rs diff --git a/pumpkin-world/src/world_gen/chunk_noise.rs b/pumpkin-world/src/generation/chunk_noise.rs similarity index 99% rename from pumpkin-world/src/world_gen/chunk_noise.rs rename to pumpkin-world/src/generation/chunk_noise.rs index 5ff2bb27..cab1abf0 100644 --- a/pumpkin-world/src/world_gen/chunk_noise.rs +++ b/pumpkin-world/src/generation/chunk_noise.rs @@ -6,11 +6,11 @@ use pumpkin_macros::block_state; use crate::{ block::BlockState, - match_ref_implementations, - world_gen::{ + generation::{ noise::{density::basic::WrapperType, lerp3}, section_coords, }, + match_ref_implementations, }; use super::{ @@ -1379,7 +1379,7 @@ impl ChunkNoiseGenerator { mod test { use pumpkin_core::math::vector2::Vector2; - use crate::world_gen::{ + use crate::generation::{ aquifer_sampler::{FluidLevel, FluidLevelSampler}, generation_shapes::GenerationShape, noise::{config::NoiseConfig, router::OVERWORLD_NOISE_ROUTER}, diff --git a/pumpkin-world/src/world_gen/generation_shapes.rs b/pumpkin-world/src/generation/generation_shapes.rs similarity index 100% rename from pumpkin-world/src/world_gen/generation_shapes.rs rename to pumpkin-world/src/generation/generation_shapes.rs diff --git a/pumpkin-world/src/world_gen/generator.rs b/pumpkin-world/src/generation/generator.rs similarity index 97% rename from pumpkin-world/src/world_gen/generator.rs rename to pumpkin-world/src/generation/generator.rs index 8a0120c7..a570c8c3 100644 --- a/pumpkin-world/src/world_gen/generator.rs +++ b/pumpkin-world/src/generation/generator.rs @@ -6,7 +6,7 @@ use crate::biome::Biome; use crate::block::block_state::BlockState; use crate::chunk::{ChunkBlocks, ChunkData}; use crate::coordinates::{BlockCoordinates, ChunkRelativeBlockCoordinates, XZBlockCoordinates}; -use crate::world_gen::Seed; +use crate::generation::Seed; pub trait GeneratorInit { fn new(seed: Seed) -> Self; diff --git a/pumpkin-world/src/world_gen/generic_generator.rs b/pumpkin-world/src/generation/generic_generator.rs similarity index 100% rename from pumpkin-world/src/world_gen/generic_generator.rs rename to pumpkin-world/src/generation/generic_generator.rs diff --git a/pumpkin-world/src/world_gen/height_limit.rs b/pumpkin-world/src/generation/height_limit.rs similarity index 100% rename from pumpkin-world/src/world_gen/height_limit.rs rename to pumpkin-world/src/generation/height_limit.rs diff --git a/pumpkin-world/src/world_gen/implementation/mod.rs b/pumpkin-world/src/generation/implementation/mod.rs similarity index 100% rename from pumpkin-world/src/world_gen/implementation/mod.rs rename to pumpkin-world/src/generation/implementation/mod.rs diff --git a/pumpkin-world/src/world_gen/implementation/overworld/biome/mod.rs b/pumpkin-world/src/generation/implementation/overworld/biome/mod.rs similarity index 100% rename from pumpkin-world/src/world_gen/implementation/overworld/biome/mod.rs rename to pumpkin-world/src/generation/implementation/overworld/biome/mod.rs diff --git a/pumpkin-world/src/world_gen/implementation/overworld/biome/plains.rs b/pumpkin-world/src/generation/implementation/overworld/biome/plains.rs similarity index 99% rename from pumpkin-world/src/world_gen/implementation/overworld/biome/plains.rs rename to pumpkin-world/src/generation/implementation/overworld/biome/plains.rs index dde27c9c..775d3e5f 100644 --- a/pumpkin-world/src/world_gen/implementation/overworld/biome/plains.rs +++ b/pumpkin-world/src/generation/implementation/overworld/biome/plains.rs @@ -7,7 +7,7 @@ use crate::{ biome::Biome, chunk::ChunkBlocks, coordinates::{BlockCoordinates, ChunkRelativeBlockCoordinates, XZBlockCoordinates}, - world_gen::{ + generation::{ generator::{BiomeGenerator, GeneratorInit, PerlinTerrainGenerator}, generic_generator::GenericGenerator, Seed, diff --git a/pumpkin-world/src/world_gen/implementation/overworld/mod.rs b/pumpkin-world/src/generation/implementation/overworld/mod.rs similarity index 100% rename from pumpkin-world/src/world_gen/implementation/overworld/mod.rs rename to pumpkin-world/src/generation/implementation/overworld/mod.rs diff --git a/pumpkin-world/src/world_gen/implementation/superflat.rs b/pumpkin-world/src/generation/implementation/superflat.rs similarity index 98% rename from pumpkin-world/src/world_gen/implementation/superflat.rs rename to pumpkin-world/src/generation/implementation/superflat.rs index 2ec9fdad..4e12eba7 100644 --- a/pumpkin-world/src/world_gen/implementation/superflat.rs +++ b/pumpkin-world/src/generation/implementation/superflat.rs @@ -4,7 +4,7 @@ use crate::{ biome::Biome, block::block_state::BlockState, coordinates::XZBlockCoordinates, - world_gen::{ + generation::{ generator::{BiomeGenerator, GeneratorInit, TerrainGenerator}, generic_generator::GenericGenerator, Seed, diff --git a/pumpkin-world/src/world_gen/implementation/test.rs b/pumpkin-world/src/generation/implementation/test.rs similarity index 99% rename from pumpkin-world/src/world_gen/implementation/test.rs rename to pumpkin-world/src/generation/implementation/test.rs index c7bf6089..3a1f08f1 100644 --- a/pumpkin-world/src/world_gen/implementation/test.rs +++ b/pumpkin-world/src/generation/implementation/test.rs @@ -14,7 +14,7 @@ use crate::{ coordinates::{ ChunkRelativeBlockCoordinates, ChunkRelativeXZBlockCoordinates, XZBlockCoordinates, }, - world_gen::{ + generation::{ generator::{BiomeGenerator, GeneratorInit, TerrainGenerator}, proto_chunk::ProtoChunk, Seed, WorldGenerator, diff --git a/pumpkin-world/src/world_gen/mod.rs b/pumpkin-world/src/generation/mod.rs similarity index 100% rename from pumpkin-world/src/world_gen/mod.rs rename to pumpkin-world/src/generation/mod.rs diff --git a/pumpkin-world/src/world_gen/noise/config.rs b/pumpkin-world/src/generation/noise/config.rs similarity index 99% rename from pumpkin-world/src/world_gen/noise/config.rs rename to pumpkin-world/src/generation/noise/config.rs index 4ce194ee..a1e16a0f 100644 --- a/pumpkin-world/src/world_gen/noise/config.rs +++ b/pumpkin-world/src/generation/noise/config.rs @@ -151,8 +151,7 @@ mod test { }; use crate::{ - read_data_from_file, - world_gen::noise::{ + generation::noise::{ config::NoiseConfig, density::{ built_in_density_function::{ @@ -165,6 +164,7 @@ mod test { }, router::OVERWORLD_NOISE_ROUTER, }, + read_data_from_file, }; use super::LegacyChunkNoiseVisitor; diff --git a/pumpkin-world/src/world_gen/noise/density/basic.rs b/pumpkin-world/src/generation/noise/density/basic.rs similarity index 99% rename from pumpkin-world/src/world_gen/noise/density/basic.rs rename to pumpkin-world/src/generation/noise/density/basic.rs index cb118a4a..a96be636 100644 --- a/pumpkin-world/src/world_gen/noise/density/basic.rs +++ b/pumpkin-world/src/generation/noise/density/basic.rs @@ -1,6 +1,6 @@ use std::{hash::Hash, marker::PhantomData}; -use crate::{match_ref_implementations, world_gen::noise::clamped_map}; +use crate::{generation::noise::clamped_map, match_ref_implementations}; use super::{ component_functions::{ @@ -419,10 +419,10 @@ mod test { use std::{fs, path::Path}; use crate::{ - read_data_from_file, - world_gen::noise::density::{ + generation::noise::density::{ component_functions::ImmutableComponentFunctionImpl, NoisePos, UnblendedNoisePos, }, + read_data_from_file, }; use super::YClampedFunction; diff --git a/pumpkin-world/src/world_gen/noise/density/blend.rs b/pumpkin-world/src/generation/noise/density/blend.rs similarity index 99% rename from pumpkin-world/src/world_gen/noise/density/blend.rs rename to pumpkin-world/src/generation/noise/density/blend.rs index 309fa345..bf6bbb70 100644 --- a/pumpkin-world/src/world_gen/noise/density/blend.rs +++ b/pumpkin-world/src/generation/noise/density/blend.rs @@ -1,6 +1,6 @@ use std::marker::PhantomData; -use crate::world_gen::blender::BlenderImpl; +use crate::generation::blender::BlenderImpl; use super::{ component_functions::{ diff --git a/pumpkin-world/src/world_gen/noise/density/component_functions.rs b/pumpkin-world/src/generation/noise/density/component_functions.rs similarity index 99% rename from pumpkin-world/src/world_gen/noise/density/component_functions.rs rename to pumpkin-world/src/generation/noise/density/component_functions.rs index 6c47665e..036c4eba 100644 --- a/pumpkin-world/src/world_gen/noise/density/component_functions.rs +++ b/pumpkin-world/src/generation/noise/density/component_functions.rs @@ -953,7 +953,7 @@ mod test { use pumpkin_core::random::{legacy_rand::LegacyRand, RandomDeriver, RandomImpl}; - use crate::world_gen::noise::{ + use crate::generation::noise::{ built_in_noise_params, density::{ noise::{InternalNoise, NoiseFunction}, diff --git a/pumpkin-world/src/world_gen/noise/density/end.rs b/pumpkin-world/src/generation/noise/density/end.rs similarity index 97% rename from pumpkin-world/src/world_gen/noise/density/end.rs rename to pumpkin-world/src/generation/noise/density/end.rs index 39ee37bc..c1c3db33 100644 --- a/pumpkin-world/src/world_gen/noise/density/end.rs +++ b/pumpkin-world/src/generation/noise/density/end.rs @@ -1,6 +1,6 @@ use pumpkin_core::random::{legacy_rand::LegacyRand, RandomImpl}; -use crate::world_gen::noise::simplex::SimplexNoiseSampler; +use crate::generation::noise::simplex::SimplexNoiseSampler; use super::{ component_functions::{ diff --git a/pumpkin-world/src/world_gen/noise/density/math.rs b/pumpkin-world/src/generation/noise/density/math.rs similarity index 100% rename from pumpkin-world/src/world_gen/noise/density/math.rs rename to pumpkin-world/src/generation/noise/density/math.rs diff --git a/pumpkin-world/src/world_gen/noise/density/mod.rs b/pumpkin-world/src/generation/noise/density/mod.rs similarity index 99% rename from pumpkin-world/src/world_gen/noise/density/mod.rs rename to pumpkin-world/src/generation/noise/density/mod.rs index ecec8350..e789b3bd 100644 --- a/pumpkin-world/src/world_gen/noise/density/mod.rs +++ b/pumpkin-world/src/generation/noise/density/mod.rs @@ -10,7 +10,7 @@ use component_functions::{ use enum_dispatch::enum_dispatch; use noise::{InternalNoise, NoiseFunction}; -use crate::world_gen::{blender::Blender, chunk_noise::ChunkNoisePos}; +use crate::generation::{blender::Blender, chunk_noise::ChunkNoisePos}; use super::perlin::DoublePerlinNoiseParameters; @@ -76,8 +76,8 @@ pub trait NoisePosImpl { pub mod built_in_density_function { use std::sync::{Arc, LazyLock}; - use crate::world_gen::noise::built_in_noise_params::{self}; - use crate::world_gen::positions::{MAX_COLUMN_HEIGHT, MIN_HEIGHT}; + use crate::generation::noise::built_in_noise_params::{self}; + use crate::generation::positions::{MAX_COLUMN_HEIGHT, MIN_HEIGHT}; use pumpkin_core::math::floor_div; @@ -879,7 +879,7 @@ mod test { legacy_rand::LegacyRand, RandomDeriver, RandomDeriverImpl, RandomImpl, }; - use crate::world_gen::noise::{ + use crate::generation::noise::{ built_in_noise_params, density::{built_in_density_function::*, NoisePos, UnblendedNoisePos}, perlin::DoublePerlinNoiseSampler, diff --git a/pumpkin-world/src/world_gen/noise/density/noise.rs b/pumpkin-world/src/generation/noise/density/noise.rs similarity index 99% rename from pumpkin-world/src/world_gen/noise/density/noise.rs rename to pumpkin-world/src/generation/noise/density/noise.rs index 353273b4..1fe13937 100644 --- a/pumpkin-world/src/world_gen/noise/density/noise.rs +++ b/pumpkin-world/src/generation/noise/density/noise.rs @@ -3,11 +3,11 @@ use std::{marker::PhantomData, sync::Arc}; use pumpkin_core::random::{xoroshiro128::Xoroshiro, RandomGenerator, RandomImpl}; use crate::{ - match_ref_implementations, - world_gen::noise::{ + generation::noise::{ clamped_lerp, perlin::{DoublePerlinNoiseParameters, DoublePerlinNoiseSampler, OctavePerlinNoiseSampler}, }, + match_ref_implementations, }; use super::{ diff --git a/pumpkin-world/src/world_gen/noise/density/offset.rs b/pumpkin-world/src/generation/noise/density/offset.rs similarity index 100% rename from pumpkin-world/src/world_gen/noise/density/offset.rs rename to pumpkin-world/src/generation/noise/density/offset.rs diff --git a/pumpkin-world/src/world_gen/noise/density/spline.rs b/pumpkin-world/src/generation/noise/density/spline.rs similarity index 99% rename from pumpkin-world/src/world_gen/noise/density/spline.rs rename to pumpkin-world/src/generation/noise/density/spline.rs index cb2aa6ee..142079a9 100644 --- a/pumpkin-world/src/world_gen/noise/density/spline.rs +++ b/pumpkin-world/src/generation/noise/density/spline.rs @@ -2,7 +2,7 @@ use std::{marker::PhantomData, sync::Arc}; use enum_dispatch::enum_dispatch; -use crate::world_gen::noise::lerp; +use crate::generation::noise::lerp; use super::{ component_functions::{ @@ -744,7 +744,7 @@ mod test { use pumpkin_core::random::{legacy_rand::LegacyRand, RandomDeriver, RandomImpl}; - use crate::world_gen::noise::density::{ + use crate::generation::noise::density::{ built_in_density_function::CONTINENTS_OVERWORLD, component_functions::{ComponentReference, NoEnvironment, SharedComponentReference}, test::{FakeEnvironment, OwnedConverter, TestConverter}, diff --git a/pumpkin-world/src/world_gen/noise/density/terrain_helpers.rs b/pumpkin-world/src/generation/noise/density/terrain_helpers.rs similarity index 99% rename from pumpkin-world/src/world_gen/noise/density/terrain_helpers.rs rename to pumpkin-world/src/generation/noise/density/terrain_helpers.rs index b19df8c6..cc8ad704 100644 --- a/pumpkin-world/src/world_gen/noise/density/terrain_helpers.rs +++ b/pumpkin-world/src/generation/noise/density/terrain_helpers.rs @@ -1,7 +1,7 @@ // From da java -use crate::world_gen::noise::density::peaks_valleys_noise; -use crate::world_gen::noise::lerp; +use crate::generation::noise::density::peaks_valleys_noise; +use crate::generation::noise::lerp; use super::component_functions::SharedComponentReference; use super::spline::{FloatAmplifier, ImmutableSpline, ImmutableSplineRef, SplineBuilder}; @@ -523,7 +523,7 @@ pub fn create_jaggedness_spline( mod test { use pumpkin_core::random::{legacy_rand::LegacyRand, RandomDeriver, RandomImpl}; - use crate::world_gen::noise::density::{ + use crate::generation::noise::density::{ built_in_density_function::{ CONTINENTS_OVERWORLD, EROSION_OVERWORLD, RIDGES_FOLDED_OVERWORLD, RIDGES_OVERWORLD, }, diff --git a/pumpkin-world/src/world_gen/noise/density/unary.rs b/pumpkin-world/src/generation/noise/density/unary.rs similarity index 100% rename from pumpkin-world/src/world_gen/noise/density/unary.rs rename to pumpkin-world/src/generation/noise/density/unary.rs diff --git a/pumpkin-world/src/world_gen/noise/density/weird.rs b/pumpkin-world/src/generation/noise/density/weird.rs similarity index 100% rename from pumpkin-world/src/world_gen/noise/density/weird.rs rename to pumpkin-world/src/generation/noise/density/weird.rs diff --git a/pumpkin-world/src/world_gen/noise/mod.rs b/pumpkin-world/src/generation/noise/mod.rs similarity index 100% rename from pumpkin-world/src/world_gen/noise/mod.rs rename to pumpkin-world/src/generation/noise/mod.rs diff --git a/pumpkin-world/src/world_gen/noise/perlin.rs b/pumpkin-world/src/generation/noise/perlin.rs similarity index 99% rename from pumpkin-world/src/world_gen/noise/perlin.rs rename to pumpkin-world/src/generation/noise/perlin.rs index 09563485..4e8de285 100644 --- a/pumpkin-world/src/world_gen/noise/perlin.rs +++ b/pumpkin-world/src/generation/noise/perlin.rs @@ -381,7 +381,7 @@ mod double_perlin_noise_sampler_test { legacy_rand::LegacyRand, xoroshiro128::Xoroshiro, RandomGenerator, RandomImpl, }; - use crate::world_gen::noise::perlin::{DoublePerlinNoiseParameters, DoublePerlinNoiseSampler}; + use crate::generation::noise::perlin::{DoublePerlinNoiseParameters, DoublePerlinNoiseSampler}; #[test] fn sample_legacy() { @@ -760,7 +760,7 @@ mod perlin_noise_sampler_test { random::{xoroshiro128::Xoroshiro, RandomDeriverImpl, RandomGenerator, RandomImpl}, }; - use crate::{read_data_from_file, world_gen::noise::perlin::PerlinNoiseSampler}; + use crate::{generation::noise::perlin::PerlinNoiseSampler, read_data_from_file}; use super::OctavePerlinNoiseSampler; diff --git a/pumpkin-world/src/world_gen/noise/router.rs b/pumpkin-world/src/generation/noise/router.rs similarity index 99% rename from pumpkin-world/src/world_gen/noise/router.rs rename to pumpkin-world/src/generation/noise/router.rs index ddf605c3..cb8093c1 100644 --- a/pumpkin-world/src/world_gen/noise/router.rs +++ b/pumpkin-world/src/generation/noise/router.rs @@ -1,6 +1,6 @@ use std::sync::{Arc, LazyLock}; -use crate::world_gen::{ +use crate::generation::{ noise::density::{ apply_blend_density, basic::RangeFunction, @@ -476,8 +476,7 @@ mod test { }; use crate::{ - read_data_from_file, - world_gen::noise::{ + generation::noise::{ config::LegacyChunkNoiseVisitor, density::{ built_in_density_function::{EROSION_OVERWORLD, SLOPED_CHEESE_OVERWORLD}, @@ -491,6 +490,7 @@ mod test { perlin::DoublePerlinNoiseSampler, router::OVERWORLD_NOISE_ROUTER, }, + read_data_from_file, }; use super::{apply_surface_slides, create_caves}; diff --git a/pumpkin-world/src/world_gen/noise/simplex.rs b/pumpkin-world/src/generation/noise/simplex.rs similarity index 99% rename from pumpkin-world/src/world_gen/noise/simplex.rs rename to pumpkin-world/src/generation/noise/simplex.rs index ff9afd6e..c69128c3 100644 --- a/pumpkin-world/src/world_gen/noise/simplex.rs +++ b/pumpkin-world/src/generation/noise/simplex.rs @@ -276,7 +276,7 @@ impl OctaveSimplexNoiseSampler { mod octave_simplex_noise_sampler_test { use pumpkin_core::random::{xoroshiro128::Xoroshiro, RandomImpl}; - use crate::world_gen::noise::simplex::OctaveSimplexNoiseSampler; + use crate::generation::noise::simplex::OctaveSimplexNoiseSampler; #[test] fn test_new() { @@ -413,7 +413,7 @@ mod simplex_noise_sampler_test { use pumpkin_core::random::{xoroshiro128::Xoroshiro, RandomImpl}; - use crate::world_gen::noise::simplex::SimplexNoiseSampler; + use crate::generation::noise::simplex::SimplexNoiseSampler; #[test] fn test_create() { diff --git a/pumpkin-world/src/world_gen/ore_sampler.rs b/pumpkin-world/src/generation/ore_sampler.rs similarity index 100% rename from pumpkin-world/src/world_gen/ore_sampler.rs rename to pumpkin-world/src/generation/ore_sampler.rs diff --git a/pumpkin-world/src/world_gen/positions.rs b/pumpkin-world/src/generation/positions.rs similarity index 100% rename from pumpkin-world/src/world_gen/positions.rs rename to pumpkin-world/src/generation/positions.rs diff --git a/pumpkin-world/src/world_gen/proto_chunk.rs b/pumpkin-world/src/generation/proto_chunk.rs similarity index 99% rename from pumpkin-world/src/world_gen/proto_chunk.rs rename to pumpkin-world/src/generation/proto_chunk.rs index 6f36cab6..056a702f 100644 --- a/pumpkin-world/src/world_gen/proto_chunk.rs +++ b/pumpkin-world/src/generation/proto_chunk.rs @@ -2,7 +2,7 @@ use pumpkin_core::math::{vector2::Vector2, vector3::Vector3}; use crate::{ block::BlockState, - world_gen::{ + generation::{ chunk_noise::CHUNK_DIM, generation_shapes::GenerationShape, noise::{config::NoiseConfig, router::OVERWORLD_NOISE_ROUTER}, diff --git a/pumpkin-world/src/world_gen/seed.rs b/pumpkin-world/src/generation/seed.rs similarity index 100% rename from pumpkin-world/src/world_gen/seed.rs rename to pumpkin-world/src/generation/seed.rs diff --git a/pumpkin-world/src/level.rs b/pumpkin-world/src/level.rs index e0b8ac12..70dcdc7a 100644 --- a/pumpkin-world/src/level.rs +++ b/pumpkin-world/src/level.rs @@ -14,7 +14,7 @@ use crate::{ chunk::{ anvil::AnvilChunkReader, ChunkData, ChunkParsingError, ChunkReader, ChunkReadingError, }, - world_gen::{get_world_gen, Seed, WorldGenerator}, + generation::{get_world_gen, Seed, WorldGenerator}, }; /// The `Level` module provides functionality for working with chunks within or outside a Minecraft world. diff --git a/pumpkin-world/src/lib.rs b/pumpkin-world/src/lib.rs index d1d6284c..3735dbb5 100644 --- a/pumpkin-world/src/lib.rs +++ b/pumpkin-world/src/lib.rs @@ -1,11 +1,11 @@ -use pumpkin_core::math::vector2::Vector2; -use world_gen::{ +use generation::{ aquifer_sampler::{FluidLevel, FluidLevelSampler}, chunk_noise::{ChunkNoiseGenerator, LAVA_BLOCK, WATER_BLOCK}, generation_shapes::GenerationShape, noise::{config::NoiseConfig, router::OVERWORLD_NOISE_ROUTER}, proto_chunk::{ProtoChunk, StandardChunkFluidLevelSampler}, }; +use pumpkin_core::math::vector2::Vector2; pub mod biome; pub mod block; @@ -13,9 +13,9 @@ pub mod chunk; pub mod coordinates; pub mod cylindrical_chunk_iterator; pub mod dimension; +mod generation; pub mod item; pub mod level; -mod world_gen; pub const WORLD_HEIGHT: usize = 384; pub const WORLD_LOWEST_Y: i16 = -64; diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index 9f0a8e07..c9e51dd1 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -57,10 +57,9 @@ use pumpkin_world::{ use tokio::sync::{Mutex, Notify}; use super::Entity; -use crate::error::PumpkinError; +use crate::{error::PumpkinError, net::GameProfile}; use crate::{ - client::{ - authentication::GameProfile, + net::{ combat::{self, player_attack_sound, AttackType}, Client, PlayerConfig, }, diff --git a/pumpkin/src/main.rs b/pumpkin/src/main.rs index c2547e78..232f30a1 100644 --- a/pumpkin/src/main.rs +++ b/pumpkin/src/main.rs @@ -35,7 +35,7 @@ compile_error!("Compiling for WASI targets is not supported!"); use log::LevelFilter; -use client::Client; +use net::{lan_broadcast, query, rcon::RCONServer, Client}; use server::{ticker::Ticker, Server}; use std::io::{self}; use tokio::io::{AsyncBufReadExt, BufReader}; @@ -50,19 +50,14 @@ use crate::server::CURRENT_MC_VERSION; use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG}; use pumpkin_core::text::{color::NamedColor, TextComponent}; use pumpkin_protocol::CURRENT_MC_PROTOCOL; -use rcon::RCONServer; use std::time::Instant; // Setup some tokens to allow us to identify which event is for which socket. pub mod block; -pub mod client; pub mod command; pub mod entity; pub mod error; -pub mod lan_broadcast; -pub mod proxy; -pub mod query; -pub mod rcon; +pub mod net; pub mod server; pub mod world; diff --git a/pumpkin/src/client/authentication.rs b/pumpkin/src/net/authentication.rs similarity index 85% rename from pumpkin/src/client/authentication.rs rename to pumpkin/src/net/authentication.rs index f99a62cb..4136a74a 100644 --- a/pumpkin/src/client/authentication.rs +++ b/pumpkin/src/net/authentication.rs @@ -2,15 +2,14 @@ use std::{collections::HashMap, net::IpAddr}; use base64::{engine::general_purpose, Engine}; use pumpkin_config::{auth::TextureConfig, ADVANCED_CONFIG}; -use pumpkin_core::ProfileAction; use pumpkin_protocol::Property; use reqwest::{StatusCode, Url}; use serde::Deserialize; -use sha1::Digest; -use sha2::Sha256; use thiserror::Error; use uuid::Uuid; +use super::GameProfile; + #[derive(Deserialize, Clone, Debug)] #[expect(dead_code)] #[serde(rename_all = "camelCase")] @@ -29,14 +28,8 @@ pub struct Texture { metadata: Option>, } -#[derive(Deserialize, Clone, Debug)] -pub struct GameProfile { - pub id: Uuid, - pub name: String, - pub properties: Vec, - #[serde(rename = "profileActions")] - pub profile_actions: Option>, -} +const MOJANG_AUTHENTICATION_URL: &str = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username={username}&serverId={server_hash}"; +const MOJANG_PREVENT_PROXY_AUTHENTICATION_URL: &str = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username={username}&serverId={server_hash}"; /// Sends a GET request to Mojang's authentication servers to verify a client's Minecraft account. /// @@ -50,20 +43,19 @@ pub struct GameProfile { /// 2. Mojang's servers verify the client's credentials and add the player to the their Servers /// 3. Now our server will send a Request to the Session servers and check if the Player has joined the Session Server . /// -/// See +/// See pub async fn authenticate( username: &str, server_hash: &str, ip: &IpAddr, auth_client: &reqwest::Client, ) -> Result { - assert!(ADVANCED_CONFIG.authentication.enabled); let address = if ADVANCED_CONFIG.authentication.prevent_proxy_connections { let auth_url = ADVANCED_CONFIG .authentication .prevent_proxy_connection_auth_url .as_deref() - .unwrap_or("https://sessionserver.mojang.com/session/minecraft/hasJoined?username={username}&serverId={server_hash}&ip={ip}"); + .unwrap_or(MOJANG_PREVENT_PROXY_AUTHENTICATION_URL); auth_url .replace("{username}", username) @@ -74,7 +66,7 @@ pub async fn authenticate( .authentication .auth_url .as_deref() - .unwrap_or("https://sessionserver.mojang.com/session/minecraft/hasJoined?username={username}&serverId={server_hash}"); + .unwrap_or(MOJANG_AUTHENTICATION_URL); auth_url .replace("{username}", username) @@ -129,10 +121,6 @@ pub fn is_texture_url_valid(url: &Url, config: &TextureConfig) -> Result<(), Tex Ok(()) } -pub fn offline_uuid(username: &str) -> Result { - Uuid::from_slice(&Sha256::digest(username)[..16]) -} - #[derive(Error, Debug)] pub enum AuthError { #[error("Missing auth client")] diff --git a/pumpkin/src/client/combat.rs b/pumpkin/src/net/combat.rs similarity index 100% rename from pumpkin/src/client/combat.rs rename to pumpkin/src/net/combat.rs diff --git a/pumpkin/src/client/container.rs b/pumpkin/src/net/container.rs similarity index 99% rename from pumpkin/src/client/container.rs rename to pumpkin/src/net/container.rs index 42a4b23c..9e06a46d 100644 --- a/pumpkin/src/client/container.rs +++ b/pumpkin/src/net/container.rs @@ -12,9 +12,9 @@ use pumpkin_inventory::{Container, WindowType}; use pumpkin_protocol::client::play::{ CCloseContainer, COpenScreen, CSetContainerContent, CSetContainerProperty, CSetContainerSlot, }; +use pumpkin_protocol::codec::slot::Slot; use pumpkin_protocol::codec::var_int::VarInt; use pumpkin_protocol::server::play::SClickContainer; -use pumpkin_protocol::slot::Slot; use pumpkin_world::item::item_registry::Item; use pumpkin_world::item::ItemStack; use std::sync::Arc; diff --git a/pumpkin/src/lan_broadcast.rs b/pumpkin/src/net/lan_broadcast.rs similarity index 100% rename from pumpkin/src/lan_broadcast.rs rename to pumpkin/src/net/lan_broadcast.rs diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/net/mod.rs similarity index 94% rename from pumpkin/src/client/mod.rs rename to pumpkin/src/net/mod.rs index 977dd6f6..0e5f9e9c 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/net/mod.rs @@ -13,34 +13,57 @@ use crate::{ server::Server, }; -use authentication::GameProfile; use crossbeam::atomic::AtomicCell; use pumpkin_config::compression::CompressionInfo; -use pumpkin_core::text::TextComponent; +use pumpkin_core::{text::TextComponent, ProfileAction}; use pumpkin_protocol::{ bytebuf::{packet_id::Packet, ReadingError}, client::{config::CConfigDisconnect, login::CLoginDisconnect, play::CPlayDisconnect}, packet_decoder::PacketDecoder, packet_encoder::{PacketEncodeError, PacketEncoder}, server::{ - config::{SAcknowledgeFinishConfig, SClientInformationConfig, SKnownPacks, SPluginMessage}, + config::{ + SAcknowledgeFinishConfig, SClientInformationConfig, SConfigCookieResponse, SKnownPacks, + SPluginMessage, + }, handshake::SHandShake, - login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart}, + login::{ + SEncryptionResponse, SLoginAcknowledged, SLoginCookieResponse, SLoginPluginResponse, + SLoginStart, + }, status::{SStatusPingRequest, SStatusRequest}, }, - ClientPacket, ConnectionState, RawPacket, ServerPacket, + ClientPacket, ConnectionState, Property, RawPacket, ServerPacket, }; +use serde::Deserialize; +use sha1::Digest; +use sha2::Sha256; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::sync::Mutex; -use pumpkin_protocol::server::config::SCookieResponse as SCCookieResponse; -use pumpkin_protocol::server::login::SCookieResponse as SLCookieResponse; use thiserror::Error; -pub mod authentication; -mod client_packet; +use uuid::Uuid; +mod authentication; pub mod combat; mod container; -pub mod player_packet; +pub mod lan_broadcast; +mod packet; +mod proxy; +pub mod query; +pub mod rcon; + +#[derive(Deserialize, Clone, Debug)] +pub struct GameProfile { + pub id: Uuid, + pub name: String, + pub properties: Vec, + #[serde(rename = "profileActions")] + pub profile_actions: Option>, +} + +pub fn offline_uuid(username: &str) -> Result { + Uuid::from_slice(&Sha256::digest(username)[..16]) +} /// Represents a player's configuration settings. /// @@ -102,8 +125,6 @@ pub struct Client { pub server_address: Mutex, /// The current connection state of the client (e.g., Handshaking, Status, Play). pub connection_state: AtomicCell, - /// Whether encryption is enabled for the connection. - pub encryption: AtomicBool, /// Indicates if the client connection is closed. pub closed: AtomicBool, /// The underlying TCP connection to the client. @@ -138,7 +159,6 @@ impl Client { connection_writer: Arc::new(Mutex::new(connection_writer)), enc: Arc::new(Mutex::new(PacketEncoder::default())), dec: Arc::new(Mutex::new(PacketDecoder::default())), - encryption: AtomicBool::new(false), closed: AtomicBool::new(false), client_packets_queue: Arc::new(Mutex::new(VecDeque::new())), make_player: AtomicBool::new(false), @@ -182,8 +202,6 @@ impl Client { shared_secret: Option<&[u8]>, // decrypted ) -> Result<(), EncryptionError> { if let Some(shared_secret) = shared_secret { - self.encryption - .store(true, std::sync::atomic::Ordering::Relaxed); let crypt_key: [u8; 16] = shared_secret .try_into() .map_err(|_| EncryptionError::SharedWrongLength)?; @@ -433,8 +451,8 @@ impl Client { SLoginAcknowledged::PACKET_ID => { self.handle_login_acknowledged(server).await; } - SLCookieResponse::PACKET_ID => { - self.handle_login_cookie_response(SLCookieResponse::read(bytebuf)?); + SLoginCookieResponse::PACKET_ID => { + self.handle_login_cookie_response(SLoginCookieResponse::read(bytebuf)?); } _ => { log::error!( @@ -469,8 +487,8 @@ impl Client { self.handle_known_packs(server, SKnownPacks::read(bytebuf)?) .await; } - SCCookieResponse::PACKET_ID => { - self.handle_config_cookie_response(SCCookieResponse::read(bytebuf)?); + SConfigCookieResponse::PACKET_ID => { + self.handle_config_cookie_response(SConfigCookieResponse::read(bytebuf)?); } _ => { log::error!( diff --git a/pumpkin/src/net/packet/config.rs b/pumpkin/src/net/packet/config.rs new file mode 100644 index 00000000..ed1d8769 --- /dev/null +++ b/pumpkin/src/net/packet/config.rs @@ -0,0 +1,98 @@ +use std::num::NonZeroU8; + +use crate::{ + entity::player::{ChatMode, Hand}, + net::{Client, PlayerConfig}, + server::Server, +}; +use core::str; +use num_traits::FromPrimitive; +use pumpkin_protocol::{ + client::config::{CFinishConfig, CRegistryData}, + codec::var_int::VarInt, + server::config::{ + SClientInformationConfig, SConfigCookieResponse, SKnownPacks, SPluginMessage, + }, + ConnectionState, +}; + +impl Client { + pub async fn handle_client_information_config( + &self, + client_information: SClientInformationConfig, + ) { + log::debug!("Handling client settings"); + if client_information.view_distance <= 0 { + self.kick("Cannot have zero or negative view distance!") + .await; + return; + } + + if let (Some(main_hand), Some(chat_mode)) = ( + Hand::from_i32(client_information.main_hand.into()), + ChatMode::from_i32(client_information.chat_mode.into()), + ) { + *self.config.lock().await = Some(PlayerConfig { + locale: client_information.locale, + view_distance: unsafe { + NonZeroU8::new_unchecked(client_information.view_distance as u8) + }, + chat_mode, + chat_colors: client_information.chat_colors, + skin_parts: client_information.skin_parts, + main_hand, + text_filtering: client_information.text_filtering, + server_listing: client_information.server_listing, + }); + } else { + self.kick("Invalid hand or chat type").await; + } + } + + pub async fn handle_plugin_message(&self, plugin_message: SPluginMessage) { + log::debug!("Handling plugin message"); + if plugin_message + .channel + .to_string() + .starts_with("minecraft:brand") + { + log::debug!("got a client brand"); + match str::from_utf8(&plugin_message.data) { + Ok(brand) => *self.brand.lock().await = Some(brand.to_string()), + Err(e) => self.kick(&e.to_string()).await, + } + } + } + + pub fn handle_config_cookie_response(&self, packet: SConfigCookieResponse) { + // TODO: allow plugins to access this + log::debug!( + "Received cookie_response[config]: key: \"{}\", has_payload: \"{}\", payload_length: \"{}\"", + packet.key.to_string(), + packet.has_payload, + packet.payload_length.unwrap_or(VarInt::from(0)).0 + ); + } + + pub async fn handle_known_packs(&self, server: &Server, _config_acknowledged: SKnownPacks) { + log::debug!("Handling known packs"); + for registry in &server.cached_registry { + self.send_packet(&CRegistryData::new( + ®istry.registry_id, + ®istry.registry_entries, + )) + .await; + } + + // We are done with configuring + log::debug!("finished config"); + self.send_packet(&CFinishConfig::new()).await; + } + + pub fn handle_config_acknowledged(&self) { + log::debug!("Handling config acknowledge"); + self.connection_state.store(ConnectionState::Play); + self.make_player + .store(true, std::sync::atomic::Ordering::Relaxed); + } +} diff --git a/pumpkin/src/net/packet/handshake.rs b/pumpkin/src/net/packet/handshake.rs new file mode 100644 index 00000000..58705210 --- /dev/null +++ b/pumpkin/src/net/packet/handshake.rs @@ -0,0 +1,29 @@ +use std::num::NonZeroI32; + +use pumpkin_protocol::{server::handshake::SHandShake, ConnectionState, CURRENT_MC_PROTOCOL}; + +use crate::{net::Client, server::CURRENT_MC_VERSION}; + +impl Client { + pub async fn handle_handshake(&self, handshake: SHandShake) { + let version = handshake.protocol_version.0; + self.protocol_version + .store(version, std::sync::atomic::Ordering::Relaxed); + *self.server_address.lock().await = handshake.server_address; + + log::debug!("Handshake: next state {:?}", &handshake.next_state); + self.connection_state.store(handshake.next_state); + if self.connection_state.load() != ConnectionState::Status { + let protocol = version; + match protocol.cmp(&NonZeroI32::from(CURRENT_MC_PROTOCOL).get()) { + std::cmp::Ordering::Less => { + self.kick(&format!("Client outdated ({protocol}), Server uses Minecraft {CURRENT_MC_VERSION}, Protocol {CURRENT_MC_PROTOCOL}")).await; + } + std::cmp::Ordering::Equal => {} + std::cmp::Ordering::Greater => { + self.kick(&format!("Server outdated, Server uses Minecraft {CURRENT_MC_VERSION}, Protocol {CURRENT_MC_PROTOCOL}")).await; + } + } + } + } +} diff --git a/pumpkin/src/client/client_packet.rs b/pumpkin/src/net/packet/login.rs similarity index 63% rename from pumpkin/src/client/client_packet.rs rename to pumpkin/src/net/packet/login.rs index 76e0ce68..db61b865 100644 --- a/pumpkin/src/client/client_packet.rs +++ b/pumpkin/src/net/packet/login.rs @@ -1,43 +1,30 @@ -use super::{authentication::AuthError, Client, PlayerConfig}; -use crate::{ - client::authentication::{self, offline_uuid, validate_textures, GameProfile}, - entity::player::{ChatMode, Hand}, - proxy::{ - bungeecord, - velocity::{self, velocity_login}, - }, - server::{Server, CURRENT_MC_VERSION}, -}; -use core::str; -use num_traits::FromPrimitive; +use std::sync::LazyLock; + use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG}; use pumpkin_core::text::TextComponent; -use pumpkin_protocol::server::config::SCookieResponse as SCCookieResponse; -use pumpkin_protocol::server::login::SCookieResponse as SLCookieResponse; -use pumpkin_protocol::{ - client::config::{CServerLinks, Label, Link, LinkType}, - codec::var_int::VarInt, -}; use pumpkin_protocol::{ client::{ - config::{CConfigAddResourcePack, CFinishConfig, CKnownPacks, CRegistryData}, + config::{CConfigAddResourcePack, CKnownPacks}, login::{CLoginSuccess, CSetCompression}, - status::CPingResponse, - }, - server::{ - config::{SClientInformationConfig, SKnownPacks, SPluginMessage}, - handshake::SHandShake, - login::{SEncryptionResponse, SLoginPluginResponse, SLoginStart}, - status::SStatusPingRequest, + play::{CServerLinks, Label, Link, LinkType}, }, - ConnectionState, KnownPack, CURRENT_MC_PROTOCOL, -}; -use std::{ - num::{NonZeroI32, NonZeroU8}, - sync::LazyLock, + codec::var_int::VarInt, + server::login::{SEncryptionResponse, SLoginCookieResponse, SLoginPluginResponse, SLoginStart}, + ConnectionState, KnownPack, }; use uuid::Uuid; +use crate::{ + net::{ + authentication::{self, AuthError}, + offline_uuid, + packet::is_valid_player_name, + proxy::{bungeecord, velocity}, + Client, GameProfile, + }, + server::Server, +}; + static LINKS: LazyLock> = LazyLock::new(|| { let mut links: Vec = Vec::new(); @@ -98,49 +85,7 @@ static LINKS: LazyLock> = LazyLock::new(|| { links }); -/// Processes incoming Packets from the Client to the Server -/// Implements the `Client` Packets -/// NEVER TRUST THE CLIENT. HANDLE EVERY ERROR, UNWRAP/EXPECT impl Client { - pub async fn handle_handshake(&self, handshake: SHandShake) { - let version = handshake.protocol_version.0; - self.protocol_version - .store(version, std::sync::atomic::Ordering::Relaxed); - *self.server_address.lock().await = handshake.server_address; - - log::debug!("Handshake: next state {:?}", &handshake.next_state); - self.connection_state.store(handshake.next_state); - if self.connection_state.load() != ConnectionState::Status { - let protocol = version; - match protocol.cmp(&NonZeroI32::from(CURRENT_MC_PROTOCOL).get()) { - std::cmp::Ordering::Less => { - self.kick(&format!("Client outdated ({protocol}), Server uses Minecraft {CURRENT_MC_VERSION}, Protocol {CURRENT_MC_PROTOCOL}")).await; - } - std::cmp::Ordering::Equal => {} - std::cmp::Ordering::Greater => { - self.kick(&format!("Server outdated, Server uses Minecraft {CURRENT_MC_VERSION}, Protocol {CURRENT_MC_PROTOCOL}")).await; - } - } - } - } - - pub async fn handle_status_request(&self, server: &Server) { - log::debug!("Handling status request"); - let status = server.get_status(); - self.send_packet(&status.lock().await.get_status()).await; - } - - pub async fn handle_ping_request(&self, ping_request: SStatusPingRequest) { - log::debug!("Handling ping request"); - self.send_packet(&CPingResponse::new(ping_request.payload)) - .await; - self.close(); - } - - fn is_valid_player_name(name: &str) -> bool { - name.len() <= 16 && name.chars().all(|c| c > 32u8 as char && c < 127u8 as char) - } - pub async fn handle_login_start(&self, server: &Server, login_start: SLoginStart) { log::debug!("login start"); @@ -154,7 +99,7 @@ impl Client { return; } - if !Self::is_valid_player_name(&login_start.name) { + if !is_valid_player_name(&login_start.name) { self.kick("Invalid characters in username").await; return; } @@ -164,9 +109,15 @@ impl Client { let proxy = &ADVANCED_CONFIG.proxy; if proxy.enabled { if proxy.velocity.enabled { - velocity_login(self).await; + velocity::velocity_login(self).await; } else if proxy.bungeecord.enabled { - match bungeecord::bungeecord_login(self, login_start.name).await { + match bungeecord::bungeecord_login( + &self.address, + &self.server_address.lock().await, + login_start.name, + ) + .await + { Ok((_ip, profile)) => { // self.address.lock() = ip; self.finish_login(&profile).await; @@ -309,24 +260,26 @@ impl Client { } // validate textures for property in &profile.properties { - validate_textures(property, &ADVANCED_CONFIG.authentication.textures) - .map_err(AuthError::TextureError)?; + authentication::validate_textures( + property, + &ADVANCED_CONFIG.authentication.textures, + ) + .map_err(AuthError::TextureError)?; } return Ok(profile); } Err(AuthError::MissingAuthClient) } - pub fn handle_login_cookie_response(&self, packet: SLCookieResponse) { + pub fn handle_login_cookie_response(&self, packet: SLoginCookieResponse) { // TODO: allow plugins to access this log::debug!( - "Received cookie_response[login]: key: \"{}\", has_payload: \"{}\", payload_length: \"{}\"", - packet.key.to_string(), - packet.has_payload, - packet.payload_length.unwrap_or(VarInt::from(0)).0 - ); + "Received cookie_response[login]: key: \"{}\", has_payload: \"{}\", payload_length: \"{}\"", + packet.key.to_string(), + packet.has_payload, + packet.payload_length.unwrap_or(VarInt::from(0)).0 + ); } - pub async fn handle_plugin_response(&self, plugin_response: SLoginPluginResponse) { log::debug!("Handling plugin"); let velocity_config = &ADVANCED_CONFIG.proxy.velocity; @@ -386,82 +339,4 @@ impl Client { .await; log::debug!("login acknowledged"); } - pub async fn handle_client_information_config( - &self, - client_information: SClientInformationConfig, - ) { - log::debug!("Handling client settings"); - if client_information.view_distance <= 0 { - self.kick("Cannot have zero or negative view distance!") - .await; - return; - } - - if let (Some(main_hand), Some(chat_mode)) = ( - Hand::from_i32(client_information.main_hand.into()), - ChatMode::from_i32(client_information.chat_mode.into()), - ) { - *self.config.lock().await = Some(PlayerConfig { - locale: client_information.locale, - view_distance: unsafe { - NonZeroU8::new_unchecked(client_information.view_distance as u8) - }, - chat_mode, - chat_colors: client_information.chat_colors, - skin_parts: client_information.skin_parts, - main_hand, - text_filtering: client_information.text_filtering, - server_listing: client_information.server_listing, - }); - } else { - self.kick("Invalid hand or chat type").await; - } - } - - pub async fn handle_plugin_message(&self, plugin_message: SPluginMessage) { - log::debug!("Handling plugin message"); - if plugin_message - .channel - .to_string() - .starts_with("minecraft:brand") - { - log::debug!("got a client brand"); - match str::from_utf8(&plugin_message.data) { - Ok(brand) => *self.brand.lock().await = Some(brand.to_string()), - Err(e) => self.kick(&e.to_string()).await, - } - } - } - - pub fn handle_config_cookie_response(&self, packet: SCCookieResponse) { - // TODO: allow plugins to access this - log::debug!( - "Received cookie_response[config]: key: \"{}\", has_payload: \"{}\", payload_length: \"{}\"", - packet.key.to_string(), - packet.has_payload, - packet.payload_length.unwrap_or(VarInt::from(0)).0 - ); - } - - pub async fn handle_known_packs(&self, server: &Server, _config_acknowledged: SKnownPacks) { - log::debug!("Handling known packs"); - for registry in &server.cached_registry { - self.send_packet(&CRegistryData::new( - ®istry.registry_id, - ®istry.registry_entries, - )) - .await; - } - - // We are done with configuring - log::debug!("finished config"); - self.send_packet(&CFinishConfig::new()).await; - } - - pub fn handle_config_acknowledged(&self) { - log::debug!("Handling config acknowledge"); - self.connection_state.store(ConnectionState::Play); - self.make_player - .store(true, std::sync::atomic::Ordering::Relaxed); - } } diff --git a/pumpkin/src/net/packet/mod.rs b/pumpkin/src/net/packet/mod.rs new file mode 100644 index 00000000..0dbc697d --- /dev/null +++ b/pumpkin/src/net/packet/mod.rs @@ -0,0 +1,9 @@ +mod config; +mod handshake; +mod login; +mod play; +mod status; + +fn is_valid_player_name(name: &str) -> bool { + name.len() <= 16 && name.chars().all(|c| c > 32u8 as char && c < 127u8 as char) +} diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/net/packet/play.rs similarity index 99% rename from pumpkin/src/client/player_packet.rs rename to pumpkin/src/net/packet/play.rs index a7b2b809..e3062678 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/net/packet/play.rs @@ -1,8 +1,8 @@ use std::num::NonZeroU8; use std::sync::Arc; -use super::PlayerConfig; use crate::block::block_manager::BlockActionResult; +use crate::net::PlayerConfig; use crate::{ command::CommandSender, entity::player::{ChatMode, Hand, Player}, diff --git a/pumpkin/src/net/packet/status.rs b/pumpkin/src/net/packet/status.rs new file mode 100644 index 00000000..0e9790c2 --- /dev/null +++ b/pumpkin/src/net/packet/status.rs @@ -0,0 +1,18 @@ +use pumpkin_protocol::{client::status::CPingResponse, server::status::SStatusPingRequest}; + +use crate::{net::Client, server::Server}; + +impl Client { + pub async fn handle_status_request(&self, server: &Server) { + log::debug!("Handling status request"); + let status = server.get_status(); + self.send_packet(&status.lock().await.get_status()).await; + } + + pub async fn handle_ping_request(&self, ping_request: SStatusPingRequest) { + log::debug!("Handling ping request"); + self.send_packet(&CPingResponse::new(ping_request.payload)) + .await; + self.close(); + } +} diff --git a/pumpkin/src/proxy/bungeecord.rs b/pumpkin/src/net/proxy/bungeecord.rs similarity index 59% rename from pumpkin/src/proxy/bungeecord.rs rename to pumpkin/src/net/proxy/bungeecord.rs index c8c9d1ce..dc197671 100644 --- a/pumpkin/src/proxy/bungeecord.rs +++ b/pumpkin/src/net/proxy/bungeecord.rs @@ -1,12 +1,10 @@ -use std::net::IpAddr; +use std::{net::IpAddr, net::SocketAddr}; use pumpkin_protocol::Property; use thiserror::Error; +use tokio::sync::Mutex; -use crate::{ - client::authentication::{offline_uuid, GameProfile}, - Client, -}; +use crate::net::{offline_uuid, GameProfile}; #[derive(Error, Debug)] pub enum BungeeCordError { @@ -20,11 +18,23 @@ pub enum BungeeCordError { FailedMakeOfflineUUID, } +/// Attempts to login a player via `BungeeCord`. +/// +/// This function should be called when receiving the `SLoginStart` packet. +/// It utilizes the `server_address` received in the `SHandShake` packet, +/// which may contain optional data about the client: +/// +/// 1. IP address (if `ip_forward` is enabled on the `BungeeCord` server) +/// 2. UUID (if `ip_forward` is enabled on the `BungeeCord` server) +/// 3. Game profile properties (if `ip_forward` and `online_mode` are enabled on the `BungeeCord` server) +/// +/// If any of the optional data is missing, the function will attempt to +/// determine the player's information locally. pub async fn bungeecord_login( - client: &Client, - username: String, + client_address: &Mutex, + server_address: &str, + name: String, ) -> Result<(IpAddr, GameProfile), BungeeCordError> { - let server_address = client.server_address.lock().await; let data = server_address.split('\0').take(4).collect::>(); // Ip of player, only given if ip_forward on bungee is true @@ -32,15 +42,13 @@ pub async fn bungeecord_login( Some(ip) => ip .parse() .map_err(|_| BungeeCordError::FailedParseAddress)?, - None => client.address.lock().await.ip(), + None => client_address.lock().await.ip(), }; // Uuid of player, only given if ip_forward on bungee is true let id = match data.get(2) { Some(uuid) => uuid.parse().map_err(|_| BungeeCordError::FailedParseUUID)?, - None => { - offline_uuid(username.as_str()).map_err(|_| BungeeCordError::FailedMakeOfflineUUID)? - } + None => offline_uuid(name.as_str()).map_err(|_| BungeeCordError::FailedMakeOfflineUUID)?, }; // Read properties and get textures @@ -57,7 +65,7 @@ pub async fn bungeecord_login( ip, GameProfile { id, - name: username, + name, properties, profile_actions: None, }, diff --git a/pumpkin/src/proxy/mod.rs b/pumpkin/src/net/proxy/mod.rs similarity index 100% rename from pumpkin/src/proxy/mod.rs rename to pumpkin/src/net/proxy/mod.rs diff --git a/pumpkin/src/proxy/velocity.rs b/pumpkin/src/net/proxy/velocity.rs similarity index 98% rename from pumpkin/src/proxy/velocity.rs rename to pumpkin/src/net/proxy/velocity.rs index 68f7d4e9..461c9e0f 100644 --- a/pumpkin/src/proxy/velocity.rs +++ b/pumpkin/src/net/proxy/velocity.rs @@ -14,7 +14,7 @@ use rand::Rng; use sha2::Sha256; use thiserror::Error; -use crate::client::{authentication::GameProfile, Client}; +use crate::net::{Client, GameProfile}; type HmacSha256 = Hmac; diff --git a/pumpkin/src/query.rs b/pumpkin/src/net/query.rs similarity index 100% rename from pumpkin/src/query.rs rename to pumpkin/src/net/query.rs diff --git a/pumpkin/src/rcon/mod.rs b/pumpkin/src/net/rcon/mod.rs similarity index 98% rename from pumpkin/src/rcon/mod.rs rename to pumpkin/src/net/rcon/mod.rs index 20bc12b0..96adbc96 100644 --- a/pumpkin/src/rcon/mod.rs +++ b/pumpkin/src/net/rcon/mod.rs @@ -13,7 +13,6 @@ pub struct RCONServer; impl RCONServer { pub async fn new(config: &RCONConfig, server: Arc) -> Result { - assert!(config.enabled, "RCON is not enabled"); let listener = tokio::net::TcpListener::bind(config.address).await.unwrap(); let password = Arc::new(config.password.clone()); diff --git a/pumpkin/src/rcon/packet.rs b/pumpkin/src/net/rcon/packet.rs similarity index 100% rename from pumpkin/src/rcon/packet.rs rename to pumpkin/src/net/rcon/packet.rs diff --git a/pumpkin/src/server/connection_cache.rs b/pumpkin/src/server/connection_cache.rs index 618fdac3..ccc8e9dd 100644 --- a/pumpkin/src/server/connection_cache.rs +++ b/pumpkin/src/server/connection_cache.rs @@ -26,6 +26,7 @@ fn load_icon_from_file>(path: P) -> Result Result> { + assert!(!png_data.is_empty(), "PNG data is empty"); let icon = png::Decoder::new(Cursor::new(&png_data)); let reader = icon.read_info()?; let info = reader.info(); @@ -70,6 +71,7 @@ impl CachedBranding { } impl CachedStatus { + #[must_use] pub fn new() -> Self { let status_response = Self::build_response(&BASIC_CONFIG); let status_response_json = serde_json::to_string(&status_response) diff --git a/pumpkin/src/server/key_store.rs b/pumpkin/src/server/key_store.rs index daf7f734..84d2c0d8 100644 --- a/pumpkin/src/server/key_store.rs +++ b/pumpkin/src/server/key_store.rs @@ -5,7 +5,7 @@ use rsa::{traits::PublicKeyParts as _, Pkcs1v15Encrypt, RsaPrivateKey}; use sha1::Sha1; use sha2::Digest; -use crate::client::EncryptionError; +use crate::net::EncryptionError; pub struct KeyStore { pub private_key: RsaPrivateKey, @@ -13,6 +13,7 @@ pub struct KeyStore { } impl KeyStore { + #[must_use] pub fn new() -> Self { log::debug!("Creating encryption keys..."); let private_key = Self::generate_private_key(); diff --git a/pumpkin/src/server/mod.rs b/pumpkin/src/server/mod.rs index 33dd0c27..d8f0fc83 100644 --- a/pumpkin/src/server/mod.rs +++ b/pumpkin/src/server/mod.rs @@ -23,12 +23,12 @@ use tokio::sync::{Mutex, RwLock}; use crate::block::block_manager::BlockManager; use crate::block::default_block_manager; -use crate::client::EncryptionError; +use crate::net::EncryptionError; use crate::world::custom_bossbar::CustomBossbars; use crate::{ - client::Client, command::{default_dispatcher, dispatcher::CommandDispatcher}, entity::player::Player, + net::Client, world::World, }; diff --git a/pumpkin/src/world/worldborder.rs b/pumpkin/src/world/worldborder.rs index 6402a3f9..3426d6c7 100644 --- a/pumpkin/src/world/worldborder.rs +++ b/pumpkin/src/world/worldborder.rs @@ -3,7 +3,7 @@ use pumpkin_protocol::client::play::{ CSetBorderWarningDelay, CSetBorderWarningDistance, }; -use crate::client::Client; +use crate::net::Client; use super::World; From 1d96701cc09a9c6a63fed1e7b2094d4fb8beb592 Mon Sep 17 00:00:00 2001 From: Alexander Medvedev Date: Tue, 24 Dec 2024 12:20:10 +0100 Subject: [PATCH 5/6] fix: Received unknown packet id 130 this was mostly because of poor naming, While there are two CServerLinks packets, I accidentally send the play CServerLinks in the login state which has a different packet id --- .../src/client/config/c_server_links.rs | 79 +------------------ .../src/client/login/c_cookie_request.rs | 4 +- .../src/client/play/c_cookie_request.rs | 4 +- .../src/client/play/c_server_links.rs | 79 +------------------ pumpkin-protocol/src/lib.rs | 72 ++++++++++++++++- pumpkin/src/net/packet/login.rs | 12 +-- 6 files changed, 90 insertions(+), 160 deletions(-) diff --git a/pumpkin-protocol/src/client/config/c_server_links.rs b/pumpkin-protocol/src/client/config/c_server_links.rs index b4150d8e..b14547ca 100644 --- a/pumpkin-protocol/src/client/config/c_server_links.rs +++ b/pumpkin-protocol/src/client/config/c_server_links.rs @@ -1,87 +1,16 @@ -use crate::VarInt; -use pumpkin_core::text::TextComponent; +use crate::{Link, VarInt}; use pumpkin_macros::client_packet; -use serde::{Serialize, Serializer}; +use serde::Serialize; #[derive(Serialize)] #[client_packet("config:server_links")] -pub struct CServerLinks<'a> { +pub struct CConfigServerLinks<'a> { links_count: &'a VarInt, links: &'a [Link<'a>], } -impl<'a> CServerLinks<'a> { +impl<'a> CConfigServerLinks<'a> { pub fn new(links_count: &'a VarInt, links: &'a [Link<'a>]) -> Self { Self { links_count, links } } } - -pub enum Label<'a> { - BuiltIn(LinkType), - TextComponent(TextComponent<'a>), -} - -impl Serialize for Label<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - Label::BuiltIn(link_type) => link_type.serialize(serializer), - Label::TextComponent(component) => component.serialize(serializer), - } - } -} - -#[derive(Serialize)] -pub struct Link<'a> { - pub is_built_in: bool, - pub label: Label<'a>, - pub url: &'a String, -} - -impl<'a> Link<'a> { - pub fn new(label: Label<'a>, url: &'a String) -> Self { - Self { - is_built_in: match label { - Label::BuiltIn(_) => true, - Label::TextComponent(_) => false, - }, - label, - url, - } - } -} - -pub enum LinkType { - BugReport, - CommunityGuidelines, - Support, - Status, - Feedback, - Community, - Website, - Forums, - News, - Announcements, -} - -impl Serialize for LinkType { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - LinkType::BugReport => VarInt(0).serialize(serializer), - LinkType::CommunityGuidelines => VarInt(1).serialize(serializer), - LinkType::Support => VarInt(2).serialize(serializer), - LinkType::Status => VarInt(3).serialize(serializer), - LinkType::Feedback => VarInt(4).serialize(serializer), - LinkType::Community => VarInt(5).serialize(serializer), - LinkType::Website => VarInt(6).serialize(serializer), - LinkType::Forums => VarInt(7).serialize(serializer), - LinkType::News => VarInt(8).serialize(serializer), - LinkType::Announcements => VarInt(9).serialize(serializer), - } - } -} diff --git a/pumpkin-protocol/src/client/login/c_cookie_request.rs b/pumpkin-protocol/src/client/login/c_cookie_request.rs index e1749fac..174e8569 100644 --- a/pumpkin-protocol/src/client/login/c_cookie_request.rs +++ b/pumpkin-protocol/src/client/login/c_cookie_request.rs @@ -6,11 +6,11 @@ use crate::codec::identifier::Identifier; #[derive(Serialize)] #[client_packet("login:cookie_request")] /// Requests a cookie that was previously stored. -pub struct CCookieRequest<'a> { +pub struct CLoginCookieRequest<'a> { key: &'a Identifier, } -impl<'a> CCookieRequest<'a> { +impl<'a> CLoginCookieRequest<'a> { pub fn new(key: &'a Identifier) -> Self { Self { key } } diff --git a/pumpkin-protocol/src/client/play/c_cookie_request.rs b/pumpkin-protocol/src/client/play/c_cookie_request.rs index 9b569cc0..fb9bc806 100644 --- a/pumpkin-protocol/src/client/play/c_cookie_request.rs +++ b/pumpkin-protocol/src/client/play/c_cookie_request.rs @@ -6,11 +6,11 @@ use crate::codec::identifier::Identifier; #[derive(Serialize)] #[client_packet("play:cookie_request")] /// Requests a cookie that was previously stored. -pub struct CCookieRequest<'a> { +pub struct CPlayCookieRequest<'a> { key: &'a Identifier, } -impl<'a> CCookieRequest<'a> { +impl<'a> CPlayCookieRequest<'a> { pub fn new(key: &'a Identifier) -> Self { Self { key } } diff --git a/pumpkin-protocol/src/client/play/c_server_links.rs b/pumpkin-protocol/src/client/play/c_server_links.rs index 7619a0c6..a2cb76fa 100644 --- a/pumpkin-protocol/src/client/play/c_server_links.rs +++ b/pumpkin-protocol/src/client/play/c_server_links.rs @@ -1,87 +1,16 @@ -use crate::VarInt; -use pumpkin_core::text::TextComponent; +use crate::{Link, VarInt}; use pumpkin_macros::client_packet; -use serde::{Serialize, Serializer}; +use serde::Serialize; #[derive(Serialize)] #[client_packet("play:server_links")] -pub struct CServerLinks<'a> { +pub struct CPlayServerLinks<'a> { links_count: &'a VarInt, links: &'a [Link<'a>], } -impl<'a> CServerLinks<'a> { +impl<'a> CPlayServerLinks<'a> { pub fn new(links_count: &'a VarInt, links: &'a [Link<'a>]) -> Self { Self { links_count, links } } } - -pub enum Label<'a> { - BuiltIn(LinkType), - TextComponent(TextComponent<'a>), -} - -impl Serialize for Label<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - Label::BuiltIn(link_type) => link_type.serialize(serializer), - Label::TextComponent(component) => component.serialize(serializer), - } - } -} - -#[derive(Serialize)] -pub struct Link<'a> { - pub is_built_in: bool, - pub label: Label<'a>, - pub url: &'a String, -} - -impl<'a> Link<'a> { - pub fn new(label: Label<'a>, url: &'a String) -> Self { - Self { - is_built_in: match label { - Label::BuiltIn(_) => true, - Label::TextComponent(_) => false, - }, - label, - url, - } - } -} - -pub enum LinkType { - BugReport, - CommunityGuidelines, - Support, - Status, - Feedback, - Community, - Website, - Forums, - News, - Announcements, -} - -impl Serialize for LinkType { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - LinkType::BugReport => VarInt(0).serialize(serializer), - LinkType::CommunityGuidelines => VarInt(1).serialize(serializer), - LinkType::Support => VarInt(2).serialize(serializer), - LinkType::Status => VarInt(3).serialize(serializer), - LinkType::Feedback => VarInt(4).serialize(serializer), - LinkType::Community => VarInt(5).serialize(serializer), - LinkType::Website => VarInt(6).serialize(serializer), - LinkType::Forums => VarInt(7).serialize(serializer), - LinkType::News => VarInt(8).serialize(serializer), - LinkType::Announcements => VarInt(9).serialize(serializer), - } - } -} diff --git a/pumpkin-protocol/src/lib.rs b/pumpkin-protocol/src/lib.rs index c6156b94..8ef37f7a 100644 --- a/pumpkin-protocol/src/lib.rs +++ b/pumpkin-protocol/src/lib.rs @@ -4,7 +4,7 @@ use bytebuf::{packet_id::Packet, ReadingError}; use bytes::{Buf, BufMut, Bytes}; use codec::{identifier::Identifier, var_int::VarInt}; use pumpkin_core::text::{style::Style, TextComponent}; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Serialize, Serializer}; pub mod bytebuf; #[cfg(feature = "clientbound")] @@ -186,3 +186,73 @@ impl PositionFlag { flags.iter().fold(0, |acc, flag| acc | flag.get_mask()) } } + +pub enum Label<'a> { + BuiltIn(LinkType), + TextComponent(TextComponent<'a>), +} + +impl Serialize for Label<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + Label::BuiltIn(link_type) => link_type.serialize(serializer), + Label::TextComponent(component) => component.serialize(serializer), + } + } +} + +#[derive(Serialize)] +pub struct Link<'a> { + pub is_built_in: bool, + pub label: Label<'a>, + pub url: &'a String, +} + +impl<'a> Link<'a> { + pub fn new(label: Label<'a>, url: &'a String) -> Self { + Self { + is_built_in: match label { + Label::BuiltIn(_) => true, + Label::TextComponent(_) => false, + }, + label, + url, + } + } +} + +pub enum LinkType { + BugReport, + CommunityGuidelines, + Support, + Status, + Feedback, + Community, + Website, + Forums, + News, + Announcements, +} + +impl Serialize for LinkType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + LinkType::BugReport => VarInt(0).serialize(serializer), + LinkType::CommunityGuidelines => VarInt(1).serialize(serializer), + LinkType::Support => VarInt(2).serialize(serializer), + LinkType::Status => VarInt(3).serialize(serializer), + LinkType::Feedback => VarInt(4).serialize(serializer), + LinkType::Community => VarInt(5).serialize(serializer), + LinkType::Website => VarInt(6).serialize(serializer), + LinkType::Forums => VarInt(7).serialize(serializer), + LinkType::News => VarInt(8).serialize(serializer), + LinkType::Announcements => VarInt(9).serialize(serializer), + } + } +} diff --git a/pumpkin/src/net/packet/login.rs b/pumpkin/src/net/packet/login.rs index db61b865..585413d6 100644 --- a/pumpkin/src/net/packet/login.rs +++ b/pumpkin/src/net/packet/login.rs @@ -4,13 +4,12 @@ use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG}; use pumpkin_core::text::TextComponent; use pumpkin_protocol::{ client::{ - config::{CConfigAddResourcePack, CKnownPacks}, + config::{CConfigAddResourcePack, CConfigServerLinks, CKnownPacks}, login::{CLoginSuccess, CSetCompression}, - play::{CServerLinks, Label, Link, LinkType}, }, codec::var_int::VarInt, server::login::{SEncryptionResponse, SLoginCookieResponse, SLoginPluginResponse, SLoginStart}, - ConnectionState, KnownPack, + ConnectionState, KnownPack, Label, Link, LinkType, }; use uuid::Uuid; @@ -326,8 +325,11 @@ impl Client { } if ADVANCED_CONFIG.server_links.enabled { - self.send_packet(&CServerLinks::new(&VarInt(LINKS.len() as i32), &LINKS)) - .await; + self.send_packet(&CConfigServerLinks::new( + &VarInt(LINKS.len() as i32), + &LINKS, + )) + .await; } // known data packs From 53949103cd3b9ceac5629de5988ff98a34af3570 Mon Sep 17 00:00:00 2001 From: Alexander Medvedev Date: Tue, 24 Dec 2024 12:40:05 +0100 Subject: [PATCH 6/6] fix: https://github.com/Snowiiii/Pumpkin/issues/406 --- pumpkin/src/entity/player.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index c9e51dd1..bc275f8b 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -562,8 +562,6 @@ impl Player { "Setting the same gamemode as already is" ); self.gamemode.store(gamemode); - // The client is using the same method for setting abilities when receiving the CGameEvent ChangeGameMode packet. - // So we can just update the abilities without sending them. { // use another scope so we instantly unlock abilities let mut abilities = self.abilities.lock().await; @@ -587,6 +585,7 @@ impl Player { } } } + self.send_abilities_update().await; self.living_entity .entity .world @@ -796,7 +795,7 @@ impl Default for Abilities { flying: false, allow_flying: false, creative: false, - fly_speed: 0.4, + fly_speed: 0.05, walk_speed_fov: 0.1, } }