Conversation
The data submodule moves from Release 3.102.3 (2025-12-28) to the upstream
`pc_26_2` branch head 4dd8762a ("fix: restore 26.2 login protocol fields",
open PR PrismarineJS/minecraft-data#1219). The branch is master plus the 26.2
boilerplate, so protocols 773-776 arrive together: 1.21.9-1.21.11, 26.1, 26.2.
26.2 data is bot-generated and not merged upstream yet.
The loader range follows: ProtocolDataOptions default ToProtocol 772 -> 776,
McpServer end 772 -> 776. Nothing else in the loader is version-name aware -
ProtocolLoader keys off the integer in each version.json, so "26.1"/"26.2"
folder names need no parser change.
Checked: `tools\mcproto-facts.cmd stats` loads the full range, 286 packets,
new ids among them (configuration.toClient.code_of_conduct,
configuration.toServer.accept_code_of_conduct). `ids --pv 776 --ns play
--direction toClient` returns 141 packet ids against 134 at --pv 772.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Nothing exposed the mapping between a protocol number and the Minecraft releases that speak it, so extending the coverage table to 773-776 had no lawful source. ProtocolMap already carries it (ProtocolInfo.MinecraftVersions, filled from each version.json); the repository just never published it. IProtocolRepository gains GetVersions() returning ProtocolVersionEntry (protocol number + release names), implemented in ProtocolRepository off the existing map. ProtocolQueryService.GetVersions() orders by protocol number and adds a joined Display string. Wired into all three surfaces: CLI `versions`, REST `GET /api/versions`, stdio MCP `get_protocol_versions`. Command and endpoint lists in AI_CONTEXT.md and README.md follow. Checked: `tools\mcproto-facts.cmd versions --format toon` prints 735-776; the new numbers read 773=1.21.9, 774=1.21.11, 775=26.1, 776=26.2. McpServer builds clean (built to a scratch output path because the running instance holds the normal one). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Spec/protocol-ids.json regenerated from the updated facts server: 286 packet entries against 245 before, because the data now reaches 26.2. The packet universe at 776 is 257 ids - 13 more than at 772 (code_of_conduct, accept_code_of_conduct, the five debug_* packets, game_test_highlight_pos, game_rule_values, low_disk_space_warning, set_game_rule, attack, spectate_entity, debug_subscription_request) and one gone (play.toServer.debug_sample_subscription). Coverage.knownVersions gains 773 "1.21.9", 774 "1.21.11", 775 "26.1", 776 "26.2" from the new facts versions surface, so the coverage report stops cutting off at 772. Checked: `dotnet run -- coverage` reports 201/257 covered on pv 776 against 202/245 on pv 772; wire gaps stay at 3 and stubs at 6. Of the 31 packets whose shape changes above 772, 15 already have a spec and need a new wire layer; 16 have no spec at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Fifteen packets change shape above protocol 772; each got a new wire layer, with the previous newest layer closed at the right boundary. Notable ones: - explosion (773): x/y/z collapse into center vec3f64, radius f32 and an i32 block count are inserted after it, and a weighted particle list is appended. Two named types carry the tail: ExplosionParticleEntry (data, weight) and ExplosionParticleInfo (particle, scaling, speed). - spawn_position (773): the body becomes RespawnData (GlobalPos, yaw, pitch), so a dimension identifier now precedes the block position and a pitch follows the old angle. RespawnData and GlobalPos are new type specs. - update_time (775): time and tickDayTime give way to a varint-counted list of clock updates (id, totalTicks as varlong, partialTick, rate) - new type ClockUpdate. - spawn_entity and entity_velocity (773): the i16 velocity triple becomes the quantized LpVec3, and in spawn_entity it also moves ahead of pitch/yaw. - login.toClient.success (776): trailing sessionId UUID - one of the two packets that change on 26.2 itself. - cookie_response in all three states (773): the value goes back to optional. Facts show it required on 772 only, so that single version keeps its own layer. - player_rotation (773): relativeYaw and relativePitch booleans after each angle. debug_sample_subscription: support now ends at 772, the packet is gone from 773. Two specs deliberately differ from the data. minecraft-data types the chat command checksum as i8 and the enchant_item button id as i8 on 774 only, with u8 and varint on both sides of it. External sources agree those are upstream defects, not protocol changes: MCProtocolLib pinned at 774 reads a plain byte and a varint respectively, the wiki revision bracketing 774 says Byte and VarInt, ViaVersion's 773->774 protocol declares the serverbound packet set identical, and PrismarineJS themselves call the i8 checksum a bug in minecraft-data#1188 and the i8 button id a bug in #1201. So the specs keep u8 from 770 on and varint from 767 on, with no 774 layer. Coverage.knownVersions display names follow the confirmed mapping: 773 covers 1.21.9 and 1.21.10, 775 covers 26.1 through 26.1.2. Checked: dotnet build clean; `dotnet run -- gen` emits no new TODO markers, only the six allowlisted stubs; `dotnet run -- coverage` reports 210/257 on pv 776. F# formatted with Fantomas. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Protocol 773 replaced the i16 velocity triple with lpVec3, which protodef declares as a native - McProtoFacts has no structure for it, so the shape came from external sources (MCProtocolLib's readLpVec3, the protocol wiki's data type page, node-minecraft-protocol's codec, Botcraft, decompiled vanilla). It is not spec-able: the encoding is 1 byte for zero, otherwise 48 bits holding a 2-bit scale, a continuation flag and three 15-bit components, with the rest of the scale trailing as a varint. So it joins position and the other hand-written runtime primitives. Runtime.cs: LpVec3 as a record struct of three doubles. Read assembles the 48 bits from an unsigned byte pair plus a big-endian uint32; write picks scale = ceil(chebyshev norm), packs each component with round-half-up (C# banker's rounding would shift bytes), and sets the continuation flag when the scale needs more than two bits. MinecraftVersion.LatestProtocol moves 772 -> 776. Console: LpVec3 is checked against the two sample vectors from the protocol documentation byte for byte (F1FF0000FFFF and F6FF4001051F02), the zero vector must be a single 0x00, and 2000 random vectors across nine magnitude decades must round-trip within one quantization step. UpdateTimePacket and SpawnPositionPacket cases now cover their new layers as well (776 alongside the older versions), since both packets lost their common fields to per-layer groups. The csproj excludes two more generated files that need the unmodelled Particle type, and LoginPacket, which needs NBT. Checked: sandbox console runs clean, every assertion passes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Nine packets that arrived above protocol 772 had no spec at all; they need nothing the codegen is missing, so they are modelled now: - configuration.toClient.code_of_conduct (contents string) and configuration.toServer.accept_code_of_conduct (empty), both 773+. - play.toClient.game_test_highlight_pos (two positions, 773+) and play.toClient.low_disk_space_warning (empty, 775+). - play.toServer.attack and play.toServer.spectate_entity (entity id varint, 775+) - two of the three packets the old use_entity union split into on 26.1. - play.toClient.game_rule_values and play.toServer.set_game_rule (775+), with the new named type GameRule (name, value). - play.toClient.login, which had no spec despite being the join packet. All nine wire layers from 736 to 776 are modelled; on 776 onlineMode is inserted before enforcesSecureChat, which three independent sources confirm against the bot-generated data. The module in Login.fs is named LoginPlay so it does not shadow the DSL's ProtocolState.Login case, which every spec has in scope. SpawnInfo is deliberately left alone. Facts rename its death field's type from DeathLocation to GlobalPos at 773, but the two types are byte-identical (dimension identifier plus position), so the rename has no wire effect - and a layer for it would not compile, because an api field cannot change its named type between versions. Checked: dotnet build clean; `gen` emits no new TODO markers; the sandbox console runs every assertion clean; `coverage` now reports 210/257 on pv 776 against 201 before this batch. F# formatted with Fantomas. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The union gap is closed on both sides. A union spec now renders to Unions/<Name>.cs as a [Union] partial record whose cases are nested partial records, and the two container paths that consume one are generated instead of stubbed: a layout's readUnion becomes Union.Read(ref reader, protocolVersion, disc), and on the write side the wire-only discriminator it pairs with is derived from the model through Union.Discriminator(protocolVersion), followed by Union.Write. Read branches on protocol version first, then switches on the discriminator; Write switches on the case; a case written at a version whose layer does not carry it throws. Case naming keeps the spec's name while the parameter list is identical in every layer that carries it, and suffixes the layer label otherwise, reusing the packet layer-label helper. TeamAction therefore has CreatedVUntil764 and CreatedV771_Last side by side, with Removed shared. Case records shadowed the same-named types they carry - partial record Rotations(Rotations Value) bound the parameter to the case, not the type - so arm type references are namespace-qualified before rendering. TeamsPacket and EntityMetadataEntry generate completely now and left the allowlist; six stubs remain, none of them union-shaped: inlineUnion (EncryptionResponse), SentinelArray, map columns, FixedBytes and array-of-array. Around the codegen: - TeamAction's 771+ arms read the team flags byte into the new TeamFlags bitflags spec instead of discarding it. With a real write path, a discarded byte meant every team this library sends carried friendly fire and see-friendly-invisible as off. - The sandbox runtime gained a minimal NBT model, because without NbtTag no union compiles there at all. It unblocked more than unions: the csproj exclusion list drops from 30 files to 10. - Spec/Unions/Codegen/UnionShapeProbe.fs is a codegen fixture, not protocol: it reproduces the three shapes EntityMetadataValue is built from (cases named after C# keywords, a case carrying a same-named type, a case carrying an array of a named type) so the sandbox actually binds them. It is never delivered. - deliver-to-mcprotonet.ps1 refuses to deliver a set whose files reference an excluded type, listing every offender, before it touches the target directory. It refuses today: the Flow aggregates reference TeamsPacket while the unions are held back, and they stay held back until McProtoNet takes a plain Dunet reference. Checked: dotnet build clean; gen emits the six allowlisted stubs and nothing else; the sandbox console runs every assertion clean, including Teams round-tripping at 764 and 772 with a byte-identical re-write, the flags byte travelling as one u8, and the probe union round-tripping all five cases. Fantomas reformatted parts of CSharp.fs that were not formatted at HEAD, so the diff there is larger than the union work alone. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Объединения на dunet (коммит
|
play.toServer.use_entity had no spec. Up to 774 the payload is a union behind the mouse discriminator - interact carries a hand, attack carries nothing, interact_at carries a hit position and a hand - with the sneaking flag after it. From 775 (26.1) the union is gone: the server takes target, hand, an LpVec3 target offset and sneaking, and the three modes became separate packets (attack and spectate_entity already have specs). New union spec InteractAction covers the pre-775 arms; the packet spec carries both layers. It generates completely - no stub - so the union backend now has a second, independent user besides Teams. Sandbox: both eras round-trip. At 774 an interact_at goes out with discriminator 2, reads back as InteractAt with its three floats and hand, and re-writes byte-identical. At 776 the flat form round-trips with the quantized offset landing inside one quantization step. Coverage on pv 776: 211/257. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
TeamsPacket and TeamAction leave the exclusion list: McProtoNet references Dunet and gates versions through its own source generator, so the union compiles there. ExplosionParticleEntry and ExplosionParticleInfo join the list instead — they carry Particle, which McProtoNet does not model, the same reason ExplosionPacket has always been held back. Checked: a real delivery run into McProtoNet copied 267 files, the dangling- reference guard stayed quiet, and McProtoNet.Protocol builds clean on net10.0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Ветка под цель «спеки на 26.2». Мультиверсия остаётся: слои дописываются поверх, ничего старого не режем.
Сделано
pc_26_2(коммит4dd8762a, открытый запрос 🎈 Add Minecraft pc 26.2 data PrismarineJS/minecraft-data#1219). Разом приехали протоколы 773–776, диапазон загрузчика поднят до 776.GetVersions(), командаversions, endpointGET /api/versions, инструментget_protocol_versions.Spec/protocol-ids.jsonпересобран (286 записей), таблица версий вCoverage.fsдоведена до 776.RespawnData,GlobalPos,ClockUpdate,ExplosionParticleEntry,ExplosionParticleInfo.LpVec3в рантайме песочницы — новый вектор скорости с 1.21.9. В protodef это «родной» тип без структуры, поэтому разметка взята из внешних источников. Спеком не выражается: 1 байт на ноль, иначе 48 бит (2 бита масштаба, флаг продолжения, три компоненты по 15 бит) и хвостовой varint. Проверен побайтно на эталонных векторах из документации плюс 2000 случайных.Версии
Подтверждено по minecraft.wiki, ViaVersion и ProtocolLib: 773 = 1.21.9 и 1.21.10, 774 = 1.21.11, 775 = 26.1–26.1.2, 776 = 26.2.
Покрытие
Тринадцать пакетов на 776 новые, один убран (
play.toServer.debug_sample_subscription).Где спеки сознательно расходятся с данными
На слое 774 minecraft-data типизирует
chat_command_signed.checksumкакi8, аenchant_item.enchantmentкакi8, хотя по обе стороны стоятu8иvarint. Внешние источники говорят, что это брак данных, а не изменение протокола: MCProtocolLib на коммите сprotocolVersion(774)читает обычный байт и varint, ревизия вики, обрамляющая 774, даёт Byte и VarInt, а ViaVersion в переходе 773→774 объявляет серверный набор пакетов неизменным. Сами PrismarineJS называют это багом в своих запросах #1188 и #1201. Слой 774 в обоих спеках убран.Что осталось
player_info,use_entity, четыреdebug_*иdebug_subscription_request— им нужны типыDebugSubscriptionUpdate/Event/DataTypeсоswitch.LpVec3нужен в самом McProtoNet до доставки генерата — сейчас он только в песочнице.DeathLocationиGlobalPosпо проводу одинаковы, на 773 вSpawnInfoданные переименовывают поле вGlobalPos. Слой для этого не заведён — модель не умеет менять тип поля между версиями (задача 9 очереди).Риски
pc_26_2жива, клон подмодуля работает; удалят после мержа — пин перевести на мастер.