Skip to content

Commit

Permalink
TMPE version 1.8.14:
Browse files Browse the repository at this point in the history
- Bugfix: Wait/flow ratio at timed traffic lights is sometimes not correctly calculated
- Bugfix: A deadlock situation can arise at junctions with priority signs such that no vehicle enters the junction
- Bugfix: When adding a junction to a timed traffic light, sometimes light states given by user input are not correctly stored
- Bugfix: Joining two timed traffic lights sets the minimum time to "1" for steps with zero minimum time assigned
- Bugfix: Modifications of timed traffic light states are sometimes not visible while editting the light (but they are applied nonetheless)
- Bugfix: Button background is not always correctly changed after clicking on a button within the main menu
- Tram lanes can now be customized by using the lane connector tool
- Minor performance optimizations for priority sign simulation
  • Loading branch information
VictorPhilipp committed Jan 7, 2017
1 parent 5a18563 commit 370f2a9
Show file tree
Hide file tree
Showing 20 changed files with 286 additions and 127 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ A work-in-progress modification for **Cities: Skylines** to add additional traff
User manual: http://www.viathinksoft.de/tmpe

# Changelog
1.8.14, 01/07/2017
- Bugfix: Wait/flow ratio at timed traffic lights is sometimes not correctly calculated
- Bugfix: A deadlock situation can arise at junctions with priority signs such that no vehicle enters the junction
- Bugfix: When adding a junction to a timed traffic light, sometimes light states given by user input are not correctly stored
- Bugfix: Joining two timed traffic lights sets the minimum time to "1" for steps with zero minimum time assigned
- Bugfix: Modifications of timed traffic light states are sometimes not visible while editting the light (but they are applied nonetheless)
- Bugfix: Button background is not always correctly changed after clicking on a button within the main menu
- Tram lanes can now be customized by using the lane connector tool
- Minor performance optimizations for priority sign simulation

1.8.13, 01/05/2017
- Bugfix: Timed traffic ligt data can become corrupt when upgrading a road segment next to a traffic light, leading to faulty UI behavior (thanks to @Brain for reporting this issue)
- Bugfix: The position of the main menu button resets after switching to the free camera mode (thanks to @Impact and @gravage for reporting this issue)
Expand Down
12 changes: 6 additions & 6 deletions TLM/TLM/Custom/AI/CustomVehicleAI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ internal static bool MayChangeSegment(ushort vehicleId, ref Vehicle vehicleData,
#endif
var currentFrameIndex2 = Singleton<SimulationManager>.instance.m_currentFrameIndex;
var frame = currentFrameIndex2 >> 4;
float speed = lastFrameData.m_velocity.magnitude;
float sqrSpeed = lastFrameData.m_velocity.sqrMagnitude;

if (vehicleState.JunctionTransitState == VehicleJunctionTransitState.None) {
#if DEBUG
Expand All @@ -389,7 +389,7 @@ internal static bool MayChangeSegment(ushort vehicleId, ref Vehicle vehicleData,
case SegmentEnd.PriorityType.Stop:
#if DEBUG
if (debug)
Log._Debug($"Vehicle {vehicleId}: STOP sign. waittime={vehicleState.WaitTime}, vel={speed}");
Log._Debug($"Vehicle {vehicleId}: STOP sign. waittime={vehicleState.WaitTime}, sqrSpeed={sqrSpeed}");
#endif

if (Options.simAccuracy <= 2 || (Options.simAccuracy >= 3 && vehicleState.WaitTime < MaxPriorityWaitTime)) {
Expand All @@ -399,7 +399,7 @@ internal static bool MayChangeSegment(ushort vehicleId, ref Vehicle vehicleData,
#endif
vehicleState.JunctionTransitState = VehicleJunctionTransitState.Stop;

if (speed <= TrafficPriorityManager.MAX_STOP_VELOCITY) {
if (sqrSpeed <= TrafficPriorityManager.MAX_SQR_STOP_VELOCITY) {
vehicleState.WaitTime++;

float minStopWaitTime = UnityEngine.Random.Range(0f, 3f);
Expand Down Expand Up @@ -454,7 +454,7 @@ internal static bool MayChangeSegment(ushort vehicleId, ref Vehicle vehicleData,
#endif
vehicleState.JunctionTransitState = VehicleJunctionTransitState.Stop;

if (speed <= TrafficPriorityManager.MAX_YÌELD_VELOCITY || Options.simAccuracy <= 2) {
if (sqrSpeed <= TrafficPriorityManager.MAX_SQR_YÌELD_VELOCITY || Options.simAccuracy <= 2) {
if (Options.simAccuracy >= 4) {
vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave;
} else {
Expand All @@ -478,7 +478,7 @@ internal static bool MayChangeSegment(ushort vehicleId, ref Vehicle vehicleData,
} else {
#if DEBUG
if (debug)
Log._Debug($"Vehicle {vehicleId}: Vehicle has not yet reached yield speed (reduce {speed} by {vehicleState.ReduceSpeedByValueToYield})");
Log._Debug($"Vehicle {vehicleId}: Vehicle has not yet reached yield speed (reduce {sqrSpeed} by {vehicleState.ReduceSqrSpeedByValueToYield})");
#endif

// vehicle has not yet reached yield speed
Expand Down Expand Up @@ -529,7 +529,7 @@ internal static bool MayChangeSegment(ushort vehicleId, ref Vehicle vehicleData,
}
return true;
}
} else if (speed <= TrafficPriorityManager.MAX_STOP_VELOCITY) {
} else if (sqrSpeed <= TrafficPriorityManager.MAX_SQR_STOP_VELOCITY) {
// vehicle is not moving. reset allowance to leave junction
#if DEBUG
if (debug)
Expand Down
26 changes: 22 additions & 4 deletions TLM/TLM/Geometry/NodeGeometry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ public SegmentEndGeometry[] SegmentEndGeometries {
get; private set;
} = new SegmentEndGeometry[8];

public byte NumSegmentEnds { get; private set; } = 0;

public bool NeedsRecalculation { get; private set; } = false; // TODO actually use this flag

/// <summary>
/// Holds a list of observers which are being notified as soon as the managed node's geometry is updated (but not neccessarily modified)
/// </summary>
Expand Down Expand Up @@ -88,8 +92,14 @@ internal void AddSegment(ushort segmentId, bool startNode, bool propagate) {
}
}

if (propagate)
RecalculateSegments(segmentId);
if (propagate) {
NeedsRecalculation = true;
try {
RecalculateSegments(segmentId);
} finally {
NeedsRecalculation = false;
}
}
Recalculate();
}

Expand All @@ -110,13 +120,20 @@ internal void RemoveSegment(ushort segmentId, bool propagate) {
}
}

if (propagate)
RecalculateSegments(segmentId);
if (propagate) {
NeedsRecalculation = true;
try {
RecalculateSegments(segmentId);
} finally {
NeedsRecalculation = false;
}
}
Recalculate();
}

private void Cleanup() {
IsSimpleJunction = false;
NumSegmentEnds = 0;
}

internal void RecalculateSegments(ushort? ignoreSegmentId= null) {
Expand Down Expand Up @@ -159,6 +176,7 @@ internal void Recalculate() {
for (int i = 0; i < 8; ++i) {
if (SegmentEndGeometries[i] == null)
continue;
++NumSegmentEnds;
#if DEBUGGEO
if (GlobalConfig.Instance.DebugSwitches[5])
Log._Debug($"NodeGeometry.Recalculate: Iterating over segment end {SegmentEndGeometries[i].SegmentId} @ node {NodeId}");
Expand Down
10 changes: 3 additions & 7 deletions TLM/TLM/Geometry/SegmentGeometry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -976,25 +976,21 @@ public bool AreHighwayRulesEnabled(bool startNode) {
/// <param name="segmentId">segment to check</param>
/// <param name="nodeId">node the given segment shall be checked at</param>
/// <returns>true, if the given segment is an outgoing one-way road at the given node, false otherwise</returns>
internal static bool calculateIsOutgoingOneWay(ushort segmentId, ushort nodeId) {
internal static bool calculateIsOutgoingOneWay(ushort segmentId, ushort nodeId) { // TODO move to SegmentEnd
if (!IsValid(segmentId))
return false;

var instance = Singleton<NetManager>.instance;

var info = instance.m_segments.m_buffer[segmentId].Info;

var dir = NetInfo.Direction.Forward;
if (instance.m_segments.m_buffer[segmentId].m_startNode == nodeId)
dir = NetInfo.Direction.Backward;
var dir2 = ((instance.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) ? dir : NetInfo.InvertDirection(dir);
var dir3 = TrafficPriorityManager.IsLeftHandDrive() ? NetInfo.InvertDirection(dir2) : dir2;
NetInfo.Direction dir = NetUtil.GetSegmentEndDirection(segmentId, ref instance.m_segments.m_buffer[segmentId], instance.m_segments.m_buffer[segmentId].m_startNode == nodeId);

var laneId = instance.m_segments.m_buffer[segmentId].m_lanes;
var laneIndex = 0;
while (laneIndex < info.m_lanes.Length && laneId != 0u) {
if (info.m_lanes[laneIndex].m_laneType != NetInfo.LaneType.Pedestrian &&
(info.m_lanes[laneIndex].m_direction == dir3)) {
((info.m_lanes[laneIndex].m_direction & dir) != NetInfo.Direction.None)) {
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion TLM/TLM/Manager/CustomSegmentLightsManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public CustomSegmentLights AddLiveSegmentLights(ushort segmentId, bool startNode
/// <param name="lightState">(optional) light state to set</param>
public CustomSegmentLights AddSegmentLights(ushort segmentId, bool startNode, RoadBaseAI.TrafficLightState lightState=RoadBaseAI.TrafficLightState.Red) {
#if DEBUG
Log.Warning($"CustomTrafficLights.AddSegmentLights: Adding segment light: {segmentId} @ startNode={startNode}");
Log._Debug($"CustomTrafficLights.AddSegmentLights: Adding segment light: {segmentId} @ startNode={startNode}");
#endif
CustomSegment customSegment = CustomSegments[segmentId];
if (customSegment == null) {
Expand Down
27 changes: 20 additions & 7 deletions TLM/TLM/Manager/TrafficPriorityManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ static TrafficPriorityManager() {
Instance = new TrafficPriorityManager();
}

public const float MAX_STOP_VELOCITY = 0.1f;
public const float MAX_SQR_STOP_VELOCITY = 0.01f;
public const float MAX_SQR_YÌELD_VELOCITY = 0.09f;
public const float MAX_YÌELD_VELOCITY = 0.3f;

/// <summary>
Expand Down Expand Up @@ -404,9 +405,10 @@ public bool HasIncomingVehiclesWithHigherPriority(ushort targetVehicleId, ref Ve
bool conflicting = false;
incomingState.ProcessCurrentAndNextPathPositionAndOtherVehicleCurrentAndNextPathPosition(ref vehManager.m_vehicles.m_buffer[incomingVehicleId], ref curPos, ref nextPos, ref targetVehicleData, delegate (ref Vehicle incomingVehicleData, ref PathUnit.Position incomingCurPos, ref PathUnit.Position incomingNextPos, ref Vehicle targetVehData, ref PathUnit.Position targetCurPos, ref PathUnit.Position targetNextPos) {

bool incomingStateChangedRecently = incomingState.IsJunctionTransitStateNew();
if (
incomingState.JunctionTransitState == VehicleJunctionTransitState.Enter ||
(incomingState.JunctionTransitState == VehicleJunctionTransitState.Leave && (incomingState.LastStateUpdate >> VehicleState.STATE_UPDATE_SHIFT) >= (frame >> VehicleState.STATE_UPDATE_SHIFT))) {
(incomingState.JunctionTransitState == VehicleJunctionTransitState.Leave && incomingStateChangedRecently)) {
// incoming vehicle is (1) entering the junction or (2) leaving but last state update ocurred very recently.
Vector3 incomingPos = incomingVehicleData.GetLastFramePosition();
Vector3 incomingVel = incomingVehicleData.GetLastFrameVelocity();
Expand Down Expand Up @@ -460,19 +462,30 @@ public bool HasIncomingVehiclesWithHigherPriority(ushort targetVehicleId, ref Ve
Log._Debug($"HasIncomingVehicles: Target is stopped.");
#endif
}
} else {
} else if (incomingState.JunctionTransitState == VehicleJunctionTransitState.Leave) {
#if DEBUG
if (debug)
Log._Debug($"HasIncomingVehicles: Incoming {incomingVehicleId} is LEAVING but state update occurred recently.");
Log._Debug($"HasIncomingVehicles: Incoming {incomingVehicleId} is LEAVING but state update did not occur recently.");
#endif

float incomingSqrSpeed = incomingVehicleData.GetLastFrameVelocity().sqrMagnitude;
if (incomingSqrSpeed <= MAX_SQR_STOP_VELOCITY) {
#if DEBUG
if (debug)
Log._Debug($"HasIncomingVehicles: Incoming {incomingVehicleId} is LEAVING but not moving. -> BLOCKED");
#endif
incomingState.JunctionTransitState = VehicleJunctionTransitState.Blocked;
incomingStateChangedRecently = true;
}
}

if (incomingState.JunctionTransitState == VehicleJunctionTransitState.Blocked &&
(incomingState.LastStateUpdate >> VehicleState.STATE_UPDATE_SHIFT) < (frame >> VehicleState.STATE_UPDATE_SHIFT)
if (!incomingStateChangedRecently &&
(incomingState.JunctionTransitState == VehicleJunctionTransitState.Blocked ||
(incomingState.JunctionTransitState == VehicleJunctionTransitState.Stop && targetVehicleId < incomingVehicleId))
) {
#if DEBUG
if (debug)
Log._Debug($"HasIncomingVehicles: Incoming {incomingVehicleId} is BLOCKED and has waited a bit. *IGNORING*");
Log._Debug($"HasIncomingVehicles: Incoming {incomingVehicleId} is BLOCKED and has waited a bit or is STOP and targetVehicleId {targetVehicleId} < incomingVehicleId {incomingVehicleId}. *IGNORING*");
#endif

// incoming vehicle waits because the junction is blocked and we waited a little. Allow target vehicle to enter the junciton.
Expand Down
1 change: 1 addition & 0 deletions TLM/TLM/State/GlobalConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ internal static void OnLevelUnloading() {

#if DEBUG
public ushort PathFindDebugNodeId = 0;
public ushort TTLDebugNodeId = 0;
#endif

/// <summary>
Expand Down
8 changes: 6 additions & 2 deletions TLM/TLM/TLM.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,17 @@
<Compile Include="Custom\Manager\CustomNetManager.cs" />
<Compile Include="Custom\Manager\CustomCitizenManager.cs" />
<Compile Include="Custom\Manager\CustomVehicleManager.cs" />
<Compile Include="GameBridge\INetLaneBridge.cs" />
<Compile Include="GameBridge\INetNodeBridge.cs" />
<Compile Include="GameBridge\INetSegmentBridge.cs" />
<Compile Include="Manager\AbstractCustomManager.cs" />
<Compile Include="Manager\AbstractNodeGeometryObservingManager.cs" />
<Compile Include="Manager\AbstractSegmentGeometryObservingManager.cs" />
<Compile Include="Manager\ExtBuildingManager.cs" />
<Compile Include="Manager\ICustomDataManager.cs" />
<Compile Include="Manager\LaneArrowManager.cs" />
<Compile Include="Manager\OptionsManager.cs" />
<Compile Include="Manager\TemplateManager.cs" />
<Compile Include="Manager\TrafficLightManager.cs" />
<Compile Include="Manager\TrafficMeasurementManager.cs" />
<Compile Include="Manager\JunctionRestrictionsManager.cs" />
Expand All @@ -122,8 +126,8 @@
<Compile Include="Geometry\SegmentEndGeometry.cs" />
<Compile Include="Manager\VehicleStateManager.cs" />
<Compile Include="Manager\VehicleRestrictionsManager.cs" />
<Compile Include="Traffic\Template\JunctionRestrictionsTemplate.cs" />
<Compile Include="Traffic\Template\JunctionTemplate.cs" />
<Compile Include="Traffic\Template\SegmentEndRestrictionsTemplate.cs" />
<Compile Include="Traffic\Template\NodeTemplate.cs" />
<Compile Include="Traffic\Template\LaneConnectionTemplate.cs" />
<Compile Include="Traffic\Template\LaneTemplate.cs" />
<Compile Include="Traffic\Template\SegmentEndTemplate.cs" />
Expand Down
8 changes: 4 additions & 4 deletions TLM/TLM/Traffic/ExtCitizenInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,9 @@ public ExtPathMode PathMode {
}
internal set {
#if DEBUG
if (GlobalConfig.Instance.DebugSwitches[7]) {
/*if (GlobalConfig.Instance.DebugSwitches[7]) {
Log.Warning($"Changing PathMode for citizen instance {InstanceId}: {pathMode} -> {value}");
}
}*/
#endif
pathMode = value;
}
Expand Down Expand Up @@ -207,9 +207,9 @@ public uint GetCitizenId() {

internal void Reset() {
#if DEBUG
if (GlobalConfig.Instance.DebugSwitches[7]) {
/*if (GlobalConfig.Instance.DebugSwitches[7]) {
Log.Warning($"Resetting PathMode for citizen instance {InstanceId}");
}
}*/
#endif
//Flags = ExtFlags.None;
PathMode = ExtPathMode.None;
Expand Down
2 changes: 1 addition & 1 deletion TLM/TLM/Traffic/SegmentEnd.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ public Dictionary<ushort, uint> GetVehicleMetricGoingToSegment(bool includeStopp
return;
}

if (!includeStopped && vehState.GetLastFrameVelocity().magnitude < TrafficPriorityManager.MAX_STOP_VELOCITY) {
if (!includeStopped && vehState.GetLastFrameVelocity().sqrMagnitude < TrafficPriorityManager.MAX_SQR_STOP_VELOCITY) {
#if DEBUGMETRIC2
if (debug)
Log._Debug($" GetVehicleMetricGoingToSegment: Vehicle {vehicleId}: too slow");
Expand Down
13 changes: 11 additions & 2 deletions TLM/TLM/Traffic/VehicleState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public float TotalLength {

private ushort VehicleId;
public int WaitTime = 0;
public float ReduceSpeedByValueToYield;
public float ReduceSqrSpeedByValueToYield;
private bool valid = false;

public bool Valid {
Expand Down Expand Up @@ -493,7 +493,7 @@ internal void OnVehicleSpawned(ref Vehicle vehicleData) {
// enforce updating trailers (they are not always present at path-finding time)
ApplyVehicleTypeToTrailers();

ReduceSpeedByValueToYield = UnityEngine.Random.Range(16f, 28f);
ReduceSqrSpeedByValueToYield = UnityEngine.Random.Range(256f, 784f);
try {
TotalLength = Singleton<VehicleManager>.instance.m_vehicles.m_buffer[VehicleId].CalculateTotalLength(VehicleId);
} catch (Exception) {
Expand Down Expand Up @@ -538,5 +538,14 @@ private void ApplyVehicleTypeToTrailers() {
otherVehicleId = vehManager.m_vehicles.m_buffer[otherVehicleId].m_trailingVehicle;
}
}

/// <summary>
/// Determines if the junction transit state has been recently modified
/// </summary>
/// <returns></returns>
internal bool IsJunctionTransitStateNew() {
uint frame = Singleton<SimulationManager>.instance.m_currentFrameIndex;
return (LastStateUpdate >> VehicleState.STATE_UPDATE_SHIFT) >= (frame >> VehicleState.STATE_UPDATE_SHIFT);
}
}
}
47 changes: 33 additions & 14 deletions TLM/TLM/TrafficLight/CustomSegmentLight.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,7 @@ public Mode CurrentMode {
return;

currentMode = value;
switch (currentMode) {
case Mode.Simple:
leftLight = LightMain;
rightLight = LightMain;
break;
case Mode.SingleLeft:
rightLight = LightMain;
break;
case Mode.SingleRight:
leftLight = LightMain;
break;
}

lights.OnChange();
EnsureModeLights();
}
}
internal Mode currentMode = Mode.Simple;
Expand Down Expand Up @@ -95,6 +82,38 @@ public RoadBaseAI.TrafficLightState LightRight {

CustomSegmentLights lights;

private void EnsureModeLights() {
bool changed = false;

switch (currentMode) {
case Mode.Simple:
if (leftLight != LightMain) {
leftLight = LightMain;
changed = true;
}
if (rightLight != LightMain) {
rightLight = LightMain;
changed = true;
}
break;
case Mode.SingleLeft:
if (rightLight != LightMain) {
rightLight = LightMain;
changed = true;
}
break;
case Mode.SingleRight:
if (leftLight != LightMain) {
leftLight = LightMain;
changed = true;
}
break;
}

if (changed)
lights.OnChange();
}

public override string ToString() {
return $"LightLeft={LightLeft} LightMain={LightMain} LightRight={LightRight} CurrentMode={CurrentMode}";
}
Expand Down
Loading

0 comments on commit 370f2a9

Please sign in to comment.