🇬🇧 English
🇬🇧 English
Appearance
🇬🇧 English
🇬🇧 English
Appearance
This page is written for:
1.20.4
This page is written for:
1.20.4
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.
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
dispatcher.register(CommandManager.literal("argtater1")
.then(CommandManager.argument("value", IntegerArgumentType.integer())
.executes(context -> {
int value = IntegerArgumentType.getInteger(context, "value");
context.getSource()
.sendFeedback(
() -> Text.literal(
"Called /argtater1 with value = %s".formatted(value)),
false);
return 1;
})));
});
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:
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
dispatcher.register(CommandManager.literal("argtater2")
.then(CommandManager.argument("value1", IntegerArgumentType.integer())
.executes(context -> {
int value1 = IntegerArgumentType.getInteger(context, "value1");
context.getSource()
.sendFeedback(
() -> Text.literal(
"Called /argtater2 with value 1 = %s".formatted(value1)),
false);
return 1;
})
.then(CommandManager.argument("value2", IntegerArgumentType.integer())
.executes(context -> {
int value1 = IntegerArgumentType.getInteger(context, "value1");
int value2 = IntegerArgumentType.getInteger(context, "value2");
context.getSource()
.sendFeedback(
() -> Text.literal(
"Called /argtater2 with value 1 = %s and value 2 = %s"
.formatted(value1, value2)),
false);
return 1;
}))));
});
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.
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
dispatcher.register(CommandManager.literal("argtater3")
.then(CommandManager.argument("value1", IntegerArgumentType.integer())
.executes(context ->
printValues(IntegerArgumentType.getInteger(context, "value1"), 0, context))
.then(CommandManager.argument("value2", IntegerArgumentType.integer())
.executes(context -> printValues(
IntegerArgumentType.getInteger(context, "value1"),
IntegerArgumentType.getInteger(context, "value2"),
context)))));
});
private static int printValues(int value1, int value2, CommandContext<ServerCommandSource> context) {
context.getSource()
.sendFeedback(
() -> Text.literal(
"Called /argtater3 with value 1 = %s and value 2 = %s".formatted(value1, value2)),
false);
return 1;
}
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}
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}");
}
}
}
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:
ArgumentTypeRegistry.registerArgumentType(
new Identifier("fabric-docs", "block_pos"),
BlockPosArgumentType.class,
ConstantArgumentSerializer.of(BlockPosArgumentType::new)
);
We can use our custom argument type in a command - by passing an instance of it into the .argument
method on the command builder.
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
dispatcher.register(CommandManager.literal("parse_pos").then(
CommandManager.argument("pos", new BlockPosArgumentType())
.executes(context -> {
BlockPos arg = context.getArgument("pos", BlockPos.class);
context.getSource().sendFeedback(
() -> Text.literal("Called /parse_pos with BlockPos: ")
.append(Text.of(arg.toString())),
false);
return 1;
})
));
});
Running the command, we can test whether or not the argument type works: