Skip to content

Command Arguments

The argument system provides type-safe command parameter parsing with validation. See Command Syntax for how raw input is tokenized before arguments are parsed.

Mandatory positional arguments. Command fails if not provided.

public class GiveCommand extends CommandBase {
private final RequiredArg<String> itemArg;
private final RequiredArg<Integer> amountArg;
public GiveCommand() {
super("give", "myplugin.commands.give.desc");
this.itemArg = this.withRequiredArg("item",
"myplugin.commands.give.item.desc", ArgTypes.STRING);
this.amountArg = this.withRequiredArg("amount",
"myplugin.commands.give.amount.desc", ArgTypes.INTEGER);
}
@Override
protected void executeSync(@Nonnull CommandContext context) {
String item = this.itemArg.get(context);
int amount = this.amountArg.get(context);
// ...
}
}

Usage: /give diamond_sword 5

Optional named arguments with --name=value syntax.

private final OptionalArg<Integer> countArg;
public MyCommand() {
// ...
this.countArg = this.withOptionalArg("count",
"desc.key", ArgTypes.INTEGER, 1); // default: 1
}
// in execute:
int count = this.countArg.get(context); // returns 1 if not specified

Usage: /mycommand --count=5 or /mycommand (uses default)

Optional positional argument with a default value.

private final DefaultArg<String> targetArg;
public MyCommand() {
// ...
this.targetArg = this.withDefaultArg("target",
"desc.key", ArgTypes.STRING, "self");
}

Usage: /mycommand target_name or /mycommand (uses “self”)

Boolean flags. Present = true, absent = false.

private final FlagArg verboseFlag;
private final FlagArg forceFlag;
public MyCommand() {
// ...
this.verboseFlag = this.withFlag("verbose", "desc.key");
this.forceFlag = this.withFlag("force", "desc.key");
}
// in execute:
boolean verbose = this.verboseFlag.get(context);
boolean force = this.forceFlag.get(context);

Usage: /mycommand --verbose --force

Located in com.hypixel.hytale.server.core.command.system.arguments.types.ArgTypes:

TypeDescriptionExample Values
ArgTypes.BOOLEANTrue/falsetrue, false
ArgTypes.INTEGERInteger numbers42, -10, 0
ArgTypes.FLOATFloating point3.14, -0.5
ArgTypes.DOUBLEDouble precision3.14159265
ArgTypes.STRINGText stringhello, "hello world"
TypeDescriptionExample Values
ArgTypes.PLAYER_REFOnline playerPlayer name or selector
ArgTypes.WORLDWorld referenceWorld name
ArgTypes.BLOCK_TYPE_ASSETBlock typestone, dirt
ArgTypes.ITEM_ASSETItem typediamond_sword
ArgTypes.PARTICLE_SYSTEMParticle effectParticle system ID
ArgTypes.SOUND_EVENT_ASSETSound eventSound event ID
ArgTypes.SOUND_CATEGORYSound categorySFX, Music, Ambient, UI
ArgTypes.NPC_ROLENPC roleRole ID
TypeDescriptionExample Values
ArgTypes.RELATIVE_BLOCK_POSITIONBlock position (supports ~)100 64 200, ~ ~5 ~
ArgTypes.RELATIVE_POSITIONDouble position100.5 64.0 200.5
ArgTypes.VECTOR3IInteger vector10 20 30
ArgTypes.VECTOR3FFloat vector1.0 2.0 3.0

Position types support relative coordinate prefixes: ~ (relative to player), _ (surface height), c (chunk scale).

Use ArgTypes.forEnum() to restrict an argument to a fixed set of values. This is the recommended approach for string-choice parameters — don’t parse strings manually.

// for any enum type
ArgTypes.forEnum("mode", GameMode.class)
// built-in enum types
ArgTypes.GAME_MODE // gameMode enum

Custom enums work the same way. Define your enum and pass it to forEnum():

public enum TimeOfDay {
DAWN,
NOON,
DUSK,
MIDNIGHT
}
// in your command constructor:
this.timeArg = this.withRequiredArg("time",
"myplugin.commands.settime.time.desc",
ArgTypes.forEnum("time", TimeOfDay.class));
// in execute:
TimeOfDay time = this.timeArg.get(context); // TimeOfDay.DAWN, etc.

Enum arguments provide:

  • Case-insensitive parsingdawn, DAWN, and Dawn all match TimeOfDay.DAWN
  • Fuzzy “did you mean?” errors — typing duskk suggests dusk

Add validators to arguments for input validation:

this.withRequiredArg("amount", "desc.key", ArgTypes.INTEGER)
.addValidator(Validators.greaterThan(0))
.addValidator(Validators.max(100));
this.withRequiredArg("name", "desc.key", ArgTypes.STRING)
.addValidator(Validators.minLength(3))
.addValidator(Validators.maxLength(16));
ValidatorDescription
Validators.greaterThan(n)Value > n
Validators.greaterThanOrEqual(n)Value >= n
Validators.lessThan(n)Value < n
Validators.lessThanOrEqual(n)Value <= n
Validators.min(n)Alias for greaterThanOrEqual
Validators.max(n)Alias for lessThanOrEqual
Validators.range(min, max)min <= value <= max
Validators.minLength(n)String length >= n
Validators.maxLength(n)String length <= n
Validators.pattern(regex)Matches regex pattern
Validators.notEmpty()String not empty

The suggestion system has two layers: argument types can provide built-in suggestions, and individual argument instances can add custom suggestions on top.

Most argument types do not provide suggestions by default. The types that do:

TypeSuggestions
ArgTypes.BOOLEANtrue, false (ordered by prefix match)
ArgTypes.TICK_RATE30tps, 60tps, 20tps, 33ms, 16ms, 50ms

Types like PLAYER_REF, WORLD, BLOCK_TYPE_ASSET, and ITEM_ASSET resolve names during parsing but do not provide proactive tab suggestions. Enums provide fuzzy “did you mean?” on parse failure but not proactive suggestions either.

Use Argument.suggest() to attach a SuggestionProvider to any argument instance:

this.withRequiredArg("target", "desc.key", ArgTypes.STRING)
.suggest((sender, textAlreadyEntered, numParametersTyped, result) -> {
for (PlayerRef player : Universe.get().getPlayers()) {
if (player.getUsername().toLowerCase()
.startsWith(textAlreadyEntered.toLowerCase())) {
result.suggest(player.getUsername());
}
}
});

The SuggestionProvider functional interface:

@FunctionalInterface
public interface SuggestionProvider {
void suggest(@Nonnull CommandSender sender,
@Nonnull String textAlreadyEntered,
int numParametersTyped,
@Nonnull SuggestionResult result);
}

Parameters:

  • sender — the player requesting suggestions (enables sender-aware filtering)
  • textAlreadyEntered — what the user has typed so far for this argument
  • numParametersTyped — how many tokens have been entered (for multi-token types)
  • result — accumulator to add suggestions into

The SuggestionResult accumulator provides several ways to add suggestions:

result.suggest("option1"); // raw string
result.suggest(Object::toString, myObject); // via toString function
result.suggest(myObject); // via Object.toString()
result.fuzzySuggest(input, candidates, Item::name); // fuzzy-match top 5

fuzzySuggest() ranks candidates by fuzzy distance against the input and keeps only the top 5 matches — useful for large candidate sets like asset IDs.

When suggestions are requested, both sources contribute additively:

  1. The per-argument SuggestionProvider (set via .suggest()) runs first
  2. The argument type’s built-in suggest() method runs second

Results from both are combined into a single list.

Create custom types by extending SingleArgumentType<T>:

public static final SingleArgumentType<MyObject> MY_TYPE = new SingleArgumentType<MyObject>(
"myplugin.argtype.myobject.name", "myplugin.argtype.myobject.usage"
) {
@Override
public MyObject parse(@Nonnull String input,
@Nonnull ParseResult parseResult) {
MyObject obj = MyObject.fromString(input);
if (obj == null) {
parseResult.error("myplugin.argtype.myobject.invalid");
return null;
}
return obj;
}
@Override
public void suggest(@Nonnull CommandSender sender,
@Nonnull String textAlreadyEntered,
int numParametersTyped,
@Nonnull SuggestionResult result) {
// provide suggestions for this argument type
for (String option : MyRegistry.getNames()) {
if (option.toLowerCase().startsWith(textAlreadyEntered.toLowerCase())) {
result.suggest(option);
}
}
}
};
// usage:
this.withRequiredArg("myarg", "desc.key", MY_TYPE);

Override suggest() on your argument type to provide built-in suggestions whenever this type is used. This is the pattern used by built-in types like NPC_ROLE in the NPC plugin.

Always access arguments through the CommandContext:

@Override
protected void executeSync(@Nonnull CommandContext context) {
// required - always has value
String name = this.nameArg.get(context);
// optional - returns default if not specified
int count = this.countArg.get(context);
// flag - returns true/false
boolean verbose = this.verboseFlag.get(context);
// check if optional was explicitly provided
if (this.countArg.isPresent(context)) {
// user explicitly specified --count
}
}

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