Merge pull request #2943 from BruceChenQAQ/master

fix: use HashedStack for container_click and fix enchantments parsing…
This commit is contained in:
BruceChen 2026-03-22 02:23:08 +08:00 committed by GitHub
commit 78dc74a6f0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 87 additions and 6 deletions

View file

@ -1679,6 +1679,33 @@ namespace MinecraftClient.Protocol.Handlers
return locationBytes;
}
/// <summary>
/// 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&lt;ActualItem&gt; 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.
/// </summary>
public byte[] GetHashedItemSlot(Item? item, ItemPalette itemPalette)
{
List<byte> 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();
}
/// <summary>
/// Get a byte array representing the given item as an item slot
/// </summary>

View file

@ -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;

View file

@ -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;
/// <summary>
/// 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.
/// </summary>
public class EnchantmentsComponent1215(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: EnchantmentsComponent(dataTypes, itemPalette, subComponentRegistry)
{
public override void Parse(Queue<byte> 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<byte> Serialize()
{
var data = new List<byte>();
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<byte>(data);
}
}

View file

@ -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);

View file

@ -27,7 +27,7 @@ public class StructuredComponentsRegistry12111 : StructuredComponentRegistry
RegisterComponent<ItemModelComponent>(10, "minecraft:item_model");
RegisterComponent<LoreNameComponent1206>(11, "minecraft:lore");
RegisterComponent<RarityComponent>(12, "minecraft:rarity");
RegisterComponent<EnchantmentsComponent>(13, "minecraft:enchantments");
RegisterComponent<EnchantmentsComponent1215>(13, "minecraft:enchantments");
RegisterComponent<CanPlaceOnComponent>(14, "minecraft:can_place_on");
RegisterComponent<CanBreakComponent>(15, "minecraft:can_break");
RegisterComponent<AttributeModifiersComponent>(16, "minecraft:attribute_modifiers");
@ -55,7 +55,7 @@ public class StructuredComponentsRegistry12111 : StructuredComponentRegistry
RegisterComponent<PiercingWeaponComponent>(38, "minecraft:piercing_weapon");
RegisterComponent<KineticWeaponComponent>(39, "minecraft:kinetic_weapon");
RegisterComponent<SwingAnimationComponent>(40, "minecraft:swing_animation");
RegisterComponent<StoredEnchantmentsComponent>(41, "minecraft:stored_enchantments");
RegisterComponent<StoredEnchantmentsComponent1215>(41, "minecraft:stored_enchantments");
RegisterComponent<DyeColorComponent>(42, "minecraft:dyed_color");
RegisterComponent<MapColorComponent>(43, "minecraft:map_color");
RegisterComponent<MapIdComponent>(44, "minecraft:map_id");

View file

@ -23,7 +23,7 @@ public class StructuredComponentsRegistry1215 : StructuredComponentRegistry
RegisterComponent<ItemModelComponent>(7, "minecraft:item_model");
RegisterComponent<LoreNameComponent1206>(8, "minecraft:lore");
RegisterComponent<RarityComponent>(9, "minecraft:rarity");
RegisterComponent<EnchantmentsComponent>(10, "minecraft:enchantments");
RegisterComponent<EnchantmentsComponent1215>(10, "minecraft:enchantments");
RegisterComponent<CanPlaceOnComponent>(11, "minecraft:can_place_on");
RegisterComponent<CanBreakComponent>(12, "minecraft:can_break");
RegisterComponent<AttributeModifiersComponent>(13, "minecraft:attribute_modifiers");
@ -48,7 +48,7 @@ public class StructuredComponentsRegistry1215 : StructuredComponentRegistry
RegisterComponent<TooltipStyleComponent>(31, "minecraft:tooltip_style");
RegisterComponent<DeathProtectionComponent>(32, "minecraft:death_protection");
RegisterComponent<BlocksAttacksComponent>(33, "minecraft:blocks_attacks"); // NEW
RegisterComponent<StoredEnchantmentsComponent>(34, "minecraft:stored_enchantments");
RegisterComponent<StoredEnchantmentsComponent1215>(34, "minecraft:stored_enchantments");
RegisterComponent<DyeColorComponent>(35, "minecraft:dyed_color");
RegisterComponent<MapColorComponent>(36, "minecraft:map_color");
RegisterComponent<MapIdComponent>(37, "minecraft:map_id");