Files
minecraft_protocol/packets/format-command-graph.md
T
claude-timemachine cf6aa978d0 verify pass 3: FML token correction + BungeeGuard/cmd-providers from live source
archive.org Wayback was network-blocked; pivoted to live GitHub. Key fix: FML
host token is \0FML\0 (not \0FML2/3\0 — those are FMLNETVERSION ints on the
fml:handshake channel); modern Forge uses \0FORGE/\0FORGEn. Confirmed BungeeGuard
backend token check (lucko source), 4 cmd suggestion providers, 26.2 interval_select
worldgen-only, corrected 1.14 villager metadata layout.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 19:26:37 +02:00

16 KiB
Raw Blame History

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.javaregisterDeclareCommands (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.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

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

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.