Skip to content

Command Base Classes

All commands extend one of these base classes from com.hypixel.hytale.server.core.command.system.basecommands.

The simplest base class for synchronous commands. Extends AbstractCommand directly.

public class MyCommand extends CommandBase {
public MyCommand() {
super("mycommand", "myplugin.commands.mycommand.desc");
}
@Override
protected void executeSync(@Nonnull CommandContext context) {
// command logic here
}
}

Constructor parameters:

  • name - Command name (without /)
  • descriptionKey - Translation key for description

Override: executeSync(CommandContext context)

Base class for all asynchronous commands. Extends AbstractCommand directly.

public class MyAsyncCommand extends AbstractAsyncCommand {
public MyAsyncCommand() {
super("myasynccmd", "myplugin.commands.myasynccmd.desc");
}
@Override
protected CompletableFuture<Void> executeAsync(@Nonnull CommandContext context) {
return CompletableFuture.runAsync(() -> {
// async operation (e.g., database query, file I/O)
try {
Thread.sleep(1000);
context.sendMessage(Message.raw("Done!"));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
}

Override: executeAsync(CommandContext) returning CompletableFuture<Void>

Helper method: runAsync(CommandContext, Runnable, Executor) - Wraps a runnable with error handling and returns a CompletableFuture<Void>.

For parent commands with subcommands and/or usage variants. Extends AbstractAsyncCommand.

public class TeleportCommand extends AbstractCommandCollection {
public TeleportCommand() {
super("tp", "server.commands.tp.desc");
// subcommands — dispatched by name
this.addSubCommand(new TeleportHomeCommand()); // /tp home
this.addSubCommand(new TeleportBackCommand()); // /tp back
// usage variants — dispatched by required parameter count
this.addUsageVariant(new TpToPlayerCommand()); // /tp <player> (1 param)
this.addUsageVariant(new TpToCoordinatesCommand()); // /tp <x> <y> <z> (3 params)
}
}

Usage: /tp home, /tp back (subcommands), /tp Alice (1-param variant), /tp 10 20 30 (3-param variant).

Running /tp alone shows help listing available subcommands.

Variants are keyed by required parameter count only — each variant must have a unique count. Two variants with the same number of required args (even with different types) will throw IllegalArgumentException at startup.

For commands that require a player sender. Automatically rejects non-player senders. Extends AbstractAsyncCommand and executes synchronously on the world thread.

public class MyPlayerCommand extends AbstractPlayerCommand {
public MyPlayerCommand() {
super("myplayercmd", "myplugin.commands.myplayercmd.desc");
}
@Override
protected void execute(@Nonnull CommandContext context,
@Nonnull Store<EntityStore> store,
@Nonnull Ref<EntityStore> ref,
@Nonnull PlayerRef playerRef,
@Nonnull World world) {
// access player data
String username = playerRef.getUsername();
// access world
// access entity store
}
}

Override: execute(CommandContext, Store, Ref, PlayerRef, World)

Provided context:

  • store - Entity store access
  • ref - Entity reference
  • playerRef - Player-specific reference with username, UUID, etc.
  • world - The world the player is in

Like AbstractPlayerCommand but the execute method returns a CompletableFuture for chaining async operations. Extends AbstractAsyncCommand. The player context (store, ref, playerRef, world) is resolved on the world thread, then your future runs on whatever executor you choose.

public class MyAsyncPlayerCommand extends AbstractAsyncPlayerCommand {
public MyAsyncPlayerCommand() {
super("myasyncplayercmd", "myplugin.commands.myasyncplayercmd.desc");
}
@Override
protected CompletableFuture<Void> executeAsync(@Nonnull CommandContext context,
@Nonnull Store<EntityStore> store,
@Nonnull Ref<EntityStore> ref,
@Nonnull PlayerRef playerRef,
@Nonnull World world) {
return CompletableFuture.runAsync(() -> {
// async operation with player context
context.sendMessage(Message.raw("Hello, " + playerRef.getUsername()));
});
}
}

Override: executeAsync(CommandContext, Store, Ref, PlayerRef, World) returning CompletableFuture<Void>

Provided context: Same as AbstractPlayerCommand.

Use when: You need to chain multiple async operations or return a future for the caller to await.

For commands that operate on a world. Adds a --world optional argument. Extends AbstractAsyncCommand and executes synchronously on the world thread.

public class MyWorldCommand extends AbstractWorldCommand {
public MyWorldCommand() {
super("myworldcmd", "myplugin.commands.myworldcmd.desc");
}
@Override
protected void execute(@Nonnull CommandContext context,
@Nonnull World world,
@Nonnull Store<EntityStore> store) {
// operate on the world
String worldName = world.getName();
}
}

Override: execute(CommandContext, World, Store)

Provided context:

  • world - The target world
  • store - Entity store for the world

Auto-added argument: --world=<name> (defaults to sender’s current world)

Like AbstractWorldCommand but the execute method returns a CompletableFuture. Extends AbstractAsyncCommand. The world is resolved on the world thread, then your future runs on whatever executor you choose.

public class MyAsyncWorldCommand extends AbstractAsyncWorldCommand {
public MyAsyncWorldCommand() {
super("myasyncworldcmd", "myplugin.commands.myasyncworldcmd.desc");
}
@Override
protected CompletableFuture<Void> executeAsync(@Nonnull CommandContext context,
@Nonnull World world) {
return CompletableFuture.runAsync(() -> {
// async operation with world context
context.sendMessage(Message.raw("World: " + world.getName()));
});
}
}

Override: executeAsync(CommandContext, World) returning CompletableFuture<Void>

Auto-added argument: --world=<name> (defaults to sender’s current world)

Use when: You need to chain async operations or don’t need direct entity store access.

For commands that target entities via multiple selection methods. Extends AbstractAsyncCommand. Executes on the world thread.

Automatically adds these optional arguments:

  • --world=<name> - Target world (defaults to sender’s world)
  • --radius=<n> - Select all entities within radius of sender
  • --player=<name> - Target a specific player
  • --entity=<id> - Target a specific entity by ID

If none of the targeting arguments are provided, targets the entity the player is looking at.

public class MyEntityCommand extends AbstractTargetEntityCommand {
public MyEntityCommand() {
super("myentitycmd", "myplugin.commands.myentitycmd.desc");
}
@Override
protected void execute(@Nonnull CommandContext context,
@Nonnull ObjectList<Ref<EntityStore>> entities,
@Nonnull World world,
@Nonnull Store<EntityStore> store) {
for (Ref<EntityStore> entity : entities) {
// operate on each targeted entity
}
context.sendMessage(Message.raw("Affected " + entities.size() + " entities"));
}
}

Override: execute(CommandContext, ObjectList<Ref<EntityStore>>, World, Store)

Provided context:

  • entities - List of targeted entity references
  • world - The world containing the entities
  • store - Entity store for the world

Targeting priority:

  1. --radius - All entities within radius (requires player sender)
  2. --player - Specific player
  3. --entity - Specific entity by ID
  4. Default - Entity player is looking at (requires player sender)

For commands that can target self or another player via --player argument. Extends AbstractAsyncCommand. Executes on the target player’s world thread.

Automatically adds --player=<name> optional argument. If not provided, targets the sender (requires player sender). Automatically checks .other permission when targeting another player.

public class MyTargetPlayerCommand extends AbstractTargetPlayerCommand {
public MyTargetPlayerCommand() {
super("mytargetcmd", "myplugin.commands.mytargetcmd.desc");
}
@Override
protected void execute(@Nonnull CommandContext context,
@Nullable Ref<EntityStore> sourceRef,
@Nonnull Ref<EntityStore> targetRef,
@Nonnull PlayerRef targetPlayerRef,
@Nonnull World world,
@Nonnull Store<EntityStore> store) {
// sourceRef is the sender (null if console)
// targetRef/targetPlayerRef is the target player
context.sendMessage(Message.raw("Target: " + targetPlayerRef.getUsername()));
}
}

Override: execute(CommandContext, Ref sourceRef, Ref targetRef, PlayerRef targetPlayerRef, World, Store)

Provided context:

  • sourceRef - Sender’s entity reference (null if console)
  • targetRef - Target player’s entity reference
  • targetPlayerRef - Target player’s PlayerRef component
  • world - The world the target is in
  • store - Entity store for the world

Auto-permission check: When --player is specified, the .other permission is checked via HytalePermissions.fromCommand(), which adds a hytale.command. prefix. For example, if the command uses requirePermission("speed.use"), targeting another player checks hytale.command.speed.use.other (not speed.use.other). See Self/Other Pattern for details.

// required positional argument
RequiredArg<String> nameArg = this.withRequiredArg("name", "desc.key", ArgTypes.STRING);
// optional named argument with default
OptionalArg<Integer> countArg = this.withOptionalArg("count", "desc.key", ArgTypes.INTEGER, 1);
// boolean flag
FlagArg verboseFlag = this.withFlag("verbose", "desc.key");
// require specific permission
this.requirePermission("myplugin.command.mycommand");
// require permission group
this.setPermissionGroup(GameMode.Creative);
// multiple permission groups
this.setPermissionGroups("admin", "moderator");
// add command aliases
this.addAliases("mc", "mycmd", "myc");
// constructor with confirmation required
public MyDangerousCommand() {
super("dangerous", "desc.key", true); // requiresConfirmation = true
}
// user must add --confirm flag to execute
// add subcommand
this.addSubCommand(new MySubCommand());
// add usage variant (same command, different arguments)
this.addUsageVariant(new MyCommandVariant());
AbstractCommand (core)
├── CommandBase (sync)
└── AbstractAsyncCommand (async base)
├── AbstractCommandCollection (subcommands only)
├── AbstractPlayerCommand (player sender, sync execute)
├── AbstractAsyncPlayerCommand (player sender, async execute)
├── AbstractWorldCommand (world context, sync execute)
├── AbstractAsyncWorldCommand (world context, async execute)
├── AbstractTargetEntityCommand (entity targeting)
└── AbstractTargetPlayerCommand (player targeting with .other permission)

Package: com.hypixel.hytale.server.core.command.system.basecommands