---
title: Subcommands
type: docs
weight: 3
---

Subcommands allow you to create hierarchical command structures, organizing related functionality under a single parent command.

## Creating Subcommands

### Basic Structure

```java
public class AdminCommand extends AbstractCommand {

    public AdminCommand() {
        super("admin", "Administration commands");

        // Add subcommands
        addSubCommand(new KickSubCommand());
        addSubCommand(new BanSubCommand());
        addSubCommand(new MuteSubCommand());
    }

    @Override
    protected CompletableFuture<Void> execute(CommandContext context) {
        // This runs when no subcommand is specified
        context.sender().sendMessage(Message.raw("Usage: /admin <kick|ban|mute>"));
        return null;
    }
}
```

### Subcommand Implementation

```java
public class KickSubCommand extends AbstractCommand {

    private final RequiredArg<PlayerRef> playerArg;
    private final OptionalArg<String> reasonArg;

    public KickSubCommand() {
        super("kick", "Kick a player from the server");

        playerArg = withRequiredArg("player", "Player to kick", ArgTypes.PLAYER_REF);
        reasonArg = withOptionalArg("reason", "Kick reason", ArgTypes.STRING);
    }

    @Override
    protected CompletableFuture<Void> execute(CommandContext context) {
        PlayerRef target = context.get(playerArg);
        String reason = context.get(reasonArg);

        // Check if player is online via ECS reference
        Ref<EntityStore> ref = target.getReference();
        if (ref != null && ref.isValid()) {
            // Disconnect via PacketHandler
            String kickReason = reason != null ? reason : "Kicked by admin";
            target.getPacketHandler().disconnect(kickReason);
            context.sendMessage(Message.raw("Kicked " + target.getUsername()));
        }

        return null;
    }
}
```

Usage: `/admin kick player123 --reason "Breaking rules"`

## Command Collections

For commands that only contain subcommands (no direct execution), extend `AbstractCommandCollection`:

```java
public class ManageCommand extends AbstractCommandCollection {

    public ManageCommand() {
        super("manage", "Management commands");

        addSubCommand(new ManageUsersCommand());
        addSubCommand(new ManageWorldsCommand());
        addSubCommand(new ManagePluginsCommand());
    }
}
```

With `AbstractCommandCollection`, running `/manage` without a subcommand will show available subcommands automatically.

## Nested Subcommands

Subcommands can have their own subcommands:

```java
public class ManageUsersCommand extends AbstractCommand {

    public ManageUsersCommand() {
        super("users", "User management");

        addSubCommand(new ListUsersCommand());   // /manage users list
        addSubCommand(new AddUserCommand());     // /manage users add
        addSubCommand(new RemoveUserCommand());  // /manage users remove
    }

    @Override
    protected CompletableFuture<Void> execute(CommandContext context) {
        // Show usage for /manage users
        return null;
    }
}
```

## Subcommand Aliases

Subcommands can have aliases just like regular commands:

```java
public class TeleportCommand extends AbstractCommand {

    public TeleportCommand() {
        super("teleport", "Teleport commands");
        addAliases("tp");

        addSubCommand(new TeleportHereCommand());
        addSubCommand(new TeleportAllCommand());
    }
}

public class TeleportHereCommand extends AbstractCommand {

    public TeleportHereCommand() {
        super("here", "Teleport player to you");
        addAliases("h", "tome");
    }

    // ...
}
```

Now players can use:
- `/teleport here player1`
- `/tp here player1`
- `/tp h player1`
- `/tp tome player1`

## Command Variants

Variants allow the same command to accept different argument patterns:

```java
public class TpCommand extends AbstractCommand {

    private final RequiredArg<PlayerRef> targetArg;

    public TpCommand() {
        super("tp", "Teleport command");

        // Main variant: /tp <player>
        targetArg = withRequiredArg("target", "Player to teleport to", ArgTypes.PLAYER_REF);

        // Add variant: /tp <player> <destination>
        addUsageVariant(new TpToPlayerVariant());

        // Add variant: /tp <x> <y> <z>
        addUsageVariant(new TpToPositionVariant());
    }

    @Override
    protected CompletableFuture<Void> execute(CommandContext context) {
        // Teleport sender to target player
        PlayerRef target = context.get(targetArg);
        // ...
        return null;
    }
}
```

### Variant Implementation

```java
public class TpToPlayerVariant extends AbstractCommand {

    private final RequiredArg<PlayerRef> playerArg;
    private final RequiredArg<PlayerRef> destinationArg;

    public TpToPlayerVariant() {
        // No name for variants - use description only
        super("Teleport one player to another");

        playerArg = withRequiredArg("player", "Player to teleport", ArgTypes.PLAYER_REF);
        destinationArg = withRequiredArg("destination", "Destination player", ArgTypes.PLAYER_REF);
    }

    @Override
    protected CompletableFuture<Void> execute(CommandContext context) {
        PlayerRef player = context.get(playerArg);
        PlayerRef destination = context.get(destinationArg);
        // Teleport player to destination
        return null;
    }
}
```

{{< callout type="info" >}}
Variants are distinguished by the number of required parameters. Each variant must have a different number of required arguments.
{{< /callout >}}

## Permission Inheritance

Subcommand permissions are automatically built from the parent:

```
/admin -> myplugin.command.admin
/admin kick -> myplugin.command.admin.kick
/admin ban -> myplugin.command.admin.ban
```

You can also set custom permissions:

```java
public KickSubCommand() {
    super("kick", "Kick a player");
    requirePermission("myplugin.admin.kick");
}
```
