<>>

# 事件

# 什么是事件?

玄乎其玄的解释,可以跳过

简单来说,事件是某种事物从无到有的过程。

原本玩家站在那好好地,突然有个僵尸从后面打了它一下,好了玩家受到伤害的这个过程便是一个 LivingHurtEvent
再或者,突然游戏启动了,Mod 们开始加载了,触发了 FMLCommonSetupEvent 等若干个事件。

订阅事件可以简单理解为“出现 X 事件的时候记得调用我的方法 A,我需要处理这个事件。”

# 为什么要有事件?

干涉原版行为。

Minecraft 本身没有完整的事件系统,所以我们不能轻易干涉原版逻辑。
但是修改原版逻辑又确实是 Mod 开发过程中所需要用到的,比如不同 Mod 在玩家受到伤害时可能会想要提供不同程度的伤害减免。 因此,我们需要一套能让好几个 Mod 同时需要对同一处逻辑进行修改,并且又能够同时工作的机制。
为此,Forge 引入了一套事件总线。

# 术语

  • 发布:指调用 IEventBus#post(Event) 方法。
    会立刻调用所有订阅此事件的监听器。换言之,这是同步的。
  • 取消:指 Event#setCanceled(boolean) 这个方法。
    通常所谓“取消事件”指的就是调用 setCanceled(true)
    所有可以取消的事件都有 @Cancelable 标记。试图取消不可取消的事件会抛出异常。
    “取消事件”的含义由这个事件本身定义。
  • 结果:某些事件可以有一个“结果”。这些有结果的事件都有 @HasResult 标记。
    结果有三种:允许(ALLOW)、拒绝(DENY)和默认(DEFAULT)。
    事件“结果”的含义由这个事件本身定义。

# 如何订阅事件

首先我们要写一个方法。这个方法只有一个参数,而且一定是我们要订阅的事件:

public class FirstEventListener {
    @SubscribeEvent
    public static void onEntityHurt(LivingHurtEvent event) {
        // 对于 LivingHurtEvent,取消事件意味着“这次伤害无效”。
        // 换言之,下面的代码可以无条件取消所有玩家实体受到的一切伤害。
        if (event.getEntityLiving() instanceof PlayerEntity) {
            event.setCanceled(true);
        }
    }
}
1
2
3
4
5
6
7
8
9
10

根据发布事件所用的事件总线(Event Bus),订阅事件的位置也不一样。对于上面这个例子,是:

MinecraftForge.EVENT_BUS.register(FirstEventListener.class);
1

或者,有一个看起来像是回调(Callback)的写法。若使用这个写法,@SubscribeEvent 可省略:

MinecraftForge.EVENT_BUS.addListener(FirstEventListener::onEntityHurt);
1

关于事件订阅的细节,可以参考这里