Brigadier's main object is CommandDispatcher<S>
. This is where the command nodes are registered, and it does the parsing and execution of commands.
The generic type S
can be any object; it is used as a context object that is stored in the CommandContext<S>
that's passed around to commands/argument types. (MC uses CommandSource
, while Janitor uses MessageReceivedEvent
).
Brigadier's command model is of a tree. Each node can have children of other nodes, with one node having no parent but all the children (the root node).
There are three types of nodes:
At the root, there's the RootCommandNode<S>
, of which only one can exist per tree and all other nodes are a child of.
This is auto-created by CommandDispatcher<S>
(you can also pass a previously created root node to the constructor to duplicate the tree).
Then there are LiteralCommandNode<S>
s, which represent a literal "word" in the command. It has no other special meaning, other than to allow separating branches of the command tree (think of the branches as the commands).
All children of RootCommandNode
must be a LiteralCommandNode
.
Then the last type of command node is the RequiredCommandNode<S>
, for accepting some kind of argument in the command. This is used for player-controlled input, such as a number, string, or other object (corresponding to an ArgumentType<T>
).
The mechanics of how the parsing of a command tree is done is a bit hard to explain using only words, which is why I usually visualize a tree for it.
An example of a command tree in action:
[root]
+-> 'time'
| +--> 'query' --> [executes]
| +--> 'add' --> (number) --> [executes]
| +--> 'set' --> (number) --> [executes]
| +--> 'fail'
|
+-> 'ban'
+-> <requires OP lvl 4>
+-> (player username)
+-> [executes]
+--> (string) --> [executes]
In this visualization, there's two commands: time
and ban
. (Brigadier has no concept of prefix, inputs should have the prefix removed already.)
The [root]
represents the singular RootCommandNode
. Each 'literal'
is a LiteralCommandNode
with the given literal word (this case, it's "literal"). Each (number)
represents a RequiredCommandNode
with the given argument needed.
At the end of a branch of the tree, an execution node (the executes()
call) must be present to successfully parse
Each word in the command must correspond to a node in the command tree. If it reaches the end of the command text, and it stopped on a corresponding node, and there is an [executes]
node (the executes(ctx -> {...})
), then a command is successfully parsed and it can be executed.
If one of the above conditions do not hold, then the command parsing fails.
(NOTE: there is no [executes]
node in Brigader; execution information is stored in the same command node object. For the purposes of the visualization, I have it visualized.)
Parsing starts at the root command node, and travels down, searching for a compatible node for the command text at the position being parsed.
Here's a few examples of the former command tree in action:
=
time set 10000
=
time
corresponds to a node? -- YES, literal nodetime
. Continue down that nodeset
corresponds to a node? -- YES, literal nodeset
. Continue down that node10000
corresponds to a node? -- YES, required node(number)
, requiring a number. Continue down that node- Reached end of string. Any
[executes]
nodes? -- YES.- Parsing is successful. Command can be executed.
=
time fail
=
time
corresponds to a node? -- YES, literal nodetime
. Continue down that nodefail
corresponds to a node? -- YES, literal nodefail
. Continue down that node- Reached end of string. Any
[executes]
nodes? -- NO.- Parsing failed; no [executes] node.
=
ban SomePlayerFella
=
ban
corresponds to a node? -- YES, literal nodetime
. Continue down that nodeSomePlayerFella
corresponds to a node? -- YES, required node(player username)
, requiring a player's username. Continue down that node- Reached end of string. Any
[executes]
nodes? -- YES.- *Parsing is successful. Command can be executed.
That's the basics of Brigadier's command tree system. (There's also redirects, and forking [not sure what this does yet], and suggestions, and others)
LiteralCommandNode
and RequiredCommandNode
are constructed using LiteralArgumentBuilder<S, T>
and RequiredArgumentBuilder<S, T>
, respectively. T
is the same type as the object, this is used because they parent ArgumentBuilder<S, T>
so the builder methods (then(...)
, executes(...)
) return the same object/type and generics instead of a generic ArgumentBuilder
.