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

@ -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),