CodeChickenCoreTransformer
基本信息
| 属性 | 值 |
|---|---|
| 类 | com.mitchej123.jarjar.rfb.transformer.CodeChickenCoreTransformer |
| Transformer ID | jarjar-codechickencoreTransformer |
| 目标类 | codechicken.core.ClassDiscoverer |
| 改写方法 | findClasspathMods |
CodeChickenCore 的 ClassDiscoverer 在 1.7.10 modpack 里会被多次触发——它会扫描 classpath 上的 jar/zip 并把它们加入 NEI / 其它的 discovery。JarJar 已经处理过 <mc>/mods/,不希望 CCC 又把这些 jar 当作"classpath mod"二次加载。
修改模式
原版 findClasspathMods 形如:
if (!knownLibraries.contains(minecraftSource.getName())) {
// 把这个 jar 当作 classpath mod 加入
}
JarJar 在第一个 ifne 后注入:
&& Hooks.shouldIgnore(minecraftSource)
使得"已知库"或"JarJar 禁用"的 jar 直接跳过。
ASM 模式匹配
for (final MethodNode mn : cn.methods) {
if (!mn.name.equals("findClasspathMods")) continue;
AbstractInsnNode insn = mn.instructions.getFirst();
while (insn != null) {
if (insn.getOpcode() == Opcodes.INVOKEVIRTUAL && insn instanceof MethodInsnNode mInsn
&& mInsn.owner.equals("java/io/File") && mInsn.name.equals("getName")) {
final int fileVar = ((VarInsnNode)(insn.getPrevious())).var;
insn = insn.getNext();
if (!(insn instanceof MethodInsnNode)) continue;
mInsn = (MethodInsnNode) insn;
if (!mInsn.owner.equals("java/util/List") && mInsn.name.equals("contains")) continue;
insn = insn.getNext();
if (!(insn.getOpcode() == Opcodes.IFNE && insn instanceof JumpInsnNode jInsnNode)) continue;
final LabelNode ifneJumpLabel = jInsnNode.label;
insn = insn.getNext(); // label
mn.instructions.insertBefore(insn, new VarInsnNode(Opcodes.ALOAD, fileVar));
insn = insn.getNext(); // linenumber
insn = insn.getNext(); // LDC
mn.instructions.insertBefore(
insn,
new MethodInsnNode(Opcodes.INVOKESTATIC, "com/mitchej123/jarjar/util/Hooks", "shouldIgnore", "(Ljava/io/File;)Z", false));
mn.instructions.insertBefore(insn, new JumpInsnNode(Opcodes.IFEQ, ifneJumpLabel));
break;
}
insn = insn.getNext();
}
}
按字节码顺序找到 INVOKEVIRTUAL java/io/File.getName() → 紧邻的 INVOKEVIRTUAL java/util/List.contains(...) → 紧邻的 IFNE <label>,把 IFNE <label> 之后插入 ALOAD fileVar + INVOKESTATIC Hooks.shouldIgnore + IFEQ <label>。效果是:
if (!knownLibraries.contains(file.getName()) && !Hooks.shouldIgnore(file)) { ... }
Hooks.shouldIgnore 实现:
public static boolean shouldIgnore(File file) {
return DefaultLibraries.isDefaultLibrary(file) || DirectoryModCandidateFinder.getDisabledFiles().contains(file.getName());
}
相关条目
- RFB 插件入口 - 注册该 transformer
- Hooks 跨 transformer 钩子 -
shouldIgnore实现 - DefaultLibraries 过滤 - 已知库前缀列表
- DirectoryModCandidateFinder - 已禁用文件集合