Skip to content

Commit

Permalink
Merge pull request #1626 from CitiesSkylinesMods/parkingAI-starts-par…
Browse files Browse the repository at this point in the history
…king-too-early

Parking AI confused in large parking lots
  • Loading branch information
krzychu124 authored Oct 3, 2022
2 parents 95eda6e + 1b07165 commit 4c23481
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 51 deletions.
4 changes: 2 additions & 2 deletions TLM/Benchmarks/LoopUtilPerfTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class LoopUtilPerfTests {
[Benchmark]
public void GenerateSpiralGridCoordsClockwise_Once_Radius17() {
var radius = 17;
var coords = LoopUtil.GenerateSpiralGridCoordsClockwise().Take(radius * radius);
var coords = LoopUtil.GenerateSpiralGridCoordsCounterclockwise().Take(radius * radius);
foreach (var coord in coords) {
}
}
Expand All @@ -16,7 +16,7 @@ public void GenerateSpiralGridCoordsClockwise_Once_Radius17() {
public void GenerateSpiralGridCoordsClockwise_10Times_Radius17() {
var radius = 17;
for (int i = 0; i < 10; i++) {
var coords = LoopUtil.GenerateSpiralGridCoordsClockwise().Take(radius * radius);
var coords = LoopUtil.GenerateSpiralGridCoordsCounterclockwise().Take(radius * radius);
foreach (var coord in coords) {
}
}
Expand Down
8 changes: 4 additions & 4 deletions TLM/Benchmarks/SpiralPerfTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class SpiralPerfTests {
public void SpiralGetCoords_Once_Radius17() {
var radius = 17;
var spiral = new Spiral(radius);
var coords = spiral.GetCoords(radius);
var coords = spiral.GetCoordsCounterclockwise(radius);
for (int i = 0; i < coords.Count; i++) {
var coord = coords[i];
}
Expand All @@ -20,7 +20,7 @@ public void SpiralGetCoords_10Times_Radius17() {
var radius = 17;
var spiral = new Spiral(radius);
for (int i = 0; i < 10; i++) {
var coords = spiral.GetCoords(radius);
var coords = spiral.GetCoordsCounterclockwise(radius);
for (int j = 0; j < coords.Count; j++) {
var coord = coords[j];
}
Expand All @@ -30,7 +30,7 @@ public void SpiralGetCoords_10Times_Radius17() {
[Benchmark]
public void SpiralGetCoords_Once_Radius17_Precached() {
var radius = 17;
var coords = _cachedSpiral17.GetCoords(radius);
var coords = _cachedSpiral17.GetCoordsCounterclockwise(radius);
for (int i = 0; i < coords.Count; i++) {
var coord = coords[i];
}
Expand All @@ -40,7 +40,7 @@ public void SpiralGetCoords_Once_Radius17_Precached() {
public void SpiralGetCoords_10Times_Radius17_Precached() {
var radius = 17;
for (int i = 0; i < 10; i++) {
var coords = _cachedSpiral17.GetCoords(radius);
var coords = _cachedSpiral17.GetCoordsCounterclockwise(radius);
for (int j = 0; j < coords.Count; j++) {
var coord = coords[j];
}
Expand Down
20 changes: 9 additions & 11 deletions TLM/TLM/Manager/Impl/AdvancedParkingManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class AdvancedParkingManager
IAdvancedParkingManager
{
private readonly Spiral _spiral;
private Randomizer _randomizer;

public static readonly AdvancedParkingManager Instance
= new AdvancedParkingManager(SingletonLite<Spiral>.instance);
Expand All @@ -32,6 +33,7 @@ public static readonly AdvancedParkingManager Instance

public AdvancedParkingManager(Spiral spiral) {
_spiral = spiral ?? throw new ArgumentNullException(nameof(spiral));
_randomizer = new Randomizer();

_findParkingSpaceDelegate = GameConnectionManager.Instance.PassengerCarAIConnection.FindParkingSpace;
_findParkingSpacePropDelegate = GameConnectionManager.Instance.PassengerCarAIConnection.FindParkingSpaceProp;
Expand Down Expand Up @@ -1931,7 +1933,7 @@ public bool FindParkingSpaceForCitizen(Vector3 endPos,
// found a building with parking space
if (Constants.ManagerFactory.ExtPathManager.FindPathPositionWithSpiralLoop(
parkPos,
endPos,
knownParkingSpaceLocationId.ToBuilding().m_position,
ItemClass.Service.Road,
NetInfo.LaneType.Pedestrian,
VehicleInfo.VehicleType.None,
Expand All @@ -1947,10 +1949,10 @@ public bool FindParkingSpaceForCitizen(Vector3 endPos,
if (logParkingAi) {
Log._Debug(
$"Navigating citizen instance {extDriverInstance.instanceId} to parking " +
$"building {knownParkingSpaceLocationId}! segment={endPathPos.m_segment}, " +
$"building {knownParkingSpaceLocationId}, parkPos={parkPos}! segment={endPathPos.m_segment}, " +
$"laneIndex={endPathPos.m_lane}, offset={endPathPos.m_offset}. " +
$"CurrentPathMode={extDriverInstance.pathMode} " +
$"calculateEndPos={calculateEndPos}");
$"calculateEndPos={calculateEndPos}, endPos={endPos}");
}

return true;
Expand Down Expand Up @@ -2383,14 +2385,10 @@ bool LoopHandler(int i, int j) {

// randomize target position to allow for opposite road-side parking
ParkingAI parkingAiConf = GlobalConfig.Instance.ParkingAI;
segCenter.x +=
Singleton<SimulationManager>.instance.m_randomizer.Int32(
parkingAiConf.ParkingSpacePositionRand) -
segCenter.x += rng.Int32(parkingAiConf.ParkingSpacePositionRand) -
(parkingAiConf.ParkingSpacePositionRand / 2u);

segCenter.z +=
Singleton<SimulationManager>.instance.m_randomizer.Int32(
parkingAiConf.ParkingSpacePositionRand) -
segCenter.z += rng.Int32(parkingAiConf.ParkingSpacePositionRand) -
(parkingAiConf.ParkingSpacePositionRand / 2u);

if (netSegment.GetClosestLanePosition(
Expand Down Expand Up @@ -2460,7 +2458,7 @@ bool LoopHandler(int i, int j) {
return true;
}

var coords = _spiral.GetCoords(radius);
var coords = _spiral.GetCoordsRandomDirection(radius, ref _randomizer);
for (int i = 0; i < radius * radius; i++) {
if (!LoopHandler((int)(centerI + coords[i].x), (int)(centerJ + coords[i].y))) {
break;
Expand Down Expand Up @@ -2571,7 +2569,7 @@ bool LoopHandler(int i, int j) {
return true;
}

var coords = _spiral.GetCoords(radius);
var coords = _spiral.GetCoordsRandomDirection(radius, ref _randomizer);
for (int i = 0; i < radius * radius; i++) {
if (!LoopHandler((int)(centerI + coords[i].x), (int)(centerJ + coords[i].y))) {
break;
Expand Down
18 changes: 10 additions & 8 deletions TLM/TLM/Manager/Impl/ExtPathManager.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace TrafficManager.Manager.Impl {
using ColossalFramework;
using System;
using System.Linq;
using ColossalFramework;
using ColossalFramework.Math;
using State;
using TrafficManager.API.Manager;
using TrafficManager.Util;
Expand All @@ -13,12 +13,14 @@ public class ExtPathManager
IExtPathManager
{
private readonly Spiral _spiral;
private Randomizer _randomizer;

public static readonly ExtPathManager Instance =
new ExtPathManager(SingletonLite<Spiral>.instance);

private ExtPathManager(Spiral spiral) {
_spiral = spiral ?? throw new ArgumentNullException(nameof(spiral));
_randomizer = new Randomizer();
}

/// <summary>
Expand Down Expand Up @@ -386,7 +388,7 @@ bool FindHelper(int i, int j) {

int spiralDist = Math.Max(Math.Abs(i - centerI), Math.Abs(j - centerJ)); // maximum norm

if (found && spiralDist > lastSpiralDist) {
if (found && lastSpiralDist > 0 && spiralDist > lastSpiralDist) {
// last iteration
return false;
}
Expand Down Expand Up @@ -454,8 +456,8 @@ bool FindHelper(int i, int j) {
out float laneOffsetB))
{
float dist = Vector3.SqrMagnitude(position - posA);
if (secondaryPosition != null) {
dist += Vector3.SqrMagnitude((Vector3)secondaryPosition - posA);
if (secondaryPosition.HasValue) {
dist += Vector3.SqrMagnitude(secondaryPosition.Value - posA);
}

if (dist < minDist) {
Expand All @@ -471,9 +473,9 @@ bool FindHelper(int i, int j) {
myDistanceSqrA = dist;

dist = Vector3.SqrMagnitude(position - posB);
if (secondaryPosition != null) {
if (secondaryPosition.HasValue) {
dist += Vector3.SqrMagnitude(
(Vector3)secondaryPosition - posB);
secondaryPosition.Value - posB);
}

if (laneIndexB < 0) {
Expand Down Expand Up @@ -508,7 +510,7 @@ bool FindHelper(int i, int j) {
return true;
}

var coords = _spiral.GetCoords(radius);
var coords = _spiral.GetCoordsRandomDirection(radius, ref _randomizer);
for (int i = 0; i < radius * radius; i++) {
if (!FindHelper((int)(centerI + coords[i].x), (int)(centerJ + coords[i].y))) {
break;
Expand Down
3 changes: 2 additions & 1 deletion TLM/TLM/Patch/_CitizenAI/_HumanAI/SimulationStepPatch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,8 @@ ref data.m_citizen.ToCitizen(),

data.m_flags &= ~(CitizenInstance.Flags.HangAround
| CitizenInstance.Flags.Panicking
| CitizenInstance.Flags.SittingDown);
| CitizenInstance.Flags.SittingDown
| CitizenInstance.Flags.Cheering);
ArriveAtDestination(__instance, instanceID, ref data, false);
citizenManager.ReleaseCitizenInstance(instanceID);

Expand Down
40 changes: 39 additions & 1 deletion TLM/TLM/Util/LoopUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public static IEnumerable<Vector2> GenerateSpiralGridCoordsClockwise() {
var cursorX = 0;
var cursorY = 0;

var directionX = 1;
var directionX = -1;
var directionY = 0;

var segmentLength = 1;
Expand All @@ -30,6 +30,44 @@ public static IEnumerable<Vector2> GenerateSpiralGridCoordsClockwise() {
segmentsPassed = 0; //start of new segment

//rotate clockwise
var buffer = -directionX;
directionX = directionY;
directionY = buffer;

//increase segmentLength every second time
if (directionY == 0) {
segmentLength++;
}
}
}

/// <summary>
/// Generates a stream of spiral grid coordinates counterclockwise.
/// </summary>
/// <returns>Stream of spiral grid coordinates until int.MaxValue + 1 elements were returned.</returns>
public static IEnumerable<Vector2> GenerateSpiralGridCoordsCounterclockwise() {
var cursorX = 0;
var cursorY = 0;

var directionX = 1;
var directionY = 0;

var segmentLength = 1;
var segmentsPassed = 0;

for (var n = 0; n <= int.MaxValue; n++) {
yield return new Vector2(cursorX, cursorY);

cursorX += directionX;
cursorY += directionY;

segmentsPassed++;
if (segmentsPassed != segmentLength) {
continue; //if segment is not full yet
}
segmentsPassed = 0; //start of new segment

//rotate counterClockwise
var buffer = directionX;
directionX = -directionY;
directionY = buffer;
Expand Down
80 changes: 67 additions & 13 deletions TLM/TLM/Util/Spiral.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using UnityEngine;

namespace TrafficManager.Util {
using ColossalFramework.Math;

/// <summary>
/// A spiral coords generator that will cache all previously generated values,
/// and only generate new ones if necessary.
Expand All @@ -12,9 +14,12 @@ public class Spiral {
private readonly string radiusOutOfRangeMessage = "Must be in the range [1,int.MaxValue]";

private int _maxRadius;
private IEnumerator<Vector2> _enumerator;
private List<Vector2> _spiralCoords;
private ReadOnlyCollection<Vector2> _spiralCoordsReadOnly;
private IEnumerator<Vector2> _enumeratorClockwise;
private IEnumerator<Vector2> _enumeratorCounterClockwise;
private List<Vector2> _spiralCoordsClockwise;
private List<Vector2> _spiralCoordsCounterclockwise;
private ReadOnlyCollection<Vector2> _spiralCoordsClockwiseReadOnly;
private ReadOnlyCollection<Vector2> _spiralCoordsCounterclockwiseReadOnly;

/// <summary>
/// Initializes a new instance of the <see cref="Spiral"/> class.
Expand All @@ -38,10 +43,14 @@ public Spiral(int radius) {
}

_maxRadius = 0;
_enumerator = LoopUtil.GenerateSpiralGridCoordsClockwise()
_enumeratorClockwise = LoopUtil.GenerateSpiralGridCoordsClockwise()
.GetEnumerator();
_enumeratorCounterClockwise = LoopUtil.GenerateSpiralGridCoordsCounterclockwise()
.GetEnumerator();
_spiralCoords = new List<Vector2>(radius * radius);
_spiralCoordsReadOnly = new ReadOnlyCollection<Vector2>(_spiralCoords);
_spiralCoordsClockwise = new List<Vector2>(radius * radius);
_spiralCoordsCounterclockwise = new List<Vector2>(radius * radius);
_spiralCoordsClockwiseReadOnly = new ReadOnlyCollection<Vector2>(_spiralCoordsCounterclockwise);
_spiralCoordsCounterclockwiseReadOnly = new ReadOnlyCollection<Vector2>(_spiralCoordsCounterclockwise);

Ensure(radius);
}
Expand All @@ -52,7 +61,43 @@ public Spiral(int radius) {
public int MaxRadius => _maxRadius;

/// <summary>
/// Gets spiral coords and ensures that the given radius is satisfied.
/// Gets spiral in random direction and ensired that the giver radius is satisfied
/// </summary>
/// <param name="radius">Needed radius for the spiral coords.</param>
/// <param name="r">Randomizer instance to perform randomization</param>
/// <returns>
/// A readonly collection of spiral coords.
/// The result won't generate a new collection for performance reasons,
/// meaning it will return a reference to the same mutable underlying collection.
/// The returned collection will always contain the coords for 'MaxRadius',
/// the largest radius it was ever passed.
/// </returns>
public ReadOnlyCollection<Vector2> GetCoordsRandomDirection(int radius, ref Randomizer r) {
return r.Int32(2) == 0 ? GetCoordsCounterclockwise(radius) : GetCoordsClockwise(radius);
}

/// <summary>
/// Gets spiral coords clockwise and ensures that the given radius is satisfied.
/// </summary>
/// <param name="radius">Needed radius for the spiral coords.</param>
/// <returns>
/// A readonly collection of spiral coords.
/// The result won't generate a new collection for performance reasons,
/// meaning it will return a reference to the same mutable underlying collection.
/// The returned collection will always contain the coords for 'MaxRadius',
/// the largest radius it was ever passed.
/// </returns>
public ReadOnlyCollection<Vector2> GetCoordsClockwise(int radius) {
if (radius < 1) {
throw new ArgumentOutOfRangeException(nameof(radius), radiusOutOfRangeMessage);
}

Ensure(radius);
return _spiralCoordsClockwiseReadOnly;
}

/// <summary>
/// Gets spiral coords counterclockwise and ensures that the given radius is satisfied.
/// </summary>
/// <param name="radius">Needed radius for the spiral coords.</param>
/// <returns>
Expand All @@ -62,13 +107,13 @@ public Spiral(int radius) {
/// The returned collection will always contain the coords for 'MaxRadius',
/// the largest radius it was ever passed.
/// </returns>
public ReadOnlyCollection<Vector2> GetCoords(int radius) {
public ReadOnlyCollection<Vector2> GetCoordsCounterclockwise(int radius) {
if (radius < 1) {
throw new ArgumentOutOfRangeException(nameof(radius), radiusOutOfRangeMessage);
}

Ensure(radius);
return _spiralCoordsReadOnly;
return _spiralCoordsCounterclockwiseReadOnly;
}

private void Ensure(int radius) {
Expand All @@ -77,11 +122,20 @@ private void Ensure(int radius) {
}

var enumerateCount = radius * radius;
_spiralCoords.Capacity = enumerateCount;
for (int i = _spiralCoords.Count; i < enumerateCount; i++) {
var hasNext = _enumerator.MoveNext();

_spiralCoordsClockwise.Capacity = enumerateCount;
for (int i = _spiralCoordsClockwise.Count; i < enumerateCount; i++) {
var hasNext = _enumeratorClockwise.MoveNext();
if (hasNext) {
_spiralCoordsClockwise.Add(_enumeratorClockwise.Current);
}
}

_spiralCoordsCounterclockwise.Capacity = enumerateCount;
for (int i = _spiralCoordsCounterclockwise.Count; i < enumerateCount; i++) {
var hasNext = _enumeratorCounterClockwise.MoveNext();
if (hasNext) {
_spiralCoords.Add(_enumerator.Current);
_spiralCoordsCounterclockwise.Add(_enumeratorCounterClockwise.Current);
}
}

Expand Down
Loading

0 comments on commit 4c23481

Please sign in to comment.