Skip to main content

Adding a command

All commands are subcommands of /simtale, defined as nested classes in SimTaleCommand.java.

Skeleton

private static class MyThingSubCommand extends AbstractPlayerCommand {
public MyThingSubCommand() {
super("mything", "What it does, shown in help");
}

@Override
protected void execute(@Nonnull CommandContext ctx, @Nonnull Store<EntityStore> store,
@Nonnull Ref<EntityStore> ref, @Nonnull PlayerRef playerRef, @Nonnull World world) {
ctx.sendMessage(Message.raw("[SimTale] done."));
}
}

Register it in the constructor:

this.addSubCommand(new MyThingSubCommand());

Forgetting this is the most common mistake — the class compiles and the command simply does not exist.

Arguments

private final RequiredArg<String> stageArg;

public MyThingSubCommand() {
super("mything", "...");
this.stageArg = this.withRequiredArg("stage", "BABY|TODDLER|CHILD", ArgTypes.STRING);
}

Read with ctx.get(this.stageArg).

Flags, and no decimals

Hytale passes arguments as named flags (--stage=BABY), not positionally, and the parser rejects decimal points. If you need a fractional value, take integer hundredths.

Structural writes

A command runs outside the tick, but the store may still be processing. Anything structural — addComponent, removeComponent, addEntity — should go through:

world.execute(() -> store.addComponent(ref, TYPE, value));

Mutating fields of an existing component is safe directly.

Messages

Prefer Message.translation("general.something") over Message.raw for anything a player reads. Debug commands using raw is acceptable.

Opening a UI page

Player player = store.getComponent(ref, Player.getComponentType());
if (player == null) return;
player.getPageManager().openCustomPage(ref, store, new MyPage(playerRef, player));

If the page reads from a registry that a scan populates, run the scan first. debugbeds showed an empty list for a long time precisely because it opened the page without scanning, while housecheck scanned as a side effect and looked like it worked.

Reporting nothing found

Distinguish "nothing exists" from "nothing near you". A single-target command cannot, which is why chestcheck was misleading and debugchests replaced it.

Include counts in your output.

Checklist

  • Class created
  • addSubCommand in the constructor
  • Structural writes deferred with world.execute
  • Scan before reading a lazily populated registry
  • Output distinguishes empty from out-of-range