Skip to content

Subcommands and Advanced Arguments

Redempt edited this page Aug 18, 2022 · 2 revisions

Rarely are commands as simple as one base command with a handful of primitive-typed arguments. Thankfully, Ordinate supports much more than that. Subcommands are as simple as base commands - to define them, you just nest command bodies:

basecommand {
	help = Base command
	subcommand {
		help = Subcommand
	}
}

This defines two commands: basecommand and basecommand subcommand, each with their own help entries. Ordinate will automatically detect when a player has used a command wrong, and will show the help page as well as an error about what they did wrong.

But let's define some cooler commands than this. Going back to our add example before, we can enhance it with a new type of argument: The variable-length argument, or vararg. These arguments take a list of entries - any number of them - and pass them to your hook as an array. Using this, we can improve our add command to be able to add more than two numbers together:

add int[]:nums {
	help = Adds numbers together
	hook = add
}

With this defined, let's change our hook to support this:

@CommandHook("add")
public void add(CommandSender sender, int[] nums) {
	int sum = Arrays.stream(nums).sum();
	sender.sendMessage(String.valueOf(sum));
}

But there are a lot of other ways we can get fancy with our arguments. Another common use case is making them optional, which we can do quite easily too:

helloworld int:times? {
	help = Says hello world the given number of times, or once if times is not specified
	hook = helloworld
}

The value of this argument will be passed as null if the command is run as helloworld, so we'll need to account for that in our code by changing the type from int to Integer.

@CommandHook("helloworld")
public void helloWorld(CommandSender sender, Integer times) {
	if (times == null) {
		times = 1;
	}
	for (int i = 0; i < times; i++) {
		sender.sendMessage("Hello, world!");
	}
}

But this is a bit tedious, since if we had multiple optional parameters, we would need to add null checks for all of them. It's much more convenient if we can specify a default, which we can:

helloworld int:times?(1) {
	hook = helloworld
}

Now if the argument isn't passed, its default value will be 1 without us needing to do anything in our code. Since it's not nullable anymore, we can change the type back from Integer to int and remove the null check.

The last way we can change how an argument works is by making it consuming. Consuming arguments work somewhat like variable-length arguments, but rather than parsing each argument individually, and putting them in an array, it parses the entire argument as one value. This is rarely used for anything other than strings, but it's still quite useful for messaging commands:

echo string...:message {
	hook = echo
	help = Echoes a message back to you
}
@CommandHook("echo")
public void echo(CommandSender sender, String message) {
	sender.sendMessage(message);
}

Now, if this command is run as echo Hello world!, the entire string Hello world! will be passed as a single argument instead of being treated as two.

There are still more ways to use arguments. Next, learn about Custom Argument Types.

Clone this wiki locally