feat: Wire MC 26.2 (protocol 776) routing and adapt Teams packet parsing

- Add MC_26_2_Version = 776 and bump all upper-bound feature gates
- Route 26.2 to the new item/block/entity palettes and
  StructuredComponentsRegistry262
- Reuse PacketPalette261 (play/config packet IDs are unchanged in 26.2;
  the only registry change is spectate_entity renamed to spectator_action
  at the same ID, which MCC does not send) and EntityMetadataPalette261
  (serializer list is identical)
- Add a 26.2 branch for Set Player Team parsing: field order changed to
  displayName, prefix, suffix, visibility, collision rule, then color as
  Optional<TeamColor> (absent maps to -1) and options byte last
- Register protocol 776 in both supported-protocol lists and the
  version string mappings; bump MCHighestVersion to 26.2

JoinGame gained a trailing onlineMode bool and LoginFinished a trailing
session UUID in 26.2; both sit after every field MCC reads, so parsing
is unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Reed Pennock 2026-07-02 16:43:31 -05:00
parent 22685a720c
commit e4161af158
6 changed files with 60 additions and 14 deletions

View file

@ -27,7 +27,7 @@ public abstract class EntityMetadataPalette
<= Protocol18Handler.MC_1_21_7_Version => new EntityMetadataPalette1215(), // 1.21.5 - 1.21.8
<= Protocol18Handler.MC_1_21_9_Version => new EntityMetadataPalette1219(), // 1.21.9 - 1.21.10
<= Protocol18Handler.MC_1_21_11_Version => new EntityMetadataPalette12111(), // 1.21.11
<= Protocol18Handler.MC_26_1_Version => new EntityMetadataPalette261(), // 26.1
<= Protocol18Handler.MC_26_2_Version => new EntityMetadataPalette261(), // 26.1 - 26.2 (serializers unchanged in 26.2)
_ => throw new NotImplementedException()
};
}

View file

@ -48,7 +48,7 @@ namespace MinecraftClient
public const string Version = MCHighestVersion;
public const string MCLowestVersion = "1.4.6";
public const string MCHighestVersion = "26.1";
public const string MCHighestVersion = "26.2";
public static readonly string? BuildInfo = null;
private static Tuple<Thread, CancellationTokenSource>? offlinePrompt = null;

View file

@ -48,9 +48,9 @@ namespace MinecraftClient.Protocol.Handlers
{
PacketTypePalette p = protocol switch
{
> Protocol18Handler.MC_26_1_Version => throw new NotImplementedException(Translations
> Protocol18Handler.MC_26_2_Version => throw new NotImplementedException(Translations
.exception_palette_packet),
>= Protocol18Handler.MC_26_1_Version => new PacketPalette261(),
>= Protocol18Handler.MC_26_1_Version => new PacketPalette261(), // 26.1 - 26.2 (packet IDs unchanged in 26.2)
<= Protocol18Handler.MC_1_21_11_Version and > Protocol18Handler.MC_1_21_7_Version => new PacketPalette1219(),
<= Protocol18Handler.MC_1_21_7_Version and > Protocol18Handler.MC_1_21_5_Version => new PacketPalette1216(),
<= Protocol18Handler.MC_1_21_5_Version and > Protocol18Handler.MC_1_21_4_Version => new PacketPalette1215(),

View file

@ -84,6 +84,7 @@ namespace MinecraftClient.Protocol.Handlers
internal const int MC_1_21_9_Version = 773;
internal const int MC_1_21_11_Version = 774;
internal const int MC_26_1_Version = 775;
internal const int MC_26_2_Version = 776;
private int compression_treshold = -1;
private int autocomplete_transaction_id = 0;
@ -145,21 +146,21 @@ namespace MinecraftClient.Protocol.Handlers
lastSeenMessagesCollector = protocolVersion >= MC_1_19_3_Version ? new(20) : new(5);
chunkBatchStartTime = GetNanos();
if (handler.GetTerrainEnabled() && protocolVersion > MC_26_1_Version)
if (handler.GetTerrainEnabled() && protocolVersion > MC_26_2_Version)
{
log.Error($"§c{Translations.extra_terrainandmovement_disabled}");
handler.SetTerrainEnabled(false);
}
if (handler.GetInventoryEnabled() &&
protocolVersion is < MC_1_8_Version or > MC_26_1_Version)
protocolVersion is < MC_1_8_Version or > MC_26_2_Version)
{
log.Error($"§c{Translations.extra_inventory_disabled}");
handler.SetInventoryEnabled(false);
}
if (handler.GetEntityHandlingEnabled() &&
protocolVersion is < MC_1_8_Version or > MC_26_1_Version)
protocolVersion is < MC_1_8_Version or > MC_26_2_Version)
{
log.Error($"§c{Translations.extra_entity_disabled}");
handler.SetEntityHandlingEnabled(false);
@ -168,8 +169,9 @@ namespace MinecraftClient.Protocol.Handlers
Block.Palette = protocolVersion switch
{
// Block palette
> MC_26_1_Version when handler.GetTerrainEnabled() =>
> MC_26_2_Version when handler.GetTerrainEnabled() =>
throw new NotImplementedException(Translations.exception_palette_block),
>= MC_26_2_Version => new Palette262(),
>= MC_26_1_Version => new Palette261(),
>= MC_1_21_9_Version => new Palette1219(),
>= MC_1_21_6_Version => new Palette1216(), // 1.21.7/1.21.8 blocks unchanged, reuse 1216
@ -193,8 +195,9 @@ namespace MinecraftClient.Protocol.Handlers
entityPalette = protocolVersion switch
{
// Entity palette
> MC_26_1_Version when handler.GetEntityHandlingEnabled() =>
> MC_26_2_Version when handler.GetEntityHandlingEnabled() =>
throw new NotImplementedException(Translations.exception_palette_entity),
>= MC_26_2_Version => new EntityPalette262(),
>= MC_26_1_Version => new EntityPalette261(),
>= MC_1_21_11_Version => new EntityPalette12111(),
>= MC_1_21_9_Version => new EntityPalette1219(),
@ -224,8 +227,9 @@ namespace MinecraftClient.Protocol.Handlers
itemPalette = protocolVersion switch
{
// Item palette
> MC_26_1_Version when handler.GetInventoryEnabled() =>
> MC_26_2_Version when handler.GetInventoryEnabled() =>
throw new NotImplementedException(Translations.exception_palette_item),
>= MC_26_2_Version => new ItemPalette262(),
>= MC_26_1_Version => new ItemPalette261(),
>= MC_1_21_11_Version => new ItemPalette12111(),
>= MC_1_21_9_Version => new ItemPalette1219(),
@ -2823,7 +2827,7 @@ namespace MinecraftClient.Protocol.Handlers
// Also make a palette for field? Will be a lot of work
var healthField = protocolVersion switch
{
> MC_26_1_Version => throw new NotImplementedException(Translations
> MC_26_2_Version => throw new NotImplementedException(Translations
.exception_palette_healthfield),
// 1.17 and above
>= MC_1_17_Version => 9,
@ -3196,10 +3200,15 @@ namespace MinecraftClient.Protocol.Handlers
// displayName (component), options (byte),
// nameTagVisibility, collisionRule, color (VarInt),
// prefix (component), suffix (component)
// 1.21.5+ method 0/2:
// 1.21.5-26.1 method 0/2:
// displayName (component), options (byte),
// nameTagVisibility (VarInt), collisionRule (VarInt),
// color (VarInt), prefix (component), suffix (component)
// 26.2+ method 0/2:
// displayName (component), prefix (component),
// suffix (component), nameTagVisibility (VarInt),
// collisionRule (VarInt), color (Optional<VarInt>),
// options (byte)
// method 0/3/4: players list (VarInt count + strings)
var teamName = dataTypes.ReadNextString(packetData);
var teamMethod = dataTypes.ReadNextByte(packetData);
@ -3227,6 +3236,39 @@ namespace MinecraftClient.Protocol.Handlers
teamColor = unchecked((sbyte)dataTypes.ReadNextByte(packetData));
}
else if (protocolVersion >= MC_26_2_Version)
{
teamDisplayName = dataTypes.ReadNextChat(packetData);
teamPrefix = dataTypes.ReadNextChat(packetData);
teamSuffix = dataTypes.ReadNextChat(packetData);
// STREAM_CODEC: 0=always, 1=never, 2=hideForOtherTeams, 3=hideForOwnTeam
teamNameTagVisibility = dataTypes.ReadNextVarInt(packetData) switch
{
0 => "always",
1 => "never",
2 => "hideForOtherTeams",
3 => "hideForOwnTeam",
_ => "always"
};
// STREAM_CODEC: 0=always, 1=never, 2=pushOtherTeams, 3=pushOwnTeam
teamCollisionRule = dataTypes.ReadNextVarInt(packetData) switch
{
0 => "always",
1 => "never",
2 => "pushOtherTeams",
3 => "pushOwnTeam",
_ => "always"
};
// Optional<TeamColor>: bool + VarInt id (ids match legacy color ordinals 0-15)
teamColor = dataTypes.ReadNextBool(packetData)
? dataTypes.ReadNextVarInt(packetData)
: -1;
teamFriendlyFlags = dataTypes.ReadNextByte(packetData);
}
else
{
teamDisplayName = dataTypes.ReadNextChat(packetData);

View file

@ -33,6 +33,7 @@ public class StructuredComponentsHandler
{
Protocol18Handler.MC_1_20_6_Version => typeof(StructuredComponentsRegistry1206),
Protocol18Handler.MC_1_21_Version => typeof(StructuredComponentsRegistry121),
>= Protocol18Handler.MC_26_2_Version => typeof(StructuredComponentsRegistry262),
>= Protocol18Handler.MC_26_1_Version => typeof(StructuredComponentsRegistry261),
>= Protocol18Handler.MC_1_21_11_Version => typeof(StructuredComponentsRegistry12111),
>= Protocol18Handler.MC_1_21_5_Version => typeof(StructuredComponentsRegistry1215),

View file

@ -156,7 +156,7 @@ namespace MinecraftClient.Protocol
{
4, 5, 47, 107, 108, 109, 110, 210, 315, 316, 335, 338, 340, 393, 401, 404, 477, 480, 485, 490, 498, 573,
575, 578, 735, 736, 751, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768,
769, 770, 771, 772, 773, 774, 775
769, 770, 771, 772, 773, 774, 775, 776
};
if (Array.IndexOf(suppoertedVersionsProtocol18, normalizedVersion) > -1)
@ -374,6 +374,8 @@ namespace MinecraftClient.Protocol
return 774;
case "26.1":
return 775;
case "26.2":
return 776;
default:
return 0;
}
@ -396,7 +398,7 @@ namespace MinecraftClient.Protocol
4, 5, 47, 107, 108, 109, 110, 210, 315, 316, 335, 338, 340, 393, 401, 404,
477, 480, 485, 490, 498, 573, 575, 578, 735, 736, 751, 753, 754, 755, 756,
757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771,
772, 773, 774, 775
772, 773, 774, 775, 776
];
/// <summary>
@ -518,6 +520,7 @@ namespace MinecraftClient.Protocol
773 => "1.21.9",
774 => "1.21.11",
775 => "26.1",
776 => "26.2",
_ => "0.0"
};
}