v3 KamiCommand - Jake-Moore/KamiCommon GitHub Wiki

❗ This Documentation is Outdated! It is recommended to use v4 with its documentation instead.

See V4 Getting Started for more information.

⚠️ Usage ⚠️

This feature is only available in spigot-utils and its inheritors (spigot-jar).

KamiCommon provides a command system with parameters and requirements that are designed to be easy to use.
We would like to acknowledge MassiveCraft's MassiveCore plugin for the original source and inspiration for this system.

KamiCommand

KamiCommon provides a class called KamiCommand which is meant to be extended by each part of your command chain.
To create a command simply extend KamiCommand, configure it in the constructor, and optionally override the perform method to respond to the command.
The bottom of this page contains a full command example using a custom type and parameter.

Help Commands

Any command with children added and no perform method will use the auto-generated help command.
The help command will display the possible subcommands and their descriptions.
Similarly there are default messages when commands are used incorrectly.
You need not create your own help command, the system will handle it for you.

Parameters & Types

KamiCommon provides a "parameters" system for automatically parsing arguments into Java types ready for use in the perform method.
Many existing types are already present in KamiCommon, but you can also create your own types.

Custom Type Example

public class TypeOutpostKey extends TypeAbstract<OutpostHandler> {
    // Singleton instance
    private static final TypeOutpostKey i = new TypeOutpostKey();
    public TypeOutpostKey() { super(OutpostHandler.class); }
    public static TypeOutpostKey get() {
        return i;
    }

    // The read method handles converting a string into your type
    // Note: you are expected to throw a KamiCommonException with an error message for the user for invalid inputs
    // This is completely safe, the command system will catch the exception and send the message to the player
    // Only return if you have parsed a value, and do not return a null value
    @Override
    public OutpostHandler read(String str, CommandSender sender) throws KamiCommonException {
        OutpostHandler handler = OutpostPlugin.get().getOutpostHandler(str);
        if (handler == null) {
            throw new KamiCommonException().addMsg("&cNo Outpost matching '&4%s<b>'. Use outpost config keys.", str);
        }
        return handler;
    }

    // The command system automatically handles tab completion for you, you just need
    //  to provide it with your tab list for a given input string
    // The second parameter: 's' is the current string stem (can be empty)
    // Using streams makes this very easy and you can filter by the stem to make the completions more fluid
    @Override
    public Collection<String> getTabList(CommandSender commandSender, String s) {
        return OutpostPlugin.get().getOutpostKeys()
                .stream()
                .filter(id -> id.toLowerCase().startsWith(s.toLowerCase()))
                .limit(20)
                .toList();
    }
}

Requirements

Requirements are the way to ensure that a command is only executed if certain conditions are met.
It is guaranteed that all requirements are met before the perform method is called.
Each requirement must have an error message that will be sent if the requirement is not met.

Custom Requirement Example

public class RequirementHasRank extends RequirementAbstract {
    private final @NotNull Rank minRank;
    public RequirementHasRank(@NotNull Rank minRank) {
        this.minRank = minRank;
    }
    // Static Access (Optional, but easier to use this way)
    public static RequirementHasRank get(@NotNull Rank minRank) {
        return new RequirementHasRank(minRank);
    }

    // The apply method return true iff the requirement is met
    // When returning false, the command system will automatically call the createErrorMessage method
    //  and send it to the player
    @Override
    public boolean apply(CommandSender sender, KamiCommand command) {
        // Require Player
        if (!(sender instanceof Player player)) {
            return false;
        }
        // Require Rank
        return RankUtil.getRank(player).isAtLeast(this.minRank);
    }

    // What message should we send the player if the requirement is not met?
    @Override
    public String createErrorMessage(CommandSender sender, KamiCommand command) {
        return StringUtil.t("&cThis command can only be used by a faction " + minRank.name() + ".");
    }
}

Command Children

As mentioned before, every command or child command is a class extending KamiCommon.
As such each command class should have its own aliases, and other configuration.
The command hierarchy is defined by the developer by adding children to 'parent' commands.
This is done through the addChild() method, and when added it is assumed there are no parameters because the children aliases are used instead.

Command System Example

Root Command: /outpost

public class OutpostCommand extends KamiCommand {
    public OutpostCommand() {
        addAliases("outpost");
        
        // We create one child command to reset the outpost capture state
        addChild(new CmdReset());
    }
}

Child Command: /outpost reset <outpost>

public class CmdReset extends KamiCommand {
    public CmdReset() {
        addAliases("reset");

        // We use our custom type to receive a OutpostHandler from the command argument
        addParameter(TypeOutpostKey.get(), "outpost");
        // Each parameter you add becomes an argument for the command for the user
        // There are various addParameter methods, like addParameter(default, Type, name, description) which makes an argument optional, using your default value when not provided

        addRequirements(RequirementHasPerm.get("outpost.reset"));
        addRequirements(RequirementHasRank.get(Rank.ADMIN)); // Custom requirement
    }

    @Override
    public void perform() throws KamiCommonException {
        // Reading arguments is done via readArg and implicitly casting to the correct type
        // readArg throws a KamiCommonException (from the type) and is caught by the command system
        OutpostHandler handler = readArg();
        handler.reset();
    }
}

Command Registration

To register a command, create an instance of the parent command(s) you need, and call its register method.
This is typically done in your plugin's onEnable method.

OutpostCommand command = new OutpostCommand();
command.registerCommand(kamiPlugin);

You should also, although not strictly necessary, unregister your commands in your onDisable method.

// Assuming you have a reference to the command
command.unregisterCommand();

Command Visibility

Sometimes we want to hide a command from the help command output.
In your command constructor your can setVisibility with an enum value of Visibility.
For instance a INVISIBLE command will not be shown on anyone's help command output.

⚠️ **GitHub.com Fallback** ⚠️