Command Base Classes
All commands extend one of these base classes from com.hypixel.hytale.server.core.command.system.basecommands.
CommandBase
Section titled “CommandBase”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)
AbstractAsyncCommand
Section titled “AbstractAsyncCommand”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>.
AbstractCommandCollection
Section titled “AbstractCommandCollection”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.
AbstractPlayerCommand
Section titled “AbstractPlayerCommand”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 accessref- Entity referenceplayerRef- Player-specific reference with username, UUID, etc.world- The world the player is in
AbstractAsyncPlayerCommand
Section titled “AbstractAsyncPlayerCommand”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.
AbstractWorldCommand
Section titled “AbstractWorldCommand”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 worldstore- Entity store for the world
Auto-added argument: --world=<name> (defaults to sender’s current world)
AbstractAsyncWorldCommand
Section titled “AbstractAsyncWorldCommand”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.
AbstractTargetEntityCommand
Section titled “AbstractTargetEntityCommand”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 referencesworld- The world containing the entitiesstore- Entity store for the world
Targeting priority:
--radius- All entities within radius (requires player sender)--player- Specific player--entity- Specific entity by ID- Default - Entity player is looking at (requires player sender)
AbstractTargetPlayerCommand
Section titled “AbstractTargetPlayerCommand”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 referencetargetPlayerRef- Target player’s PlayerRef componentworld- The world the target is instore- 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.
Common Methods (All Base Classes)
Section titled “Common Methods (All Base Classes)”Arguments
Section titled “Arguments”// required positional argumentRequiredArg<String> nameArg = this.withRequiredArg("name", "desc.key", ArgTypes.STRING);
// optional named argument with defaultOptionalArg<Integer> countArg = this.withOptionalArg("count", "desc.key", ArgTypes.INTEGER, 1);
// boolean flagFlagArg verboseFlag = this.withFlag("verbose", "desc.key");Permissions
Section titled “Permissions”// require specific permissionthis.requirePermission("myplugin.command.mycommand");
// require permission groupthis.setPermissionGroup(GameMode.Creative);
// multiple permission groupsthis.setPermissionGroups("admin", "moderator");Aliases
Section titled “Aliases”// add command aliasesthis.addAliases("mc", "mycmd", "myc");Confirmation
Section titled “Confirmation”// constructor with confirmation requiredpublic MyDangerousCommand() { super("dangerous", "desc.key", true); // requiresConfirmation = true}// user must add --confirm flag to executeSubcommands and Variants
Section titled “Subcommands and Variants”// add subcommandthis.addSubCommand(new MySubCommand());
// add usage variant (same command, different arguments)this.addUsageVariant(new MyCommandVariant());Class Hierarchy
Section titled “Class Hierarchy”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)Code Location
Section titled “Code Location”Package: com.hypixel.hytale.server.core.command.system.basecommands