Skip to content

命令参数

大多数的命令都有参数。 有些时候他们是可选的,这意味着如果你不提供这些参数命令照样可以工作 一个节点可能有多个参数类型导致用户感到困惑,请注意避免这个问题。

java
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;
					})));
});

比如说,在命令文本/argtater之后,您应该输入一个整型数字。 比如说,在命令文本/argtater之后,您应该输入一个整型数字。 举个例子,如果您输入了/argtater 3,您应该会收到一条反馈消息:Called /argtater with value = 3。 如果您输入了 /argtataer 并且没有任何参数,那么这个命令将不会被正确解析。 如果您输入了 /argtataer 并且没有任何参数,那么这个命令将不会被正确解析。

接下来我们将添加第二个可选的参数:

java
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;
							}))));
});

现在您可以输入一个或者两个整型数字了。 如果您提供了一个整型数字,那么会打印单个值的反馈文本。 现在您可以输入一个或者两个整型数字了。 如果您提供了一个整型数字,那么会打印单个值的反馈文本。 如果您提供了两个整型数字,那么会打印有两个值的反馈文本。

您可能会发现没有必要指定两次相似的执行。 因此,我们可以创建一个方法,用于两次执行。 因此,我们可以创建一个方法,用于两次执行。

java
	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;
}

自定义参数类型

如果原版并没有提供您想要的命令参数类型,您可以创建您自己的类型。 为此,您需要创建一个继承ArgumentType < T > 接口的类,其中 T 是参数的类型。

您想要实现 parse 这个方法,这个方法会把输入的字符串解析为期望的类型。

举个例子,您可以创建一个可以把格式形如 {x, y, z} 的字符串解析为一个 BlockPos 参数类型。

java
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

您需要在服务端和客户端把您的自定义参数类型都注册一次,否则您的命令将不会工作!

您可以在您的模组的初始化方法 onInitialize 中使用 ArgumentTypeRegistry 类来注册:

java
ArgumentTypeRegistry.registerArgumentType(
		new Identifier("fabric-docs", "block_pos"),
		BlockPosArgumentType.class,
		ConstantArgumentSerializer.of(BlockPosArgumentType::new)
);

使用自定义参数类型

我们可以在命令中使用我们的自定义参数类型──通过传递实例到 .argument 方法到 command builder 中即可。

java
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;
					})
	));
});

运行命令,我们可以测试我们的参数类型是否可以正常工作:

Invalid argument.

Valid argument.

Command result.