CommandTypes is an unrequired argument, defaults to CommandTypes.commandMap(). For more information about it, take a look at the source code of the .
Command Information:
There are 2 ways to do this, via a Consumer<CommandInfo> or just access the methods in Commands. I will use the consumer as it's a bit nicer to read.
Commands.command("broadcast", CommandTypes.commandMap())
.info(info -> {
info.usage("Usage: /broadcast <text>");
info.aliases("bc", "bcmsg");
info.description(
"Allows the player or server to broadcast a message"
);
info.permission("admin.broadcast");
info.namespace("exampleplugin");
info.permissionMessage(
TextStyle.style("Insufficient permissions.")
);
})
// ...
None of those methods are required, you can ignore everything (including namespace, it's there if you want to register the command under a custom namespace, which isn't entirely recommended)
usage(String) - The String is shown whenever you return false while executing the command. It will send the usage message. This should be sent whenever you want to tell the player that they used the command incorrectly.
aliases(String... | List<String>) - If you execute an alias from the aliases it will redirect to the command you created (in this case it will redirect to /broadcast)
description(String) - Shown when executing /help <command> as information regarding what this command does.
permission(String | String, String) - The permission required to execute the command. If you're using permission(String prefix, String prefix) and you want admin.broadcast as the permission, do permission("admin", "broadcast")
namespace(String) - You can set this to literally anything. If you want to register your command under the namespace of minecraft, do namespace("minecraft")
permissionMessage(Component) - The Component to be sent to the player/sender when they do not meet the permission requirement for the command.
All of these methods exist outside of CommandInfo, specifically in Commands. (Commands.methodName(params...))
Command Arguments
Commands.command("broadcast", CommandTypes.commandMap())
.info(info -> {
info.usage("Usage: /broadcast <text>");
info.aliases("bc", "bcmsg");
info.description(
"Allows the player or server to broadcast a message"
);
info.permission("admin.broadcast");
info.namespace("exampleplugin");
info.permissionMessage(
TextStyle.style("Insufficient permissions.")
);
})
.argument(Argument.of("<text>")
.suggestions(ctx -> List.of())
.onError((ctx, errType) -> true))
.type(ComponentListArgument.arg())
.defaultVal("N/A"))
// ...
Argument.of(String <== [THIS IN PARTICULAR]) - The parameter is what identifier your argument will use. This should be unique, and no other argument should have the same identifier as this.
suggestions(SuggestionDispatcher) - WARNING: This shouldn't be used for any list arguments. Defines what is supposed to be shown as in tab completions/suggestions for the argument's index.
onError(BiFunction<CommandContext, ArgumentExType, Boolean>) - Allows you to interrupt/cancel ArgumentParseExceptions to run your own action. Return true or false to stop execution of the command.
type(T) - The type of the argument.
defaultVal(String) - The default value to be used whenever the argument is not provided in the user's inputs.
public class PlaceholderArgument implements CustomArgument<String> {
/**
* {@inheritDoc}
*/
@Override
public @Nullable String parse(
@NotNull CommandContext ctx, @Nullable String arg
) throws ArgumentParseException {
ObjectUtils.nonNull(arg, () -> new ArgumentParseException(
"CustomArgument cannot be null", ArgumentExType.ARG_IS_NULL
));
return PlaceholderAPI.setPlaceholders(ctx.player(), arg);
}
}
PlaceholderListArgument Example
public class PlaceholderListArgument extends CustomListArgument<String> {
@Override
public @Nullable String parse(
@Nullable List<String> args
) throws ArgumentParseException {
if (args == null || args.isEmpty()) {
throw new ArgumentParseException(
"CustomArgument list cannot be null or empty",
ArgumentExType.ARG_IS_NULL
);
}
return StringListArgument.arg().parse(args);
}
@Override
public @Nullable String parse(
@NotNull CommandContext ctx, int indexStart
) throws ArgumentParseException {
List<String> rawArgs = ctx.rawArgs();
if (indexStart < 0 || indexStart >= rawArgs.size()) {
throw new ArgumentParseException(
"Invalid indexStart value",
ArgumentExType.INVALID_SYNTAX
);
}
return PlaceholderAPI.setPlaceholders(
ctx.player(),
StringListArgument.arg().parse(rawArgs)
);
}
}
Requirements
Premade requirements can be found in the Requirements class.
When adding a requirement using requirement(Predicate) you should return:
true if you want to stop execution of the command,
false if you want to continue execution of the command
We don't need any requirements for the broadcast command in this case, since the argument has a default value, and we're allowing console to use our command.
But let's say we hypothetically wanted to not allow console.
Here's how you could do it:
Require sender to be a player and not console
// ...
.requirement(ctx -> {
// Returns true if the sender is a player
// Returns false if the sender is the console
if (!ctx.senderInstanceOfPlayer()) {
ctx.sender().sendMessage(
TextStyle.style("<red>Only players can execute this command!")
);
// Stops execution of the command here
return true;
}
// Continues the execution, as it is normally.
return false;
})
// ...
or alternatively:
.requirement(Requirements.playerOnly(
emptyParams | Component | Consumer<CommandContext> | Runnable
)
Executor (Dispatcher)
All Command Results:
SUCCESS, FAILURE
SUCCESS is the alternative to true. It will stop the execution of the command.
FAILURE is the alternative to false. It will stop the execution of the command and then print the usage message.
You can either use a lambda or create a new class that implements CommandDispatcher for this.
In this case we're gonna use a Lambda.
Commands.command("broadcast", CommandTypes.commandMap())
.info(info -> {
info.usage("Usage: /broadcast <text>");
info.aliases("bc", "bcmsg");
info.description(
"Allows the player or server to broadcast a message"
);
info.permission("admin.broadcast");
info.namespace("exampleplugin");
info.permissionMessage(
TextStyle.style("Insufficient permissions.")
);
})
.argument(Argument.of("<text>")
.suggestions(ctx -> List.of())
.onError((ctx, errType) -> true)
.type(ComponentListArgument.arg())
.defaultVal("N/A"))
.executes(ctx -> {
Component textArg = ctx.argAt("<text>", Component.class);
Bukkit.broadcast(TextStyle.style(""));
Bukkit.broadcast(TextStyle.style("BROADCAST"));
Bukkit.broadcast(textArg);
Bukkit.broadcast(TextStyle.style(""));
return CommandResult.success();
})
// ...
Suggester/Completer
Once again, you can either use a Lambda or a class that implements SuggestionDispatcher for this.
Let's use a lambda here.
Commands.command("broadcast", CommandTypes.commandMap())
.info(info -> {
info.usage("Usage: /broadcast <text>");
info.aliases("bc", "bcmsg");
info.description(
"Allows the player or server to broadcast a message"
);
info.permission("admin.broadcast");
info.namespace("exampleplugin");
info.permissionMessage(
TextStyle.style("Insufficient permissions.")
);
})
.argument(Argument.of("<text>")
.suggestions(ctx -> List.of())
.onError((ctx, errType) -> true)
.type(ComponentListArgument.arg())
.defaultVal("N/A"))
.executes(ctx -> {
// Please inform me if this throws any exceptions.
// I haven't actually checked if this worked, so consider
// doing `Component textArg = (Component) ctx.argAt("<text>");`
// instead.
Component textArg = ctx.argAt("<text>", Component.class);
Bukkit.broadcast(TextStyle.style(""));
Bukkit.broadcast(TextStyle.style("BROADCAST"));
Bukkit.broadcast(textArg);
Bukkit.broadcast(TextStyle.style(""));
return true;
})
.completes(ctx -> {
if (ctx.size() >= 1) {
return Suggestions.of(Suggestion.text("<text>"));
}
// or return null;
return Suggestions.empty();
})
// ...
Registration
Finally, you can register the command.
After you've made every change you need to your command, you call:
.build()
.register();
You can skip build() if you'd like to.
You can also provide a JavaPlugin instance to the register() method if you want to, but it's really unnecessary.
As of 31/12/2023 there is now a Commodore/Brigadier option if you'd like to enable it, however it's currently experimental and may not work.