RedirectorTransformer 与 ClassHeirachyManager
基本信息
| 属性 | 值 |
|---|---|
| 转换器 1 | codechicken.lib.asm.RedirectorTransformer |
| 转换器 2 | codechicken.lib.asm.ClassHeirachyManager |
| 注册位置 | CodeChickenCorePlugin.java:63 getASMTransformerClass(),无条件返回 |
| 实现接口 | 均实现 net.minecraft.launchwrapper.IClassTransformer |
两者是本模组仅有的两个无条件注册的 ASM 转换器(getASMTransformerClass() 固定返回这 2 个字符串),与 TweakTransformer、DelegatedTransformer 的条件注册形成对比。
RedirectorTransformer
作用
它做的是一次字节码级 API 兼容:把老版本 CodeChickenLib 中对 CCRenderState 静态字段/静态方法的访问,改写成对 ThreadLocal 实例的访问。
CCRenderState 现在持有 private static final ThreadLocal<CCRenderState> instances = ThreadLocal.withInitial(CCRenderState::new) 与 public static CCRenderState instance()(CCRenderState.java:32、:38-40),并带注释 Backported from CCL - 1.16.x(:25)——即这套实例化设计是从 CCL 1.16 分支回移植到 1.7.10 的。老 mod 编译产物里的 GETSTATIC 一旦对不上现在的实例字段,类加载就会失败,转换器的作用正是在此拦一道。
触发条件
transform()(RedirectorTransformer.java:91-94)先用常量池解析器判断字节码里是否出现过 codechicken/lib/render/CCRenderState 这个 owner(RenderStateClass 常量在 :35),没出现就原样返回。ClassConstantPoolParser 在静态块中以该类名构造(:89)。
重定向目标
三个目标集合在静态块中用 Collections.addAll 填充(RedirectorTransformer.java:44-88),计数经脚本解析核实:
| 集合 | 数量 | 行 | 变换方式 |
|---|---|---|---|
redirectedFields |
25 | :44-70 |
GETSTATIC → 插入 INVOKESTATIC instance() 后改 GETFIELD;PUTSTATIC → 插入 instance() + SWAP 后改 PUTFIELD(:106-127) |
redirectedSimpleMethods |
5 | :72 |
INVOKESTATIC name(...) → 插入 instance() 后改 INVOKEVIRTUAL name**Instance**(...)(:129-138) |
redirectedMethods |
11 | :73-86 |
已是 INVOKEVIRTUAL 的调用保持不变(:139-141 注释:处理已迁移到新 API 的 mod) |
25 个字段名:pipeline、model、firstVertexIndex、lastVertexIndex、vertexIndex、baseColour、alphaOverride、useNormals、computeLighting、useColour、lightMatrix、vert、hasNormal、normal、hasColour、colour、hasBrightness、brightness、side、lc、normalAttrib、colourAttrib、lightCoordAttrib、sideAttrib、lightingAttrib。
5 个简单方法名:reset、pullLightmap、pushLightmap、setDynamic、draw。
11 个方法名:setPipeline、bindModel、setModel、setVertexRange、render、runPipeline、writeVert、setNormal、setColour、setBrightness、startDrawing。
关键实现事实
对 redirectedSimpleMethods,方法名被追加后缀 Instance(:135 mNode.name = mNode.name + "Instance")。已逐个核实这 5 个目标在 CCRenderState 中确实存在:resetInstance、pullLightmapInstance、pushLightmapInstance、setDynamicInstance、drawInstance 各命中 1 处。
而 25 个 redirectedFields 目标在当前 CCRenderState 中已无一是静态字段。对 CCRenderState.java 全文件枚举静态字段声明,只剩两处且都不在重定向列表内:
| 行 | 声明 | 是否在重定向列表 |
|---|---|---|
:32 |
private static final ThreadLocal<CCRenderState> instances |
否 |
:42 |
private static volatile int nextOperationIndex |
否 |
也就是说,字段分支是一层纯粹的历史兼容层,服务于仍持有旧版静态字段字节码的第三方 mod;方法分支则仍在服务当前 API 生态。
调试开关
DUMP_CLASSES 由系统属性 -Dccl.dumpClass 控制(:34),配合 Textifier / TraceClassVisitor 输出反编译文本。
ClassHeirachyManager
codechicken.lib.asm.ClassHeirachyManager(拼写为 Heirachy,非 Hierarchy)是第二个无条件转换器。它的类注释写明用途:“This is added as a class transformer if CodeChickenCore is installed. Adding it as a class transformer will speed evaluation up slightly by automatically caching superclasses when they are first loaded.”(ClassHeirachyManager.java:14-16)
机制:transform()(:27-33)对每个未见过的类名调用 declareASM(),用 ClassReader 读出继承信息存进 ConcurrentHashMap<String, ClassInfo>(:20)。declareReflection()(:41-45)提供反射路径作为补充。
它在本仓内的唯一消费者是 codechicken.lib.asm.CC_ClassWriter:
| 调用 | 行 |
|---|---|
ClassHeirachyManager.classExtends(d, c) |
CC_ClassWriter.java:22 |
ClassHeirachyManager.classExtends(c, d) |
CC_ClassWriter.java:23 |
ClassHeirachyManager.getSuperClass(c, runtime) |
CC_ClassWriter.java:25 |
ClassHeirachyManager.classExtends(d, c) |
CC_ClassWriter.java:26 |
即:写回字节码时需要判断两个类型是否继承相关,缓存避免每次重走反射。CC_ClassWriter 是 ASM 工具包 的一部分。
相关条目
- CodeChickenCorePlugin - 返回这两个转换器的
getASMTransformerClass() - ASM 工具包 -
CC_ClassWriter、ClassConstantPoolParser的所在包 - 渲染管线 -
CCRenderState所属的 API 子系统