Hi.
I am trying to write a small coremod for my 1.12.2 private server to disable the "Moved wrongly" and maybe the "Moved too quickly" checks in NetHandlerPlayServer, as it is very buggy with Psi's Blink-spell, just teleports you back constantly.
First of all, I know this is a security risk because of hacking, but as I said, it's a private server so I don't care about that.
Second, I sadly don't have much experience in modding Minecraft and especially not in bytecode and that sort of stuff in Java.
So I got most of the code from this post and just tried to update it for 1.12.2.
But according to the printlns I added in analyzeClass the methods I need to patch (processVehicleMove and processPlayer) aren't even scanned through.
So I don't know if I'm doing the scanning wrong or if there is something else.
Everything else seems to work, the mod is loaded and is shown in the Mods-section as expected, so the error must be in this class.
Any help would be appreciated.
Thanks : )
package rsge.mods.blinkfixer.asm;
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.InsnList;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodNode;
import net.minecraft.launchwrapper.IClassTransformer;
/**
* Removes the "Moved Wrongly" checks from {@link net.minecraft.network.NetHandlerPlayServer}
*
* @author Rsge
*/
public class NetHandlerPlayServerTransformer implements IClassTransformer
{
private static enum MovedWronglyState
{
FIND_LDC, FIND_DCMPL, FIND_IFLE, DONE
}
/**
* Before: LDC2_W 0.0625 DCMPL IFLE <label> (code to execute if the value was greater) After: LDC2_W 0.0625 DCMPL IFLE <label> GOTO <same label> (code that
* no longer ever gets executed) I leave the IFLE in just so the DCMPL result gets popped off the stack
*/
private boolean disableMovedWrongly(MethodNode node)
{
MovedWronglyState state = MovedWronglyState.FIND_LDC;
InsnList insnList = node.instructions;
AbstractInsnNode insn = insnList.getFirst();
AbstractInsnNode patchTarget = null;
LabelNode gotoLabel = null;
while (insn != null && state != MovedWronglyState.DONE)
{
switch (state)
{
case FIND_LDC:
if (insn.getOpcode() == Opcodes.LDC)
{
Object value = ((LdcInsnNode) insn).cst;
// 0.0625 is 1/16, which can be perfectly represented by a float (power of two denominator)
if (value instanceof Double && ((Double) value).doubleValue() == 0.0625)
{
state = MovedWronglyState.FIND_DCMPL;
}
}
break;
case FIND_DCMPL:
if (insn.getOpcode() == Opcodes.DCMPL)
{
state = MovedWronglyState.FIND_IFLE;
}
else
{
state = MovedWronglyState.FIND_LDC;
}
break;
case FIND_IFLE:
if (insn.getOpcode() == Opcodes.IFLE)
{
state = MovedWronglyState.DONE;
gotoLabel = ((JumpInsnNode) insn).label;
patchTarget = insn;
}
else
{
state = MovedWronglyState.FIND_LDC;
}
break;
case DONE:
break;
default:
break;
}
insn = insn.getNext();
}
if (state == MovedWronglyState.DONE)
{
applyGotoPatch(insnList, gotoLabel, patchTarget);
return true;
}
else
{
return false;
}
}
/* ————————————————————————————————————————————————————— */
private static enum MovedTooQuicklyState
{
FIND_LDC, FIND_DCMPL, FIND_IFLE, DONE
}
/**
* Before: LDC2_W 100.0 DCMPL IFLE <label> (code to execute if the value was greater) After: LDC2_W 100.0 DCMPL IFLE <label> GOTO <same label> (code that no
* longer ever gets executed) As above, I leave the IFLE in so the DCMPL result gets popped off the stack
*/
private boolean disableMovedTooQuickly(MethodNode node)
{
MovedTooQuicklyState state = MovedTooQuicklyState.FIND_LDC;
InsnList insnList = node.instructions;
AbstractInsnNode insn = insnList.getFirst();
AbstractInsnNode patchTarget = null;
LabelNode gotoLabel = null;
while (insn != null && state != MovedTooQuicklyState.DONE)
{
switch (state)
{
case FIND_LDC:
if (insn.getOpcode() == Opcodes.LDC)
{
Object value = ((LdcInsnNode) insn).cst;
if (value instanceof Double && ((Double) value).doubleValue() == 100.0)
{
state = MovedTooQuicklyState.FIND_DCMPL;
}
}
break;
case FIND_DCMPL:
if (insn.getOpcode() == Opcodes.DCMPL)
{
state = MovedTooQuicklyState.FIND_IFLE;
}
else
{
state = MovedTooQuicklyState.FIND_LDC;
}
break;
case FIND_IFLE:
if (insn.getOpcode() == Opcodes.IFLE)
{
state = MovedTooQuicklyState.DONE;
gotoLabel = ((JumpInsnNode) insn).label;
patchTarget = insn;
}
else
{
state = MovedTooQuicklyState.FIND_LDC;
}
break;
case DONE:
break;
default:
break;
}
insn = insn.getNext();
}
if (state == MovedTooQuicklyState.DONE)
{
applyGotoPatch(insnList, gotoLabel, patchTarget);
return true;
}
else
{
return false;
}
}
/* ————————————————————————————————————————————————————— */
private void applyGotoPatch(InsnList instr, LabelNode lbl, AbstractInsnNode trg)
{
instr.insert(trg, generatePatch(lbl));
}
private InsnList generatePatch(LabelNode lbl)
{
InsnList list = new InsnList();
list.add(new JumpInsnNode(Opcodes.GOTO, lbl));
return list;
}
/* ————————————————————————————————————————————————————— */
private boolean analyzeClass(ClassNode node)
{
boolean successVehicleMove = false;
boolean successProcessPlayer = false;
for (MethodNode method : node.methods)
{
System.out.println("Method: " + method.name);
// Method processVehicleMove
if (method.name.equals("a") && method.desc.equals("(Lll;)V"))
{
successVehicleMove = disableMovedTooQuickly(method) && disableMovedWrongly(method);
}
// Method processPlayer
if (method.name.equals("a") && method.desc.equals("(Llk;)V"))
{
successProcessPlayer = disableMovedTooQuickly(method) && disableMovedWrongly(method);
}
}
if (!(successVehicleMove && successProcessPlayer))
System.out.println("Unabled to find method to patch");
return successVehicleMove && successProcessPlayer;
}
@Override
public byte[] transform(String name, String transname, byte[] bytes)
{
if (transname.contains("net.minecraft.network"))
System.out.println(name + "; " + transname);
if (transname.contains("net.minecraft.network.NetHandlerPlayServer"))
{
System.out.println("Class to transform: " + transname);
ClassReader reader = new ClassReader(bytes);
ClassNode node = new ClassNode();
reader.accept(node, 0);
if (analyzeClass(node))
{
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
node.accept(writer);
bytes = writer.toByteArray();
}
else
{
System.out.println("Failed to patch methods");
}
}
return bytes;
}
}