From 35dd3c4f069c64fb2583632c7c49b061f68d10e1 Mon Sep 17 00:00:00 2001 From: BruceChen Date: Tue, 31 Mar 2026 01:27:27 +0800 Subject: [PATCH] Add support for ItemStackTemplate in DataTypes and Protocol18 - Implemented ReadNextItemStackTemplate method to read ItemStackTemplate data with item-first encoding. - Updated Protocol18 to utilize ReadItemStackTemplateLabel for improved item display handling. - Enhanced item component parsing to accommodate new structured components. --- .../Protocol/Handlers/DataTypes.cs | 31 +++++++++++++++++++ .../Protocol/Handlers/Protocol18.cs | 11 ++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/MinecraftClient/Protocol/Handlers/DataTypes.cs b/MinecraftClient/Protocol/Handlers/DataTypes.cs index 669ba5b3..6a0d27aa 100644 --- a/MinecraftClient/Protocol/Handlers/DataTypes.cs +++ b/MinecraftClient/Protocol/Handlers/DataTypes.cs @@ -411,6 +411,37 @@ namespace MinecraftClient.Protocol.Handlers return ReadNextNbt(cache, true); } + /// + /// Read an ItemStackTemplate (26.1+) from a cache of bytes. + /// Unlike ItemStack, this uses item-first encoding: item_id, count, DataComponentPatch. + /// ItemStackTemplate is always non-empty (no count=0 sentinel). + /// + public Item ReadNextItemStackTemplate(Queue cache, ItemPalette itemPalette) + { + var itemId = ReadNextVarInt(cache); + var itemCount = ReadNextVarInt(cache); + var item = new Item(itemPalette.FromId(itemId), itemCount, null); + + var numberOfComponentsToAdd = ReadNextVarInt(cache); + var numberofComponentsToRemove = ReadNextVarInt(cache); + var structuredComponentHandler = new StructuredComponentsHandler(protocolversion, this, itemPalette); + var strcturedComponentsToAdd = new List(numberOfComponentsToAdd); + + for (var i = 0; i < numberOfComponentsToAdd; i++) + { + var componentTypeId = ReadNextVarInt(cache); + strcturedComponentsToAdd.Add(structuredComponentHandler.Parse(componentTypeId, cache)); + } + + for (var i = 0; i < numberofComponentsToRemove; i++) + ReadNextVarInt(cache); + + if (strcturedComponentsToAdd.Count > 0) + item.Components = strcturedComponentsToAdd; + + return item; + } + /// /// Read a single item slot from a cache of bytes and remove it from the cache /// diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index eeabc8e0..45bde28f 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -3530,7 +3530,7 @@ namespace MinecraftClient.Protocol.Handlers 2 => ReadWithAnyPotionSlotDisplayLabel(packetData), 3 => ReadOnlyWithComponentSlotDisplayLabel(packetData), 4 => Item.GetTypeString(itemPalette.FromId(dataTypes.ReadNextVarInt(packetData))), - 5 => dataTypes.ReadNextItemSlot(packetData, itemPalette)?.GetTypeString() ?? "Empty", + 5 => ReadItemStackTemplateLabel(packetData), 6 => "#" + dataTypes.ReadNextString(packetData), 7 => ReadDyedSlotDisplayLabel(packetData), 8 => ReadSmithingTrimSlotDisplayLabel(packetData), @@ -3612,6 +3612,15 @@ namespace MinecraftClient.Protocol.Handlers return label; } + /// + /// Read an ItemStackTemplate (26.1+) which encodes fields in a different order + /// than ItemStack: item_id (VarInt), count (VarInt), DataComponentPatch. + /// + private string ReadItemStackTemplateLabel(Queue packetData) + { + return dataTypes.ReadNextItemStackTemplate(packetData, itemPalette).GetTypeString(); + } + private void SkipOptionalCraftingRequirements(Queue packetData) { if (!dataTypes.ReadNextBool(packetData))