aboutsummaryrefslogtreecommitdiff
path: root/azalea-protocol
diff options
context:
space:
mode:
authormat <git@matdoes.dev>2025-03-29 23:10:55 +0000
committermat <git@matdoes.dev>2025-03-29 23:10:55 +0000
commit43ebbee94a24e1f797759d3abe002b8ddfe0523c (patch)
tree8c861f2cfaf3b0df11d8999c929d39700454751b /azalea-protocol
parentd0b459e82764987e1f820978e2af2d01a4b91084 (diff)
downloadazalea-drasl-43ebbee94a24e1f797759d3abe002b8ddfe0523c.tar.xz
update ServerboundContainerClick to use HashedStack from 1.21.5
Diffstat (limited to 'azalea-protocol')
-rw-r--r--azalea-protocol/Cargo.toml4
-rwxr-xr-xazalea-protocol/azalea-protocol-macros/src/lib.rs5
-rwxr-xr-xazalea-protocol/src/packets/game/s_container_click.rs68
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))
+ }
+}