Files
Landtrain/tools/java/LandtrainConstraintAuthHelper.java
2026-02-12 17:55:25 -05:00

199 lines
7.0 KiB
Java

package zombie.vehicles;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import zombie.characters.IsoGameCharacter;
import zombie.characters.IsoPlayer;
/**
* Resolves the effective driver for constraint auth in chained towing.
* For middle vehicles in a chain, scan through links so long trains still resolve authority.
*/
public final class LandtrainConstraintAuthHelper {
private LandtrainConstraintAuthHelper() {
}
public static IsoGameCharacter resolveConstraintDriver(BaseVehicle vehicle) {
if (vehicle == null) {
return null;
}
IsoGameCharacter driver = findDriverAlongChain(vehicle, true);
if (driver != null) return driver;
return findDriverAlongChain(vehicle, false);
}
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;
}
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;
}
public static void authorizationChangedLandtrain(BaseVehicle vehicle, IsoGameCharacter character) {
if (vehicle == null) {
return;
}
if (character != null) {
applyAuthorizationAcrossChain(
vehicle, BaseVehicle.Authorization.Local, character.getOnlineID(), false);
} else {
applyAuthorizationAcrossChain(vehicle, BaseVehicle.Authorization.Server, -1, false);
}
}
public static void authorizationClientCollideLandtrain(BaseVehicle vehicle, IsoPlayer driver) {
if (vehicle == null || driver == null || vehicle.getDriver() != null) {
return;
}
applyAuthorizationAcrossChain(
vehicle, BaseVehicle.Authorization.LocalCollide, driver.getOnlineID(), true);
}
public static void authorizationServerCollideLandtrain(
BaseVehicle vehicle, short playerID, boolean isCollide) {
if (vehicle == null) {
return;
}
if (vehicle.isNetPlayerAuthorization(BaseVehicle.Authorization.Local)) {
return;
}
if (isCollide) {
applyAuthorizationAcrossChain(
vehicle, BaseVehicle.Authorization.LocalCollide, playerID, false);
return;
}
BaseVehicle.Authorization auth =
playerID == -1 ? BaseVehicle.Authorization.Server : BaseVehicle.Authorization.Local;
applyAuthorizationAcrossChain(vehicle, auth, playerID, false);
}
public static void authorizationServerOnSeatLandtrain(
BaseVehicle vehicle, IsoPlayer player, boolean enter) {
if (vehicle == null || player == null) {
return;
}
BaseVehicle vehicleA = vehicle.getVehicleTowing();
BaseVehicle vehicleB = vehicle.getVehicleTowedBy();
if (vehicle.isNetPlayerId((short) -1) && enter) {
if (vehicleA != null && vehicleA.getDriver() == null) {
vehicle.addPointConstraint(
null, vehicleA, vehicle.getTowAttachmentSelf(), vehicleA.getTowAttachmentSelf());
} else if (vehicleB != null && vehicleB.getDriver() == null) {
vehicle.addPointConstraint(
null, vehicleB, vehicle.getTowAttachmentSelf(), vehicleB.getTowAttachmentSelf());
} else {
applyAuthorizationAcrossChain(
vehicle, BaseVehicle.Authorization.Local, player.getOnlineID(), false);
}
} else if (vehicle.isNetPlayerId(player.getOnlineID()) && !enter) {
if (vehicleA != null && vehicleA.getDriver() != null) {
vehicleA.addPointConstraint(
null, vehicle, vehicleA.getTowAttachmentSelf(), vehicle.getTowAttachmentSelf());
} else if (vehicleB != null && vehicleB.getDriver() != null) {
vehicleB.addPointConstraint(
null, vehicle, vehicleB.getTowAttachmentSelf(), vehicle.getTowAttachmentSelf());
} else {
applyAuthorizationAcrossChain(vehicle, BaseVehicle.Authorization.Server, -1, false);
}
}
}
private static List<BaseVehicle> collectConnectedChain(BaseVehicle start) {
ArrayList<BaseVehicle> chain = new ArrayList<>();
if (start == null) {
return chain;
}
ArrayDeque<BaseVehicle> pending = new ArrayDeque<>();
Set<Integer> visitedIds = new HashSet<>();
pending.add(start);
while (!pending.isEmpty()) {
BaseVehicle cursor = pending.removeFirst();
if (cursor == null) {
continue;
}
int id = cursor.getId();
if (!visitedIds.add(id)) {
continue;
}
chain.add(cursor);
BaseVehicle front = cursor.getVehicleTowedBy();
BaseVehicle rear = cursor.getVehicleTowing();
if (front != null && front != cursor) {
pending.add(front);
}
if (rear != null && rear != cursor) {
pending.add(rear);
}
}
return chain;
}
private static void applyAuthorizationAcrossChain(
BaseVehicle start,
BaseVehicle.Authorization authorization,
int playerId,
boolean refreshSimulation) {
long now = System.currentTimeMillis();
for (BaseVehicle vehicle : collectConnectedChain(start)) {
if (vehicle == null) {
continue;
}
vehicle.setNetPlayerAuthorization(authorization, playerId);
if (refreshSimulation) {
vehicle.authSimulationTime = now;
if (vehicle.interpolation != null) {
vehicle.interpolation.clear();
}
}
}
}
}