自动事件总线

基本信息

属性 值
类 com.gtnewhorizon.gtnhlib.eventbus.AutoEventBus
注解 com.gtnewhorizon.gtnhlib.eventbus.EventBusSubscriber
阶段枚举 com.gtnewhorizon.gtnhlib.eventbus.Phase
包路径 src/main/java/com/gtnewhorizon/gtnhlib/eventbus/(6 个类)
执行入口 AutoEventBus.executePhase(Phase)

功能

给类加 @EventBusSubscriber 即可让其中的 @SubscribeEvent 方法自动注册到 Forge 事件总线,无需手动 MinecraftForge.EVENT_BUS.register(...)。README 的表述(README.md Events 节):

Mark a class @EventBusSubscriber to auto-register its @SubscribeEvent methods. Choose the side and load phase in the annotation. No manual registration needed.

GTNHLib 自身在 CommonProxy 的 4 个生命周期方法中按阶段驱动(CommonProxy.java:64-107):

调用点 阶段
CommonProxy.construct() Phase.CONSTRUCT
CommonProxy.preInit() Phase.PRE
CommonProxy.init() Phase.INIT

@EventBusSubscriber

eventbus/EventBusSubscriber.java:18,@Retention(RUNTIME)、@Target(TYPE):

成员 默认值 说明
side() { Side.CLIENT, Side.SERVER } 订阅侧,两端都订阅
phase() Phase.INIT 等价于 FML LoaderState,在哪个加载阶段注册

重要约束(EventBusSubscriber.java:16 注释):

All methods annotated with @SubscribeEvent are expected to be static.

条件方法

嵌套注解 @EventBusSubscriber.Condition(:38)可标在一个 boolean 方法上,作为整类的注册条件。契约(EventBusSubscriber.java:32-36 注释):

  • 方法必须是 static、返回 boolean、无参数
  • 一个类至多一个条件方法

条件求值失败时的行为(eventbus/AutoEventBus.java:196-199)——记录 error 并保守地不注册:

} catch (Throwable e) {
    LOGGER.error("Failed to invoke condition {} for class {}", condition, clazz, e);
    return false;
}

即条件方法抛异常会导致该类静默不被注册(仅有日志),这是排查"事件不触发"时的首要检查点。

Phase

eventbus/Phase.java 定义 3 个阶段值,与 FML 生命周期事件一一对应:

枚举值 对应 FML 事件 触发点
CONSTRUCT FMLConstructionEvent CommonProxy.construct()(:65)
PRE FMLPreInitializationEvent CommonProxy.preInit()(:69)
INIT FMLInitializationEvent CommonProxy.init()(:107)

每个枚举值自带一个 boolean hasExecuted 标志与 Object2ObjectMap<ModContainer, ObjectSet<String>> modClassesForPhase(Lombok @Getter(AccessLevel.PACKAGE)),用于保证每阶段只执行一次并记录已注册类。

注意 Phase 与 mixin 的 EARLY/LATE 是两套互不相干的阶段划分,见 Mixin 引导流程。

数值

数值名 值
eventbus 包类数 6(AutoEventBus、EventBusSubscriber、EventBusUtil、MethodInfo、Phase、StaticASMEventHandler)
@EventBusSubscriber 成员数 2(side、phase)+ 1 个嵌套注解 Condition
Phase 枚举值数 3(CONSTRUCT、PRE、INIT)
executePhase 调用点 3(CommonProxy 的 construct / preInit / init)
AutoEventBus 中 catch (Throwable) 1 处(条件求值,:196)

交互

典型用法:

@EventBusSubscriber(side = Side.CLIENT, phase = Phase.INIT)
public class MyHandler {
    @Condition
    public static boolean isEnabled() { return ...; }

    @SubscribeEvent
    public static void onEvent(SomeEvent e) { ...; }
}

CommonProxy 自身就标了 @EventBusSubscriber(CommonProxy.java:61),其 onPlayerLogin 静态方法在玩家加入时把服务端视距发给客户端(CommonProxy.java:197-202)。

相关条目