|
| 1 | +--- |
| 2 | +order: 2 |
| 3 | +authors: |
| 4 | + - JorelAli |
| 5 | + - willkroboth |
| 6 | + - DerEchtePilz |
| 7 | +--- |
| 8 | + |
| 9 | +# Brigadier + CommandAPI |
| 10 | + |
| 11 | +So far, we've been using only the CommandAPI to register commands. As a result, this makes the CommandAPI's features limited by whatever the CommandAPI has implemented. To push past these limits, the CommandAPI includes some extra methods to help with invoking brigadier methods. Of course, to use these methods, brigadier is required. The brigadier dependency's installation instructions can be found [here](https://github.com/Mojang/brigadier#installation). |
| 12 | + |
| 13 | +> **Developer's Note:** |
| 14 | +> |
| 15 | +> For those that are unaware, [brigadier](https://github.com/Mojang/brigadier) is Mojang's command parser and dispatching framework. This is what the CommandAPI wraps around and is the main underlying source of its functionality. |
| 16 | +
|
| 17 | +The CommandAPI has been designed in such a way that you shouldn't have to access NMS in order to make use of the more "advanced" arguments and features - if you find that NMS is required to do something, [please make a new issue](https://github.com/CommandAPI/CommandAPI/issues/new/choose)! |
| 18 | + |
| 19 | +## Brigadier support functions |
| 20 | + |
| 21 | +The CommandAPI offers the following methods in the `dev.jorel.commandapi.Brigadier` class: |
| 22 | + |
| 23 | +```java |
| 24 | +public static CommandDispatcher getCommandDispatcher(); |
| 25 | +public static RootCommandNode getRootNode(); |
| 26 | +public static LiteralArgumentBuilder fromLiteralArgument(LiteralArgument literalArgument); |
| 27 | +public static RedirectModifier fromPredicate(BiPredicate<CommandSender, Object[]> predicate, List<Argument> args); |
| 28 | +public static Command fromCommand(CommandAPICommand command); |
| 29 | +public static RequiredArgumentBuilder fromArgument(List<Argument> args, Argument<?> argument); |
| 30 | +public static RequiredArgumentBuilder fromArgument(Argument argument); |
| 31 | +public static SuggestionProvider toSuggestions(Argument<?> argument, List<Argument> args); |
| 32 | +public static Object[] parseArguments(CommandContext cmdCtx, List<Argument> args); |
| 33 | +public static Object getBrigadierSourceFromCommandSender(CommandSender sender); |
| 34 | +public static CommandSender getBukkitCommandSenderFromContext(CommandContext cmdCtx); |
| 35 | +``` |
| 36 | + |
| 37 | +Briefly, here's what each of these functions do (you can view the JavaDocs for more information): |
| 38 | + |
| 39 | +| Method | Description | |
| 40 | +|---------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------| |
| 41 | +| `getCommandDispatcher` | Returns the Minecraft command dispatcher graph | |
| 42 | +| `getRootNode` | Returns the root node of the command dispatcher.<br>This is equivalent to using<br />`getCommandDispatcher().getRoot();` | |
| 43 | +| `fromLiteralArgument` | Creates a `LiteralArgumentBuilder` from a `LiteralArgument` | |
| 44 | +| `fromPredicate` | Converts a predicate and some arguments into a `RedirectModifier`. This can be used for the `fork` method in brigadier's `ArgumentBuilder` | |
| 45 | +| `fromCommand` | Converts a `CommandAPICommand` into a brigadier `Command` object | |
| 46 | +| `fromArgument` | Converts an argument, or a list of arguments, into a `RequiredArgumentBuilder` | |
| 47 | +| `toSuggestions` | Converts an argument's suggestions into brigadier's `SuggestionProvider`, with a list of previously declared arguments | |
| 48 | +| `parseArguments` | Parses a list of CommandAPI arguments into their respective objects for a provided `CommandContext` | |
| 49 | +| `getBrigadierSourceFromCommandSender` | Converts a Bukkit `CommandSender` into the NMS command sender source object | |
| 50 | +| `getBukkitCommandSenderFromContext` | Converts a Brigadier `CommandContext` into a Bukkit `CommandSender` | |
| 51 | + |
| 52 | +## Examples |
| 53 | + |
| 54 | +I hope these examples help understand how the CommandAPI can help with registering more "powerful" commands with the use of brigadier as well! Please bear with with it - these examples can be long, but I'm certain that they've been explained well and will be useful! |
| 55 | + |
| 56 | +::::tip Example - Adding a predicate to the 'execute' command |
| 57 | + |
| 58 | +Say we wanted to add a predicate to the `/execute` command. In this example, we'll create a predicate which handles random chances. To illustrate this, we want to be able to run commands such as: |
| 59 | + |
| 60 | +```mccmd |
| 61 | +/execute if randomchance 1 4 run say Hello! |
| 62 | +``` |
| 63 | + |
| 64 | +In this scenario, if we ran this command, we would expect "Hello!" to appear in the chat with a $\frac{1}{4}$ chance. In particular, this is what we're trying to achieve: |
| 65 | + |
| 66 | +- We want to create a predicate (true/false value) for the following syntax: |
| 67 | + |
| 68 | + ```mccmd |
| 69 | + randomchance <numerator> <denominator> |
| 70 | + ``` |
| 71 | + |
| 72 | +- We also want this predicate to come _after_ `execute if`: |
| 73 | + |
| 74 | +```mermaid |
| 75 | +graph TD |
| 76 | + A(execute) --> B(if) |
| 77 | + B --> C("randomchance <numerator> <denominator>") |
| 78 | +``` |
| 79 | + |
| 80 | +- After entering our predicate, we want to route back to `execute` (because the argument after `execute` is `run`, which is used in our example command above): |
| 81 | + |
| 82 | +```mermaid |
| 83 | +graph TD |
| 84 | + A(execute) --> B(if) |
| 85 | + B --> C("randomchance <numerator> <denominator>") |
| 86 | + C --> D(execute) |
| 87 | +``` |
| 88 | + |
| 89 | +#### Writing the code |
| 90 | + |
| 91 | +Now that we've established what we want, we can finally begin writing the code! First we want to create a literal `randomchance`. It's a literal because literal values don't change (similar to say `run` or `if` from the `/execute` command). To create a literal, we'll use the `fromLiteralArgument` method described above, and then build it using the `.build()` method: |
| 92 | + |
| 93 | +:::tabs |
| 94 | +===Java |
| 95 | +<<< @/../reference-code/src/main/java/internal/BrigadierPlusCommandAPI.java#addPredicateExampleStep1 |
| 96 | +===Kotlin |
| 97 | +<<< @/../reference-code/src/main/kotlin/internal/BrigadierPlusCommandAPI.kt#addPredicateExampleStep1 |
| 98 | +::: |
| 99 | + |
| 100 | +With that completed, we can now create our "argument" to this predicate. To do this, we'll use the regular declaration of arguments that we would normally use for commands. In this example, because we're computing $\frac{numerator}{denominator}$, we want our numerator to be 0 or greater and our denominator to be 1 or greater (we don't want any negative numbers or division by zero!): |
| 101 | + |
| 102 | +:::tabs |
| 103 | +===Java |
| 104 | +<<< @/../reference-code/src/main/java/internal/BrigadierPlusCommandAPI.java#addPredicateExampleStep2 |
| 105 | +===Kotlin |
| 106 | +<<< @/../reference-code/src/main/kotlin/internal/BrigadierPlusCommandAPI.kt#addPredicateExampleStep2 |
| 107 | +::: |
| 108 | + |
| 109 | +Now we're going to get into the very nitty-gritty part - the predicate declaration. First, we'll create some variables `numerator` and `denominator` to represent the brigadier instances of these arguments. This can be handled by using the `Brigadier.argBuildOf` function: |
| 110 | + |
| 111 | +:::tabs |
| 112 | +===Java |
| 113 | +<<< @/../reference-code/src/main/java/internal/BrigadierPlusCommandAPI.java#addPredicateExampleStep3 |
| 114 | +===Kotlin |
| 115 | +<<< @/../reference-code/src/main/kotlin/internal/BrigadierPlusCommandAPI.kt#addPredicateExampleStep3 |
| 116 | +::: |
| 117 | + |
| 118 | +Now we'll define our predicate. Since this is sort of a "meta-command" (it directly affects the outcome of the `run` command), we need to use the `ArgumentBuilder`'s `fork` method. Remember that after we run this predicate, we want to link back to `execute` again, so our first argument is the `CommandNode` for `execute`, which we can get using `Brigadier.getRootNode().getChild("execute")`. Then, we can simply use `Brigadier.fromPredicate` to finish our declaration: |
| 119 | + |
| 120 | +:::tabs |
| 121 | +===Java |
| 122 | +<<< @/../reference-code/src/main/java/internal/BrigadierPlusCommandAPI.java#addPredicateExampleStep4 |
| 123 | +===Kotlin |
| 124 | +<<< @/../reference-code/src/main/kotlin/internal/BrigadierPlusCommandAPI.kt#addPredicateExampleStep4 |
| 125 | +::: |
| 126 | + |
| 127 | +Finally, we can now link everything up. We know that `numerator` comes first, **then** `denominator`, so we have to have `numerator.then(denominator)`. We also know that these arguments are the **children** of the `randomChance` literal, so we use the following code to state all of this: |
| 128 | + |
| 129 | +:::tabs |
| 130 | +===Java |
| 131 | +<<< @/../reference-code/src/main/java/internal/BrigadierPlusCommandAPI.java#addPredicateExampleStep5 |
| 132 | +===Kotlin |
| 133 | +<<< @/../reference-code/src/main/kotlin/internal/BrigadierPlusCommandAPI.kt#addPredicateExampleStep5 |
| 134 | +::: |
| 135 | + |
| 136 | +Finally, we "register" the command. In this case, we're actually just adding the `randomChance` node under `execute → if`, which we can add using the following code: |
| 137 | + |
| 138 | +:::tabs |
| 139 | +===Java |
| 140 | +<<< @/../reference-code/src/main/java/internal/BrigadierPlusCommandAPI.java#addPredicateExampleStep6 |
| 141 | +===Kotlin |
| 142 | +<<< @/../reference-code/src/main/kotlin/internal/BrigadierPlusCommandAPI.kt#addPredicateExampleStep6 |
| 143 | +::: |
| 144 | + |
| 145 | +#### Code summary |
| 146 | + |
| 147 | +So, hopefully that wasn't too confusing! If you're still lost, here's the whole code that we wrote: |
| 148 | + |
| 149 | +:::tabs |
| 150 | +===Java |
| 151 | +<<< @/../reference-code/src/main/java/internal/BrigadierPlusCommandAPI.java#addPredicateExample |
| 152 | +===Kotlin |
| 153 | +<<< @/../reference-code/src/main/kotlin/internal/BrigadierPlusCommandAPI.kt#addPredicateExample |
| 154 | +::: |
| 155 | + |
| 156 | +:::: |
0 commit comments