ImmersiveEngineeringTransformer

基本信息

属性 值
类 ...loading.fml.compat.transformers.specific.ImmersiveEngineeringTransformer
路径 src/main/java/com/gtnewhorizons/angelica/loading/fml/compat/transformers/specific/ImmersiveEngineeringTransformer.java
行数 109
类型 public class ... implements IClassTransformer(:23)
注册方 ImmersiveEngineeringCompatHandler.extraTransformers() :40-42

它是什么 / 挂在哪个阶段

真正的 IClassTransformer,与 4 个 generic/ 的静态工具不同。跑在 LaunchWrapper 类加载期(IClassTransformer#transform),排在 GenericCompatTransformer 之后(CompatHandlers.getTransformers() 先收集 extraTransformers() 再追加 GenericCompatTransformer,:48-59)。

RFB 路径不提供本 transformer —— AngelicaRfbPlugin.makeTransformers 只返回 3 个 RFB transformer。

目标类集合(:24-40)

两个静态列表,在 static {} 块里填充:

列表 内容 数量
transformedClasses BlockRenderClothDevices、BlockRenderMetalDevices2、BlockRenderStoneDevices、ClientUtils 4
staticRenderPassPatches 上列前 3 个(不含 ClientUtils) 3

命名一致地省略了 blusunrize.immersiveengineering.client.render. / .client. 前缀(常量声明在 :24-28)。

:46 早退:if (!transformedClasses.contains(transformedName)) return basicClass;。

它改写什么

transform(:42-66)按目标类分派到两个互斥的补丁:

补丁 A:staticRenderPassPatcher(:68-85)—— 作用于 3 个 BlockRender* 类

在 renderWorldBlock 方法里,把所有 GETSTATIC 且字段名恰为 renderPass 的指令替换为:

INVOKESTATIC  net/minecraftforge/client/ForgeHooksClient.getWorldRenderPass()I

即把 IE 缓存下来的静态 render-pass 标志,换成每帧从 Forge 钩子现取。

补丁 B:transformClientUtils(:87-107)—— 作用于 ClientUtils

只处理两个方法:renderStaticWavefrontModelWithIcon 与 renderStaticWavefrontModel,且要求描述符逐字符匹配:

(Lnet/minecraft/world/IBlockAccess;IIILnet/minecraftforge/client/model/obj/WavefrontObject;
 Lnet/minecraft/util/IIcon;Lnet/minecraft/client/renderer/Tessellator;
 Lblusunrize/immersiveengineering/common/util/chickenbones/Matrix4;
 Lblusunrize/immersiveengineering/common/util/chickenbones/Matrix4;IZFFF[Ljava/lang/String;)V

在方法内找到第一条 IFNULL,把它改成 IFEQ 并在其前插入 ICONST_0(:102-104),然后 break。

源码注释 :88-91 解释动机:原代码是 if (world != null) { ... },块内调用 OpenGL 更新光照贴图坐标,在 Angelica 的 ISBRH 里是非法操作;注释断言「让它不发生似乎不会破坏任何东西」。

写出字节码

:60-61 用 MixinClassWriter(MixinClassWriter.COMPUTE_FRAMES) —— 唯一使用 COMPUTE_FRAMES(而非仅 COMPUTE_MAXS)的 transformer。COMPUTE_FRAMES 需要类加载器能解析合并后的公共父类/接口,在 classloader 早期可能抛 TypeNotPresentException。

:63 日志前缀 [AngelicaCompat]Extra Transformers: —— 注意是 AngelicaCompat 而非 Angelica,与 StacksOnStacksTransformer 一致,说明这两个「specific」transformer 是从下游 AngelicaCompat 包移植过来的,日志字符串未随移植改名。这是一个可直接观察到的移植痕迹。

已知问题

  1. 字段名硬编码为 renderPass(:75)。源码注释 :73-74 自陈:「目前每一个都恰好叫 renderPass,将来可能需要让名字动态化、并考虑 owner」。上游一旦改名即静默失效。
  2. transformClientUtils 描述符硬编码(:96-98):两条完整描述符字面量,且两个方法的描述符内容完全相同(源文件 :96 与 :97 只有换行差异)。IE 改签名即漏匹配。
  3. break 只处理第一条 IFNULL(:104):若方法里有多个 world != null 检查,只有第一个被改写。
  4. break 在插入后立即退出,而 staticRenderPassPatcher 是全量扫描——两个补丁的遍历策略不一致。
  5. COMPUTE_FRAMES 的早期类加载风险:见上。
  6. 日志里的 AngelicaCompat 前缀误导排障:用户搜 AngelicaCompat 找不到这个 mod。

相关条目