206 lines
7.2 KiB
Java
206 lines
7.2 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;
|
|
import zombie.core.physics.CarController;
|
|
|
|
/**
|
|
* 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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void safeParkControllerLandtrain(CarController controller) {
|
|
if (controller != null) {
|
|
controller.park();
|
|
}
|
|
}
|
|
}
|