EventHandler - HimxhMC/HimDSL GitHub Wiki

@EventHandler

事件驱动 / Event-Driven

前面所有脚本都是"运行一次就结束"。事件驱动是另一种模式:脚本定义逻辑,等待游戏事件触发。例如玩家上线、破坏方块、执行命令——这些时刻触发对应的处理函数。

Every script so far ran once and finished. Event-driven is another model: the script defines logic and waits for game events. A player joins, a block breaks, a command runs — these moments trigger the corresponding handler.

用 @EventHandler 注解标记处理函数:

Mark a handler function with @EventHandler:

@EventHandler
void onJoin(event(PlayerJoinEvent)) {
    player p = @s;
    runcmd("CONSOLE", "say 欢迎 " + p.name);
}

几点说明:

  • @EventHandler 是注解,写在返回类型前面。
  • 参数 event(PlayerJoinEvent) 声明这个函数处理哪种事件。
  • @s 在事件里指向触发者(这里是加入的玩家)。
  • 返回类型通常是 void。

A few notes:

  • @EventHandler is an annotation, placed before the return type.
  • The parameter event(PlayerJoinEvent) declares which event this handles.
  • @s inside an event points at the trigger (the joining player here).
  • The return type is usually void.

光定义不够,还要启动 / Defining Is Not Enough — You Must Start It

仅仅写 @EventHandler 函数不会让它生效。你必须在脚本的某个入口显式启动:

Writing the function alone does nothing. You must explicitly start it from a script entry:

@EventHandler
void onJoin(event(PlayerJoinEvent)) {
    player p = @s;
    runcmd("CONSOLE", "say 欢迎 " + p.name);
}

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

这个设计让事件监听的生命周期可控:脚本决定什么时候开始监听,也可以随时 stop 停止。

This design keeps event listener lifecycle under control: the script decides when to start and can stop at any time.

如果你把事件函数定义在 onServerLoad.himdsl 里,main 会在服务器加载完成后执行,start 就在那时生效。这是最常见的事件脚本写法。

Defining event functions in onServerLoad.himdsl and starting them in main is the most common pattern: main runs after server load, so start takes effect then.


一个完整例子 / A Complete Example

把事件监听写进 onServerLoad.himdsl,每次玩家加入时欢迎他们:

Put the listener in onServerLoad.himdsl to welcome every player on join:

@EventHandler
void onJoin(event(PlayerJoinEvent)) {
    player p = @s;
    runcmd("CONSOLE", "say 欢迎 " + p.name + " 加入服务器!");
}

@EventHandler
void onQuit(event(PlayerQuitEvent)) {
    player p = @s;
    runcmd("CONSOLE", "say " + p.name + " 离开了");
}

int main() {
    start("onJoin");
    start("onQuit");
    runcmd("CONSOLE", "say 事件监听已启动");
}

每个事件函数都要单独 start。启动不是批量的。

Each event function is started individually. There is no batch start.


多个函数处理同一事件 / Multiple Handlers for One Event

同一个事件可以有多个处理函数,它们都会被触发,顺序不保证:

One event may have several handlers; all fire, order not guaranteed:

@EventHandler
void logJoin(event(PlayerJoinEvent)) {
    player p = @s;
    runcmd("CONSOLE", "say [日志] " + p.name + " 加入");
}

@EventHandler
void welcomeJoin(event(PlayerJoinEvent)) {
    player p = @s;
    runcmd(p.name, "title @s title {\"text\":\"欢迎\"}");
}

int main() {
    start("logJoin");
    start("welcomeJoin");
}

不要让多个处理函数依赖彼此的执行顺序。需要顺序时,把逻辑合并进一个函数。

Never rely on handler ordering. If order matters, merge the logic into one function.


事件函数里能做什么 / What You Can Do Inside

事件函数和普通函数一样,可以用变量、条件、循环、调用其他函数:

Event functions are ordinary functions — variables, conditionals, loops, calls all work:

@EventHandler
void onBreak(event(BlockBreakEvent)) {
    player p = @s;
    if (p.gamemode == "creative") {
        return;                 // 创造模式不处理
    }
    runcmd("CONSOLE", "say " + p.name + " 破坏了方块");
}

return 在事件函数里结束当前这次处理,不影响后续事件的触发。

return ends this invocation; future events still fire.


返回值没有意义 / Return Value Is Ignored

事件函数的返回值被忽略。写 int 返回类型不会让调用方拿到什么。

The event function's return value is ignored. An int return type does not deliver anything to the caller.

@EventHandler
int onJoin(event(PlayerJoinEvent)) { ... }     // 返回类型无意义

统一用 void。

Use void uniformly.


小结 / Summary

  • @EventHandler 标记事件处理函数。

  • 参数 event(TypeName) 声明事件类型。

  • @s 在事件里指向触发者。

  • 函数必须 start 才生效。

  • 同一事件可以有多个处理函数,顺序不保证。

  • 返回值被忽略,统一用 void。

  • 常见模式:写在 onServerLoad.himdsl 里,main 中 start。

  • @EventHandler marks an event handler.

  • Parameter event(TypeName) declares the event type.

  • @s points at the trigger.

  • The function only works after start.

  • Multiple handlers per event; order not guaranteed.

  • Return value ignored; use void.

  • Common pattern: place in onServerLoad.himdsl, start inside main.


下一步 / Next Steps

下一章 [事件类型解析 / Event-Type-Resolution] 讲怎么知道用哪个事件类型名。

Next, [事件类型解析 / Event-Type-Resolution] shows how to find the right event type name.