Commands and Sleep - HimxhMC/HimDSL GitHub Wiki

命令与 sleep / Commands and sleep

runcmd:执行命令 / runcmd: Run a Command

runcmd(executor, command) 是 HimDSL 里执行 Minecraft 命令的方式。第一个参数是执行者,第二个是命令文本。

runcmd(executor, command) executes a Minecraft command. First is the executor, second is the command text.

runcmd("CONSOLE", "say 服务器已就绪");
runcmd("Steve", "spawn");
runcmd(p.name, "give " + p.name + " diamond 5");

命令文本不带前导斜杠。写 "spawn",不写 "/spawn"。

No leading slash in the command text. Write "spawn", not "/spawn".


执行者 / Executor

执行者 效果
"CONSOLE" 控制台执行,权限最高
玩家名 该玩家执行,受权限限制
Executor Effect
"CONSOLE" console executes, full permission
player name that player executes, subject to permissions

"CONSOLE" 不区分大小写:"console"、"Console" 都行。

"CONSOLE" is case-insensitive: "console" and "Console" work.

给玩家执行命令时,玩家必须在线。玩家名拼错或玩家已离线,命令会静默丢弃——不报错,也不执行。这是常见的"命令没反应"原因。

When executing as a player, they must be online. A misspelled name or offline player results in the command being silently dropped — no error, no execution. This is a common cause of "command does nothing".

稳妥的做法:

Safe pattern:

var p = Bukkit.getPlayerExact("Steve");
if (p != null) {
    runcmd(p.name, "spawn");
}

(用 Bukkit.getPlayerExact 通过 Java 互操作检查玩家是否存在。)

(Use Bukkit.getPlayerExact via Java interop to check existence.)


异步派发 / Asynchronous Dispatch

runcmd 不会立即执行命令。它把命令排入主线程的下一 tick 执行。

runcmd does not run the command immediately. It schedules it for the next tick on the main thread.

这意味着:

This means:

  • runcmd 之后紧接着的代码,命令还没执行。

  • 脚本执行完成时,命令可能还在队列里。

  • 命令之间顺序保证,但与其他脚本的命令顺序不保证。

  • Right after runcmd, the command has not run yet.

  • When the script finishes, commands may still be queued.

  • Commands are ordered among themselves, but not against other scripts' commands.

日常脚本里不需要关心这些。只想说"我不依赖执行结果"——runcmd 是"发出命令",不是"执行并等待"。

Daily scripts need not worry. Just remember runcmd fires and forgets — it dispatches, it does not wait.


常用命令模式 / Common Command Patterns

广播 / Broadcast

runcmd("CONSOLE", "say " + message);

给玩家发消息 / Message a Player

runcmd(p.name, "msg " + p.name + " 你好");

发放物品 / Give Items

runcmd("CONSOLE", "give " + p.name + " diamond 5");

传送 / Teleport

runcmd("CONSOLE", "tp " + p.name + " 100 64 200");

显示标题 / Title

runcmd(p.name, "title @s title {\"text\":\"欢迎\"}");
runcmd(p.name, "title @s subtitle {\"text\":\"欢迎回来\"}");

sleep:阻塞当前线程 / sleep: Block the Current Thread

sleep(ms) 让脚本暂停指定毫秒数。参数是毫秒。

sleep(ms) pauses the script for the given milliseconds.

runcmd("CONSOLE", "say 开始");
sleep(2000);                        // 停 2 秒
runcmd("CONSOLE", "say 结束");

这个函数会阻塞当前线程。

This function blocks the current thread.


sleep 的危险性 / Why sleep Is Dangerous

在 main 里调用 sleep 会阻塞服务器主线程。主线程负责处理玩家动作、更新世界、运行所有插件的逻辑。阻塞它意味着整个服务器卡住。

Calling sleep inside main blocks the server main thread. That thread handles player actions, world updates, and every plugin. Blocking it freezes the whole server.

int main() {
    runcmd("CONSOLE", "say 处理中");
    sleep(10000);                   // ✗ 所有玩家卡 10 秒
    runcmd("CONSOLE", "say 完成");
}

10 秒的 sleep 会让所有玩家卡 10 秒——TPS 掉到 2 以下,服务器基本不可用。

A 10-second sleep freezes every player for 10 seconds — TPS drops below 2, essentially unusable.


正确的"等待"方式 / The Right Way to Wait

需要"等一段时间再执行下一步"时,用 @BukkitRunnable 定时任务,把逻辑拆成多次执行:

To "wait then continue", use a @BukkitRunnable scheduled task, splitting logic across ticks:

int step;

@BukkitRunnable
void process() sche = 2s {
    if (step == 0) {
        runcmd("CONSOLE", "say 第一步");
        step = 1;
    } else if (step == 1) {
        runcmd("CONSOLE", "say 第二步");
        step = 2;
    } else {
        runcmd("CONSOLE", "say 完成");
        stop("process");
        step = 0;
    }
}

int main() {
    step = 0;
    start("process");
}

这是唯一正确的"延迟执行"模式——用状态变量 + 定时任务,把等待拆成多次 tick。

This is the correct pattern — state variable + scheduled task, splitting waits across ticks.

一次性延迟 / One-Shot Delay

如果只需要"延迟一次",@BukkitRunnable 不带 sche 是异步的,仍然不能直接操作游戏。稳妥做法是用带 sche 的任务执行一次然后 stop:

For a one-shot delay, @BukkitRunnable without sche runs async — still cannot directly touch the game. A safer pattern: a scheduled task that runs once and stops.

@BukkitRunnable
void delayed() sche = 3s {
    runcmd("CONSOLE", "say 3 秒后执行");
    stop("delayed");
}

int main() {
    start("delayed");
}

注意:start("delayed") 后 3 秒才触发,下次想再启动需要先 stop。上面代码里任务自己 stop 了,所以可以再次 start。

Note: after start("delayed"), it fires 3s later. To fire again, stop first. The code above stops itself, so re-start works.


什么时候可以用 sleep / When sleep Is Acceptable

唯一安全的使用场景是异步线程里——但 HimDSL 里你很少直接控制线程。

The only safe place is inside an async thread — rare in HimDSL.

实际建议:日常脚本里不要用 sleep。它带来的麻烦远大于便利。

Practical advice: avoid sleep in daily scripts. Its problems outweigh its convenience.


常见错误 / Common Mistakes

错误一:命令带了斜杠

runcmd("CONSOLE", "/say hello");    // ✗ 报错:未知命令 "/say"

去掉前导斜杠。

错误二:玩家名拼错

runcmd("Stev", "spawn");            // ✗ 静默失败

检查拼写,或先用 Java 互操作确认在线。

错误三:main 里 sleep

sleep(5000);                        // ✗ 卡服

用 @BukkitRunnable 替代。

Mistake 1: Leading slash

Drop it.

Mistake 2: Misspelled player name

Silent failure. Verify online first.

Mistake 3: sleep in main

Blocks the server. Use @BukkitRunnable.


小结 / Summary

  • runcmd(executor, command),命令不带斜杠。

  • "CONSOLE" 或玩家名作为执行者。

  • 玩家离线时命令静默丢弃。

  • 命令在下一 tick 执行,异步派发。

  • sleep(ms) 阻塞当前线程,main 里不要用。

  • "等待后执行"用 @BukkitRunnable + 状态变量。

  • 日常脚本不要 sleep。

  • runcmd(executor, command); no leading slash.

  • "CONSOLE" or a player name as executor.

  • Offline players: command silently dropped.

  • Commands run next tick, async dispatch.

  • sleep(ms) blocks the thread; avoid in main.

  • "Wait then continue" via @BukkitRunnable + state variable.

  • No sleep in daily scripts.


内置函数部分回顾 / Built-ins Review

内置函数部分到此结束。六章覆盖了:数学、高精度、字符串速查、集合速查、文件 I/O、命令与 sleep。

The Built-ins section ends here. Six chapters: math, BigDecimal, string cheat sheet, collection cheat sheet, file I/O, commands and sleep.

关键约定:

Key conventions:

  • 数学:多数返回 double,参数是弧度。

  • 钱:用 big*,不用 double。

  • 字符串与集合:优先方法形式,别用函数形式。

  • 文件:日常用 freadlines/fwritelines;追加用 "a" 模式。

  • 命令:runcmd 不带斜杠。

  • sleep:日常脚本不要用。

  • Math: mostly returns double; angles in radians.

  • Money: use big*, not double.

  • Strings and collections: method form over function form.

  • Files: freadlines/fwritelines daily; "a" for appends.

  • Commands: runcmd without slash.

  • sleep: avoid in daily scripts.


下一步 / Next Steps

下一部分进入进阶。第十章 [反射与类解析 / Reflection] 讲 HimDSL 怎么定位 Java 类。

The next part covers Advanced. Chapter [反射与类解析 / Reflection] explains how HimDSL locates Java classes.