Merge pull request #17 from milutinke/fix/shulker-crash

This commit is contained in:
Anon 2026-05-07 19:59:30 +02:00 committed by GitHub
commit 6331478e30
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 205 additions and 13 deletions

View file

@ -411,6 +411,12 @@ namespace MinecraftClient.Protocol.Handlers
return ReadNextNbt(cache, true); return ReadNextNbt(cache, true);
} }
public object? ReadNextNbtTag(Queue<byte> cache)
{
var tagType = ReadNextByte(cache);
return tagType == 0 ? null : ReadNbtField(cache, tagType);
}
/// <summary> /// <summary>
/// Read an ItemStackTemplate (26.1+) from a cache of bytes. /// Read an ItemStackTemplate (26.1+) from a cache of bytes.
/// Unlike ItemStack, this uses item-first encoding: item_id, count, DataComponentPatch. /// Unlike ItemStack, this uses item-first encoding: item_id, count, DataComponentPatch.
@ -1441,6 +1447,17 @@ namespace MinecraftClient.Protocol.Handlers
return GetNbt(nbt, true); return GetNbt(nbt, true);
} }
public byte[] GetNbtTag(object? tag)
{
if (tag is null)
return [0];
var tagData = GetNbtField(tag, out var tagType);
var data = new List<byte> { tagType };
data.AddRange(tagData);
return data.ToArray();
}
/// <summary> /// <summary>
/// Build an uncompressed Named Binary Tag blob for sending over the network (internal) /// Build an uncompressed Named Binary Tag blob for sending over the network (internal)
/// </summary> /// </summary>
@ -1892,6 +1909,39 @@ namespace MinecraftClient.Protocol.Handlers
return slotData.ToArray(); return slotData.ToArray();
} }
/// <summary>
/// Get a byte array representing the given item as a non-empty ItemStackTemplate.
/// </summary>
/// <param name="item">Item</param>
/// <param name="itemPalette">Item Palette</param>
/// <returns>ItemStackTemplate representation</returns>
public byte[] GetItemStackTemplate(Item item, ItemPalette itemPalette)
{
List<byte> slotData = new();
slotData.AddRange(GetVarInt(itemPalette.ToId(item.Type)));
slotData.AddRange(GetVarInt(item.Count));
if (item.Components is not null && item.Components.Count > 0)
{
slotData.AddRange(GetVarInt(item.Components.Count));
slotData.AddRange(GetVarInt(0)); // components to remove
foreach (var component in item.Components)
{
slotData.AddRange(GetVarInt(component.TypeId));
var serialized = component.Serialize();
slotData.AddRange(serialized);
}
}
else
{
slotData.AddRange(GetVarInt(0)); // no components to add
slotData.AddRange(GetVarInt(0)); // no components to remove
}
return slotData.ToArray();
}
/// <summary> /// <summary>
/// Get a byte array representing an array of item slots /// Get a byte array representing an array of item slots
/// </summary> /// </summary>

View file

@ -0,0 +1,34 @@
using System.Collections.Generic;
using MinecraftClient.Inventory;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._26_1;
public class ContainerComponent261(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public List<Item?> Items { get; set; } = [];
public override void Parse(Queue<byte> data)
{
var count = DataTypes.ReadNextVarInt(data);
for (var i = 0; i < count; i++)
Items.Add(DataTypes.ReadNextBool(data) ? DataTypes.ReadNextItemStackTemplate(data, ItemPalette) : null);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(Items.Count));
foreach (var item in Items)
{
var hasItem = item is not null && !item.IsEmpty;
data.AddRange(DataTypes.GetBool(hasItem));
if (hasItem)
data.AddRange(DataTypes.GetItemStackTemplate(item!, ItemPalette));
}
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,31 @@
using System.Collections.Generic;
using MinecraftClient.Inventory;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._26_1;
public class ItemStackTemplateListComponent261(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public List<Item> Items { get; set; } = [];
public override void Parse(Queue<byte> data)
{
var count = DataTypes.ReadNextVarInt(data);
for (var i = 0; i < count; i++)
Items.Add(DataTypes.ReadNextItemStackTemplate(data, ItemPalette));
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(Items.Count));
foreach (var item in Items)
data.AddRange(DataTypes.GetItemStackTemplate(item, ItemPalette));
return new Queue<byte>(data);
}
}

View file

@ -0,0 +1,21 @@
using System.Collections.Generic;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._26_1;
public class NbtTagComponent261(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public object? Tag { get; set; }
public override void Parse(Queue<byte> data)
{
Tag = DataTypes.ReadNextNbtTag(data);
}
public override Queue<byte> Serialize()
{
return new Queue<byte>(DataTypes.GetNbtTag(Tag));
}
}

View file

@ -0,0 +1,29 @@
using System.Collections.Generic;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._26_1;
public class TypedEntityDataComponent261(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public int EntityTypeId { get; set; }
public Dictionary<string, object>? Nbt { get; set; }
public override void Parse(Queue<byte> data)
{
EntityTypeId = DataTypes.ReadNextVarInt(data);
Nbt = DataTypes.ReadNextNbt(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(EntityTypeId));
data.AddRange(DataTypes.GetNbt(Nbt));
return new Queue<byte>(data);
}
}
public class BlockEntityDataComponent261(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: TypedEntityDataComponent261(dataTypes, itemPalette, subComponentRegistry) {}

View file

@ -0,0 +1,25 @@
using System.Collections.Generic;
using MinecraftClient.Inventory;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._26_1;
public class UseRemainderComponent261(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public Item? ConvertInto { get; set; }
public override void Parse(Queue<byte> data)
{
ConvertInto = DataTypes.ReadNextItemStackTemplate(data, ItemPalette);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
if (ConvertInto is not null && !ConvertInto.IsEmpty)
data.AddRange(DataTypes.GetItemStackTemplate(ConvertInto, ItemPalette));
return new Queue<byte>(data);
}
}

View file

@ -4,6 +4,8 @@ using MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_20_6;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21; using MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_2; using MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_2;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_5; using MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_5;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_8;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_9;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_11; using MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_11;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components._26_1; using MinecraftClient.Protocol.Handlers.StructuredComponents.Components._26_1;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core; using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
@ -31,7 +33,7 @@ public class StructuredComponentsRegistry261 : StructuredComponentRegistry
RegisterComponent<EnchantmentsComponent1215>(13, "minecraft:enchantments"); RegisterComponent<EnchantmentsComponent1215>(13, "minecraft:enchantments");
RegisterComponent<CanPlaceOnComponent1215>(14, "minecraft:can_place_on"); RegisterComponent<CanPlaceOnComponent1215>(14, "minecraft:can_place_on");
RegisterComponent<CanBreakComponent1215>(15, "minecraft:can_break"); RegisterComponent<CanBreakComponent1215>(15, "minecraft:can_break");
RegisterComponent<AttributeModifiersComponent>(16, "minecraft:attribute_modifiers"); RegisterComponent<AttributeModifiersComponent1218>(16, "minecraft:attribute_modifiers");
RegisterComponent<CustomModelDataComponent>(17, "minecraft:custom_model_data"); RegisterComponent<CustomModelDataComponent>(17, "minecraft:custom_model_data");
RegisterComponent<TooltipDisplayComponent>(18, "minecraft:tooltip_display"); RegisterComponent<TooltipDisplayComponent>(18, "minecraft:tooltip_display");
RegisterComponent<RepairCostComponent>(19, "minecraft:repair_cost"); RegisterComponent<RepairCostComponent>(19, "minecraft:repair_cost");
@ -40,14 +42,14 @@ public class StructuredComponentsRegistry261 : StructuredComponentRegistry
RegisterComponent<IntangibleProjectileComponent>(22, "minecraft:intangible_projectile"); RegisterComponent<IntangibleProjectileComponent>(22, "minecraft:intangible_projectile");
RegisterComponent<FoodComponent1212>(23, "minecraft:food"); RegisterComponent<FoodComponent1212>(23, "minecraft:food");
RegisterComponent<ConsumableComponent>(24, "minecraft:consumable"); RegisterComponent<ConsumableComponent>(24, "minecraft:consumable");
RegisterComponent<UseRemainderComponent>(25, "minecraft:use_remainder"); RegisterComponent<UseRemainderComponent261>(25, "minecraft:use_remainder");
RegisterComponent<UseCooldownComponent>(26, "minecraft:use_cooldown"); RegisterComponent<UseCooldownComponent>(26, "minecraft:use_cooldown");
RegisterComponent<HolderSetComponent261>(27, "minecraft:damage_resistant"); RegisterComponent<HolderSetComponent261>(27, "minecraft:damage_resistant");
RegisterComponent<ToolComponent>(28, "minecraft:tool"); RegisterComponent<ToolComponent1215>(28, "minecraft:tool");
RegisterComponent<WeaponComponent>(29, "minecraft:weapon"); RegisterComponent<WeaponComponent>(29, "minecraft:weapon");
RegisterComponent<AttackRangeComponent>(30, "minecraft:attack_range"); RegisterComponent<AttackRangeComponent>(30, "minecraft:attack_range");
RegisterComponent<EnchantableComponent>(31, "minecraft:enchantable"); RegisterComponent<EnchantableComponent>(31, "minecraft:enchantable");
RegisterComponent<EquippableComponent>(32, "minecraft:equippable"); RegisterComponent<EquippableComponent1218>(32, "minecraft:equippable");
RegisterComponent<RepairableComponent>(33, "minecraft:repairable"); RegisterComponent<RepairableComponent>(33, "minecraft:repairable");
RegisterComponent<GliderComponent>(34, "minecraft:glider"); RegisterComponent<GliderComponent>(34, "minecraft:glider");
RegisterComponent<TooltipStyleComponent>(35, "minecraft:tooltip_style"); RegisterComponent<TooltipStyleComponent>(35, "minecraft:tooltip_style");
@ -64,24 +66,24 @@ public class StructuredComponentsRegistry261 : StructuredComponentRegistry
RegisterComponent<MapIdComponent>(46, "minecraft:map_id"); RegisterComponent<MapIdComponent>(46, "minecraft:map_id");
RegisterComponent<MapDecorationsComponent>(47, "minecraft:map_decorations"); RegisterComponent<MapDecorationsComponent>(47, "minecraft:map_decorations");
RegisterComponent<MapPostProcessingComponent>(48, "minecraft:map_post_processing"); RegisterComponent<MapPostProcessingComponent>(48, "minecraft:map_post_processing");
RegisterComponent<ChargedProjectilesComponent>(49, "minecraft:charged_projectiles"); RegisterComponent<ItemStackTemplateListComponent261>(49, "minecraft:charged_projectiles");
RegisterComponent<BundleContentsComponent>(50, "minecraft:bundle_contents"); RegisterComponent<ItemStackTemplateListComponent261>(50, "minecraft:bundle_contents");
RegisterComponent<PotionContentsComponent>(51, "minecraft:potion_contents"); RegisterComponent<PotionContentsComponent1212>(51, "minecraft:potion_contents");
RegisterComponent<PotionDurationScaleComponent>(52, "minecraft:potion_duration_scale"); RegisterComponent<PotionDurationScaleComponent>(52, "minecraft:potion_duration_scale");
RegisterComponent<SuspiciousStewEffectsComponent>(53, "minecraft:suspicious_stew_effects"); RegisterComponent<SuspiciousStewEffectsComponent>(53, "minecraft:suspicious_stew_effects");
RegisterComponent<WritableBlookContentComponent>(54, "minecraft:writable_book_content"); RegisterComponent<WritableBlookContentComponent>(54, "minecraft:writable_book_content");
RegisterComponent<WrittenBlookContentComponent>(55, "minecraft:written_book_content"); RegisterComponent<WrittenBlookContentComponent>(55, "minecraft:written_book_content");
RegisterComponent<TrimComponent1215>(56, "minecraft:trim"); RegisterComponent<TrimComponent1215>(56, "minecraft:trim");
RegisterComponent<DebugStickStateComponent>(57, "minecraft:debug_stick_state"); RegisterComponent<DebugStickStateComponent>(57, "minecraft:debug_stick_state");
RegisterComponent<EntityDataComponent>(58, "minecraft:entity_data"); RegisterComponent<TypedEntityDataComponent261>(58, "minecraft:entity_data");
RegisterComponent<BucketEntityDataComponent>(59, "minecraft:bucket_entity_data"); RegisterComponent<BucketEntityDataComponent>(59, "minecraft:bucket_entity_data");
RegisterComponent<BlockEntityDataComponent>(60, "minecraft:block_entity_data"); RegisterComponent<BlockEntityDataComponent261>(60, "minecraft:block_entity_data");
RegisterComponent<InstrumentComponent261>(61, "minecraft:instrument"); RegisterComponent<InstrumentComponent261>(61, "minecraft:instrument");
RegisterComponent<ProvidesTrimMaterialComponent261>(62, "minecraft:provides_trim_material"); RegisterComponent<ProvidesTrimMaterialComponent261>(62, "minecraft:provides_trim_material");
RegisterComponent<OmniousBottleAmplifierComponent>(63, "minecraft:ominous_bottle_amplifier"); RegisterComponent<OmniousBottleAmplifierComponent>(63, "minecraft:ominous_bottle_amplifier");
RegisterComponent<JukeBoxPlayableComponent>(64, "minecraft:jukebox_playable"); RegisterComponent<JukeBoxPlayableComponent1215>(64, "minecraft:jukebox_playable");
RegisterComponent<HolderSetComponent261>(65, "minecraft:provides_banner_patterns"); RegisterComponent<HolderSetComponent261>(65, "minecraft:provides_banner_patterns");
RegisterComponent<RecipesComponent>(66, "minecraft:recipes"); RegisterComponent<NbtTagComponent261>(66, "minecraft:recipes");
RegisterComponent<LodestoneTrackerComponent>(67, "minecraft:lodestone_tracker"); RegisterComponent<LodestoneTrackerComponent>(67, "minecraft:lodestone_tracker");
RegisterComponent<FireworkExplosionComponent>(68, "minecraft:firework_explosion"); RegisterComponent<FireworkExplosionComponent>(68, "minecraft:firework_explosion");
RegisterComponent<FireworksComponent>(69, "minecraft:fireworks"); RegisterComponent<FireworksComponent>(69, "minecraft:fireworks");
@ -90,9 +92,9 @@ public class StructuredComponentsRegistry261 : StructuredComponentRegistry
RegisterComponent<BannerPatternsComponent>(72, "minecraft:banner_patterns"); RegisterComponent<BannerPatternsComponent>(72, "minecraft:banner_patterns");
RegisterComponent<BaseColorComponent>(73, "minecraft:base_color"); RegisterComponent<BaseColorComponent>(73, "minecraft:base_color");
RegisterComponent<PotDecorationsComponent>(74, "minecraft:pot_decorations"); RegisterComponent<PotDecorationsComponent>(74, "minecraft:pot_decorations");
RegisterComponent<ContainerComponent>(75, "minecraft:container"); RegisterComponent<ContainerComponent261>(75, "minecraft:container");
RegisterComponent<BlockStateComponent>(76, "minecraft:block_state"); RegisterComponent<BlockStateComponent>(76, "minecraft:block_state");
RegisterComponent<BeesComponent>(77, "minecraft:bees"); RegisterComponent<BeesComponent1219>(77, "minecraft:bees");
RegisterComponent<LockComponent>(78, "minecraft:lock"); RegisterComponent<LockComponent>(78, "minecraft:lock");
RegisterComponent<ContainerLootComponent>(79, "minecraft:container_loot"); RegisterComponent<ContainerLootComponent>(79, "minecraft:container_loot");