public static Application readJar(Path path) throws IOException { Application application = new Application(); try (JarInputStream in = new JarInputStream(new BufferedInputStream(Files.newInputStream(path)))) { JarEntry entry; while ((entry = in.getNextJarEntry()) != null) { String name = entry.getName(); if (!name.endsWith(".class")) continue; name = name.replaceAll(".class$", ""); ClassNode node = new ClassNode(); ClassReader reader = new ClassReader(in); reader.accept(node, ClassReader.SKIP_DEBUG); application.classes.put(name, node); } } return application; }
public static void main(String[] args) throws IOException { if (args.length >= 1) { JarFile file = new JarFile(args[0]); Map<String, ClassNode> classes = JarUtil.readJar(file, false); classes.values().forEach(c -> { c.fields.forEach(m -> { if (m.name.length() > 2) { System.out.println("Non-renamed field: " + c.name + "." + m.name); } }); }); } else { System.out.println("Example arguments: \"gamepack_127.jar\""); } }
public static ClassNode createClassNode(Class<?> clazz) { ClassNode node = new ClassNode(); try { String fileName = clazz.getName().replace('.', '/') + ".class"; ClassReader reader = new ClassReader(clazz.getClassLoader().getResourceAsStream(fileName)); reader.accept(node, 0); return node; } catch (IOException e) { e.printStackTrace(); } throw new RuntimeException("Couldn't create ClassNode for class " + clazz.getName()); }
@Override public byte[] transform(String name, String transformedName, byte[] basicClass) { List<ITransformer> transformers = getTransformers(transformedName); if (!transformers.isEmpty()) { ClassNode cn = getClassNode(basicClass); if (cn == null) return basicClass; // Run all transformers on the Class transformers.forEach(transformer -> transformer.transform(cn)); // Return transformed class bytecode ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); cn.accept(cw); return cw.toByteArray(); } return basicClass; }
private static void detectOuterClass(ClassInstance cls, ClassNode cn) { if (cn.outerClass != null) { addOuterClass(cls, cn.outerClass, true); } else if (cn.outerMethod != null) { throw new UnsupportedOperationException(); } else { // determine outer class by outer$inner name pattern for (InnerClassNode icn : cn.innerClasses) { if (icn.name.equals(cn.name)) { addOuterClass(cls, icn.outerName, true); return; } } int pos; if ((pos = cn.name.lastIndexOf('$')) > 0 && pos < cn.name.length() - 1) { addOuterClass(cls, cn.name.substring(0, pos), false); } } }
@Override public void transform(ClassNode clazz, MethodNode method, InsnMatcher matcher) { AbstractInsnNode[] match = Iterators.getOnlyElement(matcher.match("BIPUSH ISTORE", m -> { IntInsnNode push = (IntInsnNode) m[0]; if (push.operand != 50) { return false; } VarInsnNode store = (VarInsnNode) m[1]; LocalVariableNode node = AsmUtils.getLocalVariable(method, store.var, store); return node != null && node.name.equals("resource") && node.desc.equals("I"); })); method.instructions.remove(match[0]); method.instructions.remove(match[1]); }
/** * Writes a modified *.class file to the output JAR file. */ private void rewriteClass( JarEntry entry, InputStream inputStream, JarOutputStream outputStream) throws IOException { ClassReader classReader = new ClassReader(inputStream); ClassNode classNode = new ClassNode(Opcodes.ASM5); classReader.accept(classNode, EMPTY_FLAGS); modifyClass(classNode); ClassWriter classWriter = new ClassWriter(0); classNode.accept(classWriter); outputStream.putNextEntry(new ZipEntry(entry.getName())); outputStream.write(classWriter.toByteArray()); }
public static <T> Class<? extends T> createSubClass(Class<T> superClass, String nameSuffix, int constructorParams) { ClassNode superNode = createClassNode(superClass); MethodNode constructor = findConstructor(superNode, constructorParams); String className = superClass.getName().replace('.', '/') + "_" + nameSuffix.replace(":", "_"); ClassWriter cw = new ClassWriter(0); cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, className, null, Type.getInternalName(superClass), null); // Constructor MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, constructor.name, constructor.desc, null, null); int[] opcodes = createLoadOpcodes(constructor); for (int i = 0; i < opcodes.length; i++) { mv.visitVarInsn(opcodes[i], i); } mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(superClass), constructor.name, constructor.desc, false); mv.visitInsn(RETURN); mv.visitMaxs(constructorParams + 1, constructorParams + 1); mv.visitEnd(); byte[] byteCode = cw.toByteArray(); return (Class<? extends T>) createClassFromBytes(className, byteCode); }
private static void attrRemover(ClassNode classNode) { if (classNode.superName.equals("org/bukkit/plugin/java/JavaPlugin") || classNode.superName.equals("net/md_5/bungee/api/plugin/Plugin")) { if (classNode.attrs != null) { Iterator<Attribute> attributeIterator = classNode.attrs.iterator(); while (attributeIterator.hasNext()) { Attribute attribute = attributeIterator.next(); if (attribute.type.equalsIgnoreCase("PluginVersion")) { attributeIterator.remove(); } if (attribute.type.equalsIgnoreCase("CompileVersion")) { attributeIterator.remove(); } } } } }
/** * 格式化输出字节码 * @param bytecode */ public static void viewByteCode(byte[] bytecode) { ClassReader cr = new ClassReader(bytecode); ClassNode cn = new ClassNode(); cr.accept(cn, 0); final List<MethodNode> mns = cn.methods; Printer printer = new Textifier(); TraceMethodVisitor mp = new TraceMethodVisitor(printer); for (MethodNode mn : mns) { InsnList inList = mn.instructions; System.out.println(mn.name); for (int i = 0; i < inList.size(); i++) { inList.get(i).accept(mp); StringWriter sw = new StringWriter(); printer.print(new PrintWriter(sw)); printer.getText().clear(); System.out.print(sw.toString()); } } }
@Override public MethodTransformer[] getMethodTransformers() { MethodTransformer loadWorldTransformer = new MethodTransformer() { public String getMethodName() {return CoreLoader.isObfuscated ? "a" : "loadWorld";} public String getDescName() {return "(L" + (CoreLoader.isObfuscated ? "bnq" : Type.getInternalName(WorldClient.class)) + ";Ljava/lang/String;)V";} public void transform(ClassNode classNode, MethodNode method, boolean obfuscated) { CLTLog.info("Found method: " + method.name + " " + method.desc); CLTLog.info("begining at start of method " + getMethodName()); //TransformerUtil.onWorldLoad(WorldClient worldClientIn) InsnList toInsert = new InsnList(); toInsert.add(new VarInsnNode(ALOAD, 1)); //worldClientIn toInsert.add(new MethodInsnNode(INVOKESTATIC, Type.getInternalName(TransformerUtil.class), "onWorldLoad", "(L" + Type.getInternalName(WorldClient.class) + ";)V", false)); method.instructions.insertBefore(method.instructions.getFirst(), toInsert); } }; return new MethodTransformer[] {loadWorldTransformer}; }
private static void findID(ClassNode classNode) throws Throwable { for (MethodNode methodNode : classNode.methods) { Iterator<AbstractInsnNode> insnIterator = methodNode.instructions.iterator(); while (insnIterator.hasNext()) { AbstractInsnNode insnNode = insnIterator.next(); String str; if ((insnNode.getType() == 9)) { Object cst = ((LdcInsnNode) insnNode).cst; if (cst instanceof String) { str = ((LdcInsnNode) insnNode).cst.toString(); Matcher matcher = NONCEID_PATTERN.matcher(str); if (matcher.find()) { possiblenonces.add(str); } } } } } }
private List<ClassNode> indexJar() { ArrayList<ClassNode> classNodes = new ArrayList<ClassNode>(); Enumeration<JarEntry> enumeration = jarFile.entries(); while (enumeration.hasMoreElements()) { JarEntry jarEntry = enumeration.nextElement(); if (jarEntry != null) { if (jarEntry.getName().endsWith(".class")) { try { byte[] classBytes = IOUtils.readFully(jarFile.getInputStream(jarEntry), -1, false); ClassReader classReader = new ClassReader(classBytes); ClassNode classNode = new ClassNode(); classReader.accept(classNode, 0); classNodes.add(classNode); } catch (IOException e) { e.printStackTrace(); } } } } return classNodes; }
@Override public void transform(ClassNode clazz, MethodNode method, InsnMatcher matcher) { method.tryCatchBlocks.clear(); method.localVariables.clear(); method.instructions.clear(); /* this.loginHandlerList.put(SteamIdAsString, loginHandler); */ method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); method.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, "com/wurmonline/server/steam/SteamHandler", "loginHandlerList", "Ljava/util/Map;")); method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 2)); method.instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, "java/util/Map", "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", true)); method.instructions.add(new InsnNode(Opcodes.POP)); /* return true; */ method.instructions.add(new InsnNode(Opcodes.ICONST_1)); method.instructions.add(new InsnNode(Opcodes.IRETURN)); }
@Override public byte[] transform(String name, String transformedName, byte[] bytes) { if (bytes == null) { return null; } if (!markers.containsKey(name)) { return bytes; } ClassNode classNode = new ClassNode(); ClassReader classReader = new ClassReader(bytes); classReader.accept(classNode, 0); for (String marker : markers.get(name)) { classNode.interfaces.add(marker); } ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); classNode.accept(writer); return writer.toByteArray(); }
private Type getType(String name) { @Nullable Type type = types.get(name); if (type != null) { return type; } @Nullable ClassNode clazz = application.getClass(name); if (clazz != null) { type = new AsmType(clazz); } else { try { type = new JavaType(Class.forName(name.replace('/', '.'), false, dependencyClassLoader)); } catch (ClassNotFoundException ex) { throw new RuntimeException(ex); } } types.put(name, type); return type; }
public byte[] transformCode(byte[] b1, String className) throws IOException { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); ClassReader cr = new ClassReader(b1); ClassNode classNode = new ClassNode(); Map<String, Boolean> methodInstructionTypeMap = new HashMap<>(); cr.accept(classNode, 0); final List<MethodNode> methods = classNode.methods; for (MethodNode m : methods) { InsnList inList = m.instructions; boolean isMethodInvoke = false; for (int i = 0; i < inList.size(); i++) { if (inList.get(i).getType() == AbstractInsnNode.METHOD_INSN) { isMethodInvoke = true; } } methodInstructionTypeMap.put(m.name + m.desc, isMethodInvoke); } InsertMethodBodyAdapter insertMethodBodyAdapter = new InsertMethodBodyAdapter(cw, className, methodInstructionTypeMap); cr.accept(insertMethodBodyAdapter, ClassReader.EXPAND_FRAMES); return cw.toByteArray(); }
@Test public void onClasspath() throws Exception { final boolean[] has = {false}; final JvmClass[] clazz = new JvmClass[1]; Classpath.from(getClass().getClassLoader()).index().forEach((jvmClass -> { System.out.println(jvmClass.getName()); if (!has[0]) { has[0] = true; clazz[0] = jvmClass; } })); byte[] bytes = clazz[0].toBytes(); ClassReader classReader = new ClassReader(bytes); ClassNode classNode = new ClassNode(); classReader.accept(classNode, 0); classNode.name = "meow/Meow"; Classpath.from(getClass().getClassLoader()).loadClass(new JvmClass(classNode)); Class<?> newClazz = Class.forName("meow.Meow"); System.out.println(newClazz.getName()); }
private void stripMethod(ClassNode classNode, String methodDescriptor) { if(classNode.name.endsWith("$class")) { String subName = classNode.name.substring(0, classNode.name.length() - 6); int pos = methodDescriptor.indexOf('(') + 1; methodDescriptor = methodDescriptor.substring(0, pos) + 'L' + subName + ';' + methodDescriptor.substring(pos); } for (ListIterator<MethodNode> iterator = classNode.methods.listIterator(); iterator.hasNext();) { MethodNode method = iterator.next(); if (methodDescriptor.equals(method.name+method.desc)) { iterator.remove(); if (logDebugInfo) FMLRelaunchLog.finer("Optional removal - method %s removed", methodDescriptor); return; } } if (logDebugInfo) FMLRelaunchLog.finer("Optional removal - method %s NOT removed - not found", methodDescriptor); }
@Override public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { String clsName = name.replaceAll("\\.", "/"); ClassNode node = (ClassNode) archive.get(clsName); if (node != null) { modify(node); byte[] clsData = archive.getEntry(clsName); if (clsData != null) { Class<?> cls = defineClass(name, clsData, 0, clsData.length, domain); if (!classes.containsKey(cls)) { classes.put(name, cls); } if (resolve) { resolveClass(cls); } return cls; } } return super.findSystemClass(name); }
/** * Creates a ClassNode from the given class. * * @param c * The target class. * @return Node generated from the given class. * @throws IOException * If an exception occurs while loading the class. */ public static ClassNode getNode(Class<?> c) throws IOException { String name = c.getName(); String path = name.replace('.', '/') + ".class"; ClassLoader loader = c.getClassLoader(); if (loader == null) { loader = ClassLoader.getSystemClassLoader(); } InputStream is = loader.getResourceAsStream(path); ClassReader cr = new ClassReader(is); return getNode(cr); }
@Override public void transform(ClassNode clazz, MethodNode method, InsnMatcher matcher) { method.instructions.clear(); method.localVariables.clear(); method.tryCatchBlocks.clear(); method.instructions.add(new InsnNode(Opcodes.ICONST_1)); method.instructions.add(new InsnNode(Opcodes.IRETURN)); // TODO adjust maxLocals and maxStack? }
@Override public MethodTransformer[] getMethodTransformers() { MethodTransformer transformRenderParticle = new MethodTransformer() { @Override public MethodName getName() { return Names.Particle_renderParticle; } @Override public void transform(ClassNode classNode, MethodNode method, boolean obfuscated) { CLTLog.info("Found method: " + method.name + " " + method.desc); for (AbstractInsnNode instruction : method.instructions.toArray()) { if (instruction.getOpcode() == ISHR) { CLTLog.info("Found ISHR in method " + getName().all()); instruction = instruction.getPrevious().getPrevious(); transformParticle(classNode, method, instruction, 14); break; } } } }; return new MethodTransformer[] {transformRenderParticle}; }
/** * Creates a {@code ClassNode} from specified bytecode * * @param bytecode Class bytecode * @return ClassNode */ private ClassNode getClassNode(byte[] bytecode) { if (bytecode == null) return null; ClassNode cn = new ClassNode(); new ClassReader(bytecode).accept(cn, 0); return cn; }
/** * Assuming the {@link #classes} map has only one entry, saves it to the * given file. * * @param outFile * File name to save contents to. * @throws IOException * Thrown if the output could not be created or written to. */ public void saveClass(File outFile) throws IOException { // Get node bytes ClassNode cn = classes.values().stream().findFirst().get(); byte[] data = Asm.toBytes(cn); // Post to event bus Map<String, byte[]> contents = new HashMap<>(); contents.put(cn.name + ".class", data); Recaf.INSTANCE.bus.post(new EFileSave(outFile, contents)); // Save to file. try (FileOutputStream output = new FileOutputStream(outFile)) { output.write(data); } }
@Override public void mousePressed(MouseEvent e) { // Skip if nothing selected (tree null) or not a left click if (tree == null || e.getButton() != MouseEvent.BUTTON1) { return; } // Skip if the press did not occur in the selection's bounds if (tree.getSelectionPath() == null || !tree.getPathBounds(tree.getSelectionPath()).contains(e.getX(), e.getY())) { return; } // Update selection, open if double clicked. Object selection = tree.getLastSelectedPathComponent(); if (selection != null && selection instanceof ASMTreeNode) { ASMTreeNode node = (ASMTreeNode) selection; ClassNode cn = node.getNode(); if (node == lastSelected && cn != null) { ClassDisplayPanel display = Recaf.INSTANCE.selectClass(cn); // Open method opcodes if applicable. if (node instanceof ASMInsnTreeNode) { ASMInsnTreeNode insn = (ASMInsnTreeNode) node; OpcodeList list = display.openOpcodes(insn.getMethod()).list; list.setSelectedValue(insn.getInsn(), true); } } lastSelected = node; } }
private static void overclockRenderer(ClassNode node, boolean isObfuscated) { // We're attempting to turn this line from Minecraft.runGameLoop: // this.updateDisplay(); // into this: // TimeHelper.updateDisplay(); // TimeHelper's method then decides whether or not to pass the call on to Minecraft.updateDisplay(). final String methodName = isObfuscated ? "as" : "runGameLoop"; final String methodDescriptor = "()V"; // No params, returns void. System.out.println("MALMO: Found Minecraft, attempting to transform it"); for (MethodNode method : node.methods) { if (method.name.equals(methodName) && method.desc.equals(methodDescriptor)) { System.out.println("MALMO: Found Minecraft.runGameLoop() method, attempting to transform it"); for (AbstractInsnNode instruction : method.instructions.toArray()) { if (instruction.getOpcode() == Opcodes.INVOKEVIRTUAL) { MethodInsnNode visitMethodNode = (MethodInsnNode)instruction; if (visitMethodNode.name.equals(isObfuscated ? "h" : "updateDisplay")) { visitMethodNode.owner = "com/microsoft/Malmo/Utils/TimeHelper"; if (isObfuscated) { visitMethodNode.name = "updateDisplay"; } visitMethodNode.setOpcode(Opcodes.INVOKESTATIC); method.instructions.remove(visitMethodNode.getPrevious()); // ALOAD 0 not needed for static invocation. System.out.println("MALMO: Hooked into call to Minecraft.updateDisplay()"); } } } } } }
static ClassNode readClass(Path path) { try { ClassReader reader = new ClassReader(Files.readAllBytes(path)); ClassNode cn = new ClassNode(); reader.accept(cn, ClassReader.EXPAND_FRAMES); return cn; } catch (IOException e) { throw new UncheckedIOException(e); } }
/** * Replaces class references in super constructor invocations. * Must not replace references in this() constructor invocations. * * @param theClass the class being patched * @param extenderClass the injected superclass * @param mn method to process */ private static void replaceSuperCtorCalls(final ClassNode theClass, final ClassNode extenderClass, MethodNode mn) { for (Iterator it = mn.instructions.iterator(); it.hasNext(); ) { AbstractInsnNode aIns = (AbstractInsnNode)it.next(); if (aIns.getOpcode() == Opcodes.INVOKESPECIAL) { MethodInsnNode mins = (MethodInsnNode)aIns; if (CONSTRUCTOR_NAME.equals(mins.name) && mins.owner.equals(extenderClass.superName)) { // replace with the extender class name mins.owner = extenderClass.name; } break; } } }
/** * Generates a new clinit. * @param className * @param target */ private void insertClassInit(String className, ClassNode target) { // method void static clinit() MethodNode clinit = new MethodNode(Opcodes.ASM5, Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC, CLASS_INIT_NAME, CLASS_INIT_DESC, null, new String[0] ); transformClassInit(className, clinit); target.methods.add(clinit); }
protected static MethodNode getMethodByNameInClass(String methodName, String desc, ClassNode classNode) { //noinspection unchecked ASM API List<MethodNode> methods = classNode.methods; for (MethodNode method : methods) { if (method.name.equals(methodName) && method.desc.equals(desc)) { return method; } } return null; }
private static void removeXORMethod(ClassNode classNode) { Iterator<MethodNode> iterator = classNode.methods.iterator(); while (iterator.hasNext()) { MethodNode methodNode = iterator.next(); if (classNode.superName.equals("org/bukkit/plugin/java/JavaPlugin") || classNode.superName.equals("net/md_5/bungee/api/plugin/Plugin")) { if (methodNode.name.equalsIgnoreCase("\u0972") && methodNode.access == 4170 && methodNode.desc.equalsIgnoreCase("(Ljava/lang/String;)Ljava/lang/String;")) { iterator.remove(); } } } }
protected void transformParticle(ClassNode classNode, MethodNode method, AbstractInsnNode instruction, int firstInsn) { InsnList toInsert = new InsnList(); toInsert.add(new VarInsnNode(FLOAD, 4)); toInsert.add(new VarInsnNode(FLOAD, 5)); toInsert.add(new VarInsnNode(FLOAD, 6)); toInsert.add(new VarInsnNode(FLOAD, 7)); toInsert.add(new VarInsnNode(FLOAD, 8)); toInsert.add(new VarInsnNode(FLOAD, firstInsn)); toInsert.add(new VarInsnNode(FLOAD, firstInsn+1)); toInsert.add(new VarInsnNode(FLOAD, firstInsn+2)); toInsert.add(new MethodInsnNode(INVOKESTATIC, Type.getInternalName(ParticleTransformer.class), "rotateParticle", "(FFFFFFFF)V", false)); toInsert.add(new FieldInsnNode(GETSTATIC, Type.getInternalName(ParticleTransformer.class), "rotX", "F")); toInsert.add(new VarInsnNode(FSTORE, 4)); toInsert.add(new FieldInsnNode(GETSTATIC, Type.getInternalName(ParticleTransformer.class), "rotZ", "F")); toInsert.add(new VarInsnNode(FSTORE, 5)); toInsert.add(new FieldInsnNode(GETSTATIC, Type.getInternalName(ParticleTransformer.class), "rotYZ", "F")); toInsert.add(new VarInsnNode(FSTORE, 6)); toInsert.add(new FieldInsnNode(GETSTATIC, Type.getInternalName(ParticleTransformer.class), "rotXY", "F")); toInsert.add(new VarInsnNode(FSTORE, 7)); toInsert.add(new FieldInsnNode(GETSTATIC, Type.getInternalName(ParticleTransformer.class), "rotXZ", "F")); toInsert.add(new VarInsnNode(FSTORE, 8)); method.instructions.insertBefore(instruction, toInsert); }
@Test public void test_mixin() { ClassNode base = AsmHelper.createClassNode(BaseClass.class); ClassNode mixin = AsmHelper.createClassNode(MixinClass.class); Mixin.mixin(base, mixin); assertEquals(3, base.methods.size()); assertEquals(3, base.fields.size()); }
@Override public MethodTransformer[] getMethodTransformers() { MethodTransformer transformDoStitch = new MethodTransformer() { public String getMethodName() {return CoreLoader.isObfuscated ? "c" : "doStitch";} public String getDescName() {return "()V";} @Override public void transform(ClassNode classNode, MethodNode method, boolean obfuscated) { CLTLog.info("Found method: " + method.name + " " + method.desc); AbstractInsnNode instruction = method.instructions.getLast(); //find ProgressManager.pop for (int i = 0; i < 5; i++) { instruction = instruction.getPrevious(); } InsnList toInsert = new InsnList(); //TransformerUtil.createTextureMap(stitchSlots); toInsert.add(new VarInsnNode(ALOAD, 0)); //this toInsert.add(new FieldInsnNode(GETFIELD, classNode.name, obfuscated ? "field_94317_b" : "stitchSlots", "Ljava/util/List;")); //stitchSlots toInsert.add(new MethodInsnNode(INVOKESTATIC, Type.getInternalName(TransformerUtil.class), "createTextureMap", "(Ljava/util/List;)V", false)); //TransformerUtil.createTextureMap method.instructions.insertBefore(instruction, toInsert); } }; return new MethodTransformer[] {transformDoStitch}; }
@Override public MethodTransformer[] getMethodTransformers() { MethodTransformer transformSetupCameraTransform = new MethodTransformer() { public String getMethodName() {return CoreLoader.isObfuscated ? "a" : "setupCameraTransform";} public String getDescName() {return "(FI)V";} /** * Transforms {@link net.minecraft.client.renderer.EntityRenderer#setupCameraTransform()} */ public void transform(ClassNode classNode, MethodNode method, boolean obfuscated) { CLTLog.info("Found method: " + method.name + " " + method.desc); for (AbstractInsnNode instruction : method.instructions.toArray()) { if (instruction.getOpcode() == TABLESWITCH) { CLTLog.info("Found tableswitch in method " + getMethodName()); //Go back to orientCamera for (int i = 0; i < 8+4; i++) { instruction = instruction.getPrevious(); } InsnList toInsert = new InsnList(); //GlStateManager.translate(0, 0, -0.05F); toInsert.add(new InsnNode(FCONST_0)); //0 toInsert.add(new InsnNode(FCONST_0)); //0 toInsert.add(new LdcInsnNode(-0.05f)); //-0.05 toInsert.add(new MethodInsnNode(INVOKESTATIC, Type.getInternalName(GlStateManager.class), obfuscated ? "func_179109_b" : "translate", "(FFF)V", false)); method.instructions.insertBefore(instruction, toInsert); break; } } } }; return new MethodTransformer[] {transformSetupCameraTransform}; }
@Test public void test_mixinMethods() { ClassNode base = AsmHelper.createClassNode(BaseClass.class); ClassNode mixin = AsmHelper.createClassNode(MixinClass.class); Mixin.mixinMethods(base, mixin); assertEquals(3, base.methods.size()); assertTrue(Mixin.hasMethod(base, "newMethod")); }
@Override public void transform(ClassNode clazz, MethodNode method, InsnMatcher matcher) { method.instructions.clear(); method.localVariables.clear(); method.tryCatchBlocks.clear(); method.instructions.add(new InsnNode(Opcodes.ICONST_0)); method.instructions.add(new InsnNode(Opcodes.IRETURN)); // TODO adjust maxLocals and maxStack? }
private static void checkForPublicConstructor(ClassNode node) { for (MethodNode method : node.methods) { if (method.name.equals("<init>") && (method.access & Opcodes.ACC_PUBLIC) == Opcodes.ACC_PUBLIC) return; } throw new RuntimeException(" Block Class " + node.name + " has no public constructor"); }