CompatHandlers(ASM 兼容处理器枚举)

基本信息

属性 值
类 com.gtnewhorizons.angelica.loading.fml.compat.CompatHandlers
路径 src/main/java/com/gtnewhorizons/angelica/loading/fml/compat/CompatHandlers.java
行数 61
类型 public enum CompatHandlers(:14)
枚举项数 5

5 个枚举项

:16-20,每项绑定一个 CompatConfig 开关(Supplier<Boolean>)与一个处理器实例:

枚举项 applyIf 绑定 行
STACKS_ON_STACKS CompatConfig.fixStacksOnStacks :16
EXTRA_UTILS CompatConfig.fixExtraUtils :17
IMMERSIVE_ENGINEERING CompatConfig.fixImmersiveEngineering :18
THAUMCRAFT CompatConfig.fixThaumcraft :19
THAUMIC_HORIZONS CompatConfig.fixThaumicHorizons :20

注意 new XXXCompatHandler() 是在枚举常量构造时立即实例化的(不是懒加载),5 个处理器对象在类加载时就全部创建,无论对应开关是否打开。开关只影响 getHandlers() 是否返回它们,不影响是否创建。

getHandlers:带缓存的过滤

:30-43:

private static List<ICompatHandler> compatHandlers = null;

public static List<ICompatHandler> getHandlers() {
    if (compatHandlers != null) return compatHandlers;
    compatHandlers = new ArrayList<>();
    for (CompatHandlers value : values()) {
        if (value.applyIf.get()) {
            compatHandlers.add(value.handler);
        }
    }
    return compatHandlers;
}
  • 结果缓存在静态字段里,只算一次;
  • 用 values() 遍历(枚举声明顺序:STACKS_ON_STACKS → EXTRA_UTILS → IMMERSIVE_ENGINEERING → THAUMCRAFT → THAUMIC_HORIZONS)。

因为缓存发生在 coremod 阶段(见 AngelicaClientTweaker 第 (1) 段),此时 CompatConfig 已加载,所以缓存的是正确结果。

getTransformers:真正的 transformer 名来源

:48-60:

public static List<String> getTransformers() {
    final List<ICompatHandler> handlers = getHandlers();
    List<String> transformers = new ArrayList<>();
    for (ICompatHandler handler : handlers) {
        if (handler.extraTransformers() != null) {
            transformers.addAll(handler.extraTransformers());
        }
    }
    if (!handlers.isEmpty()) {
        transformers.add("com.gtnewhorizons.angelica.loading.fml.transformers.GenericCompatTransformer");
    }
    return transformers;
}

这是「枚举 + 条件循环」导致不能靠数调用点计数的典型:5 个枚举项展开后,transformer 数量取决于 (a) 哪些开关打开、(b) 每个 handler 的 extraTransformers() 返回几个类名、© 是否非空。因此 transformer 总数是运行时决定的,不是常量。

GenericCompatTransformer 只在至少一个 handler 启用时追加一次(:56-58),不会重复。

接口 ICompatHandler

loading/fml/compat/ICompatHandler.java(28 行)共 5 个 default 方法,全部默认返回 null:

方法 行 默认返回 语义
getFieldLevelTessellator() :8-10 null 类名 → 方法名列表
getTileEntityNullGuard() :12-14 null 同上
getThreadSafeISBRHAnnotations() :16-18 null 类名 → boolean
getHUDCachingEarlyReturn() :20-22 null 类名 → 方法名列表
extraTransformers() :24-26 null 额外 transformer 类名列表

CompatHandlers.getTransformers() 里的 if (handler.extraTransformers() != null) 正是配合这个默认值。

extraTransformers 只有 2 个实现覆写

5 个 handler 里只有 2 个覆写了 extraTransformers(),其余 3 个走接口默认的 null,在 getTransformers() 里被跳过:

Handler 覆写 返回内容
StacksOnStacksCompatHandler :30-32 ImmutableList.of("...transformers.specific.StacksOnStacksTransformer")
ImmersiveEngineeringCompatHandler :40-42 ImmutableList.of("...transformers.specific.ImmersiveEngineeringTransformer")
ExtraUtilsCompatHandler 否 null
ThaumcraftCompatHandler 否 null
ThaumicHorizonsCompatHandler 否 null

因此全开关打开时,getTransformers() 返回的列表长度为:

2 个 extraTransformers(StacksOnStacks + ImmersiveEngineering)
+ 1 个 GenericCompatTransformer(非空时追加一次)
= 3

其余 3 个 handler 仍然生效,但走的是 GenericCompatTransformer 这条通用通道,靠 getFieldLevelTessellator() / getHUDCachingEarlyReturn() 等返回的数据表工作,而不是各自独立的 transformer 类。

举例:ThaumcraftCompatHandler 返回 ImmutableMap.of("thaumcraft.client.lib.RenderEventHandler", ImmutableList.of("renderOverlay"))(:14),即 HUDCaching 早退补丁的目标。

与 CompatConfig 的 9 项差 4

CompatConfig 有 9 个开关,本枚举只覆盖 5 个。未被本枚举消费的 4 项是 fixLotr、fixMinefactoryReloaded、fixSecurityCraft、fixNTMSpace —— 它们走 Mixin 或 Proxy 直接生效。

相关条目