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 直接生效。
相关条目
- CompatConfig - 9 个开关及其绑定
- AngelicaClientTweaker -
getTransformers()的第 (1) 段调用点 - FML Transformers - transformer 实现类
- AngelicaCompat - 下游独立兼容包,处理器清单与本枚举部分重叠