working
This commit is contained in:
@@ -3,27 +3,34 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
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.InsnNode;
|
||||
import org.objectweb.asm.tree.InsnList;
|
||||
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.Opcodes;
|
||||
|
||||
/**
|
||||
* Patches zombie.vehicles.BaseVehicle so addPointConstraint() no longer force-breaks
|
||||
* both vehicles before creating a new constraint.
|
||||
* Patches zombie.vehicles.BaseVehicle for Landtrain chain support:
|
||||
* 1) remove forced breakConstraint() in addPointConstraint()
|
||||
* 2) route constraintChanged() driver lookups through helper that handles chain middle vehicles
|
||||
*/
|
||||
public final class BaseVehicleConstraintPatch {
|
||||
private static final String TARGET_NAME = "addPointConstraint";
|
||||
private static final String CONSTRAINT_CHANGED_NAME = "constraintChanged";
|
||||
private static final String CLINIT_NAME = "<clinit>";
|
||||
private static final String VOID_NOARG_DESC = "()V";
|
||||
private static final String PATCH_LOG_LINE = "[Landtrain][BaseVehiclePatch] BaseVehicle override enabled";
|
||||
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 GET_DRIVER_DESC = "()Lzombie/characters/IsoGameCharacter;";
|
||||
private static final String HELPER_OWNER = "zombie/vehicles/LandtrainConstraintAuthHelper";
|
||||
private static final String HELPER_METHOD = "resolveConstraintDriver";
|
||||
private static final String HELPER_DESC =
|
||||
"(Lzombie/vehicles/BaseVehicle;)Lzombie/characters/IsoGameCharacter;";
|
||||
|
||||
private BaseVehicleConstraintPatch() {
|
||||
}
|
||||
@@ -43,12 +50,16 @@ public final class BaseVehicleConstraintPatch {
|
||||
|
||||
int removedCalls = 0;
|
||||
int inspectedAddPointMethods = 0;
|
||||
int patchedConstraintDriverCalls = 0;
|
||||
|
||||
for (MethodNode method : classNode.methods) {
|
||||
if (!TARGET_NAME.equals(method.name) || !isTargetAddPointConstraint(method.desc)) {
|
||||
continue;
|
||||
if (TARGET_NAME.equals(method.name) && isTargetAddPointConstraint(method.desc)) {
|
||||
inspectedAddPointMethods++;
|
||||
removedCalls += patchAddPointConstraint(method);
|
||||
} else if (CONSTRAINT_CHANGED_NAME.equals(method.name)
|
||||
&& VOID_NOARG_DESC.equals(method.desc)) {
|
||||
patchedConstraintDriverCalls += patchConstraintChangedDriverCalls(method);
|
||||
}
|
||||
inspectedAddPointMethods++;
|
||||
removedCalls += patchAddPointConstraint(method);
|
||||
}
|
||||
|
||||
if (removedCalls < 2) {
|
||||
@@ -59,6 +70,11 @@ public final class BaseVehicleConstraintPatch {
|
||||
+ inspectedAddPointMethods
|
||||
+ ")");
|
||||
}
|
||||
if (patchedConstraintDriverCalls < 1) {
|
||||
throw new IllegalStateException(
|
||||
"Expected to patch at least 1 constraintChanged getDriver call, patched "
|
||||
+ patchedConstraintDriverCalls);
|
||||
}
|
||||
if (!ensureClassInitLog(classNode)) {
|
||||
throw new IllegalStateException("Failed to inject BaseVehicle class-init debug log");
|
||||
}
|
||||
@@ -71,12 +87,12 @@ public final class BaseVehicleConstraintPatch {
|
||||
System.out.println(
|
||||
"Patched BaseVehicle.class; removed breakConstraint calls: "
|
||||
+ removedCalls
|
||||
+ ", constraint driver hooks: "
|
||||
+ patchedConstraintDriverCalls
|
||||
+ ", class-init debug log: enabled");
|
||||
}
|
||||
|
||||
private static boolean isTargetAddPointConstraint(String methodDesc) {
|
||||
// We only want the 5-arg overload:
|
||||
// (IsoPlayer, BaseVehicle, String, String, boolean|Boolean) -> void
|
||||
return "(Lzombie/characters/IsoPlayer;Lzombie/vehicles/BaseVehicle;Ljava/lang/String;Ljava/lang/String;Z)V"
|
||||
.equals(methodDesc)
|
||||
|| "(Lzombie/characters/IsoPlayer;Lzombie/vehicles/BaseVehicle;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;)V"
|
||||
@@ -97,9 +113,8 @@ public final class BaseVehicleConstraintPatch {
|
||||
node = next;
|
||||
continue;
|
||||
}
|
||||
// Keep stack-map frames valid by preserving stack effect:
|
||||
|
||||
// breakConstraint(...) consumes objectref + 2 args and returns void.
|
||||
// Replace invoke with POP2 + POP (consume 3 category-1 stack slots).
|
||||
InsnList replacement = new InsnList();
|
||||
replacement.add(new InsnNode(Opcodes.POP2));
|
||||
replacement.add(new InsnNode(Opcodes.POP));
|
||||
@@ -113,6 +128,36 @@ public final class BaseVehicleConstraintPatch {
|
||||
return patched;
|
||||
}
|
||||
|
||||
private static int patchConstraintChangedDriverCalls(MethodNode method) {
|
||||
int patched = 0;
|
||||
InsnList insns = method.instructions;
|
||||
for (AbstractInsnNode node = insns.getFirst(); node != null; ) {
|
||||
AbstractInsnNode next = node.getNext();
|
||||
if (!(node instanceof MethodInsnNode call)) {
|
||||
node = next;
|
||||
continue;
|
||||
}
|
||||
if (!BASE_VEHICLE_OWNER.equals(call.owner)
|
||||
|| !"getDriver".equals(call.name)
|
||||
|| !GET_DRIVER_DESC.equals(call.desc)) {
|
||||
node = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
MethodInsnNode replacement =
|
||||
new MethodInsnNode(
|
||||
Opcodes.INVOKESTATIC,
|
||||
HELPER_OWNER,
|
||||
HELPER_METHOD,
|
||||
HELPER_DESC,
|
||||
false);
|
||||
insns.set(call, replacement);
|
||||
patched++;
|
||||
node = next;
|
||||
}
|
||||
return patched;
|
||||
}
|
||||
|
||||
private static boolean ensureClassInitLog(ClassNode classNode) {
|
||||
MethodNode clinit = null;
|
||||
for (MethodNode method : classNode.methods) {
|
||||
|
||||
38
tools/java/LandtrainConstraintAuthHelper.java
Normal file
38
tools/java/LandtrainConstraintAuthHelper.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package zombie.vehicles;
|
||||
|
||||
import zombie.characters.IsoGameCharacter;
|
||||
|
||||
/**
|
||||
* Resolves the effective driver for constraint auth in chained towing.
|
||||
* For middle vehicles in a chain, prefer the front/lead driver's authority.
|
||||
*/
|
||||
public final class LandtrainConstraintAuthHelper {
|
||||
private LandtrainConstraintAuthHelper() {
|
||||
}
|
||||
|
||||
public static IsoGameCharacter resolveConstraintDriver(BaseVehicle vehicle) {
|
||||
if (vehicle == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
IsoGameCharacter driver = vehicle.getDriver();
|
||||
if (driver != null) {
|
||||
return driver;
|
||||
}
|
||||
|
||||
BaseVehicle front = vehicle.getVehicleTowedBy();
|
||||
if (front != null) {
|
||||
driver = front.getDriver();
|
||||
if (driver != null) {
|
||||
return driver;
|
||||
}
|
||||
}
|
||||
|
||||
BaseVehicle rear = vehicle.getVehicleTowing();
|
||||
if (rear != null) {
|
||||
return rear.getDriver();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user