Working
This commit is contained in:
@@ -4,6 +4,7 @@ import java.nio.file.Paths;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.InsnList;
|
||||
@@ -11,6 +12,7 @@ import org.objectweb.asm.tree.InsnNode;
|
||||
import org.objectweb.asm.tree.LdcInsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import org.objectweb.asm.tree.VarInsnNode;
|
||||
|
||||
/**
|
||||
* Patches zombie.vehicles.BaseVehicle for Landtrain chain support:
|
||||
@@ -20,10 +22,21 @@ import org.objectweb.asm.tree.MethodNode;
|
||||
public final class BaseVehicleConstraintPatch {
|
||||
private static final String TARGET_NAME = "addPointConstraint";
|
||||
private static final String CONSTRAINT_CHANGED_NAME = "constraintChanged";
|
||||
private static final String AUTHORIZATION_CHANGED_NAME = "authorizationChanged";
|
||||
private static final String AUTHORIZATION_CLIENT_COLLIDE_NAME = "authorizationClientCollide";
|
||||
private static final String AUTHORIZATION_SERVER_COLLIDE_NAME = "authorizationServerCollide";
|
||||
private static final String AUTHORIZATION_SERVER_ON_SEAT_NAME = "authorizationServerOnSeat";
|
||||
private static final String IS_ENTER_BLOCKED_NAME = "isEnterBlocked";
|
||||
private static final String IS_ENTER_BLOCKED2_NAME = "isEnterBlocked2";
|
||||
private static final String CLINIT_NAME = "<clinit>";
|
||||
private static final String VOID_NOARG_DESC = "()V";
|
||||
private static final String AUTHORIZATION_CHANGED_DESC =
|
||||
"(Lzombie/characters/IsoGameCharacter;)V";
|
||||
private static final String AUTHORIZATION_CLIENT_COLLIDE_DESC =
|
||||
"(Lzombie/characters/IsoPlayer;)V";
|
||||
private static final String AUTHORIZATION_SERVER_COLLIDE_DESC = "(SZ)V";
|
||||
private static final String AUTHORIZATION_SERVER_ON_SEAT_DESC =
|
||||
"(Lzombie/characters/IsoPlayer;Z)V";
|
||||
private static final String ENTER_BLOCKED_DESC = "(Lzombie/characters/IsoGameCharacter;I)Z";
|
||||
private static final String EXIT_BLOCKED_DESC = "(Lzombie/characters/IsoGameCharacter;I)Z";
|
||||
private static final String EXIT_BLOCKED2_DESC = "(I)Z";
|
||||
@@ -31,6 +44,11 @@ public final class BaseVehicleConstraintPatch {
|
||||
private static final String BREAK_DESC_OBJECT_BOOL = "(ZLjava/lang/Boolean;)V";
|
||||
private static final String BREAK_DESC_PRIMITIVE_BOOL = "(ZZ)V";
|
||||
private static final String BASE_VEHICLE_OWNER = "zombie/vehicles/BaseVehicle";
|
||||
private static final String BULLET_OWNER = "zombie/core/physics/Bullet";
|
||||
private static final String BULLET_ADD_ROPE = "addRopeConstraint";
|
||||
private static final String BULLET_ADD_POINT = "addPointConstraint";
|
||||
private static final String BULLET_ADD_ROPE_DESC = "(IIFFFFFFF)I";
|
||||
private static final String BULLET_ADD_POINT_DESC = "(IIFFFFFF)I";
|
||||
private static final String GET_DRIVER_DESC = "()Lzombie/characters/IsoGameCharacter;";
|
||||
private static final String HELPER_OWNER = "zombie/vehicles/LandtrainConstraintAuthHelper";
|
||||
private static final String HELPER_METHOD = "resolveConstraintDriver";
|
||||
@@ -41,6 +59,27 @@ public final class BaseVehicleConstraintPatch {
|
||||
"(Lzombie/vehicles/BaseVehicle;Lzombie/characters/IsoGameCharacter;I)Z";
|
||||
private static final String HELPER_ENTER_BLOCKED2 = "isEnterBlocked2Landtrain";
|
||||
private static final String HELPER_ENTER_BLOCKED2_DESC = "(Lzombie/vehicles/BaseVehicle;I)Z";
|
||||
private static final String HELPER_AUTHORIZATION_CHANGED =
|
||||
"authorizationChangedLandtrain";
|
||||
private static final String HELPER_AUTHORIZATION_CHANGED_DESC =
|
||||
"(Lzombie/vehicles/BaseVehicle;Lzombie/characters/IsoGameCharacter;)V";
|
||||
private static final String HELPER_AUTHORIZATION_CLIENT_COLLIDE =
|
||||
"authorizationClientCollideLandtrain";
|
||||
private static final String HELPER_AUTHORIZATION_CLIENT_COLLIDE_DESC =
|
||||
"(Lzombie/vehicles/BaseVehicle;Lzombie/characters/IsoPlayer;)V";
|
||||
private static final String HELPER_AUTHORIZATION_SERVER_COLLIDE =
|
||||
"authorizationServerCollideLandtrain";
|
||||
private static final String HELPER_AUTHORIZATION_SERVER_COLLIDE_DESC =
|
||||
"(Lzombie/vehicles/BaseVehicle;SZ)V";
|
||||
private static final String HELPER_AUTHORIZATION_SERVER_ON_SEAT =
|
||||
"authorizationServerOnSeatLandtrain";
|
||||
private static final String HELPER_AUTHORIZATION_SERVER_ON_SEAT_DESC =
|
||||
"(Lzombie/vehicles/BaseVehicle;Lzombie/characters/IsoPlayer;Z)V";
|
||||
|
||||
private static final class AddPointPatchStats {
|
||||
int removedBreakCalls;
|
||||
int forcedRigidCalls;
|
||||
}
|
||||
|
||||
private BaseVehicleConstraintPatch() {
|
||||
}
|
||||
@@ -59,18 +98,49 @@ public final class BaseVehicleConstraintPatch {
|
||||
new ClassReader(original).accept(classNode, 0);
|
||||
|
||||
int removedCalls = 0;
|
||||
int forcedRigidCalls = 0;
|
||||
int inspectedAddPointMethods = 0;
|
||||
int patchedConstraintDriverCalls = 0;
|
||||
int patchedEnterBlockedCalls = 0;
|
||||
int patchedEnterBlocked2Calls = 0;
|
||||
int patchedAuthorizationChangedMethods = 0;
|
||||
int patchedAuthorizationClientCollideMethods = 0;
|
||||
int patchedAuthorizationServerCollideMethods = 0;
|
||||
int patchedAuthorizationServerOnSeatMethods = 0;
|
||||
|
||||
for (MethodNode method : classNode.methods) {
|
||||
if (TARGET_NAME.equals(method.name) && isTargetAddPointConstraint(method.desc)) {
|
||||
inspectedAddPointMethods++;
|
||||
removedCalls += patchAddPointConstraint(method);
|
||||
AddPointPatchStats stats = patchAddPointConstraint(method);
|
||||
removedCalls += stats.removedBreakCalls;
|
||||
forcedRigidCalls += stats.forcedRigidCalls;
|
||||
} else if (CONSTRAINT_CHANGED_NAME.equals(method.name)
|
||||
&& VOID_NOARG_DESC.equals(method.desc)) {
|
||||
patchedConstraintDriverCalls += patchConstraintChangedDriverCalls(method);
|
||||
} else if (AUTHORIZATION_CHANGED_NAME.equals(method.name)
|
||||
&& AUTHORIZATION_CHANGED_DESC.equals(method.desc)) {
|
||||
patchedAuthorizationChangedMethods += patchMethodDelegateToHelper(
|
||||
method,
|
||||
HELPER_AUTHORIZATION_CHANGED,
|
||||
HELPER_AUTHORIZATION_CHANGED_DESC);
|
||||
} else if (AUTHORIZATION_CLIENT_COLLIDE_NAME.equals(method.name)
|
||||
&& AUTHORIZATION_CLIENT_COLLIDE_DESC.equals(method.desc)) {
|
||||
patchedAuthorizationClientCollideMethods += patchMethodDelegateToHelper(
|
||||
method,
|
||||
HELPER_AUTHORIZATION_CLIENT_COLLIDE,
|
||||
HELPER_AUTHORIZATION_CLIENT_COLLIDE_DESC);
|
||||
} else if (AUTHORIZATION_SERVER_COLLIDE_NAME.equals(method.name)
|
||||
&& AUTHORIZATION_SERVER_COLLIDE_DESC.equals(method.desc)) {
|
||||
patchedAuthorizationServerCollideMethods += patchMethodDelegateToHelper(
|
||||
method,
|
||||
HELPER_AUTHORIZATION_SERVER_COLLIDE,
|
||||
HELPER_AUTHORIZATION_SERVER_COLLIDE_DESC);
|
||||
} else if (AUTHORIZATION_SERVER_ON_SEAT_NAME.equals(method.name)
|
||||
&& AUTHORIZATION_SERVER_ON_SEAT_DESC.equals(method.desc)) {
|
||||
patchedAuthorizationServerOnSeatMethods += patchMethodDelegateToHelper(
|
||||
method,
|
||||
HELPER_AUTHORIZATION_SERVER_ON_SEAT,
|
||||
HELPER_AUTHORIZATION_SERVER_ON_SEAT_DESC);
|
||||
} else if (IS_ENTER_BLOCKED_NAME.equals(method.name)
|
||||
&& ENTER_BLOCKED_DESC.equals(method.desc)) {
|
||||
patchedEnterBlockedCalls += patchEnterBlockedCall(
|
||||
@@ -98,11 +168,36 @@ public final class BaseVehicleConstraintPatch {
|
||||
+ inspectedAddPointMethods
|
||||
+ ")");
|
||||
}
|
||||
if (forcedRigidCalls < 1) {
|
||||
throw new IllegalStateException(
|
||||
"Expected to force at least 1 rope->point constraint call, patched "
|
||||
+ forcedRigidCalls);
|
||||
}
|
||||
if (patchedConstraintDriverCalls < 1) {
|
||||
throw new IllegalStateException(
|
||||
"Expected to patch at least 1 constraintChanged getDriver call, patched "
|
||||
+ patchedConstraintDriverCalls);
|
||||
}
|
||||
if (patchedAuthorizationChangedMethods < 1) {
|
||||
throw new IllegalStateException(
|
||||
"Expected to patch authorizationChanged, patched "
|
||||
+ patchedAuthorizationChangedMethods);
|
||||
}
|
||||
if (patchedAuthorizationClientCollideMethods < 1) {
|
||||
throw new IllegalStateException(
|
||||
"Expected to patch authorizationClientCollide, patched "
|
||||
+ patchedAuthorizationClientCollideMethods);
|
||||
}
|
||||
if (patchedAuthorizationServerCollideMethods < 1) {
|
||||
throw new IllegalStateException(
|
||||
"Expected to patch authorizationServerCollide, patched "
|
||||
+ patchedAuthorizationServerCollideMethods);
|
||||
}
|
||||
if (patchedAuthorizationServerOnSeatMethods < 1) {
|
||||
throw new IllegalStateException(
|
||||
"Expected to patch authorizationServerOnSeat, patched "
|
||||
+ patchedAuthorizationServerOnSeatMethods);
|
||||
}
|
||||
if (patchedEnterBlockedCalls < 1) {
|
||||
throw new IllegalStateException(
|
||||
"Expected to patch isEnterBlocked call, patched " + patchedEnterBlockedCalls);
|
||||
@@ -123,8 +218,18 @@ public final class BaseVehicleConstraintPatch {
|
||||
System.out.println(
|
||||
"Patched BaseVehicle.class; removed breakConstraint calls: "
|
||||
+ removedCalls
|
||||
+ ", forced rigid constraints: "
|
||||
+ forcedRigidCalls
|
||||
+ ", constraint driver hooks: "
|
||||
+ patchedConstraintDriverCalls
|
||||
+ ", auth hooks (changed/client/server/seat): "
|
||||
+ patchedAuthorizationChangedMethods
|
||||
+ "/"
|
||||
+ patchedAuthorizationClientCollideMethods
|
||||
+ "/"
|
||||
+ patchedAuthorizationServerCollideMethods
|
||||
+ "/"
|
||||
+ patchedAuthorizationServerOnSeatMethods
|
||||
+ ", enter-block hooks: "
|
||||
+ patchedEnterBlockedCalls
|
||||
+ "/"
|
||||
@@ -139,8 +244,8 @@ public final class BaseVehicleConstraintPatch {
|
||||
.equals(methodDesc);
|
||||
}
|
||||
|
||||
private static int patchAddPointConstraint(MethodNode method) {
|
||||
int patched = 0;
|
||||
private static AddPointPatchStats patchAddPointConstraint(MethodNode method) {
|
||||
AddPointPatchStats stats = new AddPointPatchStats();
|
||||
InsnList insns = method.instructions;
|
||||
|
||||
for (AbstractInsnNode node = insns.getFirst(); node != null; ) {
|
||||
@@ -160,12 +265,27 @@ public final class BaseVehicleConstraintPatch {
|
||||
replacement.add(new InsnNode(Opcodes.POP));
|
||||
insns.insert(node, replacement);
|
||||
insns.remove(node);
|
||||
patched++;
|
||||
stats.removedBreakCalls++;
|
||||
} else if (node instanceof MethodInsnNode call
|
||||
&& BULLET_OWNER.equals(call.owner)
|
||||
&& BULLET_ADD_ROPE.equals(call.name)
|
||||
&& BULLET_ADD_ROPE_DESC.equals(call.desc)) {
|
||||
// Drop the rope-length float and call Bullet.addPointConstraint(...) instead.
|
||||
insns.insertBefore(call, new InsnNode(Opcodes.POP));
|
||||
MethodInsnNode replacement =
|
||||
new MethodInsnNode(
|
||||
Opcodes.INVOKESTATIC,
|
||||
BULLET_OWNER,
|
||||
BULLET_ADD_POINT,
|
||||
BULLET_ADD_POINT_DESC,
|
||||
false);
|
||||
insns.set(call, replacement);
|
||||
stats.forcedRigidCalls++;
|
||||
}
|
||||
node = next;
|
||||
}
|
||||
|
||||
return patched;
|
||||
return stats;
|
||||
}
|
||||
|
||||
private static int patchConstraintChangedDriverCalls(MethodNode method) {
|
||||
@@ -198,6 +318,45 @@ public final class BaseVehicleConstraintPatch {
|
||||
return patched;
|
||||
}
|
||||
|
||||
private static int patchMethodDelegateToHelper(
|
||||
MethodNode method, String helperMethod, String helperDesc) {
|
||||
InsnList insns = new InsnList();
|
||||
|
||||
int localIndex = 0;
|
||||
int maxStack = 0;
|
||||
if ((method.access & Opcodes.ACC_STATIC) == 0) {
|
||||
insns.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
||||
localIndex = 1;
|
||||
maxStack = 1;
|
||||
}
|
||||
|
||||
Type[] argumentTypes = Type.getArgumentTypes(method.desc);
|
||||
for (Type argumentType : argumentTypes) {
|
||||
insns.add(new VarInsnNode(argumentType.getOpcode(Opcodes.ILOAD), localIndex));
|
||||
localIndex += argumentType.getSize();
|
||||
maxStack += argumentType.getSize();
|
||||
}
|
||||
|
||||
insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, HELPER_OWNER, helperMethod, helperDesc, false));
|
||||
|
||||
Type returnType = Type.getReturnType(method.desc);
|
||||
if (returnType.getSort() == Type.VOID) {
|
||||
insns.add(new InsnNode(Opcodes.RETURN));
|
||||
} else {
|
||||
insns.add(new InsnNode(returnType.getOpcode(Opcodes.IRETURN)));
|
||||
}
|
||||
|
||||
method.instructions.clear();
|
||||
method.instructions.add(insns);
|
||||
method.tryCatchBlocks.clear();
|
||||
if (method.localVariables != null) {
|
||||
method.localVariables.clear();
|
||||
}
|
||||
method.maxLocals = Math.max(method.maxLocals, localIndex);
|
||||
method.maxStack = Math.max(method.maxStack, maxStack);
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int patchEnterBlockedCall(
|
||||
MethodNode method,
|
||||
String targetCallName,
|
||||
|
||||
Reference in New Issue
Block a user