Schmedium
This commit is contained in:
@@ -20,8 +20,13 @@ 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 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 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";
|
||||
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";
|
||||
@@ -31,6 +36,11 @@ public final class BaseVehicleConstraintPatch {
|
||||
private static final String HELPER_METHOD = "resolveConstraintDriver";
|
||||
private static final String HELPER_DESC =
|
||||
"(Lzombie/vehicles/BaseVehicle;)Lzombie/characters/IsoGameCharacter;";
|
||||
private static final String HELPER_ENTER_BLOCKED = "isEnterBlockedLandtrain";
|
||||
private static final String HELPER_ENTER_BLOCKED_DESC =
|
||||
"(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 BaseVehicleConstraintPatch() {
|
||||
}
|
||||
@@ -51,6 +61,8 @@ public final class BaseVehicleConstraintPatch {
|
||||
int removedCalls = 0;
|
||||
int inspectedAddPointMethods = 0;
|
||||
int patchedConstraintDriverCalls = 0;
|
||||
int patchedEnterBlockedCalls = 0;
|
||||
int patchedEnterBlocked2Calls = 0;
|
||||
|
||||
for (MethodNode method : classNode.methods) {
|
||||
if (TARGET_NAME.equals(method.name) && isTargetAddPointConstraint(method.desc)) {
|
||||
@@ -59,6 +71,22 @@ public final class BaseVehicleConstraintPatch {
|
||||
} else if (CONSTRAINT_CHANGED_NAME.equals(method.name)
|
||||
&& VOID_NOARG_DESC.equals(method.desc)) {
|
||||
patchedConstraintDriverCalls += patchConstraintChangedDriverCalls(method);
|
||||
} else if (IS_ENTER_BLOCKED_NAME.equals(method.name)
|
||||
&& ENTER_BLOCKED_DESC.equals(method.desc)) {
|
||||
patchedEnterBlockedCalls += patchEnterBlockedCall(
|
||||
method,
|
||||
"isExitBlocked",
|
||||
EXIT_BLOCKED_DESC,
|
||||
HELPER_ENTER_BLOCKED,
|
||||
HELPER_ENTER_BLOCKED_DESC);
|
||||
} else if (IS_ENTER_BLOCKED2_NAME.equals(method.name)
|
||||
&& ENTER_BLOCKED_DESC.equals(method.desc)) {
|
||||
patchedEnterBlocked2Calls += patchEnterBlockedCall(
|
||||
method,
|
||||
"isExitBlocked2",
|
||||
EXIT_BLOCKED2_DESC,
|
||||
HELPER_ENTER_BLOCKED2,
|
||||
HELPER_ENTER_BLOCKED2_DESC);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +103,14 @@ public final class BaseVehicleConstraintPatch {
|
||||
"Expected to patch at least 1 constraintChanged getDriver call, patched "
|
||||
+ patchedConstraintDriverCalls);
|
||||
}
|
||||
if (patchedEnterBlockedCalls < 1) {
|
||||
throw new IllegalStateException(
|
||||
"Expected to patch isEnterBlocked call, patched " + patchedEnterBlockedCalls);
|
||||
}
|
||||
if (patchedEnterBlocked2Calls < 1) {
|
||||
throw new IllegalStateException(
|
||||
"Expected to patch isEnterBlocked2 call, patched " + patchedEnterBlocked2Calls);
|
||||
}
|
||||
if (!ensureClassInitLog(classNode)) {
|
||||
throw new IllegalStateException("Failed to inject BaseVehicle class-init debug log");
|
||||
}
|
||||
@@ -89,6 +125,10 @@ public final class BaseVehicleConstraintPatch {
|
||||
+ removedCalls
|
||||
+ ", constraint driver hooks: "
|
||||
+ patchedConstraintDriverCalls
|
||||
+ ", enter-block hooks: "
|
||||
+ patchedEnterBlockedCalls
|
||||
+ "/"
|
||||
+ patchedEnterBlocked2Calls
|
||||
+ ", class-init debug log: enabled");
|
||||
}
|
||||
|
||||
@@ -158,6 +198,41 @@ public final class BaseVehicleConstraintPatch {
|
||||
return patched;
|
||||
}
|
||||
|
||||
private static int patchEnterBlockedCall(
|
||||
MethodNode method,
|
||||
String targetCallName,
|
||||
String targetCallDesc,
|
||||
String helperMethod,
|
||||
String helperDesc) {
|
||||
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)
|
||||
|| !targetCallName.equals(call.name)
|
||||
|| !targetCallDesc.equals(call.desc)) {
|
||||
node = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
MethodInsnNode replacement =
|
||||
new MethodInsnNode(
|
||||
Opcodes.INVOKESTATIC,
|
||||
HELPER_OWNER,
|
||||
helperMethod,
|
||||
helperDesc,
|
||||
false);
|
||||
insns.set(call, replacement);
|
||||
patched++;
|
||||
node = next;
|
||||
}
|
||||
return patched;
|
||||
}
|
||||
|
||||
private static boolean ensureClassInitLog(ClassNode classNode) {
|
||||
MethodNode clinit = null;
|
||||
for (MethodNode method : classNode.methods) {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package zombie.vehicles;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
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.
|
||||
* For middle vehicles in a chain, scan through links so long trains still resolve authority.
|
||||
*/
|
||||
public final class LandtrainConstraintAuthHelper {
|
||||
private LandtrainConstraintAuthHelper() {
|
||||
@@ -15,24 +17,49 @@ public final class LandtrainConstraintAuthHelper {
|
||||
return null;
|
||||
}
|
||||
|
||||
IsoGameCharacter driver = vehicle.getDriver();
|
||||
if (driver != null) {
|
||||
return driver;
|
||||
}
|
||||
IsoGameCharacter driver = findDriverAlongChain(vehicle, true);
|
||||
if (driver != null) return driver;
|
||||
return findDriverAlongChain(vehicle, false);
|
||||
}
|
||||
|
||||
BaseVehicle front = vehicle.getVehicleTowedBy();
|
||||
if (front != null) {
|
||||
driver = front.getDriver();
|
||||
private static IsoGameCharacter findDriverAlongChain(BaseVehicle start, boolean towardFront) {
|
||||
BaseVehicle cursor = start;
|
||||
Set<Integer> visited = new HashSet<>();
|
||||
|
||||
while (cursor != null) {
|
||||
int id = cursor.getId();
|
||||
if (!visited.add(id)) {
|
||||
// Safety: malformed link graph; stop scanning.
|
||||
return null;
|
||||
}
|
||||
|
||||
IsoGameCharacter driver = cursor.getDriver();
|
||||
if (driver != null) {
|
||||
return driver;
|
||||
}
|
||||
}
|
||||
|
||||
BaseVehicle rear = vehicle.getVehicleTowing();
|
||||
if (rear != null) {
|
||||
return rear.getDriver();
|
||||
cursor = towardFront ? cursor.getVehicleTowedBy() : cursor.getVehicleTowing();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isEnterBlockedLandtrain(
|
||||
BaseVehicle vehicle, IsoGameCharacter chr, int seat) {
|
||||
if (isVehicleBeingTowedInLandtrain(vehicle)) {
|
||||
return true;
|
||||
}
|
||||
return vehicle != null && vehicle.isExitBlocked(chr, seat);
|
||||
}
|
||||
|
||||
public static boolean isEnterBlocked2Landtrain(BaseVehicle vehicle, int seat) {
|
||||
if (isVehicleBeingTowedInLandtrain(vehicle)) {
|
||||
return true;
|
||||
}
|
||||
return vehicle != null && vehicle.isExitBlocked2(seat);
|
||||
}
|
||||
|
||||
private static boolean isVehicleBeingTowedInLandtrain(BaseVehicle vehicle) {
|
||||
return vehicle != null && vehicle.getVehicleTowedBy() != null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user