Skip to content

Commit

Permalink
Merge pull request #1746 from CitiesSkylinesMods/bugfix/potential-par…
Browse files Browse the repository at this point in the history
…king-vehicle-desync

Fixes for potential desync of parked vehicles when Parking AI is enabled
  • Loading branch information
krzychu124 committed May 24, 2023
2 parents aa76470 + 9cea0ea commit 6a3ce09
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 20 deletions.
85 changes: 72 additions & 13 deletions TLM/TLM/Manager/Impl/AdvancedParkingManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1994,51 +1994,84 @@ private ExtSoftPathState
() => $"Trying to spawn parked passenger car for citizen {citizenId}, " +
$"home {homeId} @ {refPos}");

bool roadParkSuccess = TrySpawnParkedPassengerCarRoadSide(
bool roadParkSuccess = TrySpawnParkedPassengerCarRoadSideInternal(
citizenId,
refPos,
vehicleInfo,
out Vector3 roadParkPos,
out ParkingError roadParkReason);
out ParkingError roadParkReason,
out ushort roadParkedVehicleId,
updateCitizenParkedVehicle: false);

bool buildingParkSuccess = TrySpawnParkedPassengerCarBuilding(
bool buildingParkSuccess = TrySpawnParkedPassengerCarBuildingInternal(
citizenId,
ref citizen,
homeId,
refPos,
vehicleInfo,
out Vector3 buildingParkPos,
out ParkingError buildingParkReason);
out ParkingError buildingParkReason,
out ushort buildingParkedVehicleId,
updateCitizenParkedVehicle: false);

if ((!roadParkSuccess && !buildingParkSuccess)
|| (roadParkSuccess && !buildingParkSuccess)) {
if (!buildingParkSuccess) {
if (roadParkSuccess) {
roadParkedVehicleId.AssignToCitizenAndMakeVisible(citizenId);
}
parkPos = roadParkPos;
reason = roadParkReason;
return roadParkSuccess;
}

if (!roadParkSuccess) {
buildingParkedVehicleId.AssignToCitizenAndMakeVisible(citizenId);
parkPos = buildingParkPos;
reason = buildingParkReason;
return true;
}

/*
* Two parked vehicles available, assign the closer one, release the other
*/
if ((roadParkPos - refPos).sqrMagnitude < (buildingParkPos - refPos).sqrMagnitude) {
VehicleManager.instance.ReleaseParkedVehicle(buildingParkedVehicleId);
roadParkedVehicleId.AssignToCitizenAndMakeVisible(citizenId);
parkPos = roadParkPos;
reason = roadParkReason;
return true;
}

VehicleManager.instance.ReleaseParkedVehicle(roadParkedVehicleId);
buildingParkedVehicleId.AssignToCitizenAndMakeVisible(citizenId);
parkPos = buildingParkPos;
reason = buildingParkReason;
return true;
}

[UsedImplicitly]
public bool TrySpawnParkedPassengerCarRoadSide(uint citizenId,
Vector3 refPos,
VehicleInfo vehicleInfo,
out Vector3 parkPos,
out ParkingError reason) {
return TrySpawnParkedPassengerCarRoadSideInternal(
citizenId,
refPos,
vehicleInfo,
out parkPos,
out reason,
out _,
updateCitizenParkedVehicle: true);
}


private bool TrySpawnParkedPassengerCarRoadSideInternal(uint citizenId,
Vector3 refPos,
VehicleInfo vehicleInfo,
out Vector3 parkPos,
out ParkingError reason,
out ushort roadParkVehicleId,
bool updateCitizenParkedVehicle = true) {
#if DEBUG
bool citizenDebug = DebugSettings.CitizenId == 0 || DebugSettings.CitizenId == citizenId;
bool logParkingAi = DebugSwitch.BasicParkingAILog.Get() && citizenDebug;
Expand All @@ -2054,6 +2087,7 @@ private ExtSoftPathState
() => $"Trying to spawn parked passenger car at road side for citizen {citizenId} @ {refPos}");

parkPos = Vector3.zero;
roadParkVehicleId = 0;

if (FindParkingSpaceRoadSide(
0,
Expand All @@ -2075,9 +2109,10 @@ private ExtSoftPathState
parkRot,
citizenId))
{
CitizenManager.instance.m_citizens.m_buffer[citizenId].SetParkedVehicle(citizenId, parkedVehicleId);

parkedVehicleId.ToParkedVehicle().m_flags &= (ushort)(VehicleParked.Flags.All & ~VehicleParked.Flags.Parking);
roadParkVehicleId = parkedVehicleId;
if (updateCitizenParkedVehicle) {
parkedVehicleId.AssignToCitizenAndMakeVisible(citizenId);
}

if (logParkingAi) {
Log._Debug(
Expand All @@ -2100,13 +2135,35 @@ private ExtSoftPathState
return false;
}

[UsedImplicitly]
public bool TrySpawnParkedPassengerCarBuilding(uint citizenId,
ref Citizen citizen,
ushort homeId,
Vector3 refPos,
VehicleInfo vehicleInfo,
out Vector3 parkPos,
out ParkingError reason) {
return TrySpawnParkedPassengerCarBuildingInternal(
citizenId,
ref citizen,
homeId,
refPos,
vehicleInfo,
out parkPos,
out reason,
out _,
updateCitizenParkedVehicle: true);
}

public bool TrySpawnParkedPassengerCarBuildingInternal(uint citizenId,
ref Citizen citizen,
ushort homeId,
Vector3 refPos,
VehicleInfo vehicleInfo,
out Vector3 parkPos,
out ParkingError reason,
out ushort buildingParkVehicleId,
bool updateCitizenParkedVehicle = true) {
#if DEBUG
bool citizenDebug = DebugSettings.CitizenId == 0 || DebugSettings.CitizenId == citizenId;
bool logParkingAi = DebugSwitch.BasicParkingAILog.Get() && citizenDebug;
Expand All @@ -2122,6 +2179,7 @@ private ExtSoftPathState
$"{citizenId} @ {refPos}");

parkPos = Vector3.zero;
buildingParkVehicleId = 0;

if (FindParkingSpaceBuilding(
vehicleInfo,
Expand All @@ -2144,9 +2202,10 @@ private ExtSoftPathState
parkRot,
citizenId))
{
citizen.SetParkedVehicle(citizenId, parkedVehicleId);

parkedVehicleId.ToParkedVehicle().m_flags &= (ushort)(VehicleParked.Flags.All & ~VehicleParked.Flags.Parking);
buildingParkVehicleId = parkedVehicleId;
if (updateCitizenParkedVehicle) {
parkedVehicleId.AssignToCitizenAndMakeVisible(citizenId);
}

if (extendedLogParkingAi && homeId != 0) {
Log._Debug(
Expand Down Expand Up @@ -2274,7 +2333,7 @@ private ExtSoftPathState
Randomizer rng = Singleton<SimulationManager>.instance.m_randomizer;

// choose nearest parking position, after a bit of randomization
if ((roadParkPos - targetPos).magnitude < (buildingParkPos - targetPos).magnitude
if ((roadParkPos - targetPos).sqrMagnitude < (buildingParkPos - targetPos).sqrMagnitude
&& rng.Int32(GlobalConfig.Instance.ParkingAI.VicinityParkingSpaceSelectionRand) != 0) {
// road parking space is closer

Expand Down
2 changes: 2 additions & 0 deletions TLM/TLM/Manager/Impl/ExtCitizenInstanceManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,8 @@ bool citizenDebug
rotation: parkedVehicle.m_rotation,
electricVehicleInfo: out VehicleInfo electricVehicleInfo)) {
vehicleInfo = electricVehicleInfo;
parkedVehicleId = citizen.m_parkedVehicle;
parkedVehicle = ref parkedVehicleId.ToParkedVehicle();
}
}

Expand Down
24 changes: 18 additions & 6 deletions TLM/TLM/Patch/_VehicleAI/UpdatePathTargetPositionsPatch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -971,7 +971,9 @@ public class UpdatePathTargetPositionsPatch {
Mathf.Min(targetPos.w, curMaxSpeed));
float sqrMagnitude2 = (bezierPos - refPos).sqrMagnitude;

Log._Debug(
Log._DebugIf(
logLogic,
() =>
$"CustomVehicle.CustomUpdatePathTargetPositions({vehicleID}): " +
"Preparing to update node target positions (2). " +
$"pathOffset={pathOffset}, bezierPos={bezierPos}, " +
Expand All @@ -981,7 +983,9 @@ public class UpdatePathTargetPositionsPatch {
continue;
}

Log._Debug(
Log._DebugIf(
logLogic,
() =>
$"CustomVehicle.CustomUpdatePathTargetPositions({vehicleID}): " +
$"sqrMagnitude2={sqrMagnitude2} >= minSqrDistA={minSqrDistA} and no need to stop at node");

Expand Down Expand Up @@ -1030,13 +1034,17 @@ public class UpdatePathTargetPositionsPatch {
refPos = targetPos;
targetPos.w = 1000f;

Log._Debug(
Log._DebugIf(
logLogic,
() =>
$"CustomVehicle.CustomUpdatePathTargetPositions({vehicleID}): " +
$"After updating node target positions. minSqrDistA={minSqrDistA}, " +
$"refPos={refPos}");

if (index == max) {
Log._Debug(
Log._DebugIf(
logLogic,
() =>
$"CustomVehicle.CustomUpdatePathTargetPositions({vehicleID}): " +
$"index == max ({max}). " +
"FINISH.");
Expand All @@ -1046,7 +1054,9 @@ public class UpdatePathTargetPositionsPatch {
}
} else {
PathUnit.CalculatePathPositionOffset(nextLaneId, targetPos, out nextSegOffset);
Log._Debug(
Log._DebugIf(
logLogic,
() =>
$"CustomVehicle.CustomUpdatePathTargetPositions({vehicleID}): " +
$"Same lane or cargo lane. curLaneId={curLaneId}, nextLaneId={nextLaneId}, " +
$"laneInfo.m_laneType={laneInfo.m_laneType}, targetPos={targetPos}, " +
Expand Down Expand Up @@ -1136,7 +1146,9 @@ public class UpdatePathTargetPositionsPatch {
laneInfo = nextLaneInfo;
firstIter = false; // NON-STOCK CODE

Log._Debug(
Log._DebugIf(
logLogic,
() =>
$"CustomVehicle.CustomUpdatePathTargetPositions({vehicleID}): " +
"Prepared next main loop iteration. currentPosition" +
$"=[seg={currentPosition.m_segment}, lane={currentPosition.m_lane}, " +
Expand Down
8 changes: 7 additions & 1 deletion TLM/TLM/Util/Extensions/ParkedVehicleExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,17 @@ public static class ParkedVehicleExtensions
private static readonly VehicleParked[] _parkedVehiclesBuffer = Singleton<VehicleManager>.instance.m_parkedVehicles.m_buffer;

public static ref VehicleParked ToParkedVehicle(this ushort parkedVehicleId) => ref _parkedVehiclesBuffer[parkedVehicleId];

public static ref VehicleParked ToParkedVehicle(this uint parkedVehicleId) => ref _parkedVehiclesBuffer[parkedVehicleId];

public static bool IsCreated(this ref VehicleParked parkedVehicle) =>
((VehicleParked.Flags)parkedVehicle.m_flags).IsFlagSet(VehicleParked.Flags.Created);

public static void AssignToCitizenAndMakeVisible(this ushort parkedVehicleId,
uint citizenId) {
CitizenManager.instance.m_citizens.m_buffer[citizenId].SetParkedVehicle(citizenId, parkedVehicleId);
_parkedVehiclesBuffer[parkedVehicleId].m_flags &= (ushort)(VehicleParked.Flags.All & ~VehicleParked.Flags.Parking);
}
}
}

0 comments on commit 6a3ce09

Please sign in to comment.