Skip to content

Commit

Permalink
TMPE version 1.8.13:
Browse files Browse the repository at this point in the history
- 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)
- Improved selection of overlay markers on underground roads (thanks to @padi for reminding me of that issue)
- Minor performance improvements
  • Loading branch information
VictorPhilipp committed Jan 4, 2017
1 parent 35e1992 commit 2fd094b
Show file tree
Hide file tree
Showing 17 changed files with 177 additions and 67 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@ A work-in-progress modification for **Cities: Skylines** to add additional traff
User manual: http://www.viathinksoft.de/tmpe

# Changelog
1.8.13, 01/01/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)
- Improved selection of overlay markers on underground roads (thanks to @Padi for reminding me of that issue)
- Minor performance improvements

1.8.12, 01/02/2017
- Updated for game version 1.6.2-f1
- Bugfix: After leaving the "Manual traffic lights" mode traffic light simulation is not cleaned up correctly (thanks to @ diezelunderwood for reporting this issue)
- Bugfix: After leaving the "Manual traffic lights" mode the traffic light simulation is not cleaned up correctly (thanks to @diezelunderwood for reporting this issue)
- Bugfix: Insufficient access rights to log file causes the mod to crash

1.8.11, 01/02/2017
Expand Down
1 change: 1 addition & 0 deletions TLM/TLM/Custom/AI/CustomCitizenAI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using static TrafficManager.Traffic.ExtCitizenInstance;

namespace TrafficManager.Custom.AI {
// TODO move Parking AI features from here to a distinct manager
public class CustomCitizenAI : CitizenAI {
/// <summary>
/// Finds a free parking space in the vicinity of the given target position <paramref name="endPos"/> for the given citizen instance <paramref name="extDriverInstance"/>.
Expand Down
2 changes: 1 addition & 1 deletion TLM/TLM/Custom/AI/CustomHumanAI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -867,7 +867,7 @@ public bool CustomCheckTrafficLights(ushort node, ushort segment) {
// NON-STOCK CODE START //
RoadBaseAI.TrafficLightState pedestrianLightState;
bool startNode = instance.m_segments.m_buffer[segment].m_startNode == node;
CustomSegmentLights lights = CustomSegmentLightsManager.Instance.GetSegmentLights(segment, startNode);
CustomSegmentLights lights = CustomSegmentLightsManager.Instance.GetSegmentLights(segment, startNode, false);

if (lights == null || nodeSimulation == null || !nodeSimulation.IsSimulationActive()) {
RoadBaseAI.TrafficLightState vehicleLightState;
Expand Down
1 change: 1 addition & 0 deletions TLM/TLM/Custom/AI/CustomPassengerCarAI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using System.IO;

namespace TrafficManager.Custom.AI {
// TODO move Parking AI features from here to a distinct manager
public class CustomPassengerCarAI : CarAI {
public void CustomSimulationStep(ushort vehicleId, ref Vehicle vehicleData, Vector3 physicsLodRefPos) {
if ((vehicleData.m_flags & Vehicle.Flags.Congestion) != 0 && Options.enableDespawning) {
Expand Down
2 changes: 1 addition & 1 deletion TLM/TLM/Custom/AI/CustomRoadAI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ private static void GetCustomTrafficLightState(ushort vehicleId, ref Vehicle veh
// determine node position at `fromSegment` (start/end)
bool isStartNode = geometry.StartNodeId() == nodeId;

CustomSegmentLights lights = CustomSegmentLightsManager.Instance.GetSegmentLights(fromSegmentId, isStartNode);
CustomSegmentLights lights = CustomSegmentLightsManager.Instance.GetSegmentLights(fromSegmentId, isStartNode, false);

if (lights != null) {
// get traffic lights state for pedestrians
Expand Down
76 changes: 69 additions & 7 deletions TLM/TLM/Manager/TrafficLightSimulationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using TrafficManager.Util;
using TrafficManager.TrafficLight;
using TrafficManager.Traffic;
using System.Linq;

namespace TrafficManager.Manager {
public class TrafficLightSimulationManager : AbstractNodeGeometryObservingManager, ICustomDataManager<List<Configuration.TimedTrafficLights>> {
Expand Down Expand Up @@ -72,7 +73,7 @@ public void RemoveNodeFromSimulation(ushort nodeId, bool destroyGroup, bool remo
TrafficLightManager tlm = TrafficLightManager.Instance;

if (sim.TimedLight != null) {
// remove/destroy other timed traffic lights in group
// remove/destroy all timed traffic lights in group
List<ushort> oldNodeGroup = new List<ushort>(sim.TimedLight.NodeGroup);
foreach (var timedNodeId in oldNodeGroup) {
var otherNodeSim = GetNodeSimulation(timedNodeId);
Expand All @@ -95,7 +96,7 @@ public void RemoveNodeFromSimulation(ushort nodeId, bool destroyGroup, bool remo
}

//Flags.setNodeTrafficLight(nodeId, false);
sim.DestroyTimedTrafficLight();
//sim.DestroyTimedTrafficLight();
sim.DestroyManualTrafficLight();
sim.NodeGeoUnsubscriber?.Dispose();
RemoveNodeFromSimulation(nodeId);
Expand Down Expand Up @@ -138,17 +139,75 @@ public bool LoadData(List<Configuration.TimedTrafficLights> data) {

TrafficLightManager tlm = TrafficLightManager.Instance;

HashSet<ushort> nodesWithSimulation = new HashSet<ushort>();
foreach (Configuration.TimedTrafficLights cnfTimedLights in data) {
nodesWithSimulation.Add(cnfTimedLights.nodeId);
}

Dictionary<ushort, ushort> masterNodeIdBySlaveNodeId = new Dictionary<ushort, ushort>();
Dictionary<ushort, List<ushort>> nodeGroupByMasterNodeId = new Dictionary<ushort, List<ushort>>();
foreach (Configuration.TimedTrafficLights cnfTimedLights in data) {
try {
if (!NetUtil.IsNodeValid(cnfTimedLights.nodeId))
continue;
// TODO most of this should not be necessary at all if the classes around TimedTrafficLights class were properly designed
List<ushort> currentNodeGroup = cnfTimedLights.nodeGroup.Distinct().ToList(); // enforce uniqueness of node ids
if (!currentNodeGroup.Contains(cnfTimedLights.nodeId))
currentNodeGroup.Add(cnfTimedLights.nodeId);
// remove any nodes that are not configured to have a simulation
currentNodeGroup = new List<ushort>(currentNodeGroup.Intersect(nodesWithSimulation));

// remove invalid nodes from the group; find if any of the nodes in the group is already a master node
ushort masterNodeId = 0;
int foundMasterNodes = 0;
for (int i = 0; i < currentNodeGroup.Count;) {
ushort nodeId = currentNodeGroup[i];
if (!NetUtil.IsNodeValid(currentNodeGroup[i])) {
currentNodeGroup.RemoveAt(i);
continue;
} else if (nodeGroupByMasterNodeId.ContainsKey(nodeId)) {
// this is a known master node
if (foundMasterNodes > 0) {
// we already found another master node. ignore this node.
currentNodeGroup.RemoveAt(i);
continue;
}
// we found the first master node
masterNodeId = nodeId;
++foundMasterNodes;
}
++i;
}

if (masterNodeId == 0) {
// no master node defined yet, set the first node as a master node
masterNodeId = currentNodeGroup[0];
}

// ensure the master node is the first node in the list (TimedTrafficLights depends on this at the moment...)
currentNodeGroup.Remove(masterNodeId);
currentNodeGroup.Insert(0, masterNodeId);

tlm.AddTrafficLight(cnfTimedLights.nodeId);
// update the saved node group and master-slave info
nodeGroupByMasterNodeId[masterNodeId] = currentNodeGroup;
foreach (ushort nodeId in currentNodeGroup) {
masterNodeIdBySlaveNodeId[nodeId] = masterNodeId;
}
} catch (Exception e) {
Log.Warning($"Error building timed traffic light group for TimedNode {cnfTimedLights.nodeId} (NodeGroup: {string.Join(", ", cnfTimedLights.nodeGroup.Select(x => x.ToString()).ToArray())}): " + e.ToString());
success = false;
}
}

Log._Debug($"Adding Timed Node at node {cnfTimedLights.nodeId}");
foreach (Configuration.TimedTrafficLights cnfTimedLights in data) {
try {
if (!masterNodeIdBySlaveNodeId.ContainsKey(cnfTimedLights.nodeId))
continue;
ushort masterNodeId = masterNodeIdBySlaveNodeId[cnfTimedLights.nodeId];
List<ushort> nodeGroup = nodeGroupByMasterNodeId[masterNodeId];

Log._Debug($"Adding timed light at node {cnfTimedLights.nodeId}. NodeGroup: {string.Join(", ", nodeGroup.Select(x => x.ToString()).ToArray())}");

TrafficLightSimulation sim = AddNodeToSimulation(cnfTimedLights.nodeId);
sim.SetupTimedTrafficLight(cnfTimedLights.nodeGroup);
sim.SetupTimedTrafficLight(nodeGroup);
var timedNode = sim.TimedLight;

int j = 0;
Expand Down Expand Up @@ -198,6 +257,9 @@ public bool LoadData(List<Configuration.TimedTrafficLights> data) {
foreach (Configuration.TimedTrafficLights cnfTimedLights in data) {
try {
TrafficLightSimulation sim = GetNodeSimulation(cnfTimedLights.nodeId);
if (sim == null || sim.TimedLight == null)
continue;

var timedNode = sim.TimedLight;

timedNode.housekeeping();
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 @@ -290,6 +290,7 @@ internal static void WriteConfig() {
}

private static GlobalConfig WriteDefaultConfig(GlobalConfig oldConfig, out DateTime modifiedTime) {
Log._Debug($"Writing default config...");
GlobalConfig conf = new GlobalConfig();
if (oldConfig != null) {
conf.MainMenuButtonX = oldConfig.MainMenuButtonX;
Expand Down
5 changes: 3 additions & 2 deletions TLM/TLM/TrafficLight/CustomSegmentLights.cs
Original file line number Diff line number Diff line change
Expand Up @@ -345,15 +345,16 @@ public void OnChange(bool calculateAutoPedLight=true) {
}

internal void CalculateAutoPedestrianLightState(bool propagate=true) {
//Log._Debug($"CustomSegmentLights.CalculateAutoPedestrianLightState: Calculating pedestrian light state of node {NodeId}");
SegmentGeometry segGeo = SegmentGeometry.Get(SegmentId);
SegmentEndGeometry segmentEndGeometry = StartNode ? segGeo.StartNodeGeometry : segGeo.EndNodeGeometry;
ushort nodeId = segmentEndGeometry.NodeId();

if (segmentEndGeometry == null) {
//Log._Debug($"Could not get SegmentEndGeometry for segment {SegmentId} @ {NodeId}.");
Log._Debug($"Could not get SegmentEndGeometry for segment {SegmentId} @ {NodeId}.");
AutoPedestrianLightState = RoadBaseAI.TrafficLightState.Green;
return;
}
ushort nodeId = segmentEndGeometry.NodeId();

if (propagate) {
foreach (ushort otherSegmentId in segmentEndGeometry.ConnectedSegments) {
Expand Down
2 changes: 1 addition & 1 deletion TLM/TLM/TrafficLight/TimedTrafficLights.cs
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ public long CheckNextChange(ushort segmentId, bool startNode, ExtVehicleType veh
var numFrames = Steps[CurrentStep].MaxTimeRemaining();

RoadBaseAI.TrafficLightState currentState;
CustomSegmentLights segmentLights = CustomSegmentLightsManager.Instance.GetSegmentLights(segmentId, startNode);
CustomSegmentLights segmentLights = CustomSegmentLightsManager.Instance.GetSegmentLights(segmentId, startNode, false);
if (segmentLights == null) {
Log._Debug($"CheckNextChange: No segment lights at node {NodeId}, segment {segmentId}");
return 99;
Expand Down
4 changes: 2 additions & 2 deletions TLM/TLM/TrafficLight/TimedTrafficLightsStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ public void UpdateLiveLights(bool noTransition) {

//segLightState.makeRedOrGreen(); // TODO temporary fix

var liveSegmentLights = customTrafficLightsManager.GetSegmentLights(segmentId, curStepSegmentLights.StartNode);
var liveSegmentLights = customTrafficLightsManager.GetSegmentLights(segmentId, curStepSegmentLights.StartNode, false);
if (liveSegmentLights == null) {
continue;
}
Expand Down Expand Up @@ -388,7 +388,7 @@ public void UpdateLights() {
var segLights = e.Value;

//if (segment == 0) continue;
var liveSegLights = CustomSegmentLightsManager.Instance.GetSegmentLights(segmentId, segLights.StartNode);
var liveSegLights = CustomSegmentLightsManager.Instance.GetSegmentLights(segmentId, segLights.StartNode, false);
if (liveSegLights == null)
continue;

Expand Down
2 changes: 1 addition & 1 deletion TLM/TLM/TrafficManagerMod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace TrafficManager {
public class TrafficManagerMod : IUserMod {

public static readonly string Version = "1.8.12";
public static readonly string Version = "1.8.13";

public static readonly uint GameVersion = 159768848u;
public static readonly uint GameVersionA = 1u;
Expand Down
28 changes: 21 additions & 7 deletions TLM/TLM/UI/SubTools/LaneConnectorTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ private void ShowOverlay(bool viewOnly, RenderManager.CameraInfo cameraInfo) {
NetManager netManager = Singleton<NetManager>.instance;

var camPos = Singleton<SimulationManager>.instance.m_simulationView.m_position;
Bounds bounds = new Bounds(Vector3.zero, Vector3.one);
//Bounds bounds = new Bounds(Vector3.zero, Vector3.one);
Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);

foreach (KeyValuePair<ushort, List<NodeLaneMarker>> e in currentNodeMarkers) {
Expand All @@ -87,7 +87,6 @@ private void ShowOverlay(bool viewOnly, RenderManager.CameraInfo cameraInfo) {
continue; // do not draw if too distant

if (!viewOnly && GetMarkerSelectionMode() == MarkerSelectionMode.None) {
//MainTool.DrawOverlayCircle(cameraInfo, DefaultNodeMarkerColor, netManager.m_nodes.m_buffer[nodeId].m_position, 20f, true);
MainTool.DrawNodeCircle(cameraInfo, nodeId, DefaultNodeMarkerColor, true);
}

Expand All @@ -98,8 +97,8 @@ private void ShowOverlay(bool viewOnly, RenderManager.CameraInfo cameraInfo) {
}

if (!viewOnly && nodeId == SelectedNodeId) {
bounds.center = laneMarker.position;
bool markerIsHovered = bounds.IntersectRay(mouseRay);
//bounds.center = laneMarker.position;
bool markerIsHovered = IsLaneMarkerHovered(laneMarker, ref mouseRay);// bounds.IntersectRay(mouseRay);

// draw source marker in source selection mode,
// draw target marker (if segment turning angles are within bounds) and selected source marker in target selection mode
Expand Down Expand Up @@ -127,13 +126,23 @@ private void ShowOverlay(bool viewOnly, RenderManager.CameraInfo cameraInfo) {
hoveredMarker = laneMarker;
}

if (drawMarker)
RenderManager.instance.OverlayEffect.DrawCircle(cameraInfo, laneMarker.color, laneMarker.position, laneMarker.radius, -1f, 1280f, false, true);
if (drawMarker) {
//DrawLaneMarker(laneMarker, cameraInfo);
RenderManager.instance.OverlayEffect.DrawCircle(cameraInfo, laneMarker.color, laneMarker.position, laneMarker.radius, laneMarker.position.y - 100f, laneMarker.position.y + 100f, false, true);
}
}
}
}
}

private bool IsLaneMarkerHovered(NodeLaneMarker laneMarker, ref Ray mouseRay) {

float y = Singleton<TerrainManager>.instance.SampleDetailHeightSmooth(laneMarker.position);
Bounds bounds = new Bounds(Vector3.zero, Vector3.one);
bounds.center = new Vector3(laneMarker.position.x, y, laneMarker.position.z);
return bounds.IntersectRay(mouseRay);
}

public override void RenderOverlay(RenderManager.CameraInfo cameraInfo) {
//Log._Debug($"TppLaneConnectorTool: RenderOverlay. SelectedNodeId={SelectedNodeId} SelectedSegmentId={SelectedSegmentId} HoveredNodeId={HoveredNodeId} HoveredSegmentId={HoveredSegmentId} IsInsideUI={MainTool.GetToolController().IsInsideUI}");
// draw lane markers and connections
Expand Down Expand Up @@ -418,12 +427,17 @@ private List<NodeLaneMarker> GetNodeMarkers(ushort nodeId) {
Vector3? pos = null;
bool isSource = false;
if (connManager.GetLaneEndPoint(segmentId, !isEndNode, laneIndex, laneId, laneInfo, out isSource, out pos)) {

pos = (Vector3)pos + offset;
float terrainY = Singleton<TerrainManager>.instance.SampleDetailHeightSmooth(((Vector3)pos));
Vector3 finalPos = new Vector3(((Vector3)pos).x, terrainY > ((Vector3)pos).y ? terrainY : ((Vector3)pos).y, ((Vector3)pos).z);

nodeMarkers.Add(new NodeLaneMarker() {
segmentId = segmentId,
laneId = laneId,
nodeId = nodeId,
startNode = !isEndNode,
position = (Vector3)pos + offset,
position = finalPos,
color = colors[nodeMarkers.Count],
isSource = isSource,
laneType = laneInfo.m_laneType,
Expand Down
17 changes: 12 additions & 5 deletions TLM/TLM/UI/SubTools/ManualTrafficLightsTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ public override void OnToolGUI(Event e) {
continue;

var position = CalculateNodePositionForSegment(Singleton<NetManager>.instance.m_nodes.m_buffer[SelectedNodeId], ref Singleton<NetManager>.instance.m_segments.m_buffer[end.SegmentId]);
var segmentLights = customTrafficLightsManager.GetSegmentLights(end.SegmentId, end.StartNode);
var segmentLights = customTrafficLightsManager.GetSegmentLights(end.SegmentId, end.StartNode, false);
if (segmentLights == null)
continue;

var screenPos = Camera.main.WorldToScreenPoint(position);
screenPos.y = Screen.height - screenPos.y;
Expand Down Expand Up @@ -651,7 +653,9 @@ private void SetAlpha(int segmentId, int buttonId) {

private void RenderManualSelectionOverlay(RenderManager.CameraInfo cameraInfo) {
if (HoveredNodeId == 0) return;
var segment = Singleton<NetManager>.instance.m_segments.m_buffer[Singleton<NetManager>.instance.m_nodes.m_buffer[HoveredNodeId].m_segment0];

MainTool.DrawNodeCircle(cameraInfo, HoveredNodeId, false, false);
/*var segment = Singleton<NetManager>.instance.m_segments.m_buffer[Singleton<NetManager>.instance.m_nodes.m_buffer[HoveredNodeId].m_segment0];
//if ((node.m_flags & NetNode.Flags.TrafficLights) == NetNode.Flags.None) return;
Bezier3 bezier;
Expand All @@ -662,14 +666,17 @@ private void RenderManualSelectionOverlay(RenderManager.CameraInfo cameraInfo) {
NetSegment.CalculateMiddlePoints(bezier.a, segment.m_startDirection, bezier.d,
segment.m_endDirection, false, false, out bezier.b, out bezier.c);
MainTool.DrawOverlayBezier(cameraInfo, bezier, color);
MainTool.DrawOverlayBezier(cameraInfo, bezier, color);*/
}

private void RenderManualNodeOverlays(RenderManager.CameraInfo cameraInfo) {
var nodeSimulation = TrafficLightSimulationManager.Instance.GetNodeSimulation(SelectedNodeId);
if (nodeSimulation == null || !nodeSimulation.IsManualLight())
return;
CustomSegmentLightsManager customTrafficLightsManager = CustomSegmentLightsManager.Instance;

MainTool.DrawNodeCircle(cameraInfo, SelectedNodeId, true, false);

/*CustomSegmentLightsManager customTrafficLightsManager = CustomSegmentLightsManager.Instance;
NodeGeometry nodeGeometry = NodeGeometry.Get(SelectedNodeId);
foreach (SegmentEndGeometry end in nodeGeometry.SegmentEndGeometries) {
Expand All @@ -682,7 +689,7 @@ private void RenderManualNodeOverlays(RenderManager.CameraInfo cameraInfo) {
var width = _hoveredButton[0] == end.SegmentId ? 11.25f : 10f;
MainTool.DrawOverlayCircle(cameraInfo, colorGray, position, width, end.SegmentId != _hoveredButton[0]);
}
}*/
}

public override void Cleanup() {
Expand Down
Loading

0 comments on commit 2fd094b

Please sign in to comment.