Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/advanced/_category_.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"label": "Advanced Topics",
"position": 13
"label": "Advanced Topics",
"position": 14
}
4 changes: 4 additions & 0 deletions docs/commands/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "Commands",
"position": 13
}
Comment thread
MagnusHJensen marked this conversation as resolved.
188 changes: 188 additions & 0 deletions docs/commands/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# Commands

Commands are text-based actions triggered from chat by prefixing a message with a slash (`/`), from the server console, from command blocks, or from [functions]. A command performs some effect in the game, such as modifying the world, querying state, or exposing debug utilities. A mod can define its own commands to run dynamic actions when invoked.

Command definitions are hierarchical. Minecraft builds commands on Mojang's [Brigadier] library, which models each command as a tree of nodes rooted at a dispatcher. A **literal** node matches a fixed keyword, such as `mymod` or `reload` in `/mymod reload`; an **argument** node matches a typed, named input, such as a number or an entity selector. Nodes are joined through `#then` and made executable through `#executes`, and a node may hold execution logic, child nodes, or both. This nesting produces the tree of subcommands.

An argument is used in two places. It is **declared** while building the tree, by supplying a name and an `ArgumentType`, and its parsed value is **accessed** inside the execution logic from the `CommandContext`, using that same name. The name is the contract between the two. The sections below cover each half in turn.

## Registering Commands

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if there should be a minor note here for registering a command that's only available on the client. The process is exactly the same via RegisterClientCommandsEvent.


A command tree is passed to `CommandDispatcher#register` during the [`RegisterCommandsEvent`][event] like so:

```java
@SubscribeEvent // on the game event bus
public static void registerCommands(RegisterCommandsEvent event) {
event.getDispatcher().register(
Commands.literal("mymod")
.then(Commands.literal("reload")
.executes(context -> {
// Perform the command logic here
return Command.SINGLE_SUCCESS;
})
.then(Commands.literal("force")
.executes(context -> {
// Perform the command logic here
return Command.SINGLE_SUCCESS;
})
)
)
);
}
```

`Commands#literal` starts a literal builder, `#then` attaches a child node, and `#executes` supplies a `Command` callback whose returned `int` is the result count reported back to the caller. The example above registers `/mymod reload` and `/mymod reload force`.

:::note
For more advanced command trees that require registry access, `RegisterCommandsEvent#getBuildContext` provides a `CommandBuildContext` that can be passed to argument types that require it.
:::

## Arguments

An argument node is added with `Commands#argument`, supplying the argument name and an `ArgumentType`. The parsed value is read back inside `#executes` through the static getter that pairs with the chosen type, keyed by the same name.

```java
Commands.literal("give")
.then(Commands.argument("count", IntegerArgumentType.integer(1))
.executes(context -> {
// Access the value declared above as "count"
int count = IntegerArgumentType.getInteger(context, "count");
// Use count
return count;
}))
```

Every `ArgumentType` provides a builder used when declaring the argument and most often a static getter used when accessing the parsed value. The getter throws if the supplied name does not match a declared argument on the current path, which is why the declaration name and the access name must agree.

:::note
If an `ArgumentType` does not provide a static getter, the parsed value can be accessed through `CommandContext#getArgument` with the argument name and the expected class.
:::

An argument is not made optional through a flag. Instead, `#executes` is attached at more than one depth of the tree: once on the parent node for the case where the argument is absent, and again on the argument node for the case where it is provided.

## Argument Types

The following tables list common argument types. Each row pairs the builder used to declare the argument with the static getter used to access the parsed value.

### Brigadier

Brigadier provides the primitive types, found in `com.mojang.brigadier.arguments`.

| Argument Type | Declares (builder) | Accesses (getter) | Description |
| --------------------- | -------------------------------------- | ----------------- | ------------------------------------ |
| `BoolArgumentType` | `#bool` | `#getBool` | A boolean. |
| `IntegerArgumentType` | `#integer` (optional min and max) | `#getInteger` | A 32-bit integer. |
| `LongArgumentType` | `#longArg` (optional min and max) | `#getLong` | A 64-bit integer. |
| `FloatArgumentType` | `#floatArg` (optional min and max) | `#getFloat` | A single-precision decimal. |
| `DoubleArgumentType` | `#doubleArg` (optional min and max) | `#getDouble` | A double-precision decimal. |
| `StringArgumentType` | `#word`, `#string`, or `#greedyString` | `#getString` | A piece of text, see the note below. |

:::note
The three `StringArgumentType` builders differ in how much text they consume. `#word` reads a single unquoted word, ending at the first space. `#string` reads a single word as well, unless the input is wrapped in double quotes (`"hello world"`), in which case the whole quoted text is read. `#greedyString` reads everything after the argument, spaces included, and therefore cannot be followed by further nodes.
:::

### Built-in Minecraft

Minecraft adds game-specific argument types, found in `net.minecraft.commands.arguments`. This is not an exhaustive list.

| Argument Type | Declares (builder) | Accesses (getter) | Description |
| --------------------- | --------------------------------------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `EntityArgument` | `#entity`, `#entities`, `#player`, `#players` | `#getEntity`, `#getEntities`, `#getOptionalEntities`, `#getPlayer`, `#getPlayers`, `#getOptionalPlayers` | One or multiple entities or players, selected by name, UUID, or a selector such as `@p` or `@e`. |
| `BlockPosArgument` | `#blockPos` | `#getLoadedBlockPos`, `#getBlockPos` | A block position. |
| `Vec3Argument` | `#vec3` | `#getVec3` | A position in the world. |
| `ItemArgument` | `#item` | `#getItem` | An item stack, including data components. |
| `BlockStateArgument` | `#block` | `#getBlock` | A block state, including block entity data. |
| `ResourceArgument` | `#resource` | `#getResource` | An [`Identifier`][identifier] pointing to an entry of a given registry. |
| `ResourceKeyArgument` | `#key` | `#getRegistryKey` | A [`ResourceKey`][resourcekey] for a given registry. |

### NeoForge

NeoForge adds additional argument types in `net.neoforged.neoforge.server.command`.

| Argument Type | Declares (builder) | Accesses (getter) | Description |
| --------------- | ------------------ | ------------------------------------------------------------------- | -------------- |
| `EnumArgument` | `#enumArgument` | `CommandContext#getArgument` with the keyed name and the enum class | An enum value. |
| `ModIdArgument` | `#modIdArgument` | `CommandContext#getArgument` with the keyed name and `String.class` | A mod ID. |

## Custom Argument Types

A value that none of the existing types can parse is handled by implementing a custom argument type via. `ArgumentType<T>`, which reads the raw command text from a `StringReader` and returns a value of type `T`.
Comment thread
MagnusHJensen marked this conversation as resolved.

```java
public class SpellArgument implements ArgumentType<Spell> {
Comment thread
MagnusHJensen marked this conversation as resolved.
private static final DynamicCommandExceptionType ERROR_UNKNOWN_SPELL = new DynamicCommandExceptionType(
name -> Component.translatableEscape("commands.examplemod.spell.unknown", name)
);

// Follows the naming scheme of the vanilla argument types, used when declaring the argument
public static SpellArgument spell() {
return new SpellArgument();
}

// Consumes as much of the input as the argument needs
@Override
public Spell parse(StringReader reader) throws CommandSyntaxException {
String name = reader.readUnquotedString();
// Look up the spell, throwing ERROR_UNKNOWN_SPELL#createWithContext if there is none
Comment thread
MagnusHJensen marked this conversation as resolved.
}

// Optional, defaults to no suggestions: the completions offered while typing the argument
@Override
public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
// Suggest the names of the available spells or none
return Suggestions.empty();
Comment on lines +132 to +133

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should elaborated on as the suggestions are obtained based on the sided context, meaning that if you plan to use data on the server, it may not show up if queried in a client context unless synced and referenced.

}

// Optional, defaults to an empty list: example inputs used by Brigadier to detect
// ambiguities between sibling nodes
@Override
public Collection<String> getExamples() {
return List.of("fireball", "heal");
}
}
```

As no static getter exists for a new type, one is usually added next to the builder, so that the value can be accessed like that of a built-in type:

```java
public static Spell getSpell(CommandContext<CommandSourceStack> context, String name) {
return context.getArgument(name, Spell.class);
}
```

:::tip
If an existing argument type already parses the desired value and only the suggestions should differ, `#suggests` on the argument node replaces them without a custom type. Suggestions added this way are requested from the server as the player types.
:::

### Synchronization

The server sends its command tree to every client, allowing commands to be parsed and completed locally while being typed. Each argument node is described by an `ArgumentTypeInfo`, looked up from the `COMMAND_ARGUMENT_TYPE` registry by the class of the `ArgumentType`. The types listed in the argument types tables above already have one. A custom type without one cannot be sent to the client.

`ArgumentTypeInfos#registerByClass` associates the `ArgumentType` class with its info and returns the info, so it can be [registered][registration] in the same statement:

```java
public static final DeferredRegister<ArgumentTypeInfo<?, ?>> COMMAND_ARGUMENT_TYPES =
DeferredRegister.create(Registries.COMMAND_ARGUMENT_TYPE, ExampleMod.MOD_ID);

public static final DeferredHolder<ArgumentTypeInfo<?, ?>, SingletonArgumentInfo<SpellArgument>> SPELL = COMMAND_ARGUMENT_TYPES.register(
// The registry name of the argument type.
"spell",
() -> ArgumentTypeInfos.registerByClass(
// The class of the argument type.
SpellArgument.class,
// The info describing it. 'contextFree' is used for argument types
// constructed without parameters, 'contextAware' for those requiring
// a CommandBuildContext.
SingletonArgumentInfo.contextFree(SpellArgument::spell)
)
);
```

An argument type that holds parameters of its own, such as the bounds of `IntegerArgumentType`, needs those parameters on the client as well and therefore cannot use `SingletonArgumentInfo`. Instead, `ArgumentTypeInfo` is implemented directly, along with an `ArgumentTypeInfo.Template` holding the parameters: `#serializeToNetwork` and `#deserializeFromNetwork` transfer the template, `#serializeToJson` writes it into the JSON representation of the command tree, `#unpack` creates a template from an argument type, and `Template#instantiate` creates an argument type from a template. `EnumArgument.Info` is a small example of such an implementation.

[Brigadier]: https://github.com/Mojang/brigadier
[event]: ../concepts/events.md
[functions]: https://minecraft.wiki/w/Function_(Java_Edition)
[identifier]: ../misc/identifier.md
[registration]: ../concepts/registries.md#methods-for-registering
[resourcekey]: ../misc/identifier.md#resourcekeys
4 changes: 2 additions & 2 deletions docs/misc/_category_.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"label": "Miscellaneous",
"position": 14
"label": "Miscellaneous",
"position": 15
}
Loading