Transformer
基本信息
| 属性 | 值 |
|---|---|
| 类名 | sedridor.forgeamidst.Transformer |
| 文件 | src/main/java/sedridor/forgeamidst/Transformer.java |
| 行数 | 99 |
| 实现 | IClassTransformer |
| 注册于 | CorePlugin |
| 启用版本 | Minecraft 1.7.10 |
功能
给 Climate Control 打补丁,使其在生成世界后回调 MapWorldRTG 以完成 RTG 兼容。
目标类
private final String class1 = "climateControl.DimensionManager";
| 项 | 值 |
|---|---|
| 目标类 | climateControl.DimensionManager |
| 目标方法 | onCreateSpawn |
| 描述符 | (Lnet/minecraftforge/event/world/WorldEvent$CreateSpawnPosition;)V |
| 注入内容 | 调用 sedridor/forgeamidst/MapWorldRTG.updateGenLayers(GenLayerRiverMixWrapper) |
transform(String name, String newName, byte[] bytes)
if (newName.equals("climateControl.DimensionManager")
&& !classesPatched.containsKey("climateControl.DimensionManager")) {
classesPatched.put("climateControl.DimensionManager", true);
return transform1(bytes, !name.equals(newName));
}
return bytes;
| 机制 | 说明 |
|---|---|
classesPatched |
LinkedHashMap<String, Boolean>,幂等保护 —— 每个目标类只 patch 一次 |
匹配 newName |
而非 name —— 兼容混淆态 |
obfuscated 实参 |
!name.equals(newName) —— dev 态两者相同即 false |
⚠️ 注入点靠硬编码字节码偏移
if (targetNode.getOpcode() == 182 && index == 49) { … }
⚠️ 注入位置由 index == 49(指令流第 49 条)硬编码确定,
再按 opcode == 182(INVOKESTATIC)复核。
这是一个极其脆弱的依赖 —— Climate Control 任何改动
(哪怕只是增删一条指令)都会让偏移错位,导致:
- 注入到错误位置 → 运行时
VerifyError/NoSuchMethodError;或 - 静默不匹配 → 补丁不生效,RTG 兼容失效但不报错。
类中无版本检查、无偏移校验、无回退逻辑。
注入的指令序列
在 onCreateSpawn 的目标位置前插入 5 条指令:
| 序 | 指令 | 作用 |
|---|---|---|
| 1 | VarInsnNode(25, 0) |
压入局部变量 0(this / this$0) |
| 2 | InsnNode(3) |
POP —— 消耗掉刚压入的值 |
| 3 | MethodInsnNode(183, "climateControl/DimensionManager", "riverLayerWrapper", "(I)LclimateControl/customGenLayer/GenLayerRiverMixWrapper;") |
取河道层包装器 |
| 4 | MethodInsnNode(182, "sedridor/forgeamidst/MapWorldRTG", "updateGenLayers", "(LclimateControl/customGenLayer/GenLayerRiverMixWrapper;)V") |
实际调用点 |
| 5 | — | MethodInsnNode(25,0) 等,见源码 toInject |
⚠️ 指令 1 + 2(ALOAD 0 后立刻 POP)是空操作占位 ——
真正的入参是第 3 步的 riverLayerWrapper 返回值。
读字节码时容易误以为传的是 this。
实现要点
ClassWriter(3)—— 参数3是COMPUTE_MAXS; 未用COMPUTE_FRAMES(4),因为 1.7.10 目标字节码无 StackMapTable 需求。ClassReader.accept(classN, 0)—— 解析参数0表示不做帧展开。- 目标类需实现
sedridor/forgeamidst/MapWorldRTG中的updateGenLayers, 该类见 MapWorldRTG。
⚠️ 无 fallback
本 transformer 没有「目标类不存在则跳过」的显式判断 ——
newName.equals(...) 不匹配时自然走 return bytes,
即 Climate Control 缺席时安全无副作用(因为 modid 依赖是 after: 软依赖)。
这是本 mod 能在无 Climate Control 环境下启动的原因。
关联
- CorePlugin - 注册方
- MapWorldRTG - 注入调用的目标
- ForgeAmidst - 同 jar 的 FML mod
- Climate Control - 被 patch 的类(已登记未成文)