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).
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
-
addSubCommandin the constructor - Structural writes deferred with
world.execute - Scan before reading a lazily populated registry
- Output distinguishes empty from out-of-range