Commands¶
Module commands should extend MCommand<YourModule>. Register them with
addCommand from onEnable():
package com.example.example.greetings;
import com.golfing8.kcommon.command.CommandContext;
import com.golfing8.kcommon.command.Cmd;
import com.golfing8.kcommon.command.MCommand;
import com.golfing8.kcommon.command.argument.CommandArguments;
import com.golfing8.kcommon.struct.placeholder.Placeholder;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
@Cmd(
name = "greet",
aliases = {"hello"},
description = "Greet an online player",
forPlayers = true
)
public final class GreetingsCommand extends MCommand<GreetingsModule> {
@Override
protected void onRegister() {
addArgument("player", CommandArguments.PLAYER);
}
@Override
protected void execute(@NotNull CommandContext context) {
Player target = context.next();
getModule().sendConfigMessage(
context.getSender(),
"greeted",
Placeholder.curlyTrusted("PLAYER", target.getName())
);
}
}
@Override
public void onEnable() {
addCommand(new GreetingsCommand());
}
MCommand finds its module from the generic type and uses the module's
language config and permission prefix. KCommon unregisters the command when
the module is disabled, so register it on every enable.
Commands can own their validation messages with @LangConf, while still
sharing the module's lang.yml:
@LangConf
private Message invalidTarget = new Message("&cThat player cannot be greeted.");
// In execute(...)
if (target == null) {
invalidTarget.send(context.getSender());
return;
}
Use getModule().getLogger() for administrative or state-changing command
actions. This keeps user feedback configurable while leaving an audit trail
in the server log.
Arguments and subcommands¶
Use the built-in argument types for validation and tab completion:
addArgument("amount", CommandArguments.POSITIVE_INTEGER);
addArgument("enabled", CommandArguments.BOOLEAN_STATE);
addArgument("player", CommandArguments.PLAYER);
Read arguments in declaration order with context.next(). The context also
provides getArg(index), getInt(index), getPlayer(index), and
joinRemainingToString().
For choices loaded from configuration, use a map-backed argument so values receive validation and tab completion from the same source:
addArgument("format", CommandArgument.fromMap(
"a greeting format",
GreetingsConfig.formats
));
Build or validate the map before registering the command, and handle an empty map as a configuration error instead of exposing a command with no valid choices.
For context-sensitive tab completion, keep the argument type reusable and
configure the returned argument in onRegister():
BuiltCommandArgument amount =
addArgument("amount", CommandArguments.POSITIVE_INTEGER, sender -> 1);
amount.setAutoFillPlayersOnly(true);
amount.setRequiredPermissionExtension("admin");
Commands without an execute implementation act as directories. Add a
subcommand from onRegister():
addSubCommand(new GreetingsReloadCommand());
Permissions and execution¶
The default @Cmd permission is generated from the plugin, module, and
command names:
<plugin>.<module>.command.<command>
Set permission explicitly when the command must use a stable external
permission. Use forPlayers = true to reject console senders. Set
async = true only when the entire command body is safe away from the
Bukkit server thread; Bukkit entity, world, and inventory operations should
remain synchronous.
Language messages¶
Commands share their module's language config. Prefer
sendConfigMessage(sender, "key", placeholders...) over hard-coded output.
See Language and messages for defining and configuring those
keys.