azalea_protocol/packets/game/
s_container_click.rs1use azalea_buf::AzBuf;
2use azalea_core::{checksum::Checksum, registry_holder::RegistryHolder};
3use azalea_inventory::{ItemStack, operations::ClickType};
4use azalea_protocol_macros::ServerboundGamePacket;
5use indexmap::IndexMap;
6
7#[derive(Clone, Debug, AzBuf, PartialEq, ServerboundGamePacket)]
8pub struct ServerboundContainerClick {
9 #[var]
10 pub container_id: i32,
11 #[var]
12 pub state_id: u32,
13 pub slot_num: i16,
14 pub button_num: u8,
15 pub click_type: ClickType,
16 pub changed_slots: IndexMap<u16, HashedStack>,
17 pub carried_item: HashedStack,
18}
19
20#[derive(Clone, Debug, AzBuf, PartialEq)]
23pub struct HashedStack(pub Option<HashedActualItem>);
24
25#[derive(Clone, Debug, AzBuf, PartialEq)]
26pub struct HashedActualItem {
27 pub kind: azalea_registry::Item,
28 #[var]
29 pub count: i32,
30 pub components: HashedPatchMap,
31}
32
33#[derive(Clone, Debug, AzBuf, PartialEq)]
34pub struct HashedPatchMap {
35 #[limit(256)]
36 pub added_components: Vec<(azalea_registry::DataComponentKind, Checksum)>,
37 #[limit(256)]
38 pub removed_components: Vec<azalea_registry::DataComponentKind>,
39}
40
41impl HashedStack {
42 pub fn from_item_stack(item: &ItemStack, registries: &RegistryHolder) -> Self {
51 let ItemStack::Present(item) = item else {
52 return HashedStack(None);
53 };
54
55 let mut added_components = Vec::new();
56 let mut removed_components = Vec::new();
57
58 for (kind, data) in item.component_patch.iter() {
59 if let Some(data) = data {
60 added_components.push((kind, data.crc_hash(registries)));
61 } else {
62 removed_components.push(kind);
63 }
64 }
65
66 let components = HashedPatchMap {
67 added_components,
68 removed_components,
69 };
70 let item = HashedActualItem {
71 kind: item.kind,
72 count: item.count,
73 components,
74 };
75 Self(Some(item))
76 }
77}