Skip to content

Argumentos de Comandos

Los argumentos son usados en la mayoría de los comandos. Algunas veces pueden ser opcionales, lo que significa que el usuario no tiene que dar un argumento para que el comando corra. Un nodo puede tener múltiples tipos de argumentos, pero ten cuidado de no crear ambigüedades.

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

En este caso, después del texto del comando /argtater, debes escribir un número entero. Por ejemplo, si corres /argtater 3, obtendrás el mensaje de respuesta Called /argtater with value = 3. Si escribes /argtater sin argumentos, el comando no puede ser leído y analizado correctamente.

Ahora añadimos un segundo argumento opcional:

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

Ahora puedes escribir uno o dós números enteros. Si le das un número entero, se mostrará un mensaje de respuesta con un solo valor. Si das dos números enteros, se mostrará un mensaje de respuesta con dos valores.

Puede que sientas que sea innecesario tener que especificar ejecuciones similares dos veces. Para ello, crearemos un método que se usará para ambas ejecuciones.

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

Tipos de Argumentos Personalizados

Si el juego vanilla no tiene el tipo de argumento que necesitas, puedes crear tu propio tipo de argumento. Para esto, puedes crear una clase que implemente la interfaz ArgumentType<T>, donde T es el tipo del argumento.

Necesitarás implementar el método parse, el cual leerá y analizará la cadena de caracteres entrada por el usuario a el tipo de argumento deseado.

Por ejemplo, puedes crear un tipo de argumento que lea un BlockPos a partir de una cadena de caracteres con el siguiente formato: {x, y, z}

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

Registrar Tipos de Argumentos Personalizados

WARNING

¡Necesitas registrar el tipo de comando personalizado tanto en el servidor como en el cliente, de lo contrario, el comando no funcionará!

Puedes registrar tu propio tipo de argumento personalizado en el método onInitialize del inicializador de tu mod usando la clase ArgumentTypeRegistry:

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

Usar Argumentos de Comandos Personalizados

Podemos usar nuestro tipo de argumento personalizado en un comando pasando una instancia de él al método .argument en el constructor del comando.

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

Al correr el comando, podemos verificar que el tipo de argumento funciona:

Argumento inválido.

Argumento válido.

Resultado del comando.