HY

hytale-commands

Reference guide for building and registering custom commands in Hytale plugins.

Install

mkdir -p .claude/skills/hytale-commands && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/10498" && unzip -o skill.zip -d .claude/skills/hytale-commands && rm skill.zip

Installs to .claude/skills/hytale-commands

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Documents Hytale's command system for creating custom commands in plugins. Covers AbstractAsyncCommand, AbstractPlayerCommand, AbstractTargetPlayerCommand, AbstractTargetEntityCommand, AbstractCommandCollection, arguments (RequiredArg, OptionalArg, DefaultArg, FlagArg), ArgTypes, argument validators, custom validators, permissions, command variants, aliases, subcommands, and registration. Use when creating commands, adding arguments, validating input, requiring permissions, building command trees, or registering commands. Triggers - command, custom command, AbstractPlayerCommand, AbstractAsyncCommand, AbstractTargetPlayerCommand, AbstractTargetEntityCommand, AbstractCommandCollection, CommandContext, RequiredArg, OptionalArg, DefaultArg, FlagArg, ArgTypes, Validator, requirePermission, addUsageVariant, addAliases, addSubCommand, registerCommand, CommandRegistry.
874 chars✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Advanced

Key capabilities

  • Create custom commands
  • Add command arguments
  • Validate input
  • Register commands

How it works

Provides a framework for extending Hytale's command system with custom logic, arguments, and permissions.

Inputs & outputs

You give it
Command requirements
You get back
Registered plugin command

When to use hytale-commands

  • Create a new server command
  • Add arguments to a command
  • Register a command in a plugin

About this skill

Hytale Command System

Comprehensive reference for creating custom commands in Hytale plugins, including command types, arguments, validators, permissions, variants, subcommands, registration, and the full ArgTypes reference.

Source: https://hytalemodding.dev/en/docs/guides/plugin/creating-commands, https://hytalemodding.dev/en/docs/server/argtypes Related skills: For permissions in detail, see hytale-permissions. For player stats used in commands, see hytale-player-stats.


Quick Reference

TaskApproach
Basic async commandExtend AbstractAsyncCommand, override executeAsync()
Player-bound commandExtend AbstractPlayerCommand, override execute()
Target another playerExtend AbstractTargetPlayerCommand (adds --player arg)
Target looked-at entityExtend AbstractTargetEntityCommand (uses raycast)
Add required argumentthis.withRequiredArg("name", "desc", ArgTypes.STRING)
Add optional argumentthis.withOptionalArg("name", "desc", ArgTypes.STRING)
Add default argumentthis.withDefaultArg("name", "desc", ArgTypes.FLOAT, 100f, "default desc")
Add flag argumentthis.withFlagArg("name", "desc")
Browse all supported argument typesUse the ArgTypes server reference for the authoritative list
Get argument valuemyArg.get(commandContext)
Require permissionrequirePermission(HytalePermissions.fromCommand("name"))
Make command publicOverride canGeneratePermission() to return false
Add variantaddUsageVariant(new OtherCommand())
Add aliasaddAliases("alias1", "alias2")
Group subcommandsExtend AbstractCommandCollection, call addSubCommand(...)
Register commandgetCommandRegistry().registerCommand(new MyCommand()) in setup()

Command Types

AbstractAsyncCommand

Runs on a background thread. Cannot safely access Store or Ref without getting the world first. Best for world-independent commands (e.g., displaying rules).

public class ServerRulesCommand extends AbstractAsyncCommand {

    public ServerRulesCommand() {
        super("rules", "Lists the servers rules");
    }

    @Override
    protected CompletableFuture<Void> executeAsync(@Nonnull CommandContext context) {
        context.sendMessage(Message.raw("The only rule is there are no rules."));
        return CompletableFuture.completedFuture(null);
    }
}

Warning: AbstractAsyncCommand runs asynchronously - it cannot edit Stores or Refs without first getting the desired world. For most commands, prefer the other command types.

AbstractPlayerCommand

Tied to the executing player and their world. Runs on the world thread - safe to access Store and Ref directly. Most common command type.

public class ExampleCommand extends AbstractPlayerCommand {

    public ExampleCommand() {
        super("test", "Super test command!");
    }

    @Override
    protected void execute(@Nonnull CommandContext commandContext,
                          @Nonnull Store<EntityStore> store,
                          @Nonnull Ref<EntityStore> ref,
                          @Nonnull PlayerRef playerRef,
                          @Nonnull World world) {
        Player player = store.getComponent(ref, Player.getComponentType());
        UUIDComponent component = store.getComponent(ref, UUIDComponent.getComponentType());
        TransformComponent transform = store.getComponent(ref, TransformComponent.getComponentType());
        player.sendMessage(Message.raw("Transform : " + transform.getPosition()));
    }
}

Note: Long-running operations (like IO) in AbstractPlayerCommand will block the world thread and cause lag. Use AbstractAsyncCommand for heavy IO.

AbstractTargetPlayerCommand

Like AbstractPlayerCommand but adds a --player <value> argument to target a different player. Thread-safe - override execute(), not executeAsync().

AbstractTargetEntityCommand

Uses a raycast to target the entity the player is looking at. Runs on the world thread of the targeted entity.

@Override
protected void execute(CommandContext context,
                      Store<EntityStore> store,
                      Ref<EntityStore> ref,
                      World world) {
    // ref is the targeted entity's reference
    EntityStatMap stats = store.getComponent(ref, EntityStatMap.getComponentType());
    if (stats == null) {
        context.sendMessage(Message.raw("This entity has no stats!"));
        return;
    }
    int healthIdx = DefaultEntityStatTypes.getHealth();
    EntityStatValue health = stats.get(healthIdx);
    if (health == null) {
        context.sendMessage(Message.raw("This entity has no health!"));
        return;
    }
    stats.addValue(healthIdx, 100);
}

Arguments

Arguments are added in the command's constructor. The value is retrieved during execute by passing commandContext to the argument's get() method.

Argument Types

MethodBehaviorUsage
withRequiredArg(name, desc, type)Must be provided; parsed left-to-right positionallyRequiredArg<T>
withOptionalArg(name, desc, type)Returns null if not provided; uses --key value syntaxOptionalArg<T>
withDefaultArg(name, desc, type, default, defaultDesc)Returns default if not providedDefaultArg<T>
withFlagArg(name, desc)Boolean switch; true if present, false if not; uses --nameFlagArg

ArgTypes

Use the ArgTypes server reference as the authoritative list when you need an exact constant name or a less common parser. The most common types used in plugins are:

  • ArgTypes.STRING
  • ArgTypes.INTEGER
  • ArgTypes.BOOLEAN
  • ArgTypes.FLOAT
  • ArgTypes.DOUBLE
  • ArgTypes.UUID
  • ArgTypes.PLAYER_REF

The full ArgTypes page also covers world, coordinate, asset, range, color, block, and game-mode parsers. Check it before inventing a custom parser for something the server already supports.

Full Arguments Example

// Usage: /healplayer --health 50 --message "Feels Good" --debug
public class HealPlayerCommand extends AbstractTargetPlayerCommand {
    private final DefaultArg<Float> healthArg;
    private final OptionalArg<String> messageArg;
    private final FlagArg debugArg;

    public HealPlayerCommand() {
        super("healplayer", "Healing a player for an <input> amount of HP (default: 100)");

        this.healthArg = this.withDefaultArg("health", "Amount to heal player",
            ArgTypes.FLOAT, (float) 100, "Desc of Default: 100");
        this.messageArg = this.withOptionalArg("message",
            "Message to print while healing", ArgTypes.STRING);
        this.debugArg = this.withFlagArg("debug", "Add debug logs");
    }

    @Override
    protected void execute(@Nonnull CommandContext commandContext,
                          @Nullable Ref<EntityStore> ref,
                          @Nonnull Ref<EntityStore> ref1,
                          @Nonnull PlayerRef playerRef,
                          @Nonnull World world,
                          @Nonnull Store<EntityStore> store) {

        if (this.debugArg.get(commandContext)) {
            commandContext.sendMessage(Message.raw("We are debugging"));
        }

        EntityStatMap stats = store.getComponent(ref, EntityStatMap.getComponentType());
        int healthIdx = DefaultEntityStatTypes.getHealth();
        stats.addStatValue(healthIdx, healthArg.get(commandContext));
    }
}

Argument Validators

Add validators to arguments using .addValidator(). Built-in validators are in the Validators class:

OptionalArg<Integer> healAmount = withOptionalArg("amount", "Heal Amount", ArgTypes.INTEGER)
    .addValidator(Validators.greaterThan(0))
    .addValidator(Validators.lessThan(1000));

Custom Validators

Implement com.hypixel.hytale.codec.validation.Validator<T>:

import com.hypixel.hytale.codec.schema.SchemaContext;
import com.hypixel.hytale.codec.schema.config.Schema;
import com.hypixel.hytale.codec.validation.ValidationResults;
import com.hypixel.hytale.codec.validation.Validator;

public class MyCustomValidator implements Validator<String> {
    @Nonnull
    private final String bannedValue;

    public MyCustomValidator(@Nonnull String bannedValue) {
        this.bannedValue = bannedValue;
    }

    @Override
    public void accept(@Nullable String input, @Nonnull ValidationResults results) {
        if (this.bannedValue.equalsIgnoreCase(input)) {
            results.fail("The given value has been banned.");
        }
    }

    @Override
    public void updateSchema(SchemaContext context, @Nonnull Schema target) {
        // Optional: update schema for dynamic validation
        throw new UnsupportedOperationException("Not implemented yet.");
    }
}

Usage:

String bannedRole = "badword";
OptionalArg<String> roleArg = withOptionalArg("role", "Role to assign", ArgTypes.STRING)
    .addValidator(new MyCustomValidator(bannedRole));

Permissions

Add permission requirements in the constructor:

public HealPlayerCommand() {
    super("healplayer", "heal a player a given amount of HP");

    // Single permission
    requirePermission(HytalePermissions.fromCommand("rules"));

    // Multiple required permissions (AND)
    requirePermission(HytalePermissions.fromCommand("usercommands"));

    // OR block - needs one from a list
    requirePermission(
        PermissionRules.or(
            HytalePermissions.fromCommand("moderator"),
            HytalePermissions.fromCommand("admin")
        )
    );
}

Use /perm in-game to manage player permissions and groups. Run /perm --help for usage.

Making a Command Require No Permission

Override canGeneratePermission() (RECOMMENDED):

@Override
protected boolean canGeneratePermission() {
    return false; // Prevents auto-generated 

---

*Content truncated.*

When not to use it

  • When using standard Hytale commands
  • When the command logic is too complex for plugins

Prerequisites

Hytale plugin development environment

Limitations

  • AbstractAsyncCommand cannot access world state directly
  • Long IO operations block the world thread

How it compares

Offers a structured, type-safe approach to command creation compared to manual parsing.

Compared to similar skills

hytale-commands side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
hytale-commands (this skill)05moNo flagsAdvanced
backend-microservice-development23moNo flagsIntermediate
hexagonal-architecture03moNo flagsAdvanced
minecraft-bukkit-pro904moNo flagsAdvanced

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

backend-microservice-development

TencentBlueKing

后端微服务开发规范,涵盖目录结构、分层架构(API/Service/DAO)、依赖注入、配置管理、Spring Boot 最佳实践。当用户进行后端开发、创建新微服务、编写 Kotlin/Java 代码或设计服务架构时使用。

213

hexagonal-architecture

jssmy

Design, implement, and refactor Ports & Adapters systems with clear domain boundaries, dependency inversion, and testable use-case orchestration across TypeScript, Java, Kotlin, and Go services. Use for: new features needing long-term maintainability, decoupling domain logic from frameworks/DB/HTTP,

00

minecraft-bukkit-pro

sickn33

Master Minecraft server plugin development with Bukkit, Spigot, and Paper APIs. Specializes in event-driven architecture, command systems, world manipulation, player management, and performance optimization. Use PROACTIVELY for plugin architecture, gameplay mechanics, server-side features, or cross-version compatibility.

9078

java-coding-standards

affaan-m

Java coding standards for Spring Boot services: naming, immutability, Optional usage, streams, exceptions, generics, and project layout.

1669

springboot-tdd

affaan-m

Test-driven development for Spring Boot using JUnit 5, Mockito, MockMvc, Testcontainers, and JaCoCo. Use when adding features, fixing bugs, or refactoring.

531

kotlin-coroutines

vitorpamplona

Advanced Kotlin coroutines patterns for AmethystMultiplatform. Use when working with: (1) Structured concurrency (supervisorScope, coroutineScope), (2) Advanced Flow operators (flatMapLatest, combine, merge, shareIn, stateIn), (3) Channels and callbackFlow, (4) Dispatcher management and context switching, (5) Exception handling (CoroutineExceptionHandler, SupervisorJob), (6) Testing async code (runTest, Turbine), (7) Nostr relay connection pools and subscriptions, (8) Backpressure handling in event streams. Delegates to kotlin-expert for basic StateFlow/SharedFlow patterns. Complements nostr-expert for relay communication.

311

Search skills

Search the agent skills registry