-
Notifications
You must be signed in to change notification settings - Fork 100
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add main commands page * fix formatting using spotless * requested changes * Suggestions * Custom Argument Types * Refactor BlockPosArgumentType class to remove unnecessary print statements * Checkstyle fixes. * Checkstyle fixes. * Redirect commands. * fix checkstyle error --------- Co-authored-by: Calum <[email protected]>
- Loading branch information
1 parent
f962468
commit 6cd45d8
Showing
11 changed files
with
614 additions
and
2 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
--- | ||
title: Command Arguments | ||
description: Learn how to create commands with complex arguments. | ||
--- | ||
|
||
# Command Arguments | ||
|
||
Arguments are used in most of the commands. Sometimes they can be optional, which means if you do not provide that | ||
argument, | ||
the command will also run. One node may have multiple argument types, but be aware that there is a possibility of | ||
ambiguity, which should be avoided. | ||
|
||
@[code lang=java highlight={3} transcludeWith=:::4](@/reference/latest/src/main/java/com/example/docs/command/FabricDocsReferenceCommands.java) | ||
|
||
In this case, after the command text `/argtater`, you should type an integer. For example, if you | ||
run `/argtater 3`, you will get the feedback message `Called /argtater with value = 3`. If you | ||
type `/argtater` without arguments, the command cannot be correctly parsed. | ||
|
||
Then we add an optional second argument: | ||
|
||
@[code lang=java highlight={3,13} transcludeWith=:::5](@/reference/latest/src/main/java/com/example/docs/command/FabricDocsReferenceCommands.java) | ||
|
||
Now you can type one or two integers. If you give one integer, a feedback text with a single value is printed. If you | ||
provide two integers, a feedback text with two values will be printed. | ||
|
||
You may find it unnecessary to specify similar executions twice. Therefore, we can create a method that will be used in | ||
both executions. | ||
|
||
@[code lang=java highlight={3,5,6,7} transcludeWith=:::6](@/reference/latest/src/main/java/com/example/docs/command/FabricDocsReferenceCommands.java) | ||
|
||
## Custom Argument Types | ||
|
||
If vanilla does not have the argument type you need, you can create your own. To do this, you need to create a class that inherits the `ArgumentType<T>` interface where `T` is the type of the argument. | ||
|
||
You will need to implement the `parse` method, which will parse the input string into the desired type. | ||
|
||
For example, you can create an argument type that parses a `BlockPos` from a string with the following format: `{x, y, z}` | ||
|
||
@[code lang=java transcludeWith=:::1](@/reference/latest/src/main/java/com/example/docs/command/BlockPosArgumentType.java) | ||
|
||
### Registering Custom Argument Types | ||
|
||
::: warning | ||
You need to register the custom argument type on both the server and the client or else the command will not work! | ||
::: | ||
|
||
You can register your custom argument type in the `onInitialize` method of your mod initializer using the `ArgumentTypeRegistry` class: | ||
|
||
@[code lang=java transcludeWith=:::11](@/reference/latest/src/main/java/com/example/docs/command/FabricDocsReferenceCommands.java) | ||
|
||
### Using Custom Argument Types | ||
|
||
We can use our custom argument type in a command - by passing an instance of it into the `.argument` method on the command builder. | ||
|
||
@[code lang=java transcludeWith=:::10 highlight={3}](@/reference/latest/src/main/java/com/example/docs/command/FabricDocsReferenceCommands.java) | ||
|
||
Running the command, we can test whether or not the argument type works: | ||
|
||
![Invalid argument.](../../assets/develop/commands/custom-arguments_fail.png) | ||
|
||
![Valid argument.](../../assets/develop/commands/custom-arguments_valid.png) | ||
|
||
![Command result.](../../assets/develop/commands/custom-arguments_result.png) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
--- | ||
title: Creating Commands | ||
description: Create commands with complex arguments and actions. | ||
authors: | ||
- dicedpixels | ||
- i509VCB | ||
- pyrofab | ||
- natanfudge | ||
- Juuxel | ||
- solidblock | ||
- modmuss50 | ||
- technici4n | ||
- atakku | ||
- haykam | ||
- mschae23 | ||
- treeways | ||
--- | ||
|
||
# Creating Commands | ||
|
||
Creating commands can allow a mod developer to add functionality that can be used through a command. This tutorial will | ||
teach you how to register commands and the general command structure of Brigadier. | ||
|
||
::: info | ||
Brigadier is a command parser and dispatcher written by Mojang for Minecraft. It is a tree-based command library where | ||
you | ||
build a tree of commands and arguments. Brigadier is open source: https://github.com/Mojang/brigadier | ||
::: | ||
|
||
### The `Command` Interface | ||
|
||
`com.mojang.brigadier.Command` is a functional interface, which runs some specific code, and throws a | ||
`CommandSyntaxException` in certain cases. It has a generic type `S`, which defines the type of the _command source_. | ||
The command | ||
source provides some context in which a command was run. In Minecraft, the command source is typically a | ||
`ServerCommandSource` which can represent a server, a command block, a remote connection (RCON), a player or an entity. | ||
|
||
The single method in `Command`, `run(CommandContext<S>)` takes a `CommandContext<S>` as the sole parameter and returns | ||
an integer. The command context holds your command source of `S` and allows you to obtain arguments, look at the parsed | ||
command nodes and see the input used in this command. | ||
|
||
Like other functional interfaces, it is usually used as a lambda or a method reference: | ||
|
||
```java | ||
Command<ServerCommandSource> command = context -> { | ||
return 0; | ||
}; | ||
``` | ||
|
||
The integer can be considered the result of the command. Typically negative values mean a command has failed and will do | ||
nothing. A result of `0` means the command has passed. Positive values mean the command was successful and did | ||
something. Brigadier provides a constant to indicate success; `Command#SINGLE_SUCCESS`. | ||
|
||
#### What Can the `ServerCommandSource` Do? | ||
|
||
A `ServerCommandSource` provides some additional implementation-specific context when a command is run. This includes | ||
the | ||
ability to get the entity that executed the command, the world the command was run in or the server the command was run | ||
on. | ||
|
||
You can access the command source from a command context by calling `getSource()` on the `CommandContext` instance. | ||
|
||
```java | ||
Command<ServerCommandSource> command = context -> { | ||
ServerCommandSource source = context.getSource(); | ||
return 0; | ||
}; | ||
``` | ||
|
||
### Registering a Basic Command | ||
|
||
Commands are registered within the `CommandRegistrationCallback` provided by the Fabric API. | ||
|
||
::: info | ||
For information on registering callbacks, please see the [Events](../events.md) guide. | ||
::: | ||
|
||
The event should be registered in your mod's initializer. | ||
|
||
The callback has three parameters: | ||
|
||
* `CommandDispatcher<ServerCommandSource> dispatcher` - Used to register, parse and execute commands. `S` is the type | ||
of command source the command dispatcher supports. | ||
* `CommandRegistryAccess registryAccess` - Provides an abstraction to registries that may be passed to certain command | ||
argument methods | ||
* `CommandManager.RegistrationEnvironment environment` - Identifies the type of server the commands are being registered | ||
on. | ||
|
||
In the mod initializer, we just register a simple command: | ||
|
||
@[code lang=java transcludeWith=:::_1](@/reference/latest/src/main/java/com/example/docs/command/FabricDocsReferenceCommands.java) | ||
|
||
In the `sendFeedback()` method, the first parameter is the text to be sent, which is a `Supplier<Text>` to avoid | ||
instantiating Text objects when not needed. | ||
|
||
The second parameter determines whether to broadcast the feedback to other | ||
operators. Generally, if the command is to query something without actually affecting the world, such as query the | ||
current time or some player's score, it should be `false`. If the command does something, such as changing the | ||
time or modifying someone's score, it should be `true`. | ||
|
||
If the command fails, instead of calling `sendFeedback()`, you may directly throw any exception and the server or client | ||
will handle it appropriately. | ||
|
||
`CommandSyntaxException` is generally thrown to indicate syntax errors in commands or arguments. You can also implement | ||
your own exception. | ||
|
||
To execute this command, you must type `/foo`, which is case-sensitive. | ||
|
||
#### Registration Environment | ||
|
||
If desired, you can also make sure a command is only registered under some specific circumstances, for example, only in | ||
the dedicated environment: | ||
|
||
@[code lang=java highlight={2} transcludeWith=:::2](@/reference/latest/src/main/java/com/example/docs/command/FabricDocsReferenceCommands.java) | ||
|
||
#### Command Requirements | ||
|
||
Let's say you have a command that you only want operators to be able to execute. This is where the `requires()` method | ||
comes into play. The `requires()` method has one argument of a `Predicate<S>` which will supply a `ServerCommandSource` | ||
to test with and determine if the `CommandSource` can execute the command. | ||
|
||
@[code lang=java highlight={3} transcludeWith=:::3](@/reference/latest/src/main/java/com/example/docs/command/FabricDocsReferenceCommands.java) | ||
|
||
This command will only execute if the source of the command is a level 2 operator at a minimum, including command | ||
blocks. Otherwise, the command is not registered. | ||
|
||
This has the side effect of not showing this command in tab completion to anyone who is not a level 2 operator. This is | ||
also why you cannot tab-complete most commands when you do not enable cheats. | ||
|
||
#### Sub Commands | ||
|
||
To add a sub command, you register the first literal node of the command normally. To have a sub command, you have to append the next literal node to the existing node. | ||
|
||
@[code lang=java highlight={3} transcludeWith=:::7](@/reference/latest/src/main/java/com/example/docs/command/FabricDocsReferenceCommands.java) | ||
|
||
Similar to arguments, sub command nodes can also be set optional. In the following case, both `/subtater` | ||
and `/subtater subcommand` will be valid. | ||
|
||
@[code lang=java highlight={2,8} transcludeWith=:::8](@/reference/latest/src/main/java/com/example/docs/command/FabricDocsReferenceCommands.java) | ||
|
||
### Client Commands | ||
|
||
Fabric API has a `ClientCommandManager` in `net.fabricmc.fabric.api.client.command.v2` package that can be used to register client-side commands. The code should exist only in client-side code. | ||
|
||
@[code lang=java transcludeWith=:::1](@/reference/latest/src/client/java/com/example/docs/client/command/FabricDocsReferenceClientCommands.java) | ||
|
||
### Command Redirects | ||
|
||
Command redirects - also known as aliases - are a way to redirect the functionality of one command to another. This is useful for when you want to change the name of a command, but still want to support the old name. | ||
|
||
@[code lang=java transcludeWith=:::12](@/reference/latest/src/client/java/com/example/docs/client/command/FabricDocsReferenceClientCommands.java) | ||
|
||
### FAQ | ||
|
||
<br> | ||
|
||
###### Why does my code not compile? | ||
|
||
* Catch or throw a `CommandSyntaxException` - `CommandSyntaxException` is not a `RuntimeException`. If you throw it, | ||
where it is thrown should be in methods that throw `CommandSyntaxException` in method signatures, or be caught. | ||
Brigadier will handle the checked exceptions and forward the proper error message in the game for you. | ||
|
||
* Issues with generics - You may have an issue with generics once in a while. If you are registering server | ||
commands (which are most of the case), make sure you are using `CommandManager.literal` | ||
or `CommandManager.argument` instead of `LiteralArgumentBuilder.literal` or `RequiredArgumentBuilder.argument`. | ||
|
||
* Check `sendFeedback()` method - You may have forgotten to provide a boolean as the second argument. Also remember | ||
that, since Minecraft 1.20, the first parameter is `Supplier<Text>` instead of `Text`. | ||
|
||
* A Command should return an integer - When registering commands, the `executes()` method accepts a `Command` object, | ||
which is usually a lambda. The lambda should return an integer, instead of other types. | ||
|
||
###### Can I register commands in runtime? | ||
|
||
::: warning | ||
You can do this, but it is not recommended. You would get the `CommandManager` from the server and add anything commands | ||
you wish to its `CommandDispatcher`. | ||
|
||
After that, you need to send the command tree to every player again | ||
using `CommandManager.sendCommandTree(ServerPlayerEntity)`. | ||
|
||
This is required because the client locally caches the command tree it receives during login (or when operator packets | ||
are sent) for local completions-rich error messages. | ||
::: | ||
|
||
###### Can I unregister commands in runtime? | ||
|
||
::: warning | ||
You can also do this, however, it is much less stable than registering commands at runtime and could cause unwanted side | ||
effects. | ||
|
||
To keep things simple, you need to use reflection on Brigadier and remove nodes. After this, you need to send the | ||
command tree to every player again using `sendCommandTree(ServerPlayerEntity)`. | ||
|
||
If you don't send the updated command tree, the client may think a command still exists, even though the server will | ||
fail execution. | ||
::: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
--- | ||
title: Command Suggestions | ||
description: Learn how to suggest command argument values to users. | ||
authors: | ||
- IMB11 | ||
--- | ||
|
||
# Command Suggestions | ||
|
||
Minecraft has a powerful command suggestion system that's used in many places, such as the `/give` command. This system allows you to suggest values for command arguments to the user, which they can then select from - it's a great way to make your commands more user-friendly and ergonomic. | ||
|
||
## Suggestion Providers | ||
|
||
A `SuggestionProvider` is used to make a list of suggestions that will be sent to the client. A suggestion provider is a functional interface that takes a `CommandContext` and a `SuggestionBuilder` and returns some `Suggestions`. The `SuggestionProvider` returns a `CompletableFuture` as the suggestions may not be available immediately. | ||
|
||
## Using Suggestion Providers | ||
|
||
To use a suggestion provider, you need to call the `suggests` method on the argument builder. This method takes a `SuggestionProvider` and returns a new argument builder with the suggestion provider attached. | ||
|
||
@[code java transcludeWith=:::9 highlight={4}](@/reference/latest/src/main/java/com/example/docs/command/FabricDocsReferenceCommands.java) | ||
|
||
## Built-in Suggestion Providers | ||
|
||
There are a few built-in suggestion providers that you can use: | ||
|
||
| Suggestion Provider | Description | | ||
| ----------------------------------------- | -------------------------------------------- | | ||
| `SuggestionProviders.SUMMONABLE_ENTITIES` | Suggests all entities that can be summoned. | | ||
| `SuggestionProviders.AVAILABLE_SOUNDS` | Suggests all sounds that can be played. | | ||
| `LootCommand.SUGGESTION_PROVIDER` | Suggests all loot tables that are available. | | ||
| `SuggestionProviders.ALL_BIOMES` | Suggests all biomes that are available. | | ||
|
||
## Creating a Custom Suggestion Provider | ||
|
||
If a built-in provider doesn't satisfy your needs, you can create your own suggestion provider. To do this, you need to create a class that implements the `SuggestionProvider` interface and override the `getSuggestions` method. | ||
|
||
For this example, we'll make a suggestion provider that suggests all the player usernames on the server. | ||
|
||
@[code java transcludeWith=:::1](@/reference/latest/src/main/java/com/example/docs/command/PlayerSuggestionProvider.java) | ||
|
||
To use this suggestion provider, you would simply pass an instance of it into the `.suggests` method on the argument builder. | ||
|
||
Obviously, suggestion providers can be more complex, since they can also read the command context to provide suggestions based on the command's state - such as the arguments that have already been provided. | ||
|
||
This could be in the form of reading the player's inventory and suggesting items, or entities that are nearby the player. | ||
|
22 changes: 22 additions & 0 deletions
22
...st/src/client/java/com/example/docs/client/command/FabricDocsReferenceClientCommands.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.example.docs.client.command; | ||
|
||
import net.minecraft.text.Text; | ||
|
||
import net.fabricmc.api.ClientModInitializer; | ||
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; | ||
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; | ||
|
||
// Class to contain all mod client command registrations. | ||
public class FabricDocsReferenceClientCommands implements ClientModInitializer { | ||
@Override | ||
public void onInitializeClient() { | ||
// :::1 | ||
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> { | ||
dispatcher.register(ClientCommandManager.literal("clienttater").executes(context -> { | ||
context.getSource().sendFeedback(Text.literal("Called /clienttater with no arguments.")); | ||
return 1; | ||
})); | ||
}); | ||
// :::1 | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
reference/latest/src/main/java/com/example/docs/command/BlockPosArgumentType.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package com.example.docs.command; | ||
|
||
import com.mojang.brigadier.StringReader; | ||
import com.mojang.brigadier.arguments.ArgumentType; | ||
import com.mojang.brigadier.exceptions.CommandSyntaxException; | ||
|
||
import net.minecraft.util.math.BlockPos; | ||
|
||
// :::1 | ||
public class BlockPosArgumentType implements ArgumentType<BlockPos> { | ||
/** | ||
* Parse the BlockPos from the reader in the {x, y, z} format. | ||
*/ | ||
@Override | ||
public BlockPos parse(StringReader reader) throws CommandSyntaxException { | ||
try { | ||
// This requires the argument to be surrounded by quotation marks. | ||
// eg: "{1, 2, 3}" | ||
String string = reader.readString(); | ||
|
||
// Remove the { and } from the string using regex. | ||
string = string.replace("{", "").replace("}", ""); | ||
|
||
// Split the string into the x, y, and z values. | ||
String[] split = string.split(","); | ||
|
||
// Parse the x, y, and z values from the split string. | ||
int x = Integer.parseInt(split[0].trim()); | ||
int y = Integer.parseInt(split[1].trim()); | ||
int z = Integer.parseInt(split[2].trim()); | ||
|
||
// Return the BlockPos. | ||
return new BlockPos(x, y, z); | ||
} catch (Exception e) { | ||
// Throw an exception if anything fails inside the try block. | ||
throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherParseException().create("Invalid BlockPos format. Expected {x, y, z}"); | ||
} | ||
} | ||
} | ||
// :::1 |
Oops, something went wrong.