225 lines
5.8 KiB
Markdown
225 lines
5.8 KiB
Markdown
---
|
|
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");
|
|
}
|
|
```
|