From e0d16c74f2de6a17e12fec739eddd401e346fd3d Mon Sep 17 00:00:00 2001 From: Demetrius Kanios Date: Thu, 13 Aug 2026 11:18:26 -0700 Subject: [PATCH] chore(protocol): Clean up Bedrock by using more `derive` (#2808) --- crates/pumpkin-macros/src/lib.rs | 102 ++++++++--- .../bedrock/{server => client}/actor_event.rs | 2 +- .../src/bedrock/client/add_actor.rs | 29 +--- .../src/bedrock/client/add_item_actor.rs | 15 +- .../src/bedrock/client/add_player.rs | 41 +---- .../src/bedrock/client/available_commands.rs | 159 ++---------------- .../src/bedrock/client/crafting_data.rs | 9 +- .../src/bedrock/client/inventory_slot.rs | 22 +-- .../src/bedrock/client/mod.rs | 6 +- .../src/bedrock/client/resource_packs_info.rs | 19 +-- .../src/bedrock/client/set_spawn_position.rs | 14 +- .../src/bedrock/client/update_block.rs | 13 +- .../src/bedrock/server/animate.rs | 29 +--- .../src/bedrock/server/command_request.rs | 47 +----- .../src/bedrock/server/emote.rs | 51 +----- .../src/bedrock/server/emote_list.rs | 31 +--- .../bedrock/server/inventory_transaction.rs | 48 +----- .../src/bedrock/server/item_stack_request.rs | 32 +--- .../src/bedrock/server/login.rs | 1 + .../src/bedrock/server/mod.rs | 2 - .../src/bedrock/server/modal_form_response.rs | 33 +--- .../src/bedrock/server/request_ability.rs | 9 +- .../server/set_local_player_as_initialized.rs | 10 +- .../server/set_player_inventory_options.rs | 14 +- .../src/serial/deserializer.rs | 66 ++++---- crates/pumpkin-protocol/src/serial/mod.rs | 2 +- .../pumpkin-protocol/src/serial/serializer.rs | 7 + .../pumpkin/src/command/client_suggestions.rs | 6 +- crates/pumpkin/src/entity/living.rs | 4 +- crates/pumpkin/src/entity/passive/animal.rs | 2 +- crates/pumpkin/src/entity/passive/cat.rs | 2 +- crates/pumpkin/src/entity/passive/ocelot.rs | 2 +- .../src/entity/passive/villager/mod.rs | 2 +- crates/pumpkin/src/entity/player.rs | 4 +- crates/pumpkin/src/entity/projectile/egg.rs | 2 +- .../src/entity/projectile/ender_pearl.rs | 2 +- .../src/entity/projectile/firework_rocket.rs | 2 +- .../src/entity/projectile/lingering_potion.rs | 2 +- .../pumpkin/src/entity/projectile/snowball.rs | 2 +- .../src/entity/vehicle/minecart/tnt.rs | 2 +- crates/pumpkin/src/world/mod.rs | 12 +- 41 files changed, 205 insertions(+), 654 deletions(-) rename crates/pumpkin-protocol/src/bedrock/{server => client}/actor_event.rs (98%) diff --git a/crates/pumpkin-macros/src/lib.rs b/crates/pumpkin-macros/src/lib.rs index a21a3e698..6b35dfdff 100644 --- a/crates/pumpkin-macros/src/lib.rs +++ b/crates/pumpkin-macros/src/lib.rs @@ -509,8 +509,18 @@ pub fn derive_serialize(input: TokenStream) -> TokenStream { .into(); }; + let type_generic = match input.generics.params.len() { + 0 => quote! {}, + 1 => quote! { <'_> }, + _ => { + return syn::Error::new(name.span(), "Only up to one lifetime parameter is supported.") + .to_compile_error() + .into(); + } + }; + let expanded = quote! { - impl PacketWrite for #name { + impl PacketWrite for #name #type_generic { fn write(&self, writer: &mut W) -> Result<(), std::io::Error> { #(#fields)* Ok(()) @@ -537,26 +547,19 @@ pub fn derive_deserialize(input: TokenStream) -> TokenStream { let (is_big_endian, no_prefix) = check_serial_attributes(&f.attrs); let is_vec = is_vec(&f.ty); - if is_vec && !no_prefix { - // Vec with prefix: read VarUInt length, then data + if is_vec && no_prefix { + return syn::Error::new(name.span(), "Cannot handle non-prefixed vecs") + .to_compile_error(); + } + + // Non-Vec or Vec without no_prefix: read directly + if is_big_endian { quote! { - #ident: { - let len = crate::codec::var_uint::VarUInt::read(reader)?.0 as usize; - let mut buf = vec![0u8; len]; - reader.read_exact(&mut buf)?; - buf - } + #ident: PacketRead::read_be(reader)? } } else { - // Non-Vec or Vec with no_prefix: read directly - if is_big_endian { - quote! { - #ident: PacketRead::read_be(reader)? - } - } else { - quote! { - #ident: PacketRead::read(reader)? - } + quote! { + #ident: PacketRead::read(reader)? } } }) @@ -566,8 +569,19 @@ pub fn derive_deserialize(input: TokenStream) -> TokenStream { .into(); }; + + let type_generic = match input.generics.params.len() { + 0 => quote! {}, + 1 => quote! { <'static> }, + _ => { + return syn::Error::new(name.span(), "Only up to one lifetime parameter is supported.") + .to_compile_error() + .into(); + } + }; + let expanded = quote! { - impl PacketRead for #name { + impl PacketRead for #name #type_generic { fn read(reader: &mut R) -> std::io::Result { Ok(Self { #(#fields),* @@ -579,6 +593,56 @@ pub fn derive_deserialize(input: TokenStream) -> TokenStream { expanded.into() } +/// Derives the `PacketReadSlice` trait for a struct, enabling deserialization from a slice. +/// +/// # Arguments +/// - `input` – The input `TokenStream` representing the struct to derive `PacketReadSlice` for. +#[rustfmt::skip] +#[proc_macro_derive(PacketReadSlice, attributes(serial))] +pub fn derive_deserialize_from_slice(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let name = &input.ident; + + let fields = if let syn::Data::Struct(data) = &input.data { + data.fields.iter().map(|f| { + let ident = f.ident.as_ref().unwrap(); + let (is_big_endian, no_prefix) = check_serial_attributes(&f.attrs); + let is_vec = is_vec(&f.ty); + + if is_vec && no_prefix { + return syn::Error::new(name.span(), "Cannot handle non-prefixed vecs.") + .to_compile_error(); + } + + // Non-Vec or Vec without no_prefix: read directly + if is_big_endian { + return syn::Error::new(name.span(), "Cannot handle big-endian encoded fields") + .to_compile_error(); + } + + quote! { + #ident: PacketReadSlice::read_slice(buf)? + } + }) + } else { + return syn::Error::new(name.span(), "Only structs are supported") + .to_compile_error() + .into(); + }; + + let expanded = quote! { + impl<'a> PacketReadSlice<'a> for #name<'a> { + fn read_slice(buf: &mut &'a [u8]) -> std::io::Result { + Ok(Self { + #(#fields),* + }) + } + } + }; + + expanded.into() +} + /// Checks a field's `#[serial(...)]` attributes. /// /// # Arguments diff --git a/crates/pumpkin-protocol/src/bedrock/server/actor_event.rs b/crates/pumpkin-protocol/src/bedrock/client/actor_event.rs similarity index 98% rename from crates/pumpkin-protocol/src/bedrock/server/actor_event.rs rename to crates/pumpkin-protocol/src/bedrock/client/actor_event.rs index caecbf2aa..de02e611e 100644 --- a/crates/pumpkin-protocol/src/bedrock/server/actor_event.rs +++ b/crates/pumpkin-protocol/src/bedrock/client/actor_event.rs @@ -8,7 +8,7 @@ use crate::codec::var_int::VarInt; #[derive(Debug, PacketWrite)] #[packet(27)] -pub struct SActorEvent { +pub struct CActorEvent { pub entity_runtime_id: VarULong, pub event_type: ActorEventType, pub event_data: VarInt, diff --git a/crates/pumpkin-protocol/src/bedrock/client/add_actor.rs b/crates/pumpkin-protocol/src/bedrock/client/add_actor.rs index 7034e11bf..dffd74bca 100644 --- a/crates/pumpkin-protocol/src/bedrock/client/add_actor.rs +++ b/crates/pumpkin-protocol/src/bedrock/client/add_actor.rs @@ -1,16 +1,16 @@ use crate::{ - codec::{var_long::VarLong, var_uint::VarUInt, var_ulong::VarULong}, + codec::{var_long::VarLong, var_ulong::VarULong}, serial::PacketWrite, }; use pumpkin_macros::packet; use pumpkin_util::math::vector3::Vector3; -use std::io::{Error, Write}; use super::{ common::EntityLink, set_actor_data::{EntityMetadata, PropertySyncData}, }; +#[derive(PacketWrite)] #[packet(13)] pub struct CAddActor { pub entity_unique_id: VarLong, @@ -28,31 +28,6 @@ pub struct CAddActor { pub links: Vec, } -impl PacketWrite for CAddActor { - fn write(&self, writer: &mut W) -> Result<(), Error> { - self.entity_unique_id.write(writer)?; - self.entity_runtime_id.write(writer)?; - self.entity_type.write(writer)?; - self.position.write(writer)?; - self.velocity.write(writer)?; - self.pitch.write(writer)?; - self.yaw.write(writer)?; - self.head_yaw.write(writer)?; - self.body_yaw.write(writer)?; - VarUInt(self.attributes.len() as u32).write(writer)?; - for attr in &self.attributes { - attr.write(writer)?; - } - self.metadata.write(writer)?; - self.synced_properties.write(writer)?; - VarUInt(self.links.len() as u32).write(writer)?; - for link in &self.links { - link.write(writer)?; - } - Ok(()) - } -} - impl CAddActor { #[allow(clippy::too_many_arguments)] #[must_use] diff --git a/crates/pumpkin-protocol/src/bedrock/client/add_item_actor.rs b/crates/pumpkin-protocol/src/bedrock/client/add_item_actor.rs index ef14e0204..fd4f1a8b5 100644 --- a/crates/pumpkin-protocol/src/bedrock/client/add_item_actor.rs +++ b/crates/pumpkin-protocol/src/bedrock/client/add_item_actor.rs @@ -4,11 +4,11 @@ use crate::{ }; use pumpkin_macros::packet; use pumpkin_util::math::vector3::Vector3; -use std::io::{Error, Write}; use super::set_actor_data::EntityMetadata; use crate::bedrock::network_item::ItemStackWrapper; +#[derive(PacketWrite)] #[packet(15)] pub struct CAddItemActor { pub entity_unique_id: VarLong, @@ -19,16 +19,3 @@ pub struct CAddItemActor { pub metadata: EntityMetadata, pub from_fishing: bool, } - -impl PacketWrite for CAddItemActor { - fn write(&self, writer: &mut W) -> Result<(), Error> { - self.entity_unique_id.write(writer)?; - self.entity_runtime_id.write(writer)?; - self.item.write(writer)?; - self.position.write(writer)?; - self.velocity.write(writer)?; - self.metadata.write(writer)?; - self.from_fishing.write(writer)?; - Ok(()) - } -} diff --git a/crates/pumpkin-protocol/src/bedrock/client/add_player.rs b/crates/pumpkin-protocol/src/bedrock/client/add_player.rs index fae1d9d54..825646674 100644 --- a/crates/pumpkin-protocol/src/bedrock/client/add_player.rs +++ b/crates/pumpkin-protocol/src/bedrock/client/add_player.rs @@ -13,6 +13,7 @@ use super::{ set_actor_data::EntityMetadata, }; +#[derive(PacketWrite)] #[packet(12)] pub struct CAddPlayer { pub uuid: Uuid, @@ -34,31 +35,6 @@ pub struct CAddPlayer { pub build_platform: BuildPlatform, } -impl PacketWrite for CAddPlayer { - fn write(&self, writer: &mut W) -> Result<(), Error> { - self.uuid.write(writer)?; - self.username.write(writer)?; - self.entity_runtime_id.write(writer)?; - self.platform_chat_id.write(writer)?; - self.position.write(writer)?; - self.velocity.write(writer)?; - self.pitch.write(writer)?; - self.yaw.write(writer)?; - self.head_yaw.write(writer)?; - self.held_item.write(writer)?; - self.game_mode.write(writer)?; - self.metadata.write(writer)?; - self.properties.write(writer)?; - self.ability_data.write(writer)?; - VarUInt(self.links.len() as u32).write(writer)?; - for link in &self.links { - link.write(writer)?; - } - self.device_id.write(writer)?; - self.build_platform.write(writer) - } -} - impl CAddPlayer { #[allow(clippy::too_many_arguments)] #[must_use] @@ -125,23 +101,10 @@ impl PacketWrite for EntityProperties { } } -#[derive(Default, Clone)] +#[derive(Default, Clone, PacketWrite)] pub struct AbilityData { pub entity_unique_id: i64, pub player_permissions: u8, pub command_permissions: u8, pub layers: Vec, } - -impl PacketWrite for AbilityData { - fn write(&self, writer: &mut W) -> Result<(), Error> { - self.entity_unique_id.write(writer)?; - self.player_permissions.write(writer)?; - self.command_permissions.write(writer)?; - (self.layers.len() as u8).write(writer)?; - for layer in &self.layers { - layer.write(writer)?; - } - Ok(()) - } -} diff --git a/crates/pumpkin-protocol/src/bedrock/client/available_commands.rs b/crates/pumpkin-protocol/src/bedrock/client/available_commands.rs index 9cb0b824e..75b982462 100644 --- a/crates/pumpkin-protocol/src/bedrock/client/available_commands.rs +++ b/crates/pumpkin-protocol/src/bedrock/client/available_commands.rs @@ -1,7 +1,7 @@ use crate::{codec::var_uint::VarUInt, serial::PacketWrite}; use pumpkin_macros::packet; -use std::io::{Error, Write}; +#[derive(PacketWrite)] #[packet(76)] pub struct CAvailableCommands { pub enum_values: Vec, @@ -14,102 +14,30 @@ pub struct CAvailableCommands { pub constraints: Vec, } -impl PacketWrite for CAvailableCommands { - fn write(&self, writer: &mut W) -> Result<(), Error> { - fn write_string_slice(writer: &mut W, slice: &[String]) -> Result<(), Error> { - VarUInt(slice.len() as u32).write(writer)?; - for s in slice { - s.write(writer)?; - } - Ok(()) - } - - // 1. Enum values - write_string_slice(writer, &self.enum_values)?; - - // 2. Chained subcommand values (The flat string list) - write_string_slice(writer, &self.chained_subcommand_values)?; - - // 3. Suffixes - write_string_slice(writer, &self.suffixes)?; - - // 4. Enums - VarUInt(self.enums.len() as u32).write(writer)?; - for e in &self.enums { - e.write(writer)?; - } - - // 5. Chained Subcommands - VarUInt(self.chained_subcommands.len() as u32).write(writer)?; - for cs in &self.chained_subcommands { - cs.write(writer)?; - } - - // 6. Commands - VarUInt(self.commands.len() as u32).write(writer)?; - for cmd in &self.commands { - cmd.write(writer)?; - } - - // 7. Dynamic (Soft) Enums - VarUInt(self.soft_enums.len() as u32).write(writer)?; - for se in &self.soft_enums { - se.write(writer)?; - } - - // 8. Constraints - VarUInt(self.constraints.len() as u32).write(writer)?; - for c in &self.constraints { - c.write(writer)?; - } - - Ok(()) - } -} - // Represents a subcommand that can chain commands, e.g. /execute. // Written as a flat list in section 3 of the packet; Commands reference // entries by index via ChainedSubcommandOffsets. +#[derive(PacketWrite)] pub struct ChainedSubcommand { pub name: String, pub values: Vec, } +#[derive(PacketWrite)] pub struct ChainedSubcommandValue { /// Index into the `ChainedSubcommandValues` flat list — `VarUInt` - pub index: u32, + pub index: VarUInt, /// Argument type flags (basic types only, no `ARG_FLAG`_* modifiers) — `VarUInt` - pub value: u32, -} - -impl PacketWrite for ChainedSubcommand { - fn write(&self, writer: &mut W) -> Result<(), Error> { - self.name.write(writer)?; - VarUInt(self.values.len() as u32).write(writer)?; - for v in &self.values { - VarUInt(v.index).write(writer)?; - VarUInt(v.value).write(writer)?; - } - Ok(()) - } + pub value: VarUInt, } +#[derive(PacketWrite)] pub struct CommandEnum { pub name: String, - pub value_indices: Vec, -} - -impl CommandEnum { - fn write(&self, writer: &mut W) -> Result<(), Error> { - self.name.write(writer)?; - VarUInt(self.value_indices.len() as u32).write(writer)?; - for &index in &self.value_indices { - writer.write_all(&(index as u32).to_le_bytes())?; - } - Ok(()) - } + pub value_indices: Vec, } +#[derive(PacketWrite)] pub struct Command { pub name: String, pub description: String, @@ -124,28 +52,7 @@ pub struct Command { pub overloads: Vec, } -impl PacketWrite for Command { - fn write(&self, writer: &mut W) -> Result<(), Error> { - self.name.write(writer)?; - self.description.write(writer)?; - writer.write_all(&self.flags.to_le_bytes())?; - self.permission.write(writer)?; - writer.write_all(&self.aliases_enum_index.to_le_bytes())?; - - // Chained subcommand offsets - VarUInt(self.chained_subcommand_offsets.len() as u32).write(writer)?; - for &offset in &self.chained_subcommand_offsets { - writer.write_all(&offset.to_le_bytes())?; - } - - VarUInt(self.overloads.len() as u32).write(writer)?; - for overload in &self.overloads { - overload.write(writer)?; - } - Ok(()) - } -} - +#[derive(PacketWrite)] pub struct CommandOverload { /// Written as a single byte before parameter count ← MISSING in original /// true = this overload uses chained subcommands instead of regular params @@ -153,20 +60,7 @@ pub struct CommandOverload { pub parameters: Vec, } -impl PacketWrite for CommandOverload { - fn write(&self, writer: &mut W) -> Result<(), Error> { - // Chaining bool ← MISSING in original — client reads this byte first - writer.write_all(&[u8::from(self.chaining)])?; - - VarUInt(self.parameters.len() as u32).write(writer)?; - for param in &self.parameters { - param.write(writer)?; - } - Ok(()) - } -} - -#[derive(Clone)] +#[derive(Clone, PacketWrite)] pub struct CommandParameter { pub name: String, /// LE u32 — encodes type flags (`ARG_FLAG_VALID` | `ARG_FLAG_ENUM` | index, or raw type) @@ -176,16 +70,6 @@ pub struct CommandParameter { pub options: u8, } -impl PacketWrite for CommandParameter { - fn write(&self, writer: &mut W) -> Result<(), Error> { - self.name.write(writer)?; - writer.write_all(&self.type_info.to_le_bytes())?; - writer.write_all(&[u8::from(self.optional)])?; - writer.write_all(&[self.options])?; - Ok(()) - } -} - // Constants matching PocketMine's ARG_FLAG_* and ARG_TYPE_* values pub mod arg_flags { pub const ARG_FLAG_VALID: u32 = 0x100000; @@ -224,34 +108,15 @@ pub mod command_permissions { pub const INTERNAL: &str = "internal"; } +#[derive(Clone, PacketWrite)] pub struct SoftEnum { pub name: String, pub values: Vec, } -impl PacketWrite for SoftEnum { - fn write(&self, writer: &mut W) -> Result<(), Error> { - self.name.write(writer)?; - VarUInt(self.values.len() as u32).write(writer)?; - for value in &self.values { - value.write(writer)?; - } - Ok(()) - } -} - +#[derive(Clone, PacketWrite)] pub struct CommandEnumConstraint { pub affected_value_index: i32, pub enum_index: i32, pub constraints: Vec, } - -impl PacketWrite for CommandEnumConstraint { - fn write(&self, writer: &mut W) -> Result<(), Error> { - writer.write_all(&self.affected_value_index.to_le_bytes())?; - writer.write_all(&self.enum_index.to_le_bytes())?; - VarUInt(self.constraints.len() as u32).write(writer)?; - writer.write_all(&self.constraints)?; - Ok(()) - } -} diff --git a/crates/pumpkin-protocol/src/bedrock/client/crafting_data.rs b/crates/pumpkin-protocol/src/bedrock/client/crafting_data.rs index 6505d3f64..f2e0a2a09 100644 --- a/crates/pumpkin-protocol/src/bedrock/client/crafting_data.rs +++ b/crates/pumpkin-protocol/src/bedrock/client/crafting_data.rs @@ -5,6 +5,7 @@ use crate::{ }; use pumpkin_macros::packet; use std::io::{Error, Write}; +use uuid::Uuid; #[derive(Clone, Debug)] pub struct ItemDescriptorCount { @@ -48,7 +49,7 @@ pub struct BedrockShapelessRecipe { pub recipe_id: String, pub input: Vec, pub output: Vec, - pub uuid: [u8; 16], + pub uuid: Uuid, pub block: String, pub priority: VarInt, pub unlock_requirement: RecipeUnlockRequirement, @@ -72,7 +73,7 @@ impl PacketWrite for BedrockShapelessRecipe { } // uuid - writer.write_all(&self.uuid)?; + self.uuid.write(writer)?; // block self.block.write(writer)?; @@ -97,7 +98,7 @@ pub struct BedrockShapedRecipe { pub height: VarInt, pub input: Vec, pub output: Vec, - pub uuid: [u8; 16], + pub uuid: Uuid, pub block: String, pub priority: VarInt, pub assume_symmetry: bool, @@ -123,7 +124,7 @@ impl PacketWrite for BedrockShapedRecipe { } // uuid - writer.write_all(&self.uuid)?; + self.uuid.write(writer)?; // block self.block.write(writer)?; diff --git a/crates/pumpkin-protocol/src/bedrock/client/inventory_slot.rs b/crates/pumpkin-protocol/src/bedrock/client/inventory_slot.rs index a7bb50c59..78ee9fd15 100644 --- a/crates/pumpkin-protocol/src/bedrock/client/inventory_slot.rs +++ b/crates/pumpkin-protocol/src/bedrock/client/inventory_slot.rs @@ -4,8 +4,8 @@ use crate::{ serial::PacketWrite, }; use pumpkin_macros::packet; -use std::io::{Error, Write}; +#[derive(PacketWrite)] #[packet(50)] pub struct CInventorySlot { pub window_id: VarUInt, @@ -14,23 +14,3 @@ pub struct CInventorySlot { pub storage: Option, pub item: NetworkItemStackDescriptor, } - -impl PacketWrite for CInventorySlot { - fn write(&self, writer: &mut W) -> Result<(), Error> { - self.window_id.write(writer)?; - self.inventory_slot.write(writer)?; - - self.container_name.is_some().write(writer)?; - if let Some(container_name) = &self.container_name { - container_name.write(writer)?; - } - - self.storage.is_some().write(writer)?; - if let Some(storage) = &self.storage { - storage.write(writer)?; - } - - self.item.write(writer)?; - Ok(()) - } -} diff --git a/crates/pumpkin-protocol/src/bedrock/client/mod.rs b/crates/pumpkin-protocol/src/bedrock/client/mod.rs index 60563529e..5b2a09176 100644 --- a/crates/pumpkin-protocol/src/bedrock/client/mod.rs +++ b/crates/pumpkin-protocol/src/bedrock/client/mod.rs @@ -1,3 +1,4 @@ +pub mod actor_event; pub mod add_actor; pub mod add_item_actor; pub mod add_player; @@ -22,6 +23,7 @@ pub mod item_registry; pub mod item_stack_response; pub mod level_chunk; pub mod level_event; +pub mod level_sound_event; pub mod mob_effect; pub mod mob_equipment; pub mod modal_form_request; @@ -39,6 +41,7 @@ pub mod resource_packs_info; pub mod respawn; pub mod scoreboard; pub mod set_actor_data; +pub mod set_actor_link; pub mod set_actor_motion; pub mod set_difficulty; pub mod set_health; @@ -54,9 +57,6 @@ pub mod update_abilities; pub mod update_attributes; pub mod update_block; -pub mod level_sound_event; -pub mod set_actor_link; - pub use add_actor::*; pub use add_item_actor::*; pub use add_player::*; diff --git a/crates/pumpkin-protocol/src/bedrock/client/resource_packs_info.rs b/crates/pumpkin-protocol/src/bedrock/client/resource_packs_info.rs index 157fb3aba..4db6a6523 100644 --- a/crates/pumpkin-protocol/src/bedrock/client/resource_packs_info.rs +++ b/crates/pumpkin-protocol/src/bedrock/client/resource_packs_info.rs @@ -1,6 +1,8 @@ use crate::serial::PacketWrite; use pumpkin_macros::packet; use std::io::{Error, Write}; + +#[derive(PacketWrite)] pub struct ResourcePackEntry { pub uuid: uuid::Uuid, pub version: String, @@ -14,23 +16,6 @@ pub struct ResourcePackEntry { pub download_url: String, } -impl PacketWrite for ResourcePackEntry { - fn write(&self, writer: &mut W) -> Result<(), Error> { - self.uuid.write(writer)?; - self.version.write(writer)?; - // Bedrock uses Little Endian u64 for size - writer.write_all(&self.size.to_le_bytes())?; - self.content_key.write(writer)?; - self.sub_pack_name.write(writer)?; - self.content_id.write(writer)?; - self.has_scripts.write(writer)?; - self.addon_pack.write(writer)?; - self.rtx_enabled.write(writer)?; - self.download_url.write(writer)?; - Ok(()) - } -} - #[packet(6)] pub struct CResourcePacksInfo { pub resource_pack_required: bool, diff --git a/crates/pumpkin-protocol/src/bedrock/client/set_spawn_position.rs b/crates/pumpkin-protocol/src/bedrock/client/set_spawn_position.rs index c5a05a38b..a2eb2d168 100644 --- a/crates/pumpkin-protocol/src/bedrock/client/set_spawn_position.rs +++ b/crates/pumpkin-protocol/src/bedrock/client/set_spawn_position.rs @@ -1,11 +1,9 @@ -use std::io::{Error, Write}; - use pumpkin_macros::packet; use pumpkin_util::math::position::BlockPos; use crate::{codec::var_int::VarInt, serial::PacketWrite}; -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PacketWrite)] #[packet(43)] pub struct CSetSpawnPosition { pub spawn_type: VarInt, @@ -30,13 +28,3 @@ impl CSetSpawnPosition { } } } - -impl PacketWrite for CSetSpawnPosition { - fn write(&self, writer: &mut W) -> Result<(), Error> { - self.spawn_type.write(writer)?; - self.position.write(writer)?; - self.dimension.write(writer)?; - self.spawn_position.write(writer)?; - Ok(()) - } -} diff --git a/crates/pumpkin-protocol/src/bedrock/client/update_block.rs b/crates/pumpkin-protocol/src/bedrock/client/update_block.rs index 64ec99192..9ba70dfbe 100644 --- a/crates/pumpkin-protocol/src/bedrock/client/update_block.rs +++ b/crates/pumpkin-protocol/src/bedrock/client/update_block.rs @@ -1,10 +1,9 @@ -use std::io::{Error, Write}; - use pumpkin_macros::packet; use pumpkin_util::math::position::BlockPos; use crate::{codec::var_uint::VarUInt, serial::PacketWrite}; +#[derive(PacketWrite)] #[packet(21)] pub struct CUpdateBlock { pub position: BlockPos, @@ -24,13 +23,3 @@ impl CUpdateBlock { } } } - -impl PacketWrite for CUpdateBlock { - fn write(&self, writer: &mut W) -> Result<(), Error> { - self.position.write(writer)?; - self.block_runtime_id.write(writer)?; - self.flags.write(writer)?; - self.layer.write(writer)?; - Ok(()) - } -} diff --git a/crates/pumpkin-protocol/src/bedrock/server/animate.rs b/crates/pumpkin-protocol/src/bedrock/server/animate.rs index 72a9adf02..a5c011dd5 100644 --- a/crates/pumpkin-protocol/src/bedrock/server/animate.rs +++ b/crates/pumpkin-protocol/src/bedrock/server/animate.rs @@ -85,7 +85,7 @@ impl PacketWrite for AnimateSwingSource { } } -#[derive(Debug)] +#[derive(Debug, PacketRead, PacketWrite)] #[packet(44)] pub struct SAnimate { pub action: AnimateAction, @@ -94,33 +94,6 @@ pub struct SAnimate { pub swing_source: Option, } -impl PacketRead for SAnimate { - fn read(reader: &mut R) -> Result { - let action = AnimateAction::read(reader)?; - let runtime_entity_id = VarULong::read(reader)?; - let data = f32::read(reader)?; - - let swing_source = Option::::read(reader)?; - - Ok(Self { - action, - runtime_entity_id, - data, - swing_source, - }) - } -} - -impl PacketWrite for SAnimate { - fn write(&self, writer: &mut W) -> Result<(), Error> { - self.action.write(writer)?; - self.runtime_entity_id.write(writer)?; - self.data.write(writer)?; - - self.swing_source.write(writer) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/crates/pumpkin-protocol/src/bedrock/server/command_request.rs b/crates/pumpkin-protocol/src/bedrock/server/command_request.rs index c411363ab..b685668f3 100644 --- a/crates/pumpkin-protocol/src/bedrock/server/command_request.rs +++ b/crates/pumpkin-protocol/src/bedrock/server/command_request.rs @@ -2,9 +2,9 @@ use pumpkin_macros::packet; use std::borrow::Cow; use uuid::Uuid; -use crate::serial::{PacketRead, PacketReadSlice, read_str_slice}; +use crate::serial::{PacketRead, PacketReadSlice}; -#[derive(Debug)] +#[derive(Debug, PacketRead, PacketReadSlice)] #[packet(77)] pub struct SCommandRequest<'a> { pub command: Cow<'a, str>, @@ -15,46 +15,3 @@ pub struct SCommandRequest<'a> { pub is_internal_source: bool, pub version: Cow<'a, str>, } - -impl<'a> PacketReadSlice<'a> for SCommandRequest<'a> { - fn read_slice(buf: &mut &'a [u8]) -> Result { - let command = Cow::Borrowed(read_str_slice(buf)?); - let command_type = Cow::Borrowed(read_str_slice(buf)?); - let command_uuid = Uuid::read_slice(buf)?; - let request_id = Cow::Borrowed(read_str_slice(buf)?); - let player_actor_unique_id = i64::read_slice(buf)?; - let is_internal_source = bool::read_slice(buf)?; - let version = Cow::Borrowed(read_str_slice(buf)?); - Ok(Self { - command, - command_type, - command_uuid, - request_id, - player_actor_unique_id, - is_internal_source, - version, - }) - } -} - -impl PacketRead for SCommandRequest<'static> { - fn read(reader: &mut R) -> Result { - let command = Cow::Owned(String::read(reader)?); - let command_type = Cow::Owned(String::read(reader)?); - let command_uuid = Uuid::read(reader)?; - let request_id = Cow::Owned(String::read(reader)?); - let player_actor_unique_id = i64::read(reader)?; - let is_internal_source = bool::read(reader)?; - let version = Cow::Owned(String::read(reader)?); - - Ok(Self { - command, - command_type, - command_uuid, - request_id, - player_actor_unique_id, - is_internal_source, - version, - }) - } -} diff --git a/crates/pumpkin-protocol/src/bedrock/server/emote.rs b/crates/pumpkin-protocol/src/bedrock/server/emote.rs index 39c559fce..93ea490fe 100644 --- a/crates/pumpkin-protocol/src/bedrock/server/emote.rs +++ b/crates/pumpkin-protocol/src/bedrock/server/emote.rs @@ -1,13 +1,13 @@ -use crate::codec::{var_uint::VarUInt, var_ulong::VarULong}; -use crate::serial::{PacketRead, PacketReadSlice, PacketWrite, read_str_slice}; +use crate::codec::var_uint::VarUInt; +use crate::codec::var_ulong::VarULong; +use crate::serial::{PacketRead, PacketReadSlice, PacketWrite}; use pumpkin_macros::packet; use std::borrow::Cow; -use std::io::{Error, Write}; pub const EMOTE_FLAG_SERVER_SIDE: u8 = 1 << 0; pub const EMOTE_FLAG_MUTE_CHAT: u8 = 1 << 1; -#[derive(Debug)] +#[derive(Debug, PacketRead, PacketReadSlice, PacketWrite)] #[packet(138)] pub struct SEmote<'a> { pub runtime_entity_id: VarULong, @@ -17,46 +17,3 @@ pub struct SEmote<'a> { pub platform_id: Cow<'a, str>, pub flags: u8, } - -impl<'a> PacketReadSlice<'a> for SEmote<'a> { - fn read_slice(buf: &mut &'a [u8]) -> Result { - let runtime_entity_id = VarULong::read_slice(buf)?; - let emote_length = VarUInt::read_slice(buf)?; - let emote_id = Cow::Borrowed(read_str_slice(buf)?); - let xuid = Cow::Borrowed(read_str_slice(buf)?); - let platform_id = Cow::Borrowed(read_str_slice(buf)?); - let flags = u8::read_slice(buf)?; - Ok(Self { - runtime_entity_id, - emote_length, - emote_id, - xuid, - platform_id, - flags, - }) - } -} - -impl PacketRead for SEmote<'static> { - fn read(reader: &mut R) -> Result { - Ok(Self { - runtime_entity_id: VarULong::read(reader)?, - emote_length: VarUInt::read(reader)?, - emote_id: Cow::Owned(String::read(reader)?), - xuid: Cow::Owned(String::read(reader)?), - platform_id: Cow::Owned(String::read(reader)?), - flags: u8::read(reader)?, - }) - } -} - -impl PacketWrite for SEmote<'_> { - fn write(&self, writer: &mut W) -> Result<(), Error> { - self.runtime_entity_id.write(writer)?; - self.emote_length.write(writer)?; - self.emote_id.as_ref().write(writer)?; - self.xuid.as_ref().write(writer)?; - self.platform_id.as_ref().write(writer)?; - self.flags.write(writer) - } -} diff --git a/crates/pumpkin-protocol/src/bedrock/server/emote_list.rs b/crates/pumpkin-protocol/src/bedrock/server/emote_list.rs index a51c4f202..97ccb25b2 100644 --- a/crates/pumpkin-protocol/src/bedrock/server/emote_list.rs +++ b/crates/pumpkin-protocol/src/bedrock/server/emote_list.rs @@ -1,45 +1,18 @@ -use std::io::{Error, Read, Write}; use uuid::Uuid; use crate::{ - codec::{var_uint::VarUInt, var_ulong::VarULong}, + codec::var_ulong::VarULong, serial::{PacketRead, PacketWrite}, }; use pumpkin_macros::packet; -#[derive(Debug)] +#[derive(Debug, PacketRead, PacketWrite)] #[packet(152)] pub struct SEmoteList { pub runtime_entity_id: VarULong, pub emote_pieces: Vec, } -impl PacketRead for SEmoteList { - fn read(reader: &mut R) -> Result { - let runtime_entity_id = VarULong::read(reader)?; - let len = VarUInt::read(reader)?.0 as usize; - let mut emote_pieces = Vec::with_capacity(len); - for _ in 0..len { - emote_pieces.push(Uuid::read(reader)?); - } - Ok(Self { - runtime_entity_id, - emote_pieces, - }) - } -} - -impl PacketWrite for SEmoteList { - fn write(&self, writer: &mut W) -> Result<(), Error> { - self.runtime_entity_id.write(writer)?; - VarUInt(self.emote_pieces.len() as u32).write(writer)?; - for piece in &self.emote_pieces { - piece.write(writer)?; - } - Ok(()) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/crates/pumpkin-protocol/src/bedrock/server/inventory_transaction.rs b/crates/pumpkin-protocol/src/bedrock/server/inventory_transaction.rs index 0fef7dc4b..aec1a3bea 100644 --- a/crates/pumpkin-protocol/src/bedrock/server/inventory_transaction.rs +++ b/crates/pumpkin-protocol/src/bedrock/server/inventory_transaction.rs @@ -125,7 +125,7 @@ pub struct NormalTransactionData; #[derive(Debug, PacketRead)] pub struct MismatchTransactionData; -#[derive(Debug)] +#[derive(Debug, PacketRead)] pub struct UseItemTransactionData { pub action_type: VarInt, pub trigger_type: u8, @@ -140,25 +140,7 @@ pub struct UseItemTransactionData { pub client_cooldown_state: u8, } -impl PacketRead for UseItemTransactionData { - fn read(buf: &mut R) -> Result { - Ok(Self { - action_type: VarInt::read(buf)?, - trigger_type: u8::read(buf)?, - block_position: BlockPos::read(buf)?, - block_face: i32::from(u8::read(buf)?), - hot_bar_slot: VarInt::read(buf)?, - item_in_hand: NetworkItemDescriptor::read(buf)?, - player_position: Vector3::read(buf)?, - click_position: Vector3::read(buf)?, - block_runtime_id: VarUInt::read(buf)?, - client_prediction: u8::read(buf)?, - client_cooldown_state: u8::read(buf)?, - }) - } -} - -#[derive(Debug)] +#[derive(Debug, PacketRead)] pub struct UseItemOnEntityTransactionData { pub target_entity_runtime_id: VarULong, pub action_type: VarInt, @@ -168,20 +150,7 @@ pub struct UseItemOnEntityTransactionData { pub click_position: Vector3, } -impl PacketRead for UseItemOnEntityTransactionData { - fn read(buf: &mut R) -> Result { - Ok(Self { - target_entity_runtime_id: VarULong::read(buf)?, - action_type: VarInt::read(buf)?, - hot_bar_slot: VarInt::read(buf)?, - item_in_hand: NetworkItemDescriptor::read(buf)?, - player_position: Vector3::read(buf)?, - click_position: Vector3::read(buf)?, - }) - } -} - -#[derive(Debug)] +#[derive(Debug, PacketRead)] pub struct ReleaseItemTransactionData { pub action_type: VarInt, pub hot_bar_slot: VarInt, @@ -189,17 +158,6 @@ pub struct ReleaseItemTransactionData { pub head_position: Vector3, } -impl PacketRead for ReleaseItemTransactionData { - fn read(buf: &mut R) -> Result { - Ok(Self { - action_type: VarInt::read(buf)?, - hot_bar_slot: VarInt::read(buf)?, - item_in_hand: NetworkItemDescriptor::read(buf)?, - head_position: Vector3::read(buf)?, - }) - } -} - #[derive(Debug)] #[packet(30)] pub struct SInventoryTransaction { diff --git a/crates/pumpkin-protocol/src/bedrock/server/item_stack_request.rs b/crates/pumpkin-protocol/src/bedrock/server/item_stack_request.rs index 6a0d84a2e..d0ff018cf 100644 --- a/crates/pumpkin-protocol/src/bedrock/server/item_stack_request.rs +++ b/crates/pumpkin-protocol/src/bedrock/server/item_stack_request.rs @@ -1,4 +1,4 @@ -use std::io::{Error, ErrorKind, Read, Write}; +use std::io::{Error, ErrorKind, Read}; use crate::{ bedrock::network_item::FullContainerName, @@ -20,11 +20,11 @@ fn collection_length(reader: &mut R, name: &str) -> Result(buf: &mut R) -> Result { - let container_name = FullContainerName::read(buf)?; - let slot_id = u8::read(buf)?; - let stack_id = VarInt(i32::read(buf)?); - Ok(Self { - container_name, - slot_id, - stack_id, - }) - } -} - -impl PacketWrite for ItemStackRequestSlotInfo { - fn write(&self, writer: &mut W) -> Result<(), Error> { - self.container_name.write(writer)?; - self.slot_id.write(writer)?; - self.stack_id.0.write(writer)?; - Ok(()) - } -} - #[derive(Debug)] pub enum ItemStackRequestAction { Take { @@ -349,14 +327,14 @@ mod tests { dynamic_id: None, }, slot_id: 4, - stack_id: VarInt(-2), + stack_id: -2, }; let mut encoded = Vec::new(); slot.write(&mut encoded).unwrap(); assert_eq!(&encoded[encoded.len() - 4..], &(-2i32).to_le_bytes()); let decoded = ItemStackRequestSlotInfo::read(&mut encoded.as_slice()).unwrap(); - assert_eq!(decoded.stack_id, VarInt(-2)); + assert_eq!(decoded.stack_id, -2); } #[test] diff --git a/crates/pumpkin-protocol/src/bedrock/server/login.rs b/crates/pumpkin-protocol/src/bedrock/server/login.rs index 2e4edfaf2..fa76a4637 100644 --- a/crates/pumpkin-protocol/src/bedrock/server/login.rs +++ b/crates/pumpkin-protocol/src/bedrock/server/login.rs @@ -7,6 +7,7 @@ use crate::{MAX_PACKET_DATA_SIZE, codec::var_uint::VarUInt, serial::PacketRead}; #[packet(1)] pub struct SLogin { // https://mojang.github.io/bedrock-protocol-docs/html/LoginPacket.html + //#[serial(big_endian)] pub protocol_version: i32, // https://mojang.github.io/bedrock-protocol-docs/html/connectionRequest.html diff --git a/crates/pumpkin-protocol/src/bedrock/server/mod.rs b/crates/pumpkin-protocol/src/bedrock/server/mod.rs index a6a0e095e..ac9908a57 100644 --- a/crates/pumpkin-protocol/src/bedrock/server/mod.rs +++ b/crates/pumpkin-protocol/src/bedrock/server/mod.rs @@ -1,4 +1,3 @@ -pub mod actor_event; pub mod animate; pub mod block_pick_request; pub mod client_cache_blob_status; @@ -27,7 +26,6 @@ pub mod set_local_player_as_initialized; pub mod set_player_inventory_options; pub mod text; -pub use actor_event::*; pub use animate::*; pub use block_pick_request::*; pub use client_cache_blob_status::*; diff --git a/crates/pumpkin-protocol/src/bedrock/server/modal_form_response.rs b/crates/pumpkin-protocol/src/bedrock/server/modal_form_response.rs index 97bbb6289..9f111925e 100644 --- a/crates/pumpkin-protocol/src/bedrock/server/modal_form_response.rs +++ b/crates/pumpkin-protocol/src/bedrock/server/modal_form_response.rs @@ -1,41 +1,12 @@ use crate::codec::var_uint::VarUInt; -use crate::serial::{PacketRead, PacketReadSlice, read_str_slice}; +use crate::serial::{PacketRead, PacketReadSlice}; use pumpkin_macros::packet; use std::borrow::Cow; -use std::io::{Error, Read}; -#[derive(Debug)] +#[derive(Debug, PacketRead, PacketReadSlice)] #[packet(101)] pub struct SModalFormResponse<'a> { pub form_id: VarUInt, pub form_data: Option>, pub cancel_reason: Option, } - -impl<'a> PacketReadSlice<'a> for SModalFormResponse<'a> { - fn read_slice(buf: &mut &'a [u8]) -> Result { - let form_id = VarUInt::read_slice(buf)?; - let form_data = bool::read_slice(buf)? - .then(|| read_str_slice(buf).map(Cow::Borrowed)) - .transpose()?; - let cancel_reason = Option::::read_slice(buf)?; - Ok(Self { - form_id, - form_data, - cancel_reason, - }) - } -} - -impl PacketRead for SModalFormResponse<'static> { - fn read(reader: &mut R) -> Result { - let form_id = VarUInt::read(reader)?; - let form_data = Option::::read(reader)?.map(Cow::Owned); - let cancel_reason = Option::::read(reader)?; - Ok(Self { - form_id, - form_data, - cancel_reason, - }) - } -} diff --git a/crates/pumpkin-protocol/src/bedrock/server/request_ability.rs b/crates/pumpkin-protocol/src/bedrock/server/request_ability.rs index fe7d7a4ad..192390175 100644 --- a/crates/pumpkin-protocol/src/bedrock/server/request_ability.rs +++ b/crates/pumpkin-protocol/src/bedrock/server/request_ability.rs @@ -24,20 +24,13 @@ impl PacketRead for AbilityValue { } } +#[derive(PacketRead)] #[packet(184)] pub struct SRequestAbility { pub ability: VarInt, pub value: AbilityValue, } -impl PacketRead for SRequestAbility { - fn read(buf: &mut R) -> Result { - let ability = VarInt::read(buf)?; - let value = AbilityValue::read(buf)?; - Ok(Self { ability, value }) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/crates/pumpkin-protocol/src/bedrock/server/set_local_player_as_initialized.rs b/crates/pumpkin-protocol/src/bedrock/server/set_local_player_as_initialized.rs index cac359c6b..6db79e6c5 100644 --- a/crates/pumpkin-protocol/src/bedrock/server/set_local_player_as_initialized.rs +++ b/crates/pumpkin-protocol/src/bedrock/server/set_local_player_as_initialized.rs @@ -1,16 +1,8 @@ use crate::{codec::var_ulong::VarULong, serial::PacketRead}; use pumpkin_macros::packet; -use std::io::{Error, Read}; +#[derive(PacketRead)] #[packet(113)] pub struct SSetLocalPlayerAsInitialized { pub runtime_entity_id: VarULong, } - -impl PacketRead for SSetLocalPlayerAsInitialized { - fn read(reader: &mut R) -> Result { - Ok(Self { - runtime_entity_id: VarULong::read(reader)?, - }) - } -} diff --git a/crates/pumpkin-protocol/src/bedrock/server/set_player_inventory_options.rs b/crates/pumpkin-protocol/src/bedrock/server/set_player_inventory_options.rs index 83d4de253..9a681e007 100644 --- a/crates/pumpkin-protocol/src/bedrock/server/set_player_inventory_options.rs +++ b/crates/pumpkin-protocol/src/bedrock/server/set_player_inventory_options.rs @@ -1,7 +1,7 @@ use crate::{codec::var_int::VarInt, serial::PacketRead}; use pumpkin_macros::packet; -use std::io::{Error, Read}; +#[derive(PacketRead)] #[packet(307)] pub struct SSetPlayerInventoryOptions { pub left_inventory_tab: VarInt, @@ -10,15 +10,3 @@ pub struct SSetPlayerInventoryOptions { pub inventory_layout: VarInt, pub crafting_layout: VarInt, } - -impl PacketRead for SSetPlayerInventoryOptions { - fn read(reader: &mut R) -> Result { - Ok(Self { - left_inventory_tab: VarInt::read(reader)?, - right_inventory_tab: VarInt::read(reader)?, - filtering: bool::read(reader)?, - inventory_layout: VarInt::read(reader)?, - crafting_layout: VarInt::read(reader)?, - }) - } -} diff --git a/crates/pumpkin-protocol/src/serial/deserializer.rs b/crates/pumpkin-protocol/src/serial/deserializer.rs index 97e99aba3..0702479d4 100644 --- a/crates/pumpkin-protocol/src/serial/deserializer.rs +++ b/crates/pumpkin-protocol/src/serial/deserializer.rs @@ -1,4 +1,5 @@ use std::{ + borrow::Cow, io::{Error, ErrorKind, Read}, net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, }; @@ -8,7 +9,7 @@ use uuid::Uuid; use crate::{ codec::{var_int::VarInt, var_uint::VarUInt}, - serial::PacketRead, + serial::{PacketRead, PacketReadSlice, read_str_slice}, }; impl PacketRead for bool { @@ -169,18 +170,13 @@ impl PacketRead for String { } } -impl PacketRead for Vec { +impl PacketRead for Vec { fn read(reader: &mut R) -> Result { - const MAX_VECTOR_BYTES: usize = 2 * 1024 * 1024; // 2 MB safety cap - let len = VarUInt::read(reader)?.0 as usize; - if len > MAX_VECTOR_BYTES { - return Err(Error::new( - ErrorKind::InvalidData, - format!("Byte vector length {len} exceeds maximum limit of {MAX_VECTOR_BYTES}"), - )); + let len = VarUInt::read(reader)?.0 as _; + let mut buf = Self::with_capacity(len); + for _ in 0..len { + buf.push(T::read(reader)?); } - let mut buf = vec![0u8; len]; - reader.read_exact(&mut buf)?; Ok(buf) } } @@ -255,7 +251,13 @@ impl PacketRead for Option { } } -impl<'a> crate::serial::PacketReadSlice<'a> for bool { +impl PacketRead for Cow<'_, str> { + fn read(reader: &mut R) -> Result { + Ok(Self::Owned(String::read(reader)?)) + } +} + +impl<'a> PacketReadSlice<'a> for bool { fn read_slice(buf: &mut &'a [u8]) -> Result { if buf.is_empty() { return Err(Error::new(ErrorKind::UnexpectedEof, "expected bool byte")); @@ -266,7 +268,7 @@ impl<'a> crate::serial::PacketReadSlice<'a> for bool { } } -impl<'a> crate::serial::PacketReadSlice<'a> for u8 { +impl<'a> PacketReadSlice<'a> for u8 { fn read_slice(buf: &mut &'a [u8]) -> Result { if buf.is_empty() { return Err(Error::new(ErrorKind::UnexpectedEof, "expected u8")); @@ -277,13 +279,13 @@ impl<'a> crate::serial::PacketReadSlice<'a> for u8 { } } -impl<'a> crate::serial::PacketReadSlice<'a> for i8 { +impl<'a> PacketReadSlice<'a> for i8 { fn read_slice(buf: &mut &'a [u8]) -> Result { u8::read_slice(buf).map(|b| b as Self) } } -impl<'a> crate::serial::PacketReadSlice<'a> for i16 { +impl<'a> PacketReadSlice<'a> for i16 { fn read_slice(buf: &mut &'a [u8]) -> Result { if buf.len() < 2 { return Err(Error::new(ErrorKind::UnexpectedEof, "expected i16")); @@ -297,7 +299,7 @@ impl<'a> crate::serial::PacketReadSlice<'a> for i16 { } } -impl<'a> crate::serial::PacketReadSlice<'a> for i32 { +impl<'a> PacketReadSlice<'a> for i32 { fn read_slice(buf: &mut &'a [u8]) -> Result { if buf.len() < 4 { return Err(Error::new(ErrorKind::UnexpectedEof, "expected i32")); @@ -311,7 +313,7 @@ impl<'a> crate::serial::PacketReadSlice<'a> for i32 { } } -impl<'a> crate::serial::PacketReadSlice<'a> for i64 { +impl<'a> PacketReadSlice<'a> for i64 { fn read_slice(buf: &mut &'a [u8]) -> Result { if buf.len() < 8 { return Err(Error::new(ErrorKind::UnexpectedEof, "expected i64")); @@ -325,7 +327,7 @@ impl<'a> crate::serial::PacketReadSlice<'a> for i64 { } } -impl<'a> crate::serial::PacketReadSlice<'a> for u16 { +impl<'a> PacketReadSlice<'a> for u16 { fn read_slice(buf: &mut &'a [u8]) -> Result { if buf.len() < 2 { return Err(Error::new(ErrorKind::UnexpectedEof, "expected u16")); @@ -339,7 +341,7 @@ impl<'a> crate::serial::PacketReadSlice<'a> for u16 { } } -impl<'a> crate::serial::PacketReadSlice<'a> for u32 { +impl<'a> PacketReadSlice<'a> for u32 { fn read_slice(buf: &mut &'a [u8]) -> Result { if buf.len() < 4 { return Err(Error::new(ErrorKind::UnexpectedEof, "expected u32")); @@ -353,7 +355,7 @@ impl<'a> crate::serial::PacketReadSlice<'a> for u32 { } } -impl<'a> crate::serial::PacketReadSlice<'a> for u64 { +impl<'a> PacketReadSlice<'a> for u64 { fn read_slice(buf: &mut &'a [u8]) -> Result { if buf.len() < 8 { return Err(Error::new(ErrorKind::UnexpectedEof, "expected u64")); @@ -367,7 +369,7 @@ impl<'a> crate::serial::PacketReadSlice<'a> for u64 { } } -impl<'a> crate::serial::PacketReadSlice<'a> for f32 { +impl<'a> PacketReadSlice<'a> for f32 { fn read_slice(buf: &mut &'a [u8]) -> Result { if buf.len() < 4 { return Err(Error::new(ErrorKind::UnexpectedEof, "expected f32")); @@ -381,7 +383,7 @@ impl<'a> crate::serial::PacketReadSlice<'a> for f32 { } } -impl<'a> crate::serial::PacketReadSlice<'a> for f64 { +impl<'a> PacketReadSlice<'a> for f64 { fn read_slice(buf: &mut &'a [u8]) -> Result { if buf.len() < 8 { return Err(Error::new(ErrorKind::UnexpectedEof, "expected f64")); @@ -395,13 +397,13 @@ impl<'a> crate::serial::PacketReadSlice<'a> for f64 { } } -impl<'a> crate::serial::PacketReadSlice<'a> for &'a str { +impl<'a> PacketReadSlice<'a> for &'a str { fn read_slice(buf: &mut &'a [u8]) -> Result { - crate::serial::read_str_slice(buf) + read_str_slice(buf) } } -impl<'a, T: crate::serial::PacketReadSlice<'a>> crate::serial::PacketReadSlice<'a> for Option { +impl<'a, T: PacketReadSlice<'a>> PacketReadSlice<'a> for Option { fn read_slice(buf: &mut &'a [u8]) -> Result { bool::read_slice(buf)? .then(|| T::read_slice(buf)) @@ -409,7 +411,7 @@ impl<'a, T: crate::serial::PacketReadSlice<'a>> crate::serial::PacketReadSlice<' } } -impl<'a> crate::serial::PacketReadSlice<'a> for uuid::Uuid { +impl<'a> PacketReadSlice<'a> for uuid::Uuid { fn read_slice(buf: &mut &'a [u8]) -> Result { if buf.len() < 16 { return Err(Error::new(ErrorKind::UnexpectedEof, "expected Uuid")); @@ -423,20 +425,26 @@ impl<'a> crate::serial::PacketReadSlice<'a> for uuid::Uuid { } } -impl<'a> crate::serial::PacketReadSlice<'a> for crate::codec::var_int::VarInt { +impl<'a> PacketReadSlice<'a> for crate::codec::var_int::VarInt { fn read_slice(buf: &mut &'a [u8]) -> Result { Self::read(buf) } } -impl<'a> crate::serial::PacketReadSlice<'a> for crate::codec::var_uint::VarUInt { +impl<'a> PacketReadSlice<'a> for crate::codec::var_uint::VarUInt { fn read_slice(buf: &mut &'a [u8]) -> Result { Self::read(buf) } } -impl<'a> crate::serial::PacketReadSlice<'a> for crate::codec::var_ulong::VarULong { +impl<'a> PacketReadSlice<'a> for crate::codec::var_ulong::VarULong { fn read_slice(buf: &mut &'a [u8]) -> Result { Self::read(buf) } } + +impl<'a> PacketReadSlice<'a> for Cow<'a, str> { + fn read_slice(buf: &mut &'a [u8]) -> Result { + Ok(Self::Borrowed(read_str_slice(buf)?)) + } +} diff --git a/crates/pumpkin-protocol/src/serial/mod.rs b/crates/pumpkin-protocol/src/serial/mod.rs index b84ff289b..669f7493d 100644 --- a/crates/pumpkin-protocol/src/serial/mod.rs +++ b/crates/pumpkin-protocol/src/serial/mod.rs @@ -1,6 +1,6 @@ pub mod deserializer; pub mod serializer; -pub use pumpkin_macros::{PacketRead, PacketWrite}; +pub use pumpkin_macros::{PacketRead, PacketReadSlice, PacketWrite}; use std::io::{Error, Read, Write}; pub trait PacketWrite { diff --git a/crates/pumpkin-protocol/src/serial/serializer.rs b/crates/pumpkin-protocol/src/serial/serializer.rs index 8fd7119ec..98508c29b 100644 --- a/crates/pumpkin-protocol/src/serial/serializer.rs +++ b/crates/pumpkin-protocol/src/serial/serializer.rs @@ -1,4 +1,5 @@ use std::{ + borrow::Cow, io::{Error, Write}, net::SocketAddr, }; @@ -200,3 +201,9 @@ impl PacketWrite for GameMode { .write(writer) } } + +impl PacketWrite for Cow<'_, str> { + fn write(&self, writer: &mut W) -> Result<(), Error> { + self.as_ref().write(writer) + } +} diff --git a/crates/pumpkin/src/command/client_suggestions.rs b/crates/pumpkin/src/command/client_suggestions.rs index 3f492d031..2ef6099dc 100644 --- a/crates/pumpkin/src/command/client_suggestions.rs +++ b/crates/pumpkin/src/command/client_suggestions.rs @@ -588,7 +588,7 @@ fn collect_overloads_from_attached( } } -fn ensure_enum_value(enum_values: &mut Vec, value: &str) -> usize { +fn ensure_enum_value(enum_values: &mut Vec, value: &str) -> u32 { enum_values .iter() .position(|v| v == value) @@ -596,6 +596,8 @@ fn ensure_enum_value(enum_values: &mut Vec, value: &str) -> usize { enum_values.push(value.to_string()); enum_values.len() - 1 }) + .try_into() + .unwrap() } fn ensure_command_enum( @@ -608,7 +610,7 @@ fn ensure_command_enum( return pos; } - let value_indices: Vec = values + let value_indices: Vec = values .iter() .map(|val| ensure_enum_value(enum_values, val)) .collect(); diff --git a/crates/pumpkin/src/entity/living.rs b/crates/pumpkin/src/entity/living.rs index bf7748f06..64cb087f2 100644 --- a/crates/pumpkin/src/entity/living.rs +++ b/crates/pumpkin/src/entity/living.rs @@ -6,8 +6,8 @@ use pumpkin_data::tracked_data::{TrackedData, TrackedId}; use pumpkin_inventory::build_equipment_slots; use pumpkin_inventory::player::player_inventory::PlayerInventory; use pumpkin_inventory::screen_handler::InventoryPlayer; +use pumpkin_protocol::bedrock::client::actor_event::{ActorEventType, CActorEvent}; use pumpkin_protocol::bedrock::client::take_item_actor::CTakeItemActor; -use pumpkin_protocol::bedrock::server::actor_event::{ActorEventType, SActorEvent}; use pumpkin_protocol::codec::var_ulong::VarULong; use pumpkin_util::GameMode; use pumpkin_util::Hand; @@ -2485,7 +2485,7 @@ impl EntityBase for LivingEntity { (src.z - tgt.z).atan2(src.x - tgt.x).to_degrees() as f32 - self.entity.yaw.load() }); - let hurt_event = SActorEvent { + let hurt_event = CActorEvent { entity_runtime_id: VarULong(entity_id as u64), event_type: ActorEventType::Hurt, event_data: VarInt(0), diff --git a/crates/pumpkin/src/entity/passive/animal.rs b/crates/pumpkin/src/entity/passive/animal.rs index 455595813..5f9cad7dd 100644 --- a/crates/pumpkin/src/entity/passive/animal.rs +++ b/crates/pumpkin/src/entity/passive/animal.rs @@ -5,7 +5,7 @@ use pumpkin_data::particle::Particle; use pumpkin_data::sound::{Sound, SoundCategory}; use crate::entity::{EntityBaseFuture, mob::Mob, player::Player}; -use pumpkin_protocol::bedrock::server::actor_event::ActorEventType; +use pumpkin_protocol::bedrock::client::actor_event::ActorEventType; use pumpkin_util::math::vector3::Vector3; pub trait Animal: Mob { diff --git a/crates/pumpkin/src/entity/passive/cat.rs b/crates/pumpkin/src/entity/passive/cat.rs index 810849900..9943d9bea 100644 --- a/crates/pumpkin/src/entity/passive/cat.rs +++ b/crates/pumpkin/src/entity/passive/cat.rs @@ -11,7 +11,7 @@ use pumpkin_data::meta_data_type::MetaDataType; use pumpkin_data::tag::{self, Taggable}; use pumpkin_data::tracked_data::TrackedData; use pumpkin_nbt::compound::NbtCompound; -use pumpkin_protocol::bedrock::server::actor_event::ActorEventType; +use pumpkin_protocol::bedrock::client::actor_event::ActorEventType; use pumpkin_protocol::codec::var_int::VarInt; use pumpkin_protocol::java::client::play::Metadata; use rand::RngExt; diff --git a/crates/pumpkin/src/entity/passive/ocelot.rs b/crates/pumpkin/src/entity/passive/ocelot.rs index b8cbc2cc8..2e5951cc9 100644 --- a/crates/pumpkin/src/entity/passive/ocelot.rs +++ b/crates/pumpkin/src/entity/passive/ocelot.rs @@ -10,7 +10,7 @@ use pumpkin_data::meta_data_type::MetaDataType; use pumpkin_data::tag::{self, Taggable}; use pumpkin_data::tracked_data::TrackedData; use pumpkin_nbt::compound::NbtCompound; -use pumpkin_protocol::bedrock::server::actor_event::ActorEventType; +use pumpkin_protocol::bedrock::client::actor_event::ActorEventType; use pumpkin_protocol::java::client::play::Metadata; use rand::RngExt; diff --git a/crates/pumpkin/src/entity/passive/villager/mod.rs b/crates/pumpkin/src/entity/passive/villager/mod.rs index 51910bf5f..9f6b85277 100644 --- a/crates/pumpkin/src/entity/passive/villager/mod.rs +++ b/crates/pumpkin/src/entity/passive/villager/mod.rs @@ -18,7 +18,7 @@ use pumpkin_inventory::screen_handler::{ BoxFuture, InventoryPlayer, ScreenHandlerFactory, SharedScreenHandler, }; use pumpkin_nbt::compound::NbtCompound; -use pumpkin_protocol::bedrock::server::actor_event::ActorEventType; +use pumpkin_protocol::bedrock::client::actor_event::ActorEventType; use pumpkin_protocol::codec::var_int::VarInt; use pumpkin_protocol::java::client::play::{CMerchantOffers, Metadata}; use pumpkin_util::math::{boundingbox::BoundingBox, position::BlockPos, vector3::Vector3}; diff --git a/crates/pumpkin/src/entity/player.rs b/crates/pumpkin/src/entity/player.rs index e5f60329a..5e0f1f55a 100644 --- a/crates/pumpkin/src/entity/player.rs +++ b/crates/pumpkin/src/entity/player.rs @@ -64,8 +64,8 @@ use pumpkin_nbt::compound::NbtCompound; use pumpkin_nbt::tag::NbtTag; use pumpkin_protocol::IdOr; use pumpkin_protocol::SoundEvent; +use pumpkin_protocol::bedrock::client::actor_event::{ActorEventType, CActorEvent}; use pumpkin_protocol::bedrock::client::container_open::CContainerOpen; -use pumpkin_protocol::bedrock::server::actor_event::{ActorEventType, SActorEvent}; use pumpkin_protocol::codec::var_int::VarInt; use pumpkin_protocol::codec::var_long::VarLong; use pumpkin_protocol::codec::var_ulong::VarULong; @@ -3440,7 +3440,7 @@ impl Player { self.client .send_packet_now_editioned( &CCombatDeath::new(self.entity_id().into(), &death_msg), - &SActorEvent { + &CActorEvent { entity_runtime_id: VarULong(self.entity_id() as u64), event_type: ActorEventType::Death, event_data: VarInt(0), diff --git a/crates/pumpkin/src/entity/projectile/egg.rs b/crates/pumpkin/src/entity/projectile/egg.rs index a2155f4f8..0a36f22b0 100644 --- a/crates/pumpkin/src/entity/projectile/egg.rs +++ b/crates/pumpkin/src/entity/projectile/egg.rs @@ -14,7 +14,7 @@ use pumpkin_data::item::Item; use pumpkin_data::item_stack::ItemStack; use pumpkin_data::meta_data_type::MetaDataType; use pumpkin_data::tracked_data::TrackedData; -use pumpkin_protocol::bedrock::server::actor_event::ActorEventType; +use pumpkin_protocol::bedrock::client::actor_event::ActorEventType; use pumpkin_protocol::codec::item_stack_seralizer::ItemStackSerializer; use pumpkin_protocol::java::client::play::Metadata; use pumpkin_util::math::vector3::Vector3; diff --git a/crates/pumpkin/src/entity/projectile/ender_pearl.rs b/crates/pumpkin/src/entity/projectile/ender_pearl.rs index e1255be4f..87023bc30 100644 --- a/crates/pumpkin/src/entity/projectile/ender_pearl.rs +++ b/crates/pumpkin/src/entity/projectile/ender_pearl.rs @@ -13,7 +13,7 @@ use pumpkin_data::damage::DamageType; use pumpkin_data::entity::{EntityPose, EntityStatus}; use pumpkin_data::particle::Particle; use pumpkin_data::sound::{Sound, SoundCategory}; -use pumpkin_protocol::bedrock::server::actor_event::ActorEventType; +use pumpkin_protocol::bedrock::client::actor_event::ActorEventType; use pumpkin_util::math::vector3::Vector3; const GRAVITY: f64 = 0.03; diff --git a/crates/pumpkin/src/entity/projectile/firework_rocket.rs b/crates/pumpkin/src/entity/projectile/firework_rocket.rs index 7cf55bb1f..1b227cb44 100644 --- a/crates/pumpkin/src/entity/projectile/firework_rocket.rs +++ b/crates/pumpkin/src/entity/projectile/firework_rocket.rs @@ -4,7 +4,7 @@ use crate::{ world::World, }; use pumpkin_data::{entity::EntityStatus, meta_data_type::MetaDataType, tracked_data::TrackedData}; -use pumpkin_protocol::bedrock::server::actor_event::ActorEventType; +use pumpkin_protocol::bedrock::client::actor_event::ActorEventType; use pumpkin_protocol::{codec::optional_int::OptionalInt, java::client::play::Metadata}; use pumpkin_util::{ math::vector3::Vector3, diff --git a/crates/pumpkin/src/entity/projectile/lingering_potion.rs b/crates/pumpkin/src/entity/projectile/lingering_potion.rs index d7854273a..15782c5d1 100644 --- a/crates/pumpkin/src/entity/projectile/lingering_potion.rs +++ b/crates/pumpkin/src/entity/projectile/lingering_potion.rs @@ -8,7 +8,7 @@ use crate::{ }; use pumpkin_data::entity::EntityStatus; use pumpkin_data::item_stack::ItemStack; -use pumpkin_protocol::bedrock::server::actor_event::ActorEventType; +use pumpkin_protocol::bedrock::client::actor_event::ActorEventType; use pumpkin_protocol::java::client::play::CWorldEvent; use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::vector2::{Vector2, to_chunk_pos}; diff --git a/crates/pumpkin/src/entity/projectile/snowball.rs b/crates/pumpkin/src/entity/projectile/snowball.rs index cbee6e60c..27f092775 100644 --- a/crates/pumpkin/src/entity/projectile/snowball.rs +++ b/crates/pumpkin/src/entity/projectile/snowball.rs @@ -8,7 +8,7 @@ use crate::{ }; use pumpkin_data::damage::DamageType; use pumpkin_data::entity::{EntityStatus, EntityType}; -use pumpkin_protocol::bedrock::server::actor_event::ActorEventType; +use pumpkin_protocol::bedrock::client::actor_event::ActorEventType; use pumpkin_util::math::vector3::Vector3; const GRAVITY: f64 = 0.03; diff --git a/crates/pumpkin/src/entity/vehicle/minecart/tnt.rs b/crates/pumpkin/src/entity/vehicle/minecart/tnt.rs index 2d8150bc2..484f28d22 100644 --- a/crates/pumpkin/src/entity/vehicle/minecart/tnt.rs +++ b/crates/pumpkin/src/entity/vehicle/minecart/tnt.rs @@ -5,7 +5,7 @@ use pumpkin_data::entity::EntityStatus; use pumpkin_data::particle::Particle; use pumpkin_data::sound::{Sound, SoundCategory}; use pumpkin_nbt::compound::NbtCompound; -use pumpkin_protocol::bedrock::server::actor_event::ActorEventType; +use pumpkin_protocol::bedrock::client::actor_event::ActorEventType; use pumpkin_util::math::vector3::Vector3; use rand::RngExt; diff --git a/crates/pumpkin/src/world/mod.rs b/crates/pumpkin/src/world/mod.rs index bfa9e1c9e..eb5161c10 100644 --- a/crates/pumpkin/src/world/mod.rs +++ b/crates/pumpkin/src/world/mod.rs @@ -96,6 +96,7 @@ use pumpkin_protocol::{ BClientPacket, ClientPacket, IdOr, SoundEvent, bedrock::{ client::{ + actor_event::{ActorEventType, CActorEvent}, add_player::CAddPlayer, block_event::CBlockEvent as CBedrockBlockEvent, common::BuildPlatform, @@ -107,10 +108,7 @@ use pumpkin_protocol::{ start_game::{Experiments, GamePublishSetting, LevelSettings}, update_attributes::{Attribute, CUpdateAttributes}, }, - server::{ - actor_event::{ActorEventType, SActorEvent}, - text::SText, - }, + server::text::SText, }, codec::{var_int::VarInt, var_long::VarLong, var_uint::VarUInt, var_ulong::VarULong}, java::{ @@ -496,7 +494,7 @@ impl World { let chunk_pos = entity.chunk_pos.load(); let je_packet = CEntityStatus::new(entity.entity_id, java_status as i8); if let Some(be_event) = bedrock_status { - let be_packet = SActorEvent { + let be_packet = CActorEvent { entity_runtime_id: VarULong(entity.entity_id as u64), event_type: be_event, event_data: VarInt(0), @@ -2421,7 +2419,7 @@ impl World { height: VarInt(height), input, output: vec![output_descriptor], - uuid: [0; 16], + uuid: Uuid::nil(), block: "crafting_table".to_string(), priority: VarInt(1), assume_symmetry: true, @@ -2459,7 +2457,7 @@ impl World { recipe_id: format!("pumpkin:recipe_{network_id_counter}"), input, output: vec![output_descriptor], - uuid: [0; 16], + uuid: Uuid::nil(), block: "crafting_table".to_string(), priority: VarInt(1), unlock_requirement: RecipeUnlockRequirement { context: 1 },