Skip to content
Merged
38 changes: 38 additions & 0 deletions TLM/TLM/Manager/Impl/LaneArrowManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace TrafficManager.Manager.Impl {
using TrafficManager.State;
using TrafficManager.Util;
using UnityEngine;
using static TrafficManager.Util.Shortcuts;

public class LaneArrowManager
: AbstractGeometryObservingManager,
Expand Down Expand Up @@ -111,6 +112,43 @@ public bool ToggleLaneArrows(uint laneId,
return false;
}

/// <summary>
/// Resets lane arrows to their default value for the given segment end.
/// </summary>
/// <param name="segmentId">segment to reset</param>
/// <param name="startNode">determines the segment end to reset. if <c>null</c>
/// both ends are reset</param>
public void ResetLaneArrows(ushort segmentId, bool? startNode = null) {
foreach (var lane in netService.GetSortedLanes(
segmentId,
ref GetSeg(segmentId),
startNode,
LANE_TYPES,
VEHICLE_TYPES)) {
ResetLaneArrows(lane.laneId);
}
}

/// <summary>
/// Resets lane arrows to their default value for the given lane
/// </summary>
public void ResetLaneArrows(uint laneId) {
if (Flags.ResetLaneArrowFlags(laneId)) {
RecalculateFlags(laneId);
OnLaneChange(laneId);
}
}

private static void RecalculateFlags(uint laneId) {
NetLane[] laneBuffer = NetManager.instance.m_lanes.m_buffer;
ushort segmentId = laneBuffer[laneId].m_segment;
NetAI ai = GetSeg(segmentId).Info.m_netAI;
#if DEBUGFLAGS
Log._Debug($"Flags.RecalculateFlags: Recalculateing lane arrows of segment {segmentId}.");
#endif
ai.UpdateLanes(segmentId, ref GetSeg(segmentId), true);
}

private void OnLaneChange(uint laneId) {
Services.NetService.ProcessLane(
laneId,
Expand Down
30 changes: 30 additions & 0 deletions TLM/TLM/Manager/Impl/LaneConnectionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace TrafficManager.Manager.Impl {
using TrafficManager.State.ConfigData;
using TrafficManager.State;
using UnityEngine;
using static TrafficManager.Util.Shortcuts;

public class LaneConnectionManager
: AbstractGeometryObservingManager,
Expand Down Expand Up @@ -60,6 +61,35 @@ public bool AreLanesConnected(uint sourceLaneId, uint targetLaneId, bool sourceS
&& connectedLanes.Any(laneId => laneId == targetLaneId);
}


/// <summary>
/// determines whether or not the input lane is heading toward a start node.
/// </summary>
/// <returns>true if heading toward and start node.</returns>
private bool IsHeadingTowardsStartNode(uint sourceLaneId) {
NetLane[] laneBuffer = NetManager.instance.m_lanes.m_buffer;
ushort segmentId = laneBuffer[sourceLaneId].m_segment;
NetSegment segment = GetSeg(segmentId);
uint laneId = segment.m_lanes;
bool inverted = (segment.m_flags & NetSegment.Flags.Invert) != 0;

foreach (var laneInfo in segment.Info.m_lanes) {
if (laneId == sourceLaneId) {
return (laneInfo.m_direction == NetInfo.Direction.Forward) ^ !inverted;
}
laneId = laneBuffer[laneId].m_nextLane;
}
throw new Exception($"Unreachable code. sourceLaneId:{sourceLaneId}, segmentId:{segmentId} ");
}

public bool HasConnections(uint sourceLaneId) {
if (!Options.laneConnectorEnabled) {
return false;
}
return HasConnections(sourceLaneId, IsHeadingTowardsStartNode(sourceLaneId));
}


/// <summary>
/// Determines if the given lane has outgoing connections
/// </summary>
Expand Down
20 changes: 19 additions & 1 deletion TLM/TLM/State/Flags.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// #define DEBUGFLAGS
// #define DEBUGFLAGS

namespace TrafficManager.State {
using ColossalFramework;
Expand All @@ -10,6 +10,7 @@ namespace TrafficManager.State {
using TrafficManager.API.Traffic.Enums;
using TrafficManager.Manager.Impl;
using TrafficManager.State.ConfigData;
using static TrafficManager.Util.Shortcuts;

[Obsolete]
public class Flags {
Expand Down Expand Up @@ -732,6 +733,23 @@ public static void resetSegmentArrowFlags(ushort segmentId) {
}
}

/// <summary>
/// removes the custom lane arrow flags. requires post recalculation.
/// </summary>
/// <param name="laneId"></param>
/// <returns><c>true</c>on success, <c>false</c> otherwise</returns>
public static bool ResetLaneArrowFlags(uint laneId) {
#if DEBUGFLAGS
Log._Debug($"Flags.resetLaneArrowFlags: Resetting lane arrows of lane {laneId}.");
#endif
if (LaneConnectionManager.Instance.HasConnections(laneId)) {
return false;
}

laneArrowFlags[laneId] = null;
return true;
}

public static bool setLaneArrowFlags(uint laneId,
LaneArrows flags,
bool overrideHighwayArrows = false) {
Expand Down
53 changes: 43 additions & 10 deletions TLM/TLM/UI/SubTools/LaneArrowTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,32 @@ namespace TrafficManager.UI.SubTools {
using TrafficManager.Manager.Impl;
using TrafficManager.State;
using UnityEngine;
using static TrafficManager.Util.Shortcuts;

public class LaneArrowTool : SubTool {
private bool cursorInSecondaryPanel_;

public LaneArrowTool(TrafficManagerTool mainTool)
: base(mainTool) { }

/// <summary>
/// if the segment has at least one lane without outgoing lane connections, then it can be reset.
/// </summary>
/// <returns>true if the segemnt can be reset.</returns>
private static bool CanReset(ushort segmentId, bool startNode) {
foreach (var lanePos in netService.GetSortedLanes(
segmentId,
ref GetSeg(segmentId),
startNode,
LaneArrowManager.LANE_TYPES,
LaneArrowManager.VEHICLE_TYPES)) {
if (!LaneConnectionManager.Instance.HasConnections(lanePos.laneId)) {
return true;
}
}
return false;
}

public override bool IsCursorInPanel() {
return base.IsCursorInPanel() || cursorInSecondaryPanel_;
}
Expand Down Expand Up @@ -104,8 +123,8 @@ public override void OnToolGUI(Event e) {
}

int width = numLanes * 128;
var windowRect3 = new Rect(screenPos.x - (width / 2), screenPos.y - 70, width, 50);
GUILayout.Window(250, windowRect3, GuiLaneChangeWindow, string.Empty, BorderlessStyle);
var windowRect3 = new Rect(screenPos.x - (width / 2), screenPos.y - 70, width, 60);
windowRect3 = GUILayout.Window(250, windowRect3, GuiLaneChangeWindow, string.Empty, BorderlessStyle);
cursorInSecondaryPanel_ = windowRect3.Contains(Event.current.mousePosition);
}

Expand Down Expand Up @@ -245,19 +264,18 @@ private void GuiLaneChangeWindow(int num) {
return;
}

GUILayout.BeginVertical();
GUILayout.BeginHorizontal();

var style1 = new GUIStyle("button");
var style2 = new GUIStyle("button") {
normal = { textColor = new Color32(255, 0, 0, 255) },
hover = { textColor = new Color32(255, 0, 0, 255) },
focused = { textColor = new Color32(255, 0, 0, 255) }
};
for (var i = 0; i < laneList.Count; i++) {
var flags = (NetLane.Flags)Singleton<NetManager>
.instance.m_lanes.m_buffer[laneList[i].laneId].m_flags;

var style1 = new GUIStyle("button");
var style2 = new GUIStyle("button") {
normal = { textColor = new Color32(255, 0, 0, 255) },
hover = { textColor = new Color32(255, 0, 0, 255) },
focused = { textColor = new Color32(255, 0, 0, 255) }
};

var laneStyle = new GUIStyle { contentOffset = new Vector2(12f, 0f) };

var laneTitleStyle = new GUIStyle {
Expand Down Expand Up @@ -340,6 +358,21 @@ private void GuiLaneChangeWindow(int num) {
}

GUILayout.EndHorizontal();

if (CanReset(SelectedSegmentId, (bool)startNode)) {
if (GUILayout.Button(
"Reset all",
style1,
GUILayout.Width(135), // intentionally bigger than the text
GUILayout.Height(25))) {
Log._Debug("deleting lane arrows: " +
$"SelectedSegmentId={SelectedSegmentId} SelectedNodeId={SelectedNodeId} startNode={startNode}");
LaneArrowManager.Instance.ResetLaneArrows(SelectedSegmentId, startNode);
}
}

GUILayout.EndVertical();

}
}
}