IsbrhTessellatorAbuseTransform

基本信息

属性 值
类 com.gtnewhorizons.angelica.loading.shared.transformers.IsbrhTessellatorAbuseTransform
路径 src/main/java/com/gtnewhorizons/angelica/loading/shared/transformers/IsbrhTessellatorAbuseTransform.java
行数 73
类型 public final class(:12)
公开常量 ISBRH = "cpw/mods/fml/client/registry/ISimpleBlockRenderingHandler"(:15)
驱动者 IsbrhTessellatorAbuseTransformer + RFBIsbrhTessellatorAbuseTransformer

它是什么

处理「ISBRH 滥用 Tessellator」的核心变换。问题是 1.7.10 的 ISimpleBlockRenderingHandler#renderWorldBlock 运行在区块构建线程上,而 Tessellator 是全局共享单例(Tessellator.instance)。任何在 ISBRH 里直接用 Tessellator.instance.draw() / startDrawingQuads() / startDrawing() 的 mod,在多线程下会互相踩踏缓冲区。

关键常量

常量 值 行
ISBRH cpw/mods/fml/client/registry/ISimpleBlockRenderingHandler :15
CST_POOL_PARSER new ClassConstantPoolParser(ISBRH) :18
TESSELLATOR net/minecraft/client/renderer/Tessellator :19
RENDER_WORLD_BLOCK_DESC (Lnet/minecraft/world/IBlockAccess;IIILnet/minecraft/block/Block;ILnet/minecraft/client/renderer/RenderBlocks;)Z :20

两个公开方法

shouldTransform(:22-24)

return CST_POOL_PARSER.find(classBytes); —— 扫常量池找 ISBRH 引用。这是预筛选,两个 wrapper 各自在 transform 早期调用。

transformClassNode(:26-73)

第 1 步:定位目标方法(:27-34)

for (int i = 0, n = cn.methods.size(); i < n; i++) {
    final MethodNode mn = cn.methods.get(i);
    if ("renderWorldBlock".equals(mn.name) && RENDER_WORLD_BLOCK_DESC.equals(mn.desc)) { target = mn; break; }
}
if (target == null) return false;

要求方法名与完整描述符逐字符匹配。找不到就 false。

第 2 步:混淆名解析(:36-38)

逻辑名 混淆名(isObf = true)
draw func_78381_a
startDrawingQuads func_78382_b
startDrawing func_78371_b

第 3 步:改写(:40-73)

单趟遍历目标方法的指令,对每个 INVOKEVIRTUAL 且 owner == TESSELLATOR 的调用点,根据其名字与描述符决定插入的栈平衡指令与返回值压栈指令。:48 起用 popOp / pushIntResult 两个变量承载这个决策。

两条路径调用同一个 isObf 参数

Wrapper isObf 来源 时机
IsbrhTessellatorAbuseTransformer AngelicaClientTweaker.isObfEnv()(:23),每次 transform 现问 类加载期
RFBIsbrhTessellatorAbuseTransformer 构造期存入字段(:19、:23) plugin 构造期

已知问题

  1. RENDER_WORLD_BLOCK_DESC 硬编码为 1.7.10 原版签名:任何以不同描述符覆写 renderWorldBlock 的 mod(例如自行加了参数)完全不被处理,且无日志。
  2. 只处理 INVOKEVIRTUAL(:42):若某 mod 通过 INVOKESTATIC 转发或通过 Tessellator.getInstance() 之类的静态方法获取实例,本变换漏改。
  3. popOp/pushIntResult 决策逻辑(:48 起)在源文件里跨越 25 行且被截断于我的读取窗口;从可读部分能确认它按被调方法的返回类型决定栈平衡方式,但完整的 4 分支映射未在源码注释中列出,属于可读性较差的 ASM 代码。
  4. CST_POOL_PARSER 是 static final(:18):常量池扫描器全局共享,无状态问题,但线程安全性取决于 gtnhlib 实现。
  5. 无类级 Javadoc:public final class 后直接是常量。文件名已说明用途,但「为什么滥用 Tessellator 会出问题」这一背景在本文件里没有任何记录。

相关条目