diff --git a/MinecraftClient/Protocol/Handlers/DataTypes.cs b/MinecraftClient/Protocol/Handlers/DataTypes.cs
index 4b4f0488..bd2c84e4 100644
--- a/MinecraftClient/Protocol/Handlers/DataTypes.cs
+++ b/MinecraftClient/Protocol/Handlers/DataTypes.cs
@@ -1679,6 +1679,33 @@ namespace MinecraftClient.Protocol.Handlers
return locationBytes;
}
+ ///
+ /// Get a byte array representing the given item as a HashedStack (1.21.5+).
+ /// Used for serverbound container_click where the server expects HashedStack instead of full ItemStack.
+ /// Wire format: Optional<ActualItem> where ActualItem = holderRegistry(item_id) + VarInt(count) + HashedPatchMap.
+ /// Since MCC doesn't track component hashes, we send an empty HashedPatchMap (0 added, 0 removed).
+ /// The server will detect the stateId mismatch and resync.
+ ///
+ public byte[] GetHashedItemSlot(Item? item, ItemPalette itemPalette)
+ {
+ List slotData = new();
+
+ if (item == null || item.IsEmpty)
+ {
+ slotData.AddRange(GetBool(false));
+ }
+ else
+ {
+ slotData.AddRange(GetBool(true));
+ slotData.AddRange(GetVarInt(itemPalette.ToId(item.Type)));
+ slotData.AddRange(GetVarInt(item.Count));
+ slotData.AddRange(GetVarInt(0)); // HashedPatchMap: 0 added components
+ slotData.AddRange(GetVarInt(0)); // HashedPatchMap: 0 removed components
+ }
+
+ return slotData.ToArray();
+ }
+
///
/// Get a byte array representing the given item as an item slot
///
diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs
index 4fe6b857..ab00dfc6 100644
--- a/MinecraftClient/Protocol/Handlers/Protocol18.cs
+++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs
@@ -4567,11 +4567,19 @@ namespace MinecraftClient.Protocol.Handlers
foreach (var slot in changedSlots)
{
packet.AddRange(dataTypes.GetShort(slot.Item1)); // slot ID
- packet.AddRange(dataTypes.GetItemSlot(slot.Item2, itemPalette)); // slot Data
+ // 1.21.5+ uses HashedStack instead of ItemStack for container_click
+ if (protocolVersion >= MC_1_21_5_Version)
+ packet.AddRange(dataTypes.GetHashedItemSlot(slot.Item2, itemPalette));
+ else
+ packet.AddRange(dataTypes.GetItemSlot(slot.Item2, itemPalette));
}
}
- packet.AddRange(dataTypes.GetItemSlot(item, itemPalette)); // Carried item (Clicked item)
+ // 1.21.5+ uses HashedStack instead of ItemStack for carried item
+ if (protocolVersion >= MC_1_21_5_Version)
+ packet.AddRange(dataTypes.GetHashedItemSlot(item, itemPalette));
+ else
+ packet.AddRange(dataTypes.GetItemSlot(item, itemPalette));
SendPacket(PacketTypesOut.ClickWindow, packet);
return true;
diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_5/EnchantmentsComponent1215.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_5/EnchantmentsComponent1215.cs
new file mode 100644
index 00000000..4ade9885
--- /dev/null
+++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_5/EnchantmentsComponent1215.cs
@@ -0,0 +1,39 @@
+using System.Collections.Generic;
+using MinecraftClient.Inventory;
+using MinecraftClient.Inventory.ItemPalettes;
+using MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_20_6;
+using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
+
+namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_5;
+
+///
+/// 1.21.5+ enchantments: showInTooltip removed from wire format (moved to tooltip_display component).
+/// Wire: VarInt count, then (VarInt holder_id + VarInt level) per entry. No trailing boolean.
+///
+public class EnchantmentsComponent1215(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
+ : EnchantmentsComponent(dataTypes, itemPalette, subComponentRegistry)
+{
+ public override void Parse(Queue data)
+ {
+ NumberOfEnchantments = dataTypes.ReadNextVarInt(data);
+
+ for (var i = 0; i < NumberOfEnchantments; i++)
+ {
+ var registryId = dataTypes.ReadNextVarInt(data);
+ var level = dataTypes.ReadNextVarInt(data);
+ Enchantments.Add(new Enchantment(EnchantmentMapping.GetEnchantmentByRegistryId1206(registryId), level));
+ }
+ }
+
+ public override Queue Serialize()
+ {
+ var data = new List();
+ data.AddRange(DataTypes.GetVarInt(Enchantments.Count));
+ foreach (var enchantment in Enchantments)
+ {
+ data.AddRange(DataTypes.GetVarInt(EnchantmentMapping.GetRegistryId1206ByEnchantment(enchantment.Type)));
+ data.AddRange(DataTypes.GetVarInt(enchantment.Level));
+ }
+ return new Queue(data);
+ }
+}
diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_5/StoredEnchantmentsComponent1215.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_5/StoredEnchantmentsComponent1215.cs
new file mode 100644
index 00000000..8daf09ea
--- /dev/null
+++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/Components/1_21_5/StoredEnchantmentsComponent1215.cs
@@ -0,0 +1,7 @@
+using MinecraftClient.Inventory.ItemPalettes;
+using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
+
+namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_5;
+
+public class StoredEnchantmentsComponent1215(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
+ : EnchantmentsComponent1215(dataTypes, itemPalette, subComponentRegistry);
diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/Registries/StructuredComponentsRegistry12111.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/Registries/StructuredComponentsRegistry12111.cs
index ec848fb2..c7faf6a4 100644
--- a/MinecraftClient/Protocol/Handlers/StructuredComponents/Registries/StructuredComponentsRegistry12111.cs
+++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/Registries/StructuredComponentsRegistry12111.cs
@@ -27,7 +27,7 @@ public class StructuredComponentsRegistry12111 : StructuredComponentRegistry
RegisterComponent(10, "minecraft:item_model");
RegisterComponent(11, "minecraft:lore");
RegisterComponent(12, "minecraft:rarity");
- RegisterComponent(13, "minecraft:enchantments");
+ RegisterComponent(13, "minecraft:enchantments");
RegisterComponent(14, "minecraft:can_place_on");
RegisterComponent(15, "minecraft:can_break");
RegisterComponent(16, "minecraft:attribute_modifiers");
@@ -55,7 +55,7 @@ public class StructuredComponentsRegistry12111 : StructuredComponentRegistry
RegisterComponent(38, "minecraft:piercing_weapon");
RegisterComponent(39, "minecraft:kinetic_weapon");
RegisterComponent(40, "minecraft:swing_animation");
- RegisterComponent(41, "minecraft:stored_enchantments");
+ RegisterComponent(41, "minecraft:stored_enchantments");
RegisterComponent(42, "minecraft:dyed_color");
RegisterComponent(43, "minecraft:map_color");
RegisterComponent(44, "minecraft:map_id");
diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/Registries/StructuredComponentsRegistry1215.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/Registries/StructuredComponentsRegistry1215.cs
index 26b3b27e..a0b8a4c7 100644
--- a/MinecraftClient/Protocol/Handlers/StructuredComponents/Registries/StructuredComponentsRegistry1215.cs
+++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/Registries/StructuredComponentsRegistry1215.cs
@@ -23,7 +23,7 @@ public class StructuredComponentsRegistry1215 : StructuredComponentRegistry
RegisterComponent(7, "minecraft:item_model");
RegisterComponent(8, "minecraft:lore");
RegisterComponent(9, "minecraft:rarity");
- RegisterComponent(10, "minecraft:enchantments");
+ RegisterComponent(10, "minecraft:enchantments");
RegisterComponent(11, "minecraft:can_place_on");
RegisterComponent(12, "minecraft:can_break");
RegisterComponent(13, "minecraft:attribute_modifiers");
@@ -48,7 +48,7 @@ public class StructuredComponentsRegistry1215 : StructuredComponentRegistry
RegisterComponent(31, "minecraft:tooltip_style");
RegisterComponent(32, "minecraft:death_protection");
RegisterComponent(33, "minecraft:blocks_attacks"); // NEW
- RegisterComponent(34, "minecraft:stored_enchantments");
+ RegisterComponent(34, "minecraft:stored_enchantments");
RegisterComponent(35, "minecraft:dyed_color");
RegisterComponent(36, "minecraft:map_color");
RegisterComponent(37, "minecraft:map_id");