From 3303bb7b97121f27867022eff64d05efa6437d47 Mon Sep 17 00:00:00 2001 From: Alexander Medvedev Date: Sat, 23 May 2026 11:21:53 +0200 Subject: [PATCH] chore(net): change get_string to get_str MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit changed return value from `String` to `Box` which is smaller and makes more sense since we don't mutate packet data String — 24 bytes (ptr + len + capacity) Box — 16 bytes (ptr + len) --- Cargo.lock | 10 ++++++ Cargo.toml | 1 + .../src/bedrock/packet_decoder.rs | 6 ++-- .../java/client/play/player_chat_message.rs | 4 +-- .../src/java/server/config/cookie_response.rs | 6 ++-- .../src/java/server/config/plugin_message.rs | 6 ++-- .../src/java/server/handshake/mod.rs | 4 +-- .../src/java/server/login/cookie_response.rs | 6 ++-- .../src/java/server/login/login_start.rs | 4 +-- .../src/java/server/play/chat_message.rs | 4 +-- .../src/java/server/play/cookie_response.rs | 6 ++-- .../src/java/server/play/custom_payload.rs | 6 ++-- .../src/java/server/play/update_sign.rs | 16 ++++----- pumpkin-protocol/src/lib.rs | 6 ++-- pumpkin-protocol/src/ser/deserializer.rs | 2 +- pumpkin-protocol/src/ser/mod.rs | 14 ++++---- pumpkin-util/src/translation.rs | 6 ++++ .../feature/features/tree/decorator/mod.rs | 22 +++++++----- .../tree/decorator/place_on_ground.rs | 2 +- pumpkin/src/block/entities/sign.rs | 24 +++++++------ pumpkin/src/lib.rs | 34 +++++++++---------- pumpkin/src/net/authentication.rs | 2 +- pumpkin/src/net/bedrock/mod.rs | 4 +-- pumpkin/src/net/java/login.rs | 4 +-- pumpkin/src/net/java/mod.rs | 6 ++-- pumpkin/src/net/java/play.rs | 2 +- pumpkin/src/net/proxy/velocity.rs | 12 +++---- pumpkin/src/net/rcon/packet.rs | 11 +++--- .../wasm/wasm_host/wit/v0_1/block_entity.rs | 8 ++++- .../loader/wasm/wasm_host/wit/v0_1/player.rs | 14 ++++---- 30 files changed, 139 insertions(+), 113 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2aa6cb438..a77bdbfe0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2149,6 +2149,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -3848,6 +3857,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ "matchers", + "nu-ansi-term", "once_cell", "regex-automata", "sharded-slab", diff --git a/Cargo.toml b/Cargo.toml index 5dc699fa0..40d9532fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -171,6 +171,7 @@ tracing = { version = "0.1.44", default-features = false, features = ["std", "at tracing-subscriber = { version = "0.3.23", default-features = false, features = [ "env-filter", "fmt", + "ansi", "time", "std", ] } diff --git a/pumpkin-protocol/src/bedrock/packet_decoder.rs b/pumpkin-protocol/src/bedrock/packet_decoder.rs index c217f6967..495623e47 100644 --- a/pumpkin-protocol/src/bedrock/packet_decoder.rs +++ b/pumpkin-protocol/src/bedrock/packet_decoder.rs @@ -87,7 +87,7 @@ impl UDPNetworkDecoder { pub async fn get_packet_payload( &mut self, - full_packet: Vec, + mut full_packet: Vec, ) -> Result, PacketDecodeError> { if full_packet.is_empty() { return Err(PacketDecodeError::MalformedLength("Empty packet".into())); @@ -104,7 +104,7 @@ impl UDPNetworkDecoder { // If compression is NOT enabled yet, the payload starts at index 1. if self.compression.is_none() { - return Ok(full_packet[1..].to_vec()); + return Ok(full_packet.split_off(1)); } // If compression IS enabled, Bedrock expects a compression method byte at index 1. @@ -125,7 +125,7 @@ impl UDPNetworkDecoder { } 0xff => { // None (Compression enabled but this specific packet is raw) - Ok(full_packet[data_start..].to_vec()) + Ok(full_packet.split_off(2)) } _ => Err(PacketDecodeError::FailedDecompression(format!( "Unsupported compression method: 0x{compression_method:02x}" diff --git a/pumpkin-protocol/src/java/client/play/player_chat_message.rs b/pumpkin-protocol/src/java/client/play/player_chat_message.rs index f5cd2b55c..f754fbdef 100644 --- a/pumpkin-protocol/src/java/client/play/player_chat_message.rs +++ b/pumpkin-protocol/src/java/client/play/player_chat_message.rs @@ -27,7 +27,7 @@ pub struct CPlayerChatMessage { /// The RSA signature (256 bytes) verifying the message's authenticity. pub message_signature: Option>, /// The raw plain-text content of the message. - pub message: String, + pub message: Box, /// Epoch timestamp (milliseconds) when the message was sent. pub timestamp: i64, /// A random 64-bit value used to ensure signature uniqueness. @@ -58,7 +58,7 @@ impl CPlayerChatMessage { sender: uuid::Uuid, index: VarInt, message_signature: Option>, - message: String, + message: Box, timestamp: i64, salt: i64, previous_messages: Box<[PreviousMessage]>, diff --git a/pumpkin-protocol/src/java/server/config/cookie_response.rs b/pumpkin-protocol/src/java/server/config/cookie_response.rs index d6226af44..83a8ebf28 100644 --- a/pumpkin-protocol/src/java/server/config/cookie_response.rs +++ b/pumpkin-protocol/src/java/server/config/cookie_response.rs @@ -2,7 +2,7 @@ use std::io::Read; use pumpkin_data::packet::serverbound::CONFIG_COOKIE_RESPONSE; use pumpkin_macros::java_packet; -use pumpkin_util::{resource_location::ResourceLocation, version::JavaMinecraftVersion}; +use pumpkin_util::version::JavaMinecraftVersion; use crate::{ReadingError, ServerPacket, ser::NetworkReadExt}; @@ -16,7 +16,7 @@ const MAX_COOKIE_LENGTH: usize = 5120; #[java_packet(CONFIG_COOKIE_RESPONSE)] pub struct SConfigCookieResponse { /// The unique identifier for the cookie being returned - pub key: ResourceLocation, + pub key: Box, /// Indicates whether a payload is attached to this response pub has_payload: bool, /// The actual data stored in the cookie. Limited to 5120 bytes @@ -26,7 +26,7 @@ pub struct SConfigCookieResponse { impl ServerPacket for SConfigCookieResponse { fn read(read: impl Read, _version: &JavaMinecraftVersion) -> Result { let mut read = read; - let key = read.get_string()?; + let key = read.get_str()?; let has_payload = read.get_bool()?; if !has_payload { diff --git a/pumpkin-protocol/src/java/server/config/plugin_message.rs b/pumpkin-protocol/src/java/server/config/plugin_message.rs index 0986402ab..3f8038efd 100644 --- a/pumpkin-protocol/src/java/server/config/plugin_message.rs +++ b/pumpkin-protocol/src/java/server/config/plugin_message.rs @@ -2,7 +2,7 @@ use std::io::Read; use pumpkin_data::packet::serverbound::CONFIG_CUSTOM_PAYLOAD; use pumpkin_macros::java_packet; -use pumpkin_util::{resource_location::ResourceLocation, version::JavaMinecraftVersion}; +use pumpkin_util::version::JavaMinecraftVersion; use crate::{ReadingError, ServerPacket, ser::NetworkReadExt}; @@ -17,7 +17,7 @@ const MAX_PAYLOAD_SIZE: usize = 1_048_576; pub struct SPluginMessage { /// The name of the channel used to distinguish different types of messages. /// Example: `minecraft:brand` or `velocity:main`. - pub channel: ResourceLocation, + pub channel: Box, /// The payload sent by the client. pub data: Box<[u8]>, } @@ -25,7 +25,7 @@ pub struct SPluginMessage { impl ServerPacket for SPluginMessage { fn read(mut read: impl Read, _version: &JavaMinecraftVersion) -> Result { Ok(Self { - channel: read.get_string()?, + channel: read.get_str()?, data: read.read_remaining_to_boxed_slice(MAX_PAYLOAD_SIZE)?, }) } diff --git a/pumpkin-protocol/src/java/server/handshake/mod.rs b/pumpkin-protocol/src/java/server/handshake/mod.rs index 24a5308a6..65adcf601 100644 --- a/pumpkin-protocol/src/java/server/handshake/mod.rs +++ b/pumpkin-protocol/src/java/server/handshake/mod.rs @@ -17,7 +17,7 @@ pub struct SHandShake { /// The protocol version of the client (e.g., 767 for 1.21). pub protocol_version: VarInt, /// The hostname or IP used by the client to connect - pub server_address: String, + pub server_address: Box, /// The port number used by the client to connect pub server_port: u16, /// The state the client wants to transition to (1 for Status, 2 for Login) @@ -28,7 +28,7 @@ impl ServerPacket for SHandShake { fn read(mut read: impl Read, _version: &JavaMinecraftVersion) -> Result { Ok(Self { protocol_version: read.get_var_int()?, - server_address: read.get_string_bounded(255)?, + server_address: read.get_str_bounded(255)?, server_port: read.get_u16_be()?, next_state: read .get_var_int()? diff --git a/pumpkin-protocol/src/java/server/login/cookie_response.rs b/pumpkin-protocol/src/java/server/login/cookie_response.rs index ca4cf45d2..3f5c6ebd7 100644 --- a/pumpkin-protocol/src/java/server/login/cookie_response.rs +++ b/pumpkin-protocol/src/java/server/login/cookie_response.rs @@ -1,6 +1,6 @@ use pumpkin_data::packet::serverbound::LOGIN_COOKIE_RESPONSE; use pumpkin_macros::java_packet; -use pumpkin_util::{resource_location::ResourceLocation, version::JavaMinecraftVersion}; +use pumpkin_util::version::JavaMinecraftVersion; use std::io::Read; use crate::{ @@ -12,7 +12,7 @@ use crate::{ /// Response to a `CCookieRequest` (login) from the server. /// The Notchian server only accepts responses of up to 5 kiB in size. pub struct SLoginCookieResponse { - pub key: ResourceLocation, + pub key: Box, pub payload: Option>, // 5120, } @@ -20,7 +20,7 @@ const MAX_COOKIE_LENGTH: usize = 5120; impl ServerPacket for SLoginCookieResponse { fn read(mut read: impl Read, _version: &JavaMinecraftVersion) -> Result { - let key = read.get_string()?; + let key = read.get_str()?; let has_payload = read.get_bool()?; if !has_payload { diff --git a/pumpkin-protocol/src/java/server/login/login_start.rs b/pumpkin-protocol/src/java/server/login/login_start.rs index f3915e751..10398b272 100644 --- a/pumpkin-protocol/src/java/server/login/login_start.rs +++ b/pumpkin-protocol/src/java/server/login/login_start.rs @@ -13,14 +13,14 @@ use crate::{ #[java_packet(LOGIN_HELLO)] #[derive(Serialize)] pub struct SLoginStart { - pub name: String, // 16 + pub name: Box, // 16 pub uuid: uuid::Uuid, } impl ServerPacket for SLoginStart { fn read(mut read: impl Read, _version: &JavaMinecraftVersion) -> Result { Ok(Self { - name: read.get_string_bounded(16)?, + name: read.get_str_bounded(16)?, uuid: read.get_uuid()?, }) } diff --git a/pumpkin-protocol/src/java/server/play/chat_message.rs b/pumpkin-protocol/src/java/server/play/chat_message.rs index 40580389b..17ff1b66d 100644 --- a/pumpkin-protocol/src/java/server/play/chat_message.rs +++ b/pumpkin-protocol/src/java/server/play/chat_message.rs @@ -13,7 +13,7 @@ use crate::{ #[java_packet(PLAY_CHAT)] pub struct SChatMessage { - pub message: String, + pub message: Box, pub timestamp: i64, pub salt: i64, pub signature: Option>, @@ -25,7 +25,7 @@ pub struct SChatMessage { impl ServerPacket for SChatMessage { fn read(mut read: impl Read, _version: &JavaMinecraftVersion) -> Result { Ok(Self { - message: read.get_string_bounded(256)?, + message: read.get_str_bounded(256)?, timestamp: read.get_i64_be()?, salt: read.get_i64_be()?, signature: read.get_option(|v| v.read_boxed_slice(256))?, diff --git a/pumpkin-protocol/src/java/server/play/cookie_response.rs b/pumpkin-protocol/src/java/server/play/cookie_response.rs index eb424ce4b..f9ad1bd12 100644 --- a/pumpkin-protocol/src/java/server/play/cookie_response.rs +++ b/pumpkin-protocol/src/java/server/play/cookie_response.rs @@ -2,7 +2,7 @@ use std::io::Read; use pumpkin_data::packet::serverbound::PLAY_COOKIE_RESPONSE; use pumpkin_macros::java_packet; -use pumpkin_util::{resource_location::ResourceLocation, version::JavaMinecraftVersion}; +use pumpkin_util::version::JavaMinecraftVersion; use crate::{ ServerPacket, @@ -13,7 +13,7 @@ use crate::{ /// Response to a `CCookieRequest` (play) from the server. /// The Notchian (vanilla) server only accepts responses of up to 5 KiB in size. pub struct SCookieResponse { - pub key: ResourceLocation, + pub key: Box, pub payload: Option>, // 5120, } @@ -21,7 +21,7 @@ const MAX_COOKIE_LENGTH: usize = 5120; impl ServerPacket for SCookieResponse { fn read(mut read: impl Read, _version: &JavaMinecraftVersion) -> Result { - let key = read.get_string()?; + let key = read.get_str()?; let has_payload = read.get_bool()?; if !has_payload { diff --git a/pumpkin-protocol/src/java/server/play/custom_payload.rs b/pumpkin-protocol/src/java/server/play/custom_payload.rs index ef43d7154..7995267f9 100644 --- a/pumpkin-protocol/src/java/server/play/custom_payload.rs +++ b/pumpkin-protocol/src/java/server/play/custom_payload.rs @@ -2,7 +2,7 @@ use std::io::Read; use pumpkin_data::packet::serverbound::PLAY_CUSTOM_PAYLOAD; use pumpkin_macros::java_packet; -use pumpkin_util::{resource_location::ResourceLocation, version::JavaMinecraftVersion}; +use pumpkin_util::version::JavaMinecraftVersion; use crate::{ReadingError, ServerPacket, ser::NetworkReadExt}; @@ -17,7 +17,7 @@ const MAX_PAYLOAD_SIZE: usize = 32_767; pub struct SCustomPayload { /// The name of the channel used to distinguish different types of messages. /// Example: `minecraft:brand` or `voicechat:request_secret`. - pub channel: ResourceLocation, + pub channel: Box, /// The payload sent by the client. pub data: Box<[u8]>, } @@ -25,7 +25,7 @@ pub struct SCustomPayload { impl ServerPacket for SCustomPayload { fn read(mut read: impl Read, _version: &JavaMinecraftVersion) -> Result { Ok(Self { - channel: read.get_string()?, + channel: read.get_str()?, data: read.read_remaining_to_boxed_slice(MAX_PAYLOAD_SIZE)?, }) } diff --git a/pumpkin-protocol/src/java/server/play/update_sign.rs b/pumpkin-protocol/src/java/server/play/update_sign.rs index 67bc57c32..fbd7ed22b 100644 --- a/pumpkin-protocol/src/java/server/play/update_sign.rs +++ b/pumpkin-protocol/src/java/server/play/update_sign.rs @@ -13,10 +13,10 @@ use crate::{ pub struct SUpdateSign { pub location: BlockPos, pub is_front_text: bool, - pub line_1: String, - pub line_2: String, - pub line_3: String, - pub line_4: String, + pub line_1: Box, + pub line_2: Box, + pub line_3: Box, + pub line_4: Box, } const MAX_LINE_LENGTH: usize = 386; @@ -26,10 +26,10 @@ impl ServerPacket for SUpdateSign { Ok(Self { location: BlockPos::from_i64(read.get_i64_be()?), is_front_text: read.get_bool()?, - line_1: read.get_string_bounded(MAX_LINE_LENGTH)?, - line_2: read.get_string_bounded(MAX_LINE_LENGTH)?, - line_3: read.get_string_bounded(MAX_LINE_LENGTH)?, - line_4: read.get_string_bounded(MAX_LINE_LENGTH)?, + line_1: read.get_str_bounded(MAX_LINE_LENGTH)?, + line_2: read.get_str_bounded(MAX_LINE_LENGTH)?, + line_3: read.get_str_bounded(MAX_LINE_LENGTH)?, + line_4: read.get_str_bounded(MAX_LINE_LENGTH)?, }) } } diff --git a/pumpkin-protocol/src/lib.rs b/pumpkin-protocol/src/lib.rs index ca9869aed..62f526cf7 100644 --- a/pumpkin-protocol/src/lib.rs +++ b/pumpkin-protocol/src/lib.rs @@ -418,11 +418,11 @@ pub struct Sample { // basically game profile #[derive(Serialize, Deserialize, Clone, Debug)] pub struct Property { - pub name: String, + pub name: Box, // base 64 - pub value: String, + pub value: Box, // base 64 - pub signature: Option, + pub signature: Option>, } #[derive(Serialize)] diff --git a/pumpkin-protocol/src/ser/deserializer.rs b/pumpkin-protocol/src/ser/deserializer.rs index 77c9f4b2c..542ecd5ff 100644 --- a/pumpkin-protocol/src/ser/deserializer.rs +++ b/pumpkin-protocol/src/ser/deserializer.rs @@ -101,7 +101,7 @@ impl<'de, R: Read> de::Deserializer<'de> for &mut Deserializer { } fn deserialize_string>(self, visitor: V) -> Result { - visitor.visit_str(&self.inner.get_string()?) + visitor.visit_str(&self.inner.get_str()?) } fn deserialize_bytes>(self, _visitor: V) -> Result { diff --git a/pumpkin-protocol/src/ser/mod.rs b/pumpkin-protocol/src/ser/mod.rs index c3d932927..16fd57036 100644 --- a/pumpkin-protocol/src/ser/mod.rs +++ b/pumpkin-protocol/src/ser/mod.rs @@ -60,8 +60,8 @@ pub trait NetworkReadExt { fn get_var_uint(&mut self) -> Result; fn get_var_long(&mut self) -> Result; fn get_var_ulong(&mut self) -> Result; - fn get_string_bounded(&mut self, bound: usize) -> Result; - fn get_string(&mut self) -> Result; + fn get_str_bounded(&mut self, bound: usize) -> Result, ReadingError>; + fn get_str(&mut self) -> Result, ReadingError>; fn get_uuid(&mut self) -> Result; fn get_fixed_bitset(&mut self, bits: usize) -> Result; @@ -154,7 +154,7 @@ impl NetworkReadExt for R { VarULong::decode(self) } - fn get_string_bounded(&mut self, bound: usize) -> Result { + fn get_str_bounded(&mut self, bound: usize) -> Result, ReadingError> { let bytes_len = self.get_var_uint()?.0 as usize; // We treat `bound` as the maximum number of Java `char`s allowed. @@ -170,7 +170,7 @@ impl NetworkReadExt for R { let data = self.read_boxed_slice(bytes_len)?; let string = - String::from_utf8(data.into()).map_err(|e| ReadingError::Message(e.to_string()))?; + std::str::from_utf8(&data).map_err(|e| ReadingError::Message(e.to_string()))?; // Next, if we're able to find the (bound + 1)th UTF-16 character, the string is too big. if string.encode_utf16().nth(bound).is_some() { @@ -179,11 +179,11 @@ impl NetworkReadExt for R { ))); } - Ok(string) + Ok(string.into()) } - fn get_string(&mut self) -> Result { - self.get_string_bounded(i32::MAX as usize) + fn get_str(&mut self) -> Result, ReadingError> { + self.get_str_bounded(i32::MAX as usize) } fn get_uuid(&mut self) -> Result { diff --git a/pumpkin-util/src/translation.rs b/pumpkin-util/src/translation.rs index d3feb5ce5..74ab2c1c8 100644 --- a/pumpkin-util/src/translation.rs +++ b/pumpkin-util/src/translation.rs @@ -15,6 +15,7 @@ use std::{ use crate::text::{TextComponentBase, TextContent, style::Style}; static VANILLA_EN_US_JSON: &str = include_str!("../../assets/en_us_java.json"); +static PUMPKIN_EN_US_JSON: &str = include_str!("../../assets/translations/en_us.json"); static PUMPKIN_BRB_JSON: &str = include_str!("../../assets/translations/brb.json"); static PUMPKIN_DE_DE_JSON: &str = include_str!("../../assets/translations/de_de.json"); static PUMPKIN_ES_ES_JSON: &str = include_str!("../../assets/translations/es_es.json"); @@ -272,6 +273,8 @@ pub static TRANSLATIONS: LazyLock; Locale::COUNT] std::array::from_fn(|_| HashMap::new()); let vanilla_en_us: HashMap = serde_json::from_str(VANILLA_EN_US_JSON).expect("Could not parse en_us_java.json."); + let pumpkin_en_us: HashMap = + serde_json::from_str(PUMPKIN_EN_US_JSON).expect("Could not parse en_us.json."); let pumpkin_brb: HashMap = serde_json::from_str(PUMPKIN_BRB_JSON).expect("Could not parse brb.json."); let pumpkin_de_de: HashMap = @@ -322,6 +325,9 @@ pub static TRANSLATIONS: LazyLock; Locale::COUNT] for (key, value) in vanilla_en_us { array[Locale::EnUs as usize].insert(format!("minecraft:{key}"), value); } + for (key, value) in pumpkin_en_us { + array[Locale::EnUs as usize].insert(format!("pumpkin:{key}"), value); + } for (key, value) in pumpkin_brb { array[Locale::Brb as usize].insert(format!("pumpkin:{key}"), value); } diff --git a/pumpkin-world/src/generation/feature/features/tree/decorator/mod.rs b/pumpkin-world/src/generation/feature/features/tree/decorator/mod.rs index 8cda98c95..925b5c857 100644 --- a/pumpkin-world/src/generation/feature/features/tree/decorator/mod.rs +++ b/pumpkin-world/src/generation/feature/features/tree/decorator/mod.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use crate::generation::proto_chunk::GenerationCache; use alter_ground::AlterGroundTreeDecorator; use attached_to_leaves::AttachedToLeavesTreeDecorator; @@ -63,22 +65,24 @@ impl TreeDecorator { } } - pub(super) fn get_leaf_litter_positions( - root_positions: &[BlockPos], - log_positions: &[BlockPos], - ) -> Vec { + pub(super) fn get_leaf_litter_positions<'a>( + root_positions: &'a [BlockPos], + log_positions: &'a [BlockPos], + ) -> Cow<'a, [BlockPos]> { if root_positions.is_empty() { - return log_positions.to_vec(); + return Cow::Borrowed(log_positions); } - if let (Some(root), Some(log)) = (root_positions.first(), log_positions.first()) - && root.0.y == log.0.y + if log_positions + .first() + .is_some_and(|log| root_positions[0].0.y == log.0.y) { let mut list = Vec::with_capacity(root_positions.len() + log_positions.len()); list.extend_from_slice(log_positions); list.extend_from_slice(root_positions); - return list; + return Cow::Owned(list); } - root_positions.to_vec() + + Cow::Borrowed(root_positions) } } diff --git a/pumpkin-world/src/generation/feature/features/tree/decorator/place_on_ground.rs b/pumpkin-world/src/generation/feature/features/tree/decorator/place_on_ground.rs index 88725850b..333bd8f25 100644 --- a/pumpkin-world/src/generation/feature/features/tree/decorator/place_on_ground.rs +++ b/pumpkin-world/src/generation/feature/features/tree/decorator/place_on_ground.rs @@ -34,7 +34,7 @@ impl PlaceOnGroundTreeDecorator { let mut l = pos.0.z; let mut m = pos.0.z; - for block_pos_2 in list { + for block_pos_2 in list.iter() { if block_pos_2.0.y != i { continue; } diff --git a/pumpkin/src/block/entities/sign.rs b/pumpkin/src/block/entities/sign.rs index a1aedf49b..c9a6a3569 100644 --- a/pumpkin/src/block/entities/sign.rs +++ b/pumpkin/src/block/entities/sign.rs @@ -121,7 +121,7 @@ pub struct SignBlockEntity { pub struct Text { pub has_glowing_text: AtomicBool, color: AtomicI8, - pub messages: Arc>, + pub messages: Arc; 4]>>, } impl Clone for Text { @@ -160,7 +160,7 @@ impl From for NbtTag { .lock() .unwrap() .iter() - .map(|s| Self::String(s.clone().into())) + .map(|s| Self::String(s.clone())) .collect(), ); Self::Compound(nbt) @@ -173,28 +173,30 @@ impl From for Text { let nbt = tag.extract_compound().unwrap(); let has_glowing_text = nbt.get_bool("has_glowing_text").unwrap_or(false); let color = nbt.get_string("color").unwrap(); - let messages: Vec = nbt + let messages: Vec> = nbt .get_list("messages") .unwrap() .iter() - .filter_map(|tag| tag.extract_string().map(std::string::ToString::to_string)) + .filter_map(|tag| tag.extract_string().map(Box::from)) .collect(); + let get_message = + |i: usize| -> Box { messages.get(i).cloned().unwrap_or_else(|| Box::from("")) }; + Self { has_glowing_text: AtomicBool::new(has_glowing_text), color: AtomicI8::new(DyeColor::from(color) as i8), messages: Arc::new(std::sync::Mutex::new([ - // its important that we use unwrap_or since otherwise we may crash on older versions - messages.first().unwrap_or(&String::new()).clone(), - messages.get(1).unwrap_or(&String::new()).clone(), - messages.get(2).unwrap_or(&String::new()).clone(), - messages.get(3).unwrap_or(&String::new()).clone(), + get_message(0), + get_message(1), + get_message(2), + get_message(3), ])), } } } impl Text { - fn new(messages: [String; 4]) -> Self { + fn new(messages: [Box; 4]) -> Self { Self { has_glowing_text: AtomicBool::new(false), color: AtomicI8::new(DyeColor::default() as i8), @@ -263,7 +265,7 @@ impl BlockEntity for SignBlockEntity { impl SignBlockEntity { pub const ID: &'static str = "minecraft:sign"; #[must_use] - pub fn new(position: BlockPos, is_front: bool, messages: [String; 4]) -> Self { + pub fn new(position: BlockPos, is_front: bool, messages: [Box; 4]) -> Self { Self { position, is_waxed: AtomicBool::new(false), diff --git a/pumpkin/src/lib.rs b/pumpkin/src/lib.rs index fd10ec582..eb37c490f 100644 --- a/pumpkin/src/lib.rs +++ b/pumpkin/src/lib.rs @@ -9,6 +9,7 @@ use crate::net::java::{JavaClient, PacketHandlerResult}; use crate::net::{ClientPlatform, DisconnectReason}; use crate::net::{lan_broadcast::LANBroadcast, query, rcon::RCONServer}; use crate::server::{Server, ticker::Ticker}; +use bytes::BytesMut; use plugin::server::server_command::ServerCommandEvent; use pumpkin_config::{AdvancedConfiguration, BasicConfiguration}; use pumpkin_macros::send_cancellable; @@ -18,7 +19,7 @@ use rustyline::Editor; use rustyline::history::FileHistory; use rustyline::{Config, error::ReadlineError}; use std::collections::HashMap; -use std::io::{Cursor, ErrorKind, IsTerminal, stdin}; +use std::io::{ErrorKind, IsTerminal, stdin}; use std::process::exit; use std::str::FromStr; use std::sync::atomic::{AtomicBool, AtomicI32, Ordering}; @@ -418,14 +419,13 @@ impl PumpkinServer { } } - #[expect(clippy::too_many_lines)] pub async fn unified_listener_task( &self, master_client_id_counter: &mut u64, tasks: &Arc, bedrock_clients: &Arc>>>, ) -> bool { - let mut udp_buf = [0; 1496]; // Buffer for UDP receive + let mut udp_buf = BytesMut::with_capacity(1496); select! { // Branch for TCP connections (Java Edition) @@ -491,7 +491,10 @@ impl PumpkinServer { }, // Branch for UDP packets (Bedrock Edition) - udp_result = resolve_some(self.udp_socket.as_ref(), |sock: &Arc| sock.recv_from(&mut udp_buf)) => { + udp_result = resolve_some(self.udp_socket.as_ref(), |sock: &Arc| { + unsafe { udp_buf.set_len(1496) }; + sock.recv_from(&mut udp_buf[..]) + }) => { match udp_result { Ok((len, client_addr)) => { if len > 0 { @@ -515,25 +518,20 @@ impl PumpkinServer { new_client }).clone(); - let reader = udp_buf[..len].to_vec(); + let packet_bytes = udp_buf.split_to(len).freeze(); + udp_buf.clear(); let server = self.server.clone(); - tasks.spawn(async move { - client.process_packet(&server, reader).await; - }); - } else if let Some(sock) = self.udp_socket.as_ref() { - let _ = BedrockClient::handle_offline_packet( - &self.server, - id, - &mut Cursor::new(&udp_buf[1..len]), - client_addr, - sock - ).await; + tasks.spawn(async move { + client.process_packet(&server, packet_bytes).await; + }); } } } - Err(e) => error!("UDP socket error: {e}"), - } + Err(e) => { + error!("Failed to receive UDP packet: {e}"); + } + } }, // Branch for the global stop signal diff --git a/pumpkin/src/net/authentication.rs b/pumpkin/src/net/authentication.rs index c233fe9d6..f8bfc39cd 100644 --- a/pumpkin/src/net/authentication.rs +++ b/pumpkin/src/net/authentication.rs @@ -106,7 +106,7 @@ pub fn authenticate( pub fn validate_textures(property: &Property, config: &TextureConfig) -> Result<(), TextureError> { let from64 = general_purpose::STANDARD - .decode(&property.value) + .decode(property.value.as_bytes()) .map_err(|e| TextureError::DecodeError(e.to_string()))?; let textures: ProfileTextures = serde_json::from_slice(&from64).map_err(|e| TextureError::JSONError(e.to_string()))?; diff --git a/pumpkin/src/net/bedrock/mod.rs b/pumpkin/src/net/bedrock/mod.rs index ddeb42604..a2b4202ea 100644 --- a/pumpkin/src/net/bedrock/mod.rs +++ b/pumpkin/src/net/bedrock/mod.rs @@ -229,7 +229,7 @@ impl BedrockClient { }); } - pub async fn process_packet(self: &Arc, server: &Arc, packet: Vec) { + pub async fn process_packet(self: &Arc, server: &Arc, packet: Bytes) { self.last_seen.store(std::time::Instant::now()); if let Err(error) = self.handle_packet_payload(server, packet).await { error!( @@ -501,7 +501,7 @@ impl BedrockClient { pub async fn handle_packet_payload( self: &Arc, server: &Arc, - packet: Vec, + packet: Bytes, ) -> Result<(), Error> { let reader = &mut Cursor::new(packet); diff --git a/pumpkin/src/net/java/login.rs b/pumpkin/src/net/java/login.rs index 61cc286e7..a184959f8 100644 --- a/pumpkin/src/net/java/login.rs +++ b/pumpkin/src/net/java/login.rs @@ -61,7 +61,7 @@ impl JavaClient { match bungeecord::bungeecord_login( &self.address, &self.server_address.lock().await, - login_start.name, + login_start.name.into_string(), ) .await { @@ -82,7 +82,7 @@ impl JavaClient { let profile = GameProfile { id, - name: login_start.name, + name: login_start.name.into_string(), properties: ArcSwap::new(Arc::new(vec![])), profile_actions: None, }; diff --git a/pumpkin/src/net/java/mod.rs b/pumpkin/src/net/java/mod.rs index d4a264a24..9988a40f7 100644 --- a/pumpkin/src/net/java/mod.rs +++ b/pumpkin/src/net/java/mod.rs @@ -76,7 +76,7 @@ pub struct JavaClient { /// The client's configuration settings, Optional pub config: Mutex>, /// The Address used to connect to the Server, Send in the Handshake - pub server_address: Mutex, + pub server_address: Mutex>, /// The current connection state of the client (e.g., Handshaking, Status, Play). pub connection_state: AtomicCell, /// The client's IP address. @@ -138,7 +138,7 @@ impl JavaClient { id, gameprofile: Mutex::new(None), config: Mutex::new(None), - server_address: Mutex::new(String::new()), + server_address: Mutex::new("".into()), address: Mutex::new(address), connection_state: AtomicCell::new(ConnectionState::HandShake), close_token: CancellationToken::new(), @@ -921,7 +921,7 @@ impl JavaClient { let payload = SCustomPayload::read(payload, &version)?; let event = PlayerCustomPayloadEvent::new( player.clone(), - payload.channel, + payload.channel.to_string(), Bytes::from(payload.data), ); server.plugin_manager.fire(event).await; diff --git a/pumpkin/src/net/java/play.rs b/pumpkin/src/net/java/play.rs index fc314b735..0ed86830c 100644 --- a/pumpkin/src/net/java/play.rs +++ b/pumpkin/src/net/java/play.rs @@ -1211,7 +1211,7 @@ impl JavaClient { send_cancellable! {{ server; - PlayerChatEvent::new(player.clone(), chat_message.message.clone(), vec![]); + PlayerChatEvent::new(player.clone(), chat_message.message.to_string(), vec![]); 'after: { info!(" {}: {}", gameprofile.name, event.message); diff --git a/pumpkin/src/net/proxy/velocity.rs b/pumpkin/src/net/proxy/velocity.rs index fca2e4bef..6563dec21 100644 --- a/pumpkin/src/net/proxy/velocity.rs +++ b/pumpkin/src/net/proxy/velocity.rs @@ -80,14 +80,14 @@ fn read_game_profile(read: impl Read) -> Result { .map_err(|_| VelocityError::FailedReadProfileUUID)?; let name = read - .get_string() + .get_str() .map_err(|_| VelocityError::FailedReadProfileName)?; let properties = read .get_list(|data| { - let name = data.get_string()?; - let value = data.get_string()?; - let signature = data.get_option(NetworkReadExt::get_string)?; + let name = data.get_str()?; + let value = data.get_str()?; + let signature = data.get_option(NetworkReadExt::get_str)?; Ok(Property { name, @@ -99,7 +99,7 @@ fn read_game_profile(read: impl Read) -> Result { Ok(GameProfile { id, - name, + name: name.into_string(), properties: ArcSwap::new(Arc::from(properties)), profile_actions: None, }) @@ -131,7 +131,7 @@ pub fn receive_velocity_plugin_response( )); } let addr = data_without_signature - .get_string() + .get_str() .map_err(|_| VelocityError::FailedReadAddress)?; let socket_addr: SocketAddr = SocketAddr::new( diff --git a/pumpkin/src/net/rcon/packet.rs b/pumpkin/src/net/rcon/packet.rs index 58feb4bf2..f5417d986 100644 --- a/pumpkin/src/net/rcon/packet.rs +++ b/pumpkin/src/net/rcon/packet.rs @@ -1,5 +1,3 @@ -use std::string::FromUtf8Error; - use bytes::{BufMut, BytesMut}; use thiserror::Error; @@ -60,7 +58,7 @@ pub enum PacketError { #[error("Missing packet lull terminator")] MissingNullTerminator, #[error("Invalid packet string body")] - InvalidBody(FromUtf8Error), + InvalidBody(std::str::Utf8Error), } #[derive(Debug)] @@ -68,7 +66,7 @@ pub enum PacketError { pub struct Packet { id: i32, ptype: ServerboundPacket, - body: String, + body: Box, } impl Packet { @@ -110,8 +108,9 @@ impl Packet { } let payload = &incoming[body_start..body_end]; - let body = String::from_utf8(payload.to_vec()).map_err(PacketError::InvalidBody)?; - + let body = std::str::from_utf8(payload) + .map_err(PacketError::InvalidBody)? + .into(); incoming.drain(0..total_packet_len); Ok(Some(Self { diff --git a/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/block_entity.rs b/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/block_entity.rs index 0f4736d53..de40e6018 100644 --- a/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/block_entity.rs +++ b/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/block_entity.rs @@ -82,7 +82,13 @@ const fn to_wasm_dye_color(color: InternalDyeColor) -> DyeColor { fn to_wasm_sign_text(text: &InternalText) -> SignText { SignText { - messages: text.messages.lock().unwrap().to_vec(), + messages: text + .messages + .lock() + .unwrap() + .clone() + .map(str::into_string) + .to_vec(), color: to_wasm_dye_color(text.get_color()), has_glowing_text: text .has_glowing_text diff --git a/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/player.rs b/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/player.rs index 14db48b26..5f073a6ee 100644 --- a/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/player.rs +++ b/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/player.rs @@ -1326,10 +1326,10 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState { .properties .load() .iter() - .find(|p| p.name == "textures") + .find(|p| p.name.as_ref() == "textures") .map(|p| PlayerSkin { - value: p.value.clone(), - signature: p.signature.clone(), + value: p.value.to_string(), + signature: p.signature.as_ref().map(std::string::ToString::to_string), })) } @@ -1341,11 +1341,11 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState { let player = player_from_resource(self, &player)?; let mut properties = (**player.gameprofile.properties.load()).clone(); - properties.retain(|p| p.name != "textures"); + properties.retain(|p| p.name.as_ref() != "textures"); properties.push(Property { name: "textures".into(), - value: skin.value, - signature: skin.signature, + value: skin.value.into(), + signature: skin.signature.map(std::convert::Into::into), }); player.gameprofile.properties.store(Arc::new(properties)); @@ -1509,7 +1509,7 @@ impl pumpkin::plugin::player::HostJavaPlayer for PluginHostState { .client .java() .ok_or_else(|| wasmtime::Error::msg("Not a java player"))?; - Ok(client.server_address.lock().await.clone()) + Ok(client.server_address.lock().await.to_string()) } async fn get_settings(