package openmods.entity;
import openmods.api.IResultListener;
import openmods.asm.MappedType;
import openmods.asm.MethodMatcher;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
public class PlayerDamageEventInjector extends ClassVisitor {
private class InjectorMethodVisitor extends MethodVisitor {
public InjectorMethodVisitor(MethodVisitor mv) {
super(Opcodes.ASM5, mv);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
super.visitMethodInsn(opcode, owner, name, desc, itf);
if (markerMethod.match(name, desc)) {
visitVarInsn(Opcodes.ALOAD, 0); // this
visitVarInsn(Opcodes.ALOAD, 1); // damage source
visitVarInsn(Opcodes.FLOAD, 2); // amount
visitMethodInsn(Opcodes.INVOKESTATIC, "openmods/entity/PlayerDamageEvent", "post", injectedMethodType, false);
visitVarInsn(Opcodes.FSTORE, 2);
listener.onSuccess();
}
}
}
private final IResultListener listener;
private final MethodMatcher modifiedMethod;
private final MethodMatcher markerMethod;
private final String injectedMethodType;
public PlayerDamageEventInjector(String entityPlayerCls, ClassVisitor cv, IResultListener listener) {
super(Opcodes.ASM5, cv);
this.listener = listener;
final Type damageSourceType = MappedType.of("net.minecraft.util.DamageSource").type();
final String modifiedMethodType = Type.getMethodDescriptor(Type.VOID_TYPE, damageSourceType, Type.FLOAT_TYPE);
modifiedMethod = new MethodMatcher(entityPlayerCls, modifiedMethodType, "damageEntity", "func_70665_d");
markerMethod = new MethodMatcher(entityPlayerCls, "(F)V", "setAbsorptionAmount", "func_110149_m");
injectedMethodType = Type.getMethodDescriptor(Type.FLOAT_TYPE, MappedType.of(entityPlayerCls).type(), damageSourceType, Type.FLOAT_TYPE);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
final MethodVisitor parent = super.visitMethod(access, name, desc, signature, exceptions);
return modifiedMethod.match(name, desc)? new InjectorMethodVisitor(parent) : parent;
}
}