diff options
| author | mat <git@matdoes.dev> | 2025-03-29 23:10:55 +0000 |
|---|---|---|
| committer | mat <git@matdoes.dev> | 2025-03-29 23:10:55 +0000 |
| commit | 43ebbee94a24e1f797759d3abe002b8ddfe0523c (patch) | |
| tree | 8c861f2cfaf3b0df11d8999c929d39700454751b /azalea-protocol | |
| parent | d0b459e82764987e1f820978e2af2d01a4b91084 (diff) | |
| download | azalea-drasl-43ebbee94a24e1f797759d3abe002b8ddfe0523c.tar.xz | |
update ServerboundContainerClick to use HashedStack from 1.21.5
Diffstat (limited to 'azalea-protocol')
| -rw-r--r-- | azalea-protocol/Cargo.toml | 4 | ||||
| -rwxr-xr-x | azalea-protocol/azalea-protocol-macros/src/lib.rs | 5 | ||||
| -rwxr-xr-x | azalea-protocol/src/packets/game/s_container_click.rs | 68 |
3 files changed, 73 insertions, 4 deletions
diff --git a/azalea-protocol/Cargo.toml b/azalea-protocol/Cargo.toml index e81beea6..78e776b6 100644 --- a/azalea-protocol/Cargo.toml +++ b/azalea-protocol/Cargo.toml @@ -48,8 +48,10 @@ tokio-util = { workspace = true, features = ["codec"] } tracing.workspace = true hickory-resolver = { workspace = true, features = ["tokio-runtime"] } uuid.workspace = true +crc32fast = { workspace = true, optional = true } [features] connecting = [] default = ["packets"] -packets = ["connecting", "dep:azalea-core"] +packets = ["connecting", "dep:azalea-core", "crc32"] +crc32 = ["crc32fast"] diff --git a/azalea-protocol/azalea-protocol-macros/src/lib.rs b/azalea-protocol/azalea-protocol-macros/src/lib.rs index a33d21e0..a1255519 100755 --- a/azalea-protocol/azalea-protocol-macros/src/lib.rs +++ b/azalea-protocol/azalea-protocol-macros/src/lib.rs @@ -9,13 +9,16 @@ use syn::{ fn as_packet_derive(input: TokenStream, state: proc_macro2::TokenStream) -> TokenStream { let DeriveInput { ident, data, .. } = parse_macro_input!(input); + // technically it would still work with enums and non-named structs but for + // consistency in the api it's nicer if they are all just structs, which is why + // we enforce this here let syn::Data::Struct(syn::DataStruct { fields, .. }) = &data else { panic!("#[derive(*Packet)] can only be used on structs") }; - let (syn::Fields::Named(_) | syn::Fields::Unit) = fields else { panic!("#[derive(*Packet)] can only be used on structs with named fields") }; + let variant_name = variant_name_from(&ident); let contents = quote! { diff --git a/azalea-protocol/src/packets/game/s_container_click.rs b/azalea-protocol/src/packets/game/s_container_click.rs index ed68de6e..b7b70888 100755 --- a/azalea-protocol/src/packets/game/s_container_click.rs +++ b/azalea-protocol/src/packets/game/s_container_click.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use azalea_buf::AzBuf; +use azalea_buf::{AzBuf, AzaleaWrite}; use azalea_inventory::{ItemStack, operations::ClickType}; use azalea_protocol_macros::ServerboundGamePacket; @@ -13,6 +13,70 @@ pub struct ServerboundContainerClick { pub slot_num: i16, pub button_num: u8, pub click_type: ClickType, - pub changed_slots: HashMap<u16, ItemStack>, + pub changed_slots: HashMap<u16, HashedStack>, pub carried_item: ItemStack, } + +/// Similar to an [`ItemStack`] but only carrying a CRC32 hash of the value of +/// added data components instead of their entire contents. +#[derive(Clone, Debug, AzBuf)] +pub struct HashedStack(pub Option<HashedActualItem>); + +#[derive(Clone, Debug, AzBuf)] +pub struct HashedActualItem { + pub kind: azalea_registry::Item, + #[var] + pub count: i32, + pub components: HashedPatchMap, +} + +#[derive(Clone, Debug, AzBuf)] +pub struct HashedPatchMap { + /// The value is a CRC32 hash of the data component's network serialization. + /// (kind + data) + #[limit(256)] + pub added_components: Vec<(azalea_registry::DataComponentKind, u32)>, + #[limit(256)] + pub removed_components: Vec<azalea_registry::DataComponentKind>, +} + +/// Convert your [`ItemStack`] into a [`HashedStack`] by hashing the data +/// components. +/// +/// This will be necessary if you're writing a client or server, but if you're +/// just making a proxy then you can remove the `crc32` dependency by disabling +/// the `crc32` feature on `azalea-protocol`. +#[cfg(feature = "crc32")] +impl From<&ItemStack> for HashedStack { + fn from(item: &ItemStack) -> Self { + let ItemStack::Present(item) = item else { + return Self(None); + }; + + let mut added_components = Vec::new(); + let mut removed_components = Vec::new(); + + for (&kind, data) in &item.components.components { + if let Some(data) = data { + // encodeCap in TypedDataComponent.java + let mut buf = Vec::new(); + kind.azalea_write(&mut buf).unwrap(); + data.encode(&mut buf).unwrap(); + added_components.push((kind, crc32fast::hash(&buf))); + } else { + removed_components.push(kind); + } + } + + let components = HashedPatchMap { + added_components, + removed_components, + }; + let item = HashedActualItem { + kind: item.kind, + count: item.count, + components, + }; + Self(Some(item)) + } +} |
