Repository navigation
BukkitRunnable
前面的脚本运行一次就结束。定时任务让代码按固定间隔反复执行:每 10 秒检查一次、每分钟广播一次、每 5 分钟保存一次数据。
Previous scripts ran once. Scheduled tasks run code at fixed intervals: check every 10 seconds, broadcast every minute, save every 5 minutes.
用 @BukkitRunnable 注解标记:
Mark a function with @BukkitRunnable:
@BukkitRunnable
void tick() sche = 10s {
runcmd("CONSOLE", "say 服务器运行正常");
}
sche = 10s 是调度间隔,表示每 10 秒执行一次。
sche = 10s is the schedule interval: run every 10 seconds.
@BukkitRunnable
返回类型 函数名() sche = 间隔 {
函数体
}
-
注解写在最前。
-
参数列表通常留空(定时任务没有触发者)。
-
返回类型一般是
void。 -
sche = 间隔声明周期。 -
@BukkitRunnable函数也需要start才生效。 -
Annotation first.
-
Parameter list is usually empty (no trigger).
-
Return type is normally
void. -
sche = intervaldeclares the period. -
@BukkitRunnablefunctions also needstart.
sche 支持三种后缀:
sche accepts three suffixes:
| 后缀 | 含义 | 例子 |
|---|---|---|
s |
秒 | sche = 5s |
t |
游戏刻(tick),1 秒 = 20 刻 | sche = 100t |
ms |
毫秒 | sche = 500ms |
| Suffix | Meaning | Example |
|---|---|---|
s |
seconds | sche = 5s |
t |
ticks (20 per second) | sche = 100t |
ms |
milliseconds | sche = 500ms |
不带后缀时默认为刻:
Without a suffix, ticks are assumed:
sche = 100 // 100 刻 = 5 秒
推荐总是带后缀,5s 比 100t 更好读。
Prefer explicit suffixes; 5s reads better than 100t.
和事件函数一样,必须显式启动:
Like event handlers, explicitly start them:
@BukkitRunnable
void heartbeat() sche = 30s {
runcmd("CONSOLE", "say 心跳检测");
}
int main() {
start("heartbeat");
}
stop("heartbeat") 会取消任务,之后不再执行:
stop("heartbeat") cancels the task:
int main() {
start("heartbeat");
// 某个条件下
// stop("heartbeat");
}
start 一个已经在运行的任务会报错。必须先 stop 再 start。
start on an already-running task errors. stop first, then start.
省略 sche 时,@BukkitRunnable 变成一次性的异步任务,只执行一次:
Omitting sche makes the task a one-shot async task:
@BukkitRunnable
void warmup() {
runcmd("CONSOLE", "say 延迟初始化完成");
}
int main() {
start("warmup");
}
区别:
-
带
sche→ 重复执行,主线程,按周期。 -
不带
sche→ 执行一次,异步线程。 -
With
sche→ repeats on the main thread. -
Without → runs once on an async thread.
异步意味着不能在任务里直接操作 Bukkit 对象。下一节会讲怎么处理。
Async means you cannot directly touch Bukkit objects. See the next section.
不带 sche 的任务在异步线程执行。异步线程不能直接操作游戏世界——玩家的位置、方块状态、实体属性都只能在主线程改。
One-shot tasks run on an async thread. Async threads cannot directly touch the game world — player positions, block states, entity attributes belong to the main thread.
HimDSL 里的引用方法会自动切回主线程,所以以下代码是安全的:
Reference methods auto-switch to the main thread, so this is safe:
@BukkitRunnable
void asyncWork() {
var players = @a; // 查询在主线程
for (int i = 0; i < players.size(); i = i + 1) {
var p = players.get(i);
p.sendMessage("异步通知"); // 自动切主线程
}
}
代价是每次调用都会切线程,异步里频繁操作实体很慢。如果逻辑不涉及游戏对象,异步是高效的——例如写文件、计算。涉及游戏对象时,考虑改用带 sche 的同步任务。
The cost is a thread switch per call. Heavy entity access from async is slow. If logic touches no game objects, async is efficient (file writes, computation). Otherwise prefer a scheduled (main-thread) task.
每隔 5 分钟自动保存一次数据:
Auto-save data every 5 minutes:
@BukkitRunnable
void autosave() sche = 5m {
// 注意:sche 不支持 "m",用秒代替
}
int main() {
// 5 分钟 = 300 秒
start("autosave");
}
等等——sche 不支持分钟单位。5 分钟要写成 300s。上面示例只是示意。
Wait — sche has no minutes unit. Five minutes must be written 300s. The example above is only illustrative.
@BukkitRunnable
void autosave() sche = 300s {
var lines = vector();
lines.add("saved at " + $server(tps)$);
fwritelines("last_save.txt", lines);
runcmd("CONSOLE", "say 数据已保存");
}
int main() {
start("autosave");
}
定时任务里不要 sleep:
Do not sleep inside scheduled tasks:
@BukkitRunnable
void bad() sche = 10s {
runcmd("CONSOLE", "say 开始");
sleep(5000); // ✗ 阻塞主线程 5 秒
runcmd("CONSOLE", "say 结束");
}
sleep 会阻塞整个服务器,所有玩家都会卡顿。想要"等一段时间再执行下一步",正确做法是拆成多次任务执行,或者用状态变量记住进度。
sleep blocks the whole server. To "wait then continue", split into multiple ticks or track progress in a state variable.
-
@BukkitRunnable标记定时任务。 -
sche = 间隔声明周期,支持s、t、ms。 -
必须
start才生效。 -
带
sche同步重复执行;不带sche异步执行一次。 -
异步里操作实体自动切线程,代价是慢。
-
定时任务里不要
sleep。 -
不支持分钟单位,用秒代替。
-
@BukkitRunnablemarks scheduled tasks. -
sche = intervalwiths,t,mssuffixes. -
Must
startto take effect. -
With
sche: sync repeated. Without: async once. -
Async entity access auto-switches threads; slower.
-
No
sleepinside scheduled tasks. -
No minutes; use seconds.
下一章 start / stop 把事件和定时任务的生命周期管理放在一起讲。
Next, start / stop consolidates lifecycle management for events and scheduled tasks.
- 首页 / Home
- 安装与快速开始 / Installation & Quick Start
- 第一个脚本 / Your First Script
- 命令速查 / Command Reference
- 自动执行脚本 / Auto-run Scripts
- 定义函数 / Defining Functions
- 函数重载 / Function Overloading
- Lambda 表达式 / Lambda Expressions
- 函数式接口 / Functional Interfaces
- 选择器总览 / Selectors Overview
- 选择器过滤器 / Selector Filters
- EntityRef 引用 / EntityRef
- 占位符参考 / Placeholders Reference
- PlaceholderAPI 桥接 / PAPI Bridge
- 创建 GUI / Creating a GUI
- GUISlot 槽位 / GUISlot
- 点击回调 / Click Callbacks
- onClose 回调 / onClose Callback
- GUI 刷新 / GUI Refresh
- 数学函数 / Math Built-ins
- 高精度计算 / BigDecimal Built-ins
- 字符串函数 / String Built-ins
- 集合函数 / Collection Built-ins
- 文件 I/O / File I/O
- 命令与 sleep / Commands & sleep