-
Notifications
You must be signed in to change notification settings - Fork 2
Arguments
This guide will show you how to use command arguments.
Let's create a ban command. For this command, we will need two arguments: the member to ban and the reason.
Colossus provides an argument system. In this case, we will use the MemberArgument
for the member and the EndlessStringArgument
for the reason.
The endless string will be a regular string argument for slash commands, but for message commands, it will get everything following the argument.
All arguments must have a name and description. We are also going to make the reason
argument have a maximum length of 500 characters,
and the argument will be optional, returning "No reason provided" if the user didn't provide anything.
@CommandBuilder(
name = "ban",
description = "Ban someone."
)
public class BanCommand extends BaseCommand implements CombinedCommand {
@Override
public ArgumentSet getArguments() {
return new ArgumentSet().addArguments(
new MemberArgument()
.name("member")
.description("The member to ban"),
new EndlessStringArgument()
.setMaximum(500) // maximum reason length
.name("reason")
.description("The reason")
.optional(event -> "No reason provided") // optional value
);
}
@Override
public void execute(CommandEvent event) throws CommandException {
// ...
}
}
The argument's values can be retrieved using the event.getArgument("name")
method.
If the user provides no reason, this method will return "No reason provided" as we defined earlier.
@Override
public void execute(CommandEvent event) throws CommandException {
Member member = event.getArgument("member"); // member argument
String reason = event.getArgument("reason"); // reason argument
event.getGuild().ban(member, 0, reason).queue(); // ban the member
}
You can create your own argument types by extending the Argument<T>
class, T
being the argument return type.
For message commands, arguments are given a Deque<String>
of the remaining parameters for the command (parameters split by " ").
For slash commands, arguments are given a Deque<OptionMapping>
of the remaining parameters.
Arguments must return CompleteableFuture<T>
by default.
There are other subclasses to extend from instead to make life easier:
SingleArgument
- argument only demanding one value from the argument queue in the parser, returningargs.pop()
FutureSingleArgument
- same asSingleArgument
, except for the return type being aCompleteableFuture<T>
NumberArgument
- extendsSingleArgument
- catchesNumberFormatException
s in resolvers, then sends an errorArgumentStringResolver
- extendsSingleArgument
- combines the message and slash command resolver for stringsFutureArgumentStringResolver
- extendsFutureSingleArgument
- same asArgumentStringResolver
, except for the return type being aCompleteableFuture<T>
Let's create an argument that returns the amount of +'s provided. For this we should extend ArgumentStringResolver<Integer>
.
Throwing an ArgumentException
in a resolver method will automatically make the bot send a detailed error message, along with the exception message.
public class PlusesArgument extends ArgumentStringResolver<Integer> {
@Override
public Integer resolve(String arg, CommandEvent event) throws ArgumentException {
if (!arg.contains("+")) { // if the argument contains characters other than '+', error
throw new MalformedArgumentException("Only expected pluses (+)");
}
if (arg.length() > 5) { // if the argument has more than 5 '+', error
throw new MalformedArgumentException("You cannot specify more than 5 pluses");
}
return arg.length(); // return the amount of '+'
}
}
Instead of this approach, we could also give the user some options, if they are using a slash command.
Because we want different behaviour for slash and message commands, we're going to use a SingleArgument<Integer>
.
You can add argument options by overriding the getArgumentOptionData()
method. With this method,
you can set various types of properties about a slash command option, such as its type, minimum value, etc.
Result:
public class PlusesArgument extends SingleArgument<Integer> {
@Override
public ArgumentOptionData getArgumentOptionData() {
return (ArgumentOptionData) new ArgumentOptionData(OptionType.INTEGER)
.addChoice("+", 1)
.addChoice("++", 2)
.addChoice("+++", 3)
.addChoice("++++", 4)
.addChoice("+++++", 5);
}
@Override
public Integer resolveSlashCommandArgument(OptionMapping arg, SlashCommandEvent event) throws ArgumentException {
return arg.getAsInt();
}
@Override
public Integer resolveMessageCommandArgument(String arg, MessageCommandEvent event) throws ArgumentException {
if (!arg.contains("+")) {
throw new MalformedArgumentException("Only expected pluses (+)");
}
if (arg.length() > 5) {
throw new MalformedArgumentException("You cannot specify more than 5 pluses");
}
return arg.length();
}
}
One final, more complicated approach we could take for a message command, is presenting the user with a menu with buttons to pick an amount of pluses.
For this, we need to use futures. We will extend Argument<Integer>
, and the slash command should keep the same behaviour.
public class PlusesArgument extends Argument<Integer> {
@Override
public ArgumentOptionData getArgumentOptionData() {
return (ArgumentOptionData) new ArgumentOptionData(OptionType.INTEGER)
.addChoice("+", 1)
.addChoice("++", 2)
.addChoice("+++", 3)
.addChoice("++++", 4)
.addChoice("+++++", 5);
}
@Override
public CompletableFuture<Integer> resolveSlashCommandArgument(Deque<OptionMapping> args, SlashCommandEvent event) throws ArgumentException {
CompletableFuture<Integer> future = new CompletableFuture<>();
future.complete(args.pop().getAsInt());
return future;
}
@Override
public CompletableFuture<Integer> resolveMessageCommandArgument(Deque<String> args, MessageCommandEvent event) throws ArgumentException {
// ...
}
}
We don't need a command input from the user beforehand, so we will not touch the args
queue.
Because there is no input, we should ignore an MissingArgumentException
by overriding the ignoreMissingException()
method.
We'll create a simple menu using PresetBuilder
.
In our button consumer, we'll complete the future and set the RepliableEvent
for the command event to our button click event: so we can reply to our command correctly.
Result:
@Override
public boolean ignoreMissingException() {
return true;
}
@Override
public CompletableFuture<Integer> resolveMessageCommandArgument(Deque<String> args, MessageCommandEvent event) throws ArgumentException {
CompletableFuture<Integer> future = new CompletableFuture<>();
long userId = event.getUser().getIdLong();
PresetBuilder message = new PresetBuilder("Pick an amount of pluses")
.addButtons(
// when a button is clicked, the future is completed
BaseButton.user(userId, Button.secondary("1", "+"), clickEvent -> {
event.setRepliableEvent(clickEvent); // important to set the RepliableEvent before the future is completed
future.complete(1); // complete the future + execute the command with this value
}),
BaseButton.user(userId, Button.secondary("2", "++"), clickEvent -> {
event.setRepliableEvent(clickEvent);
future.complete(2);
}),
BaseButton.user(userId, Button.secondary("3", "+++"), clickEvent -> {
event.setRepliableEvent(clickEvent);
future.complete(3);
}),
BaseButton.user(userId, Button.secondary("4", "++++"), clickEvent -> {
event.setRepliableEvent(clickEvent);
future.complete(4);
}),
BaseButton.user(userId, Button.secondary("5", "+++++"), clickEvent -> {
event.setRepliableEvent(clickEvent);
future.complete(5);
})
);
event.reply(message);
return future;
}
Below is a list of default argument types provided by Colossus
Name | Slash command type | Slash command description | Message command description | Extra parameters | Return type |
---|---|---|---|---|---|
Primitive arguments | |||||
BooleanArgument | Boolean | Returns true if 'true', otherwise returns false | Boolean | ||
IntegerArgument | Integer | Parses String as Integer | min, max | Integer | |
DoubleArgument | Number | Parses String as Double | min, max | Double | |
FloatArgument | Number | Casts Double to Float | Parses String as Float | min, max | Float |
LongArgument | Number | Parses String as Long | min, max | Long | |
String arguments | |||||
StringArgument | String | min, max | String | ||
QuoteStringArgument | String | Normal string | Returns all text until a closing " | min, max | String |
EndlessStringArgument | String | Returns all text in the following arguments | min, max | String | |
Snowflake arguments | |||||
UserArgument | User | Gets the user using a mention or ID | User | ||
MemberArgument | User | Throws an exception if the provided user is not a member of this server | Gets the member using a mention or ID | Member | |
RoleArgument | Role | Gets the role using a mention or ID | Role | ||
GuildChannelArgument | Channel | Throws an exception if the provided channel is not permitted | permittedChannelTypes | GuildChannel | |
GuildArgument | String | Gets the guild using an ID | Gets the guild using an ID | Guild | |
AttachmentArgument | Attachment | Gets the message attachment, multiple are supported | Attachment | ||
Command arguments | |||||
BasicCommandArgument | String | Same as message command, except has all command names as autocompleteable options | Gets a BasicCommand (regular or context) using its name, and if multiple results are found, show a menu with choices | BasicCommand | |
CommandArgument | String | Same as message command, except has all regular command names as autocompleteable options | Gets a regular Command using its name | Command | |
ContextCommandArgument | String | Same as message command, except has all context command names as autocompleteable options | Gets a ContextCommand (user or message) using its name, and if multiple results are found, show a menu with choices | ContextCommand<?> | |
UserContextCommandArgument | String | Same as message command, except has all user context command names as autocompleteable options | Gets a user ContextCommand using its name | ContextCommand<User> | |
MessageContextCommandArgument | String | Same as message command, except has all message context command names as autocompleteable options | Gets a message ContextCommand using its name | ContextCommand<Message> |