diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/Core/StructuredComponent.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/Core/StructuredComponent.cs index 2c0b66e3..5fa5f82d 100644 --- a/MinecraftClient/Protocol/Handlers/StructuredComponents/Core/StructuredComponent.cs +++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/Core/StructuredComponent.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Text.Json.Serialization; using MinecraftClient.Inventory.ItemPalettes; namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Core; @@ -12,8 +13,15 @@ public abstract class StructuredComponent(DataTypes dataTypes, ItemPalette itemP /// /// The registry type ID assigned during parsing, used for round-trip serialization. /// + [JsonIgnore] public int TypeId { get; set; } = -1; + /// + /// The registry name assigned during parsing (e.g. "minecraft:custom_data"), used for NBT serialization. + /// + [JsonIgnore] + public string ComponentName { get; set; } = string.Empty; + public abstract void Parse(Queue data); public abstract Queue Serialize(); } \ No newline at end of file diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/Core/StructuredComponentRegistry.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/Core/StructuredComponentRegistry.cs index 9ff1f12c..805f2a79 100644 --- a/MinecraftClient/Protocol/Handlers/StructuredComponents/Core/StructuredComponentRegistry.cs +++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/Core/StructuredComponentRegistry.cs @@ -37,6 +37,7 @@ public abstract class StructuredComponentRegistry(DataTypes dataTypes, ItemPalet ?? throw new InvalidOperationException($"Could not instantiate a parser for a structured component type {name}"); component.TypeId = id; + component.ComponentName = name; component.Parse(data); return component; } diff --git a/MinecraftClient/Scripting/MccGameApi.cs b/MinecraftClient/Scripting/MccGameApi.cs index b7c8fbbd..9588691b 100644 --- a/MinecraftClient/Scripting/MccGameApi.cs +++ b/MinecraftClient/Scripting/MccGameApi.cs @@ -795,7 +795,8 @@ public sealed class MccGameApi { Slot = item.Key, Type = item.Value.Type.ToString(), - Count = item.Value.Count + Count = item.Value.Count, + Nbt = MccGameCommon.BuildNbt(item.Value) }) .ToArray(); @@ -856,7 +857,8 @@ public sealed class MccGameApi TypeLabel = pair.Value.GetTypeString(), Count = pair.Value.Count, IsPlayerInventory = entry.Key == 0, - HotbarSlot = isHotbar ? hotbar + 1 : null + HotbarSlot = isHotbar ? hotbar + 1 : null, + Nbt = MccGameCommon.BuildNbt(pair.Value) }; }); }) diff --git a/MinecraftClient/Scripting/MccGameCommon.cs b/MinecraftClient/Scripting/MccGameCommon.cs index 0088dc80..ffca5beb 100644 --- a/MinecraftClient/Scripting/MccGameCommon.cs +++ b/MinecraftClient/Scripting/MccGameCommon.cs @@ -35,6 +35,7 @@ public sealed class MccItemStackSnapshot { public required string Type { get; init; } public required int Count { get; init; } + public Dictionary? Nbt { get; init; } } /// @@ -177,10 +178,26 @@ public static class MccGameCommon return new MccItemStackSnapshot { Type = item.Type.ToString(), - Count = item.Count + Count = item.Count, + Nbt = BuildNbt(item) }; } + public static Dictionary? BuildNbt(Item item) + { + if (item.Components is { Count: > 0 }) + { + return item.Components + .Where(c => !string.IsNullOrEmpty(c.ComponentName)) + .ToDictionary( + c => c.ComponentName, + c => (object)System.Text.Json.JsonSerializer.SerializeToElement(c, c.GetType()) + ); + } + + return item.NBT is { Count: > 0 } ? item.NBT : null; + } + public static bool TryParseBlockQuery(string? query, out int? blockId, out int? blockMeta) { blockId = null; diff --git a/MinecraftClient/Scripting/MccGameModels.cs b/MinecraftClient/Scripting/MccGameModels.cs index 0c6b9c52..1eef6476 100644 --- a/MinecraftClient/Scripting/MccGameModels.cs +++ b/MinecraftClient/Scripting/MccGameModels.cs @@ -216,6 +216,7 @@ public sealed class MccInventorySnapshotSlot public required int Slot { get; init; } public required string Type { get; init; } public required int Count { get; init; } + public Dictionary? Nbt { get; init; } } public sealed class MccInventorySnapshotResult @@ -239,6 +240,7 @@ public sealed class MccInventorySearchMatch public required int Count { get; init; } public required bool IsPlayerInventory { get; init; } public int? HotbarSlot { get; init; } + public Dictionary? Nbt { get; init; } } public sealed class MccInventorySearchResult