|
| 1 | +--- |
| 2 | +order: 15 |
| 3 | +authors: |
| 4 | + - DerEchtePilz |
| 5 | + - JorelAli |
| 6 | + - willkroboth |
| 7 | +--- |
| 8 | + |
| 9 | +# Command arguments |
| 10 | + |
| 11 | + |
| 12 | + |
| 13 | +Command arguments allows users to provide an executable server command. The `CommandArgument` class lets you specify: |
| 14 | + |
| 15 | +- Arbitrary commands - any command that the user has permissions to run can be provided. |
| 16 | +- Restricted commands - only specific commands can be provided. |
| 17 | + |
| 18 | +Using the `CommandArgument` will return a `CommandResult`, which contains a Bukkit `Command` instance representing the command to be executed, and a `String[]` of command arguments. |
| 19 | + |
| 20 | +## Command results |
| 21 | + |
| 22 | +The `CommandResult` record contains the following methods: |
| 23 | + |
| 24 | +```java |
| 25 | +public record CommandResult { |
| 26 | + Command command(); |
| 27 | + String[] args(); |
| 28 | + |
| 29 | + boolean execute(CommandSender target); |
| 30 | +} |
| 31 | +``` |
| 32 | + |
| 33 | +These methods can be used to retrieve information about the command that was provided by the user: |
| 34 | + |
| 35 | +```java |
| 36 | +Command command(); |
| 37 | +``` |
| 38 | + |
| 39 | +`command()` returns the Bukkit `Command` instance that the user provided. For example, if a player provided `/mycommand hello world`, then `command()` will represent the `/mycommand` command. |
| 40 | + |
| 41 | +```java |
| 42 | +String[] args(); |
| 43 | +``` |
| 44 | + |
| 45 | +`args()` returns an array of string argument inputs that were provided to the command. For example, if a player provided `/mycommand hello world`, then `args()` will be the following: |
| 46 | + |
| 47 | +```java |
| 48 | +[ "hello", "world" ] |
| 49 | +``` |
| 50 | + |
| 51 | +```java |
| 52 | +boolean execute(CommandSender target); |
| 53 | +``` |
| 54 | + |
| 55 | +`execute(CommandSender)` runs the Bukkit `Command` using the arguments contained in the `CommandResult` as the given `CommandSender`. It returns true if the command dispatch succeeded, and false if it failed. Using this method is equivalent to running the following: |
| 56 | + |
| 57 | +```java |
| 58 | +result.command().execute(target, result.command().getLabel(), result.args()); |
| 59 | +``` |
| 60 | + |
| 61 | +## Arbitrary commands |
| 62 | + |
| 63 | +Arbitrary commands let the user enter any command that they have permission to execute. To use arbitrary commands, you just need to use the `CommandArgument` normally. |
| 64 | + |
| 65 | +::::tip Example - A `/sudo` command |
| 66 | + |
| 67 | +We want to create a `/sudo` command which lets you execute a command as another online player. |
| 68 | + |
| 69 | + |
| 70 | + |
| 71 | +To do this, we want to use the following command syntax: |
| 72 | + |
| 73 | +```mccmd |
| 74 | +/sudo <target> <command> |
| 75 | +``` |
| 76 | + |
| 77 | +In this example, we want to be able to run any arbitrary command, so we will simply use the `CommandArgument` on its own (without using suggestions). Using the `CommandArgument` generates a `CommandResult` and we can use the `.command()` and `.args()` methods above to access the command and arguments. We can make use of the `Command.execute()` method to execute our command and use the target player as the command sender. |
| 78 | + |
| 79 | +:::tabs |
| 80 | +===Java |
| 81 | +<<< @/../reference-code/src/main/java/createcommands/arguments/types/CommandArguments.java#sudoCommandExample |
| 82 | +===Kotlin |
| 83 | +<<< @/../reference-code/src/main/kotlin/createcommands/arguments/types/CommandArguments.kt#sudoCommandExample |
| 84 | +===Kotlin DSL |
| 85 | +<<< @/../reference-code/src/main/kotlin/createcommands/arguments/types/CommandArguments.kt#sudoCommandExampleDSL |
| 86 | +::: |
| 87 | + |
| 88 | +:::: |
| 89 | + |
| 90 | +## Restricted commands |
| 91 | + |
| 92 | +Restricted commands allows you to restrict what commands a user is allowed to submit in the `CommandArgument`. Commands can be restricted by replacing the `CommandArgument`'s suggestions using the `replaceSuggestions()` method. For better fine-tuning of what commands a user can submit, commands can also be restricted by using _suggestion branches_. |
| 93 | + |
| 94 | +<!-- TODO: Give an example using .replaceSuggestions(). --> |
| 95 | + |
| 96 | +::::tip Example – Restricting commands using suggestion branches |
| 97 | + |
| 98 | +To demonstrate restricting commands, let's create a command argument that allows players to enter one of the following commands: |
| 99 | + |
| 100 | +```mccmd |
| 101 | +/tp <player> <target> |
| 102 | +/give <player> <item> <amount> |
| 103 | +``` |
| 104 | + |
| 105 | +Let's also add a restriction that the player can only use diamonds or dirt for the `/give` command, and they can only specify an amount if they selected dirt. Overall, our command argument should allow players to follow this path: |
| 106 | + |
| 107 | +$$\begin{gather} |
| 108 | +\texttt{(start)}\\\\ |
| 109 | +\swarrow\hspace{1.2cm}\searrow\\\\ |
| 110 | +\texttt{tp}\hspace{2cm}\texttt{give}\\\\ |
| 111 | +\swarrow\hspace{3cm}\searrow\\\\ |
| 112 | +\texttt{player}\hspace{3.25cm}\texttt{player}\\\\ |
| 113 | +\hspace{0.25cm}\swarrow\hspace{3.75cm}\swarrow\hspace{1cm}\searrow\\\\ |
| 114 | +\hspace{0.25cm}\texttt{target}\hspace{3cm}\texttt{diamond}\hspace{1.75cm}\texttt{dirt}\\\\ |
| 115 | +\hspace{4.9cm}\texttt{minecraft:diamond}\hspace{1.75cm}\texttt{minecraft:dirt}\\\\ |
| 116 | +\hspace{10cm}\downarrow\\\\ |
| 117 | +\hspace{10cm}\texttt{(amount)}\\\\ |
| 118 | +\end{gather}$$ |
| 119 | + |
| 120 | +In our diagram above, we have two main branches: `/tp` and `/give`. The `/tp` branch has `player` followed by `target`, and the `/give` branch has `player` and then that branches off into two new sections. |
| 121 | + |
| 122 | +We can implement our `/tp` branch using the `SuggestionsBranch.suggest()` method, then provide argument suggestions for our options. In this case, we have `tp` and then a list of online players. We include the list of online players twice, because we need suggestions for `<player>` as well as `<target>`: |
| 123 | + |
| 124 | +:::tabs |
| 125 | +===Java |
| 126 | +<<< @/../reference-code/src/main/java/createcommands/arguments/types/CommandArguments.java#suggestionBranchesStep1 |
| 127 | +===Kotlin |
| 128 | +<<< @/../reference-code/src/main/kotlin/createcommands/arguments/types/CommandArguments.kt#suggestionBranchesStep1 |
| 129 | +::: |
| 130 | + |
| 131 | +For the `/give` branch, we can use a similar thing, but we need to tell the CommandArgument that the `/give` command branches into "diamond" and "dirt" suggestions. We can do this by using the `.branch()` method to add a new nested list of suggestions: |
| 132 | + |
| 133 | +:::tabs |
| 134 | +===Java |
| 135 | +<<< @/../reference-code/src/main/java/createcommands/arguments/types/CommandArguments.java#suggestionBranchesStep2 |
| 136 | +===Kotlin |
| 137 | +<<< @/../reference-code/src/main/kotlin/createcommands/arguments/types/CommandArguments.kt#suggestionBranchesStep2 |
| 138 | +::: |
| 139 | + |
| 140 | +Adding everything together, we get this fully completed CommandArgument: |
| 141 | + |
| 142 | +:::tabs |
| 143 | +===Java |
| 144 | +<<< @/../reference-code/src/main/java/createcommands/arguments/types/CommandArguments.java#suggestionBranchesStep3 |
| 145 | +===Kotlin |
| 146 | +<<< @/../reference-code/src/main/kotlin/createcommands/arguments/types/CommandArguments.kt#suggestionBranchesStep3 |
| 147 | +::: |
| 148 | + |
| 149 | +:::: |
| 150 | + |
| 151 | +### Null and empty suggestions |
| 152 | + |
| 153 | +In the above example about restricted commands, we used `null` and `ArgumentSuggestions.empty()` in our `SuggestionsBranch.suggest()` method. These special suggestions have specific effects when used in suggestions for the `CommandArgument`. |
| 154 | + |
| 155 | +#### Null suggestions |
| 156 | + |
| 157 | +Null suggestions ensure that the suggestions at the current position will not be overridden. In the case of the `CommandArgument`, this means that the default command suggestions will be provided. For example, if we have the following `null` entry in our suggestions, users are allowed to enter a value if they choose to do so, meaning that the examples below are all valid: |
| 158 | + |
| 159 | +```java |
| 160 | +SuggestionsBranch.suggest( |
| 161 | + ArgumentSuggestions.strings("give"), |
| 162 | + null, |
| 163 | + ArgumentSuggestions.empty() |
| 164 | +) |
| 165 | +``` |
| 166 | + |
| 167 | +```mccmd |
| 168 | +/give dirt |
| 169 | +/give diamond |
| 170 | +/give apple |
| 171 | +``` |
| 172 | + |
| 173 | +Ending the command argument with nothing is also equivalent to using `null`, for example the following suggestion branch allows any of the following commands: |
| 174 | + |
| 175 | +```java |
| 176 | +SuggestionsBranch.suggest( |
| 177 | + ArgumentSuggestions.strings("give"), |
| 178 | + ArgumentSuggestions.strings("dirt", "minecraft:dirt") |
| 179 | +) |
| 180 | +``` |
| 181 | + |
| 182 | +```mccmd |
| 183 | +/give dirt |
| 184 | +/give dirt 10 |
| 185 | +/give dirt 10 name:Hello |
| 186 | +``` |
| 187 | + |
| 188 | +#### Empty suggestions |
| 189 | + |
| 190 | +Empty suggestions that are provided using `ArgumentSuggestions.empty()` tell the `CommandArgument` to stop accepting further suggestions. This "ends" the command. Using the following example, this allows the user to enter `/give diamond` and only `/give diamond` - users cannot enter any other commands. |
| 191 | + |
| 192 | +```java |
| 193 | +SuggestionsBranch.suggest( |
| 194 | + ArgumentSuggestions.strings("give"), |
| 195 | + ArgumentSuggestions.strings("diamond", "minecraft:diamond"), |
| 196 | + ArgumentSuggestions.empty() |
| 197 | +) |
| 198 | +``` |
| 199 | + |
| 200 | +These commands are valid: |
| 201 | + |
| 202 | +```mccmd |
| 203 | +/give diamond |
| 204 | +/give minecraft:diamond |
| 205 | +``` |
| 206 | + |
| 207 | +These commands are not valid: |
| 208 | + |
| 209 | +```mccmd |
| 210 | +/give |
| 211 | +/give diamond 10 |
| 212 | +``` |
0 commit comments