Skip to content

Create a sub command

This example shows how to create a sub command and attach it to a base command.

Sub commands extend the functionality of a parent command and allow structuring more complex command systems.

→ Deep dive: [[Commands|Core-API/Command-&-Interaction/Commands]]


Steps

  1. Create a class extending PixelSubCommand
  2. Add @CommandDefinition (label + usage)
  3. Implement onPlayerCommand
  4. Attach the sub command to a parent command
  5. Register the parent command

Implementation

package net.mixelpixel.example.bukkit.command;

import net.mixelpixel.core.api.command.CommandDefinition;
import net.mixelpixel.core.bukkit.api.BukkitCoreLibrary;
import net.mixelpixel.core.bukkit.api.command.PixelSubCommand;
import net.mixelpixel.core.bukkit.api.inventory.ConfirmContent;
import net.mixelpixel.core.bukkit.api.inventory.ConfirmContentBuilder;
import net.mixelpixel.core.bukkit.api.inventory.InventoryHandler;
import net.mixelpixel.core.bukkit.api.player.BukkitPixelPlayer;
import net.mixelpixel.core.bukkit.api.player.PlayerHandler;
import net.mixelpixel.core.bukkit.api.util.item.ItemBuilder;
import net.mixelpixel.example.bukkit.ExamplePlugin;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jspecify.annotations.NonNull;

import java.util.Collection;

/**


 * Example: Sub Command
 * Shows how to create a sub command.
 */
public class ClearInventoryCommand extends PixelSubCommand<ExamplePlugin, ClearCommand> {

    @CommandDefinition(
            label = "inventory",
            usage = "<Player>"
    )
    public ClearInventoryCommand(@NonNull ClearCommand parent) {
        super(parent);
    }

    @Override
    public void onPlayerCommand(BukkitPixelPlayer player, String label, String[] args) {
        if (args.length > 1) {
            String playerUsage = getPlayerUsage();
            player.sendMessage(playerUsage);
            return;
        }

        if (args.length == 0) {
            ConfirmContent confirmContent = ConfirmContentBuilder.create(createMiddleItem()).build();
            InventoryHandler inventoryHandler = BukkitCoreLibrary.getInventoryHandler();

            inventoryHandler.openConfirmInventory(
                    player,
                    "         <red><i>Clear inventory?</i></red>",
                    confirmContent,
                    clear -> {
                        if (clear != null && clear) clear(player, player);
                    }
            );
            return;
        }

        PlayerHandler playerHandler = BukkitCoreLibrary.getPlayerHandler();
        BukkitPixelPlayer target = playerHandler.getPlayer(args[0]);

        if (target == null) {
            player.sendMessage(PLAYER_IS_NOT_ONLINE);
            return;
        }

        if (target.equals(player)) {
            onPlayerCommand(player, label, new String[0]);
            return;
        }

        ConfirmContent confirmContent = ConfirmContentBuilder.create(createMiddleItem()).build();
        String coloredTargetName = target.getColoredName();

        InventoryHandler inventoryHandler = BukkitCoreLibrary.getInventoryHandler();
        inventoryHandler.openConfirmInventory(
                player,
                "Clear " + coloredTargetName + "'s Inventory?",
                confirmContent,
                clear -> {
                    if (clear != null && clear) clear(player, target);
                }
        );
    }

    private @NotNull ItemStack createMiddleItem() {
        return ItemBuilder.material(Material.LAVA_BUCKET)
                .name("<red>Clear inventory</red>")
                .build();
    }

    private void clear(@NotNull BukkitPixelPlayer player, @NotNull BukkitPixelPlayer target) {
        target.playSound(Sound.BLOCK_ANVIL_FALL);
        target.clearInventory();

        if (player.equals(target)) {
            player.sendActionBar("<green>You've cleared your inventory.</green>");
            return;
        }

        player.sendMessage(
                "<green>Successfully cleared the inventory of</green> " + target.getColoredName()
        );
        target.sendMessage(
                "<red>Your inventory got cleared by</red> " + player.getColoredName()
        );
    }

    @Override
    public Collection<String> onPlayerTabComplete(BukkitPixelPlayer player, String label, String[] args) {
        if (args.length != 1) return null;

        PlayerHandler playerHandler = BukkitCoreLibrary.getPlayerHandler();
        return playerHandler.getOnlinePlayersNames(player);
    }

}

Registering the sub command

Sub commands are attached to the parent command before registering it:

CommandHandler commandHandler = BukkitCoreLibrary.getCommandHandler();

ClearCommand clearCommand = new ClearCommand(plugin);

// attach sub command to parent


new ClearInventoryCommand(clearCommand);

// register parent (includes all sub commands)


commandHandler.registerCommand(clearCommand);

Explanation

  • PixelSubCommand extends a parent command
  • The constructor receives the parent command instance
  • Sub commands are automatically registered when created
  • usage defines the expected arguments
  • getPlayerUsage() generates a usage message
  • Tab completion is handled via onPlayerTabComplete(...)

Notes

  • Sub commands help structuring commands into smaller units
  • They are always attached to a parent command
  • The parent command handles execution routing

Next step

[[Create an event & listener|Core-API/Build-your-first-feature/Start-Here/Create-an-event-&-listener]]