From e4161af158d930f217337bb5d61e063f5753fb35 Mon Sep 17 00:00:00 2001 From: Reed Pennock Date: Thu, 2 Jul 2026 16:43:31 -0500 Subject: [PATCH] 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 (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 --- .../Mapping/EntityMetadataPalette.cs | 2 +- MinecraftClient/Program.cs | 2 +- .../Protocol/Handlers/PacketType18Handler.cs | 4 +- .../Protocol/Handlers/Protocol18.cs | 58 ++++++++++++++++--- .../StructuredComponentsHandler.cs | 1 + MinecraftClient/Protocol/ProtocolHandler.cs | 7 ++- 6 files changed, 60 insertions(+), 14 deletions(-) diff --git a/MinecraftClient/Mapping/EntityMetadataPalette.cs b/MinecraftClient/Mapping/EntityMetadataPalette.cs index 98875ffb..85f6c1b4 100644 --- a/MinecraftClient/Mapping/EntityMetadataPalette.cs +++ b/MinecraftClient/Mapping/EntityMetadataPalette.cs @@ -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() }; } diff --git a/MinecraftClient/Program.cs b/MinecraftClient/Program.cs index c9d3a153..71ba3142 100644 --- a/MinecraftClient/Program.cs +++ b/MinecraftClient/Program.cs @@ -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? offlinePrompt = null; diff --git a/MinecraftClient/Protocol/Handlers/PacketType18Handler.cs b/MinecraftClient/Protocol/Handlers/PacketType18Handler.cs index 82ee6e69..05443e37 100644 --- a/MinecraftClient/Protocol/Handlers/PacketType18Handler.cs +++ b/MinecraftClient/Protocol/Handlers/PacketType18Handler.cs @@ -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(), diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index 90786f5b..2d0bb40f 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -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), + // 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: 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); diff --git a/MinecraftClient/Protocol/Handlers/StructuredComponents/StructuredComponentsHandler.cs b/MinecraftClient/Protocol/Handlers/StructuredComponents/StructuredComponentsHandler.cs index 48f0747a..6214b2f5 100644 --- a/MinecraftClient/Protocol/Handlers/StructuredComponents/StructuredComponentsHandler.cs +++ b/MinecraftClient/Protocol/Handlers/StructuredComponents/StructuredComponentsHandler.cs @@ -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), diff --git a/MinecraftClient/Protocol/ProtocolHandler.cs b/MinecraftClient/Protocol/ProtocolHandler.cs index a8568f38..f231976f 100644 --- a/MinecraftClient/Protocol/ProtocolHandler.cs +++ b/MinecraftClient/Protocol/ProtocolHandler.cs @@ -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 ]; /// @@ -518,6 +520,7 @@ namespace MinecraftClient.Protocol 773 => "1.21.9", 774 => "1.21.11", 775 => "26.1", + 776 => "26.2", _ => "0.0" }; }