diff --git a/src/main/java/org/ultramine/server/UltraminePlugin.java b/src/main/java/org/ultramine/server/UltraminePlugin.java index 1da388b..3a4451e 100644 --- a/src/main/java/org/ultramine/server/UltraminePlugin.java +++ b/src/main/java/org/ultramine/server/UltraminePlugin.java @@ -14,7 +14,9 @@ @Override public String[] getASMTransformerClass() { - return new String[]{}; + return new String[]{ + "org.ultramine.server.asm.transformers.TrigMathTransformer" + }; } @Override diff --git a/src/main/java/org/ultramine/server/asm/transformers/TrigMathTransformer.java b/src/main/java/org/ultramine/server/asm/transformers/TrigMathTransformer.java new file mode 100644 index 0000000..704fa4f --- /dev/null +++ b/src/main/java/org/ultramine/server/asm/transformers/TrigMathTransformer.java @@ -0,0 +1,68 @@ +package org.ultramine.server.asm.transformers; + +import java.util.ListIterator; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; + +import cpw.mods.fml.common.FMLLog; +import net.minecraft.launchwrapper.IClassTransformer; + +public class TrigMathTransformer implements IClassTransformer +{ + private static final Logger log = LogManager.getLogger(); + + private static String TRIGMATH_TYPE = "org/ultramine/server/util/TrigMath"; + private static String MATH_TYPE = "java/lang/Math"; + private static String ATAN2_NAME = "atan2"; + private static String ATAN2_DESC = "(DD)D"; + private static String ATAN_NAME = "atan"; + private static String ATAN_DESC = "(D)D"; + + @Override + public byte[] transform(String name, String transformedName, byte[] basicClass) + { + if (basicClass == null) + return null; + ClassNode classNode = new ClassNode(); + ClassReader classReader = new ClassReader(basicClass); + classReader.accept(classNode, 0); + + for (MethodNode m: classNode.methods) + { + for (ListIterator it = m.instructions.iterator(); it.hasNext(); ) + { + AbstractInsnNode insnNode = it.next(); + if (insnNode.getType() == AbstractInsnNode.METHOD_INSN) + { + MethodInsnNode fi = (MethodInsnNode)insnNode; + if (MATH_TYPE.equals(fi.owner) && ATAN2_NAME.equals(fi.name) && ATAN2_DESC.equals(fi.desc) && fi.getOpcode() == Opcodes.INVOKESTATIC) + { + log.trace("Method {}.{}{}: Replacing INVOKESTATIC Math.atan2 with INVOKESTATIC TrigMath.atan2", name, m.name, m.desc); + it.remove(); + MethodInsnNode replace = new MethodInsnNode(Opcodes.INVOKESTATIC, TRIGMATH_TYPE, ATAN2_NAME, ATAN2_DESC, false); + it.add(replace); + } + + if (MATH_TYPE.equals(fi.owner) && ATAN_NAME.equals(fi.name) && ATAN_DESC.equals(fi.desc) && fi.getOpcode() == Opcodes.INVOKESTATIC) + { + log.trace("Method {}.{}{}: Replacing INVOKESTATIC Math.atan with INVOKESTATIC TrigMath.atan", name, m.name, m.desc); + it.remove(); + MethodInsnNode replace = new MethodInsnNode(Opcodes.INVOKESTATIC, TRIGMATH_TYPE, ATAN_NAME, ATAN_DESC, false); + it.add(replace); + } + } + } + } + ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); + classNode.accept(writer); + return writer.toByteArray(); + } +} diff --git a/src/main/java/org/ultramine/server/util/TrigMath.java b/src/main/java/org/ultramine/server/util/TrigMath.java new file mode 100644 index 0000000..f156b2f --- /dev/null +++ b/src/main/java/org/ultramine/server/util/TrigMath.java @@ -0,0 +1,44 @@ +package org.ultramine.server.util; + +public class TrigMath +{ + static final double sq2p1 = 2.414213562373095048802e0; + static final double sq2m1 = .414213562373095048802e0; + static final double p4 = .161536412982230228262e2; + static final double p3 = .26842548195503973794141e3; + static final double p2 = .11530293515404850115428136e4; + static final double p1 = .178040631643319697105464587e4; + static final double p0 = .89678597403663861959987488e3; + static final double q4 = .5895697050844462222791e2; + static final double q3 = .536265374031215315104235e3; + static final double q2 = .16667838148816337184521798e4; + static final double q1 = .207933497444540981287275926e4; + static final double q0 = .89678597403663861962481162e3; + static final double PIO2 = 1.5707963267948966135E0; + + private static double mxatan(double arg) + { + double argsq = arg * arg; + + return ((((p4 * argsq + p3) * argsq + p2) * argsq + p1) * argsq + p0) / + (((((argsq + q4) * argsq + q3) * argsq + q2) * argsq + q1) * argsq + q0) * arg; + } + + private static double msatan(double arg) + { + return arg < sq2m1 ? mxatan(arg) : arg > sq2p1 ? PIO2 - mxatan(1 / arg) : PIO2 / 2 + mxatan((arg - 1) / (arg + 1)); + } + + public static double atan(double arg) + { + return arg > 0 ? msatan(arg) : -msatan(-arg); + } + + public static double atan2(double arg1, double arg2) + { + if(arg1 + arg2 == arg1) + return arg1 >= 0 ? PIO2 : -PIO2; + arg1 = atan(arg1 / arg2); + return arg2 < 0 ? arg1 <= 0 ? arg1 + Math.PI : arg1 - Math.PI : arg1; + } +}