bugfix: Fixed more components on 1.21.5, 1.21.11 and 26.1 and crashing on 1.21.8

This commit is contained in:
Anon 2026-03-25 12:50:10 +01:00 committed by GitHub
commit 52eda4ccdd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 280 additions and 13 deletions

View file

@ -2454,7 +2454,7 @@ namespace MinecraftClient.Protocol.Handlers
var bitsData = dataTypes.ReadNextByte(packetData);
// Top bit set if another entry follows, and otherwise unset if this is the last item in the array
hasNext = bitsData >> 7 == 1;
var slot2 = bitsData >> 1;
var slot2 = bitsData & 0x7F;
var item = dataTypes.ReadNextItemSlot(packetData, itemPalette);
handler.OnEntityEquipment(entityId, slot2, item);
} while (hasNext);

View file

@ -0,0 +1,136 @@
using System;
using System.Collections.Generic;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Components.Subcomponents._1_20_6;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_5;
/// <summary>
/// 1.21.5+ uses AdventureModePredicate.STREAM_CODEC:
/// list<BlockPredicate>, where each BlockPredicate ends with DataComponentMatchers.
/// Tooltip visibility moved to minecraft:tooltip_display.
/// </summary>
public sealed class CanBreakComponent1215(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: AdventureModePredicateComponent1215Base(dataTypes, itemPalette, subComponentRegistry);
/// <summary>
/// 1.21.5+ uses AdventureModePredicate.STREAM_CODEC:
/// list<BlockPredicate>, where each BlockPredicate ends with DataComponentMatchers.
/// Tooltip visibility moved to minecraft:tooltip_display.
/// </summary>
public sealed class CanPlaceOnComponent1215(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: AdventureModePredicateComponent1215Base(dataTypes, itemPalette, subComponentRegistry);
public abstract class AdventureModePredicateComponent1215Base(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public List<AdventureModeBlockPredicate1215> BlockPredicates { get; set; } = [];
public override void Parse(Queue<byte> data)
{
var predicateCount = DataTypes.ReadNextVarInt(data);
BlockPredicates = new List<AdventureModeBlockPredicate1215>(predicateCount);
var componentHandler = new StructuredComponentsHandler(DataTypes.ProtocolVersion, DataTypes, ItemPalette);
for (var i = 0; i < predicateCount; i++)
BlockPredicates.Add(ParseBlockPredicate(data, componentHandler));
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(BlockPredicates.Count));
foreach (var predicate in BlockPredicates)
SerializeBlockPredicate(data, predicate);
return new Queue<byte>(data);
}
private AdventureModeBlockPredicate1215 ParseBlockPredicate(Queue<byte> data, StructuredComponentsHandler componentHandler)
{
BlockSetSubcomponent? blockSet = null;
if (DataTypes.ReadNextBool(data))
blockSet = (BlockSetSubcomponent)SubComponentRegistry.ParseSubComponent(SubComponents.BlockSet, data);
List<PropertySubComponent> properties = [];
if (DataTypes.ReadNextBool(data))
{
var propertyCount = DataTypes.ReadNextVarInt(data);
properties = new List<PropertySubComponent>(propertyCount);
for (var i = 0; i < propertyCount; i++)
properties.Add((PropertySubComponent)SubComponentRegistry.ParseSubComponent(SubComponents.Property, data));
}
Dictionary<string, object>? nbt = null;
if (DataTypes.ReadNextBool(data))
nbt = DataTypes.ReadNextNbt(data);
var exactComponentCount = DataTypes.ReadNextVarInt(data);
var exactComponents = new List<StructuredComponent>(exactComponentCount);
for (var i = 0; i < exactComponentCount; i++)
{
var componentTypeId = DataTypes.ReadNextVarInt(data);
exactComponents.Add(componentHandler.Parse(componentTypeId, data));
}
var partialPredicateCount = DataTypes.ReadNextVarInt(data);
var partialPredicates = new List<DataComponentPredicatePayload1215>(partialPredicateCount);
for (var i = 0; i < partialPredicateCount; i++)
{
partialPredicates.Add(new DataComponentPredicatePayload1215(
DataTypes.ReadNextVarInt(data),
DataTypes.ReadNextNbt(data)));
}
return new AdventureModeBlockPredicate1215(blockSet, properties, nbt, exactComponents, partialPredicates);
}
private void SerializeBlockPredicate(List<byte> data, AdventureModeBlockPredicate1215 predicate)
{
data.AddRange(DataTypes.GetBool(predicate.BlockSet is not null));
if (predicate.BlockSet is not null)
data.AddRange(predicate.BlockSet.Serialize());
data.AddRange(DataTypes.GetBool(predicate.Properties.Count > 0));
if (predicate.Properties.Count > 0)
{
data.AddRange(DataTypes.GetVarInt(predicate.Properties.Count));
foreach (var property in predicate.Properties)
data.AddRange(property.Serialize());
}
data.AddRange(DataTypes.GetBool(predicate.Nbt is not null));
if (predicate.Nbt is not null)
data.AddRange(DataTypes.GetNbt(predicate.Nbt));
data.AddRange(DataTypes.GetVarInt(predicate.ExactComponents.Count));
foreach (var component in predicate.ExactComponents)
{
if (component.TypeId < 0)
throw new ArgumentException("Exact predicate component is missing its data component type id.", nameof(component));
data.AddRange(DataTypes.GetVarInt(component.TypeId));
data.AddRange(component.Serialize());
}
data.AddRange(DataTypes.GetVarInt(predicate.PartialPredicates.Count));
foreach (var predicatePayload in predicate.PartialPredicates)
{
data.AddRange(DataTypes.GetVarInt(predicatePayload.TypeId));
data.AddRange(DataTypes.GetNbt(predicatePayload.Payload));
}
}
}
public sealed record AdventureModeBlockPredicate1215(
BlockSetSubcomponent? BlockSet,
List<PropertySubComponent> Properties,
Dictionary<string, object>? Nbt,
List<StructuredComponent> ExactComponents,
List<DataComponentPredicatePayload1215> PartialPredicates);
public sealed record DataComponentPredicatePayload1215(int TypeId, Dictionary<string, object> Payload);

View file

@ -0,0 +1,25 @@
using System.Collections.Generic;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_5;
/// <summary>
/// 1.21.5+ dyed_color only carries the RGB integer.
/// Tooltip visibility moved to minecraft:tooltip_display.
/// </summary>
public class DyeColorComponent1215(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public int Color { get; set; }
public override void Parse(Queue<byte> data)
{
Color = DataTypes.ReadNextInt(data);
}
public override Queue<byte> Serialize()
{
return new Queue<byte>(DataTypes.GetInt(Color));
}
}

View file

@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.StructuredComponents.Core;
using MinecraftClient.Protocol.Message;
namespace MinecraftClient.Protocol.Handlers.StructuredComponents.Components._1_21_5;
/// <summary>
/// 1.21.5+ trim uses ArmorTrim.STREAM_CODEC:
/// Holder&lt;TrimMaterial&gt; + Holder&lt;TrimPattern&gt;.
/// The holder codec is ByteBufCodecs.holder(), so 0 means direct inline data and non-zero means registry reference.
/// </summary>
public class TrimComponent1215(DataTypes dataTypes, ItemPalette itemPalette, SubComponentRegistry subComponentRegistry)
: StructuredComponent(dataTypes, itemPalette, subComponentRegistry)
{
public int MaterialHolderValue { get; set; }
public DirectTrimMaterial1215? DirectMaterial { get; set; }
public int PatternHolderValue { get; set; }
public DirectTrimPattern1215? DirectPattern { get; set; }
public override void Parse(Queue<byte> data)
{
MaterialHolderValue = DataTypes.ReadNextVarInt(data);
if (MaterialHolderValue == 0)
DirectMaterial = ParseDirectMaterial(data);
PatternHolderValue = DataTypes.ReadNextVarInt(data);
if (PatternHolderValue == 0)
DirectPattern = ParseDirectPattern(data);
}
public override Queue<byte> Serialize()
{
var data = new List<byte>();
data.AddRange(DataTypes.GetVarInt(MaterialHolderValue));
if (MaterialHolderValue == 0)
{
if (DirectMaterial is null)
throw new ArgumentNullException(nameof(DirectMaterial), "Direct trim material payload is required when holder value is 0.");
data.AddRange(DataTypes.GetString(DirectMaterial.BaseSuffix));
data.AddRange(DataTypes.GetVarInt(DirectMaterial.OverrideSuffixes.Count));
foreach (var (assetKey, suffix) in DirectMaterial.OverrideSuffixes)
{
data.AddRange(DataTypes.GetString(assetKey));
data.AddRange(DataTypes.GetString(suffix));
}
data.AddRange(DataTypes.GetNbt(DirectMaterial.DescriptionNbt));
}
data.AddRange(DataTypes.GetVarInt(PatternHolderValue));
if (PatternHolderValue == 0)
{
if (DirectPattern is null)
throw new ArgumentNullException(nameof(DirectPattern), "Direct trim pattern payload is required when holder value is 0.");
data.AddRange(DataTypes.GetString(DirectPattern.AssetId));
data.AddRange(DataTypes.GetNbt(DirectPattern.DescriptionNbt));
data.AddRange(DataTypes.GetBool(DirectPattern.Decal));
}
return new Queue<byte>(data);
}
private DirectTrimMaterial1215 ParseDirectMaterial(Queue<byte> data)
{
var baseSuffix = DataTypes.ReadNextString(data);
var overrideCount = DataTypes.ReadNextVarInt(data);
var overrideSuffixes = new Dictionary<string, string>(overrideCount, StringComparer.Ordinal);
for (var i = 0; i < overrideCount; i++)
{
var assetKey = DataTypes.ReadNextString(data);
var suffix = DataTypes.ReadNextString(data);
overrideSuffixes[assetKey] = suffix;
}
var descriptionNbt = DataTypes.ReadNextNbt(data);
var description = ChatParser.ParseText(descriptionNbt);
return new DirectTrimMaterial1215(baseSuffix, overrideSuffixes, descriptionNbt, description);
}
private DirectTrimPattern1215 ParseDirectPattern(Queue<byte> data)
{
var assetId = DataTypes.ReadNextString(data);
var descriptionNbt = DataTypes.ReadNextNbt(data);
var description = ChatParser.ParseText(descriptionNbt);
var decal = DataTypes.ReadNextBool(data);
return new DirectTrimPattern1215(assetId, descriptionNbt, description, decal);
}
}
public sealed record DirectTrimMaterial1215(
string BaseSuffix,
Dictionary<string, string> OverrideSuffixes,
Dictionary<string, object> DescriptionNbt,
string Description);
public sealed record DirectTrimPattern1215(
string AssetId,
Dictionary<string, object> DescriptionNbt,
string Description,
bool Decal);

View file

@ -30,8 +30,8 @@ public class StructuredComponentsRegistry12111 : StructuredComponentRegistry
RegisterComponent<LoreNameComponent1206>(11, "minecraft:lore");
RegisterComponent<RarityComponent>(12, "minecraft:rarity");
RegisterComponent<EnchantmentsComponent1215>(13, "minecraft:enchantments");
RegisterComponent<CanPlaceOnComponent>(14, "minecraft:can_place_on");
RegisterComponent<CanBreakComponent>(15, "minecraft:can_break");
RegisterComponent<CanPlaceOnComponent1215>(14, "minecraft:can_place_on");
RegisterComponent<CanBreakComponent1215>(15, "minecraft:can_break");
RegisterComponent<AttributeModifiersComponent1218>(16, "minecraft:attribute_modifiers");
RegisterComponent<CustomModelDataComponent>(17, "minecraft:custom_model_data");
RegisterComponent<TooltipDisplayComponent>(18, "minecraft:tooltip_display");
@ -58,7 +58,7 @@ public class StructuredComponentsRegistry12111 : StructuredComponentRegistry
RegisterComponent<KineticWeaponComponent>(39, "minecraft:kinetic_weapon");
RegisterComponent<SwingAnimationComponent>(40, "minecraft:swing_animation");
RegisterComponent<StoredEnchantmentsComponent1215>(41, "minecraft:stored_enchantments");
RegisterComponent<DyeColorComponent>(42, "minecraft:dyed_color");
RegisterComponent<DyeColorComponent1215>(42, "minecraft:dyed_color");
RegisterComponent<MapColorComponent>(43, "minecraft:map_color");
RegisterComponent<MapIdComponent>(44, "minecraft:map_id");
RegisterComponent<MapDecorationsComponent>(45, "minecraft:map_decorations");
@ -70,7 +70,7 @@ public class StructuredComponentsRegistry12111 : StructuredComponentRegistry
RegisterComponent<SuspiciousStewEffectsComponent>(51, "minecraft:suspicious_stew_effects");
RegisterComponent<WritableBlookContentComponent>(52, "minecraft:writable_book_content");
RegisterComponent<WrittenBlookContentComponent>(53, "minecraft:written_book_content");
RegisterComponent<TrimComponent>(54, "minecraft:trim");
RegisterComponent<TrimComponent1215>(54, "minecraft:trim");
RegisterComponent<DebugStickStateComponent>(55, "minecraft:debug_stick_state");
RegisterComponent<EntityDataComponent>(56, "minecraft:entity_data");
RegisterComponent<BucketEntityDataComponent>(57, "minecraft:bucket_entity_data");

View file

@ -29,8 +29,8 @@ public class StructuredComponentsRegistry1215 : StructuredComponentRegistry
RegisterComponent<LoreNameComponent1206>(8, "minecraft:lore");
RegisterComponent<RarityComponent>(9, "minecraft:rarity");
RegisterComponent<EnchantmentsComponent1215>(10, "minecraft:enchantments");
RegisterComponent<CanPlaceOnComponent>(11, "minecraft:can_place_on");
RegisterComponent<CanBreakComponent>(12, "minecraft:can_break");
RegisterComponent<CanPlaceOnComponent1215>(11, "minecraft:can_place_on");
RegisterComponent<CanBreakComponent1215>(12, "minecraft:can_break");
if (uses1218AttributeAndEquippableFormats)
RegisterComponent<AttributeModifiersComponent1218>(13, "minecraft:attribute_modifiers");
else
@ -60,7 +60,7 @@ public class StructuredComponentsRegistry1215 : StructuredComponentRegistry
RegisterComponent<DeathProtectionComponent>(32, "minecraft:death_protection");
RegisterComponent<BlocksAttacksComponent>(33, "minecraft:blocks_attacks"); // NEW
RegisterComponent<StoredEnchantmentsComponent1215>(34, "minecraft:stored_enchantments");
RegisterComponent<DyeColorComponent>(35, "minecraft:dyed_color");
RegisterComponent<DyeColorComponent1215>(35, "minecraft:dyed_color");
RegisterComponent<MapColorComponent>(36, "minecraft:map_color");
RegisterComponent<MapIdComponent>(37, "minecraft:map_id");
RegisterComponent<MapDecorationsComponent>(38, "minecraft:map_decorations");
@ -72,7 +72,7 @@ public class StructuredComponentsRegistry1215 : StructuredComponentRegistry
RegisterComponent<SuspiciousStewEffectsComponent>(44, "minecraft:suspicious_stew_effects");
RegisterComponent<WritableBlookContentComponent>(45, "minecraft:writable_book_content");
RegisterComponent<WrittenBlookContentComponent>(46, "minecraft:written_book_content");
RegisterComponent<TrimComponent>(47, "minecraft:trim");
RegisterComponent<TrimComponent1215>(47, "minecraft:trim");
RegisterComponent<DebugStickStateComponent>(48, "minecraft:debug_stick_state");
RegisterComponent<EntityDataComponent>(49, "minecraft:entity_data");
RegisterComponent<BucketEntityDataComponent>(50, "minecraft:bucket_entity_data");

View file

@ -28,8 +28,8 @@ public class StructuredComponentsRegistry261 : StructuredComponentRegistry
RegisterComponent<LoreNameComponent1206>(11, "minecraft:lore");
RegisterComponent<RarityComponent>(12, "minecraft:rarity");
RegisterComponent<EnchantmentsComponent1215>(13, "minecraft:enchantments");
RegisterComponent<CanPlaceOnComponent>(14, "minecraft:can_place_on");
RegisterComponent<CanBreakComponent>(15, "minecraft:can_break");
RegisterComponent<CanPlaceOnComponent1215>(14, "minecraft:can_place_on");
RegisterComponent<CanBreakComponent1215>(15, "minecraft:can_break");
RegisterComponent<AttributeModifiersComponent>(16, "minecraft:attribute_modifiers");
RegisterComponent<CustomModelDataComponent>(17, "minecraft:custom_model_data");
RegisterComponent<TooltipDisplayComponent>(18, "minecraft:tooltip_display");
@ -58,7 +58,7 @@ public class StructuredComponentsRegistry261 : StructuredComponentRegistry
RegisterComponent<VarIntComponent>(41, "minecraft:additional_trade_cost"); // New in 26.1
RegisterComponent<StoredEnchantmentsComponent1215>(42, "minecraft:stored_enchantments");
RegisterComponent<VarIntComponent>(43, "minecraft:dye"); // New in 26.1
RegisterComponent<DyeColorComponent>(44, "minecraft:dyed_color");
RegisterComponent<DyeColorComponent1215>(44, "minecraft:dyed_color");
RegisterComponent<MapColorComponent>(45, "minecraft:map_color");
RegisterComponent<MapIdComponent>(46, "minecraft:map_id");
RegisterComponent<MapDecorationsComponent>(47, "minecraft:map_decorations");
@ -70,7 +70,7 @@ public class StructuredComponentsRegistry261 : StructuredComponentRegistry
RegisterComponent<SuspiciousStewEffectsComponent>(53, "minecraft:suspicious_stew_effects");
RegisterComponent<WritableBlookContentComponent>(54, "minecraft:writable_book_content");
RegisterComponent<WrittenBlookContentComponent>(55, "minecraft:written_book_content");
RegisterComponent<TrimComponent>(56, "minecraft:trim");
RegisterComponent<TrimComponent1215>(56, "minecraft:trim");
RegisterComponent<DebugStickStateComponent>(57, "minecraft:debug_stick_state");
RegisterComponent<EntityDataComponent>(58, "minecraft:entity_data");
RegisterComponent<BucketEntityDataComponent>(59, "minecraft:bucket_entity_data");