packets/: packet model + catalogs + wire-format deep-dives

Control-state catalogs (handshake/status/login/config), categorized Play
catalog (~182 packets), and deep-dives on the four hard formats: chunk data
(paletted containers + light), entity metadata (type registry), slot/structured
components, command graph (Brigadier). Sourced from minecraft-data + ViaVersion.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
claude-timemachine
2026-06-19 15:15:26 +02:00
parent a3d5f64ef5
commit 90b711d12a
8 changed files with 2159 additions and 0 deletions
+442
View File
@@ -0,0 +1,442 @@
# Commands (Declare Commands) Packet
Clientbound · Play state
Added: **1.13** (protocol 393)
Sends the server's Brigadier command graph to the client so it can populate tab-completion and validate syntax client-side before sending the command.
Packet IDs by version:
| Version | Packet ID |
|---------|-----------|
| 1.13 | `0x11` |
| 1.19 | `0x0F` |
| 1.21.1 | `0x11` |
Sources:
- `minecraft-data/data/pc/1.13/protocol.json` — top-level `types.command_node` + `play.toClient` packet list
- `minecraft-data/data/pc/1.19/protocol.json` — same, post-VarInt-parser change
- `minecraft-data/data/pc/1.21.1/protocol.json` — same, 1.21.1 parser table
- `ViaVersion/common/src/main/java/com/viaversion/viaversion/rewriter/CommandRewriter.java``registerDeclareCommands` (String era) and `handle1_19` / `registerDeclareCommands1_19` (VarInt era)
- `ViaVersion/…/protocols/v1_18_2to1_19/Protocol1_18_2To1_19.java` lines 178210 — transition handler (reads `Types.STRING`, writes `Types.VAR_INT`)
See also: [../versions/1.13.md](../versions/1.13.md) · [../versions/1.19.md](../versions/1.19.md)
---
## Packet Layout
```
Count VarInt number of nodes in the flat node array
Nodes[] command_node[] one record per node (see below)
Root Index VarInt index into Nodes[] of the root node
```
The node array is **flat** — nodes reference each other by index, not by nesting. The root node is always type 0 (root); its index is given by `Root Index` at the end of the packet.
---
## Node Record (`command_node`)
Fields are conditional on the `flags` byte:
```
Flags byte (bitfield)
Children VarInt count, then VarInt[] of child node indices
Redirect Node VarInt — only if flags bit 3 (0x08) set
Name String — only for literal (type 1) and argument (type 2) nodes
Parser ID String|VarInt — only for argument nodes (type 2); encoding changed in 1.19
Properties (variable) — only for argument nodes; depends on Parser ID
Suggestions String/Identifier — only if flags bit 4 (0x10) set
```
### Flags Byte (bitfield)
The byte is parsed from **LSB to MSB**:
```
Bit(s) Mask Field
------ ----- -------------------------------------------
01 0x03 node type: 0 = root, 1 = literal, 2 = argument
2 0x04 is_executable — this node itself is a valid end-of-input
3 0x08 has_redirect — a Redirect Node index follows Children
4 0x10 has_suggestions — a Suggestions Type identifier follows Properties
(argument nodes only; ignored on other types)
57 0xE0 unused
```
Note: `minecraft-data` names these `command_node_type` (bits 01), `has_command` (bit 2), `has_redirect_node` (bit 3), `has_custom_suggestions` (bit 4).
### Children
```
ChildCount VarInt number of children
Children[] VarInt[] indices into the flat node array
```
### Redirect Node
Present only when `flags & 0x08 != 0`. A single VarInt index into the flat node array. Used for command aliases — e.g. `/tp` and `/teleport` can share the same subgraph via redirect.
### Name
Present for node types **literal** (1) and **argument** (2). Not present for root (0). A length-prefixed UTF-8 String (max 32767 chars per the standard String encoding).
### Parser ID + Properties
Present only for argument nodes (type 2). The parser encoding **changed in 1.19**.
---
## Parser Encoding: String (1.13) vs VarInt (1.19+)
### Pre-1.19 (1.13 through 1.18.x)
Parser is a plain **String** (identifier, e.g. `"brigadier:string"`, `"minecraft:entity"`).
```
Parser String e.g. "brigadier:integer"
```
Source: `minecraft-data/data/pc/1.13/protocol.json` `types.command_node` extraNodeData type=2 → `parser: "string"`.
ViaVersion `CommandRewriter.registerDeclareCommands()` reads `Types.STRING` for the parser name.
### 1.19+ (protocol 759 onwards)
Parser is a **VarInt** registry index (a compact enum of all known parser names).
```
Parser VarInt e.g. 5 = "brigadier:string"
```
Source: `minecraft-data/data/pc/1.19/protocol.json` `types.command_node` extraNodeData type=2 → `parser: ["mapper", {"type": "varint", ...}]`.
ViaVersion `Protocol1_18_2To1_19.java` lines 194200: reads `Types.STRING`, looks up `MAPPINGS.getArgumentTypeMappings().mappedId(argumentType)`, writes `Types.VAR_INT`.
ViaVersion `CommandRewriter.handle1_19()` line 131: reads `Types.VAR_INT` and resolves it to a name via `argumentType(argumentTypeId)`.
The property format **did not change** — only the parser identifier encoding changed. Properties are still parsed by the same per-parser logic after resolving the VarInt to a name.
---
## Common Parsers and Their Properties
All parsers with no listed properties send nothing (`void`).
### Brigadier parsers (no namespace qualifier needed for these 6)
| Parser name | VarInt ID (1.19+) | Properties |
|---------------------|:-----------------:|------------|
| `brigadier:bool` | 0 | none |
| `brigadier:float` | 1 | flags byte (bit 0 = min present, bit 1 = max present), then optional f32 min, optional f32 max |
| `brigadier:double` | 2 | flags byte (bit 0 = min present, bit 1 = max present), then optional f64 min, optional f64 max |
| `brigadier:integer` | 3 | flags byte (bit 0 = min present, bit 1 = max present), then optional i32 min, optional i32 max |
| `brigadier:long` | 4 | flags byte (bit 0 = min present, bit 1 = max present), then optional i64 min, optional i64 max |
| `brigadier:string` | 5 | VarInt mode: 0 = SINGLE_WORD, 1 = QUOTABLE_PHRASE, 2 = GREEDY_PHRASE |
Numeric range flags detail (same pattern for float/double/integer/long):
```
Bit 0 (0x01) — minimum bound present → read min value
Bit 1 (0x02) — maximum bound present → read max value
Bits 27 — unused
```
### Minecraft parsers (selected; full table below)
| Parser name | VarInt ID (1.19+) | Properties |
|------------------------------|:-----------------:|------------|
| `minecraft:entity` | 6 | flags byte: bit 0 (0x01) = only allow entities (not players), bit 1 (0x02) = only allow players |
| `minecraft:game_profile` | 7 | none |
| `minecraft:block_pos` | 8 | none |
| `minecraft:column_pos` | 9 | none |
| `minecraft:vec3` | 10 | none |
| `minecraft:vec2` | 11 | none |
| `minecraft:block_state` | 12 | none |
| `minecraft:block_predicate` | 13 | none |
| `minecraft:item_stack` | 14 | none |
| `minecraft:item_predicate` | 15 | none |
| `minecraft:color` | 16 | none |
| `minecraft:component` | 17 | none |
| `minecraft:message` | 18 (1.19) / 19 (1.21.1) | none |
| `minecraft:nbt` | 19 (1.19) / 20 (1.21.1) | none |
| `minecraft:nbt_path` | 21 (1.19) / 22 (1.21.1) | none |
| `minecraft:objective` | 22 (1.19) / 23 (1.21.1) | none |
| `minecraft:scoreboard_slot` | 28 (1.19) / 29 (1.21.1) | none |
| `minecraft:score_holder` | 29 (1.19) / 30 (1.21.1) | flags byte: bit 0 (0x01) = allow multiple |
| `minecraft:swizzle` | 30 (1.19) | none |
| `minecraft:team` | 31 (1.19) | none |
| `minecraft:resource_location`| 33 (1.19) | none |
| `minecraft:resource_or_tag` | 43 (1.19) | String registry name |
| `minecraft:resource` | 44 (1.19) | String registry name |
| `minecraft:uuid` | 47 (1.19) / 53 (1.21.1) | none |
Note: IDs shift across versions as new parsers are inserted. The VarInt ID is version-specific. Use the `minecraft-data` protocol.json for the authoritative table for a given protocol version.
#### `minecraft:entity` flags detail
```
Bit 0 (0x01) — onlyAllowEntities (non-player entities only)
Bit 1 (0x02) — onlyAllowPlayers
Bits 27 — unused
```
Both bits 0 and 1 can be 0 simultaneously (allow any selector).
#### `minecraft:score_holder` flags detail
```
Bit 0 (0x01) — allowMultiple (accept `*` and selectors matching multiple holders)
Bits 17 — unused
```
### Full 1.19 VarInt Parser Table
```
0 brigadier:bool
1 brigadier:float
2 brigadier:double
3 brigadier:integer
4 brigadier:long
5 brigadier:string
6 minecraft:entity
7 minecraft:game_profile
8 minecraft:block_pos
9 minecraft:column_pos
10 minecraft:vec3
11 minecraft:vec2
12 minecraft:block_state
13 minecraft:block_predicate
14 minecraft:item_stack
15 minecraft:item_predicate
16 minecraft:color
17 minecraft:component
18 minecraft:message
19 minecraft:nbt
20 minecraft:nbt_tag
21 minecraft:nbt_path
22 minecraft:objective
23 minecraft:objective_criteria
24 minecraft:operation
25 minecraft:particle
26 minecraft:angle
27 minecraft:rotation
28 minecraft:scoreboard_slot
29 minecraft:score_holder
30 minecraft:swizzle
31 minecraft:team
32 minecraft:item_slot
33 minecraft:resource_location
34 minecraft:mob_effect
35 minecraft:function
36 minecraft:entity_anchor
37 minecraft:int_range
38 minecraft:float_range
39 minecraft:item_enchantment
40 minecraft:entity_summon
41 minecraft:dimension
42 minecraft:time
43 minecraft:resource_or_tag
44 minecraft:resource
45 minecraft:template_mirror
46 minecraft:template_rotation
47 minecraft:uuid
```
Source: `minecraft-data/data/pc/1.19/protocol.json` `types.command_node` parser mapper mappings.
### Full 1.21.1 VarInt Parser Table (additions highlighted)
```
0 brigadier:bool
1 brigadier:float
2 brigadier:double
3 brigadier:integer
4 brigadier:long
5 brigadier:string
6 minecraft:entity
7 minecraft:game_profile
8 minecraft:block_pos
9 minecraft:column_pos
10 minecraft:vec3
11 minecraft:vec2
12 minecraft:block_state
13 minecraft:block_predicate
14 minecraft:item_stack
15 minecraft:item_predicate
16 minecraft:color
17 minecraft:component
18 minecraft:style ← new in 1.21.x era
19 minecraft:message
20 minecraft:nbt
21 minecraft:nbt_tag
22 minecraft:nbt_path
23 minecraft:objective
24 minecraft:objective_criteria
25 minecraft:operation
26 minecraft:particle
27 minecraft:angle
28 minecraft:rotation
29 minecraft:scoreboard_slot
30 minecraft:score_holder
31 minecraft:swizzle
32 minecraft:team
33 minecraft:item_slot
34 minecraft:item_slots ← new
35 minecraft:resource_location
36 minecraft:function
37 minecraft:entity_anchor
38 minecraft:int_range
39 minecraft:float_range
40 minecraft:dimension
41 minecraft:gamemode ← new
42 minecraft:time
43 minecraft:resource_or_tag
44 minecraft:resource_or_tag_key ← new
45 minecraft:resource
46 minecraft:resource_key ← new
47 minecraft:template_mirror
48 minecraft:template_rotation
49 minecraft:heightmap ← new
50 minecraft:loot_table ← new
51 minecraft:loot_predicate ← new
52 minecraft:loot_modifier ← new
53 minecraft:uuid
```
Source: `minecraft-data/data/pc/1.21.1/protocol.json` `types.command_node` parser mapper mappings.
---
## Suggestions Type
When flags bit 4 (`0x10`) is set, an extra field follows Properties:
```
Suggestions String an Identifier naming the suggestion provider
```
Known values:
- `minecraft:ask_server` — client sends a Tab-Complete request to the server for this argument
- `minecraft:all_recipes` — client fills from the known recipe list
- `minecraft:available_sounds` — client fills from the sound registry
- `minecraft:summonable_entities` — client fills from entity type registry
<!-- UNCONFIRMED: whether additional built-in suggestion providers exist beyond these four; wiki.vg lists these as the documented set -->
---
## Example: `/teleport <target>`
A minimal `/teleport <target>` command with one argument. Three nodes total:
```
Node 0: type=root, executable=false, children=[1]
Node 1: type=literal, executable=false, name="teleport", children=[2]
Node 2: type=argument, executable=true, name="target",
parser="minecraft:entity" (VarInt 6 in 1.19+),
properties=flags(0x02 = onlyAllowPlayers),
children=[]
Root Index = 0
```
Wire layout (hex, showing field-by-field):
```
Count 03 (3 nodes)
Node 0:
flags 00 (type=root, not executable, no redirect)
childCount 01 (1 child)
children 01 (index 1)
[no name — root node]
Node 1:
flags 04 (type=literal 0x01 | executable=false; wait — not executable here, so 0x01)
-- actually flags = 0x01 (type=literal, not executable)
childCount 01
children 02
name 08 74 65 6c 65 70 6f 72 74 ("teleport", length-prefixed string)
Node 2:
flags 06 (type=argument 0x02 | is_executable 0x04)
childCount 00
name 06 74 61 72 67 65 74 ("target")
parser 06 (VarInt 6 = minecraft:entity, in 1.19+)
properties 02 (onlyAllowPlayers flag)
Root Index 00
```
ASCII graph:
```
[ROOT node=0]
|
v
[LITERAL "teleport" node=1]
|
v
[ARGUMENT "target" node=2] parser=minecraft:entity executable
```
---
## Redirect Example
`/tp` can alias `/teleport` by using a redirect:
```
Node 3: type=literal, executable=false, flags=0x09 (literal | has_redirect),
name="tp", children=[], redirect=1
```
`flags = 0x01 | 0x08 = 0x09`. The redirect points to node 1 (the `teleport` literal), so the client treats `/tp` as if it navigated into the `teleport` subgraph.
---
## Node-Record Pseudocode
```python
def read_command_node(buf):
flags = buf.read_byte()
node_type = flags & 0x03 # 0=root, 1=literal, 2=argument
is_executable = bool(flags & 0x04)
has_redirect = bool(flags & 0x08)
has_suggestions = bool(flags & 0x10)
child_count = buf.read_varint()
children = [buf.read_varint() for _ in range(child_count)]
redirect = buf.read_varint() if has_redirect else None
name = None
if node_type in (1, 2): # literal or argument
name = buf.read_string()
parser = None
properties = None
if node_type == 2: # argument
# Pre-1.19: parser = buf.read_string()
# 1.19+: parser = PARSER_TABLE[buf.read_varint()]
parser = read_parser_id(buf)
properties = read_parser_properties(buf, parser)
suggestions = None
if has_suggestions: # argument nodes only in practice
suggestions = buf.read_string() # identifier
return CommandNode(node_type, is_executable, children, redirect,
name, parser, properties, suggestions)
```
---
## Version History
| Version | Protocol | Change |
|------------|----------|--------|
| 1.13 | 393 | Packet added; parser = String identifier |
| 1.14 | 477 | New argument parsers added (e.g. `minecraft:uuid`, `minecraft:nbt_compound_tag`) |
| 1.19 | 759 | Parser identifier changed from String to VarInt registry index; new parsers added |
| 1.19.3 | 761 | Additional parser entries added |
| 1.21.1 | 767 | `minecraft:style`, `minecraft:item_slots`, `minecraft:gamemode`, `minecraft:resource_or_tag_key`, `minecraft:resource_key`, `minecraft:heightmap`, `minecraft:loot_*` parsers added |
The `minecraft-data` `types.command_node.extraNodeData[type=2].parser` field is `"string"` for 1.131.18, and `["mapper", {"type": "varint", ...}]` for 1.19+.
ViaVersion `Protocol1_18_2To1_19.java:194200` is the canonical protocol transition point: it reads `Types.STRING` from the 1.18 upstream and writes `Types.VAR_INT` to the 1.19 client.
<!-- UNCONFIRMED: whether 1.13-pre versions had a slightly different flag layout before 1.13 release; only release 1.13 data confirmed via minecraft-data -->