GenericCompatTransformer

基本信息

属性 值
类 com.gtnewhorizons.angelica.loading.fml.transformers.GenericCompatTransformer
路径 src/main/java/com/gtnewhorizons/angelica/loading/fml/transformers/GenericCompatTransformer.java
行数 91
类型 public class ... implements IClassTransformer(:22)
驱动的子 transformer 4 个 compat/transformers/generic/ 静态工具

它是什么

数据驱动的通用兼容 transformer。它自己不写任何字节码规则,而是把 5 个 ICompatHandler 提供的数据在构造期合并成 4 张查表 + 1 个目标类集合,然后在类加载时按表分派。

这是本 mod 唯一使用 fastutil 集合(Object2ObjectOpenHashMap / Object2BooleanOpenHashMap / ObjectOpenHashSet)的地方。

5 个字段(:24-28)

字段 类型 来源方法
fieldLevelTessellator Map<String, List<String>> getFieldLevelTessellator()
tileEntityNullGuard Map<String, List<String>> getTileEntityNullGuard()
threadSafeIBSRH Map<String, Boolean> getThreadSafeISBRHAnnotations()
hudCachingEarlyReturn Map<String, List<String>> getHUDCachingEarlyReturn()
targetedClasses Set<String> 上述 4 表 key 的并集(buildTargetClassSet() :48-53)

构造期(:30-35)

for (ICompatHandler handler : CompatHandlers.getHandlers()) { registerHandler(handler); }
buildTargetClassSet();

registerHandler(:37-45)对 4 个方法各做一次 != null 守卫后 putAll。由于 5 个 handler 的目标类名互不重叠,putAll 不存在互相覆盖。

注意 CompatHandlers.getHandlers() 的结果已被静态缓存(见 CompatHandlers :31-33),且此时 coremod 阶段 CompatConfig 已装载,所以表内容是确定的。

挂在哪个阶段

LaunchWrapper 类加载期,且是 CompatHandlers.getTransformers() :56-58 在 handler 非空时唯一追加一次的类:

if (!handlers.isEmpty()) {
    transformers.add("com.gtnewhorizons.angelica.loading.fml.transformers.GenericCompatTransformer");
}

它在 getTransformers() 的末尾追加,即排在 2 个 specific/ transformer 之后。RFB 路径不提供本类 —— 这是 5 个 handler 全部失效的根因。

transform 的分派(:55-88)

行 动作
:57 basicClass == null → 返回 null
:59 不在 targetedClasses → 原样返回(绝大多数类走这条)
:61-62 ClassReader → ClassNode
:64-74 依次尝试 4 个子 transformer,每张表独立判断,命中就调
:76-78 MixinClassWriter(COMPUTE_MAXS | COMPUTE_FRAMES) 写出
:79 dump

一个类可同时命中多张表:例如 Stacks on Stacks 的 RenderTilePile 同时在 tileEntityNullGuard 与 threadSafeIBSRH 里,会被两个子 transformer 依次处理。

已知问题

  1. 即使一个子 transformer 都没实际改动,仍会重写字节码(:76-79):4 张表命中判断基于「类名在表里」,而子 transformer 内部可能因为字节码模式不匹配而什么都不做(如 TileEntityNullGuardTransformer 的三层邻接匹配)。此时该类仍被 MixinClassWriter 重新序列化并 dump,产生一次无意义的字节码往返。COMPUTE_FRAMES 还会在早期类加载时有 TypeNotPresentException 风险。
  2. COMPUTE_FRAMES 的早期风险:本类与其他 transformer 不同,用了 COMPUTE_MAXS | COMPUTE_FRAMES。帧重算需要解析类的公共父类/接口,coremod 阶段可能尚不可用。
  3. 数据在构造期冻结:CompatConfig 若在构造后被修改(理论上不会,因为 coremod 早于 preInit),表不会更新。
  4. 日志缺失:本类不打印任何日志(对比 StacksOnStacksTransformer :53)。用户无法确认哪些类被处理了,只能查 AngelicaClassDump 的产物。
  5. threadSafeIBSRH 拼写错误:字段名是 threadSafeIBSRH(大写 ISBRH),其余 3 张表用全小写或驼峰 Tessellator/Entity/Hud。:80 的调用点写的是 threadSafeIBSRH.get(...)——一致,但命名不统一。

相关条目