diff --git a/TLM/TLM/Constants.cs b/TLM/TLM/Constants.cs index 733dfdb15..2da522b93 100644 --- a/TLM/TLM/Constants.cs +++ b/TLM/TLM/Constants.cs @@ -1,4 +1,5 @@ namespace TrafficManager { + using TrafficManager.API.Hook; using TrafficManager.API.Manager; using TrafficManager.API.Notifier; using TrafficManager.API.UI; @@ -37,6 +38,8 @@ public static float ByteToFloat(byte b) { public static IManagerFactory ManagerFactory => Manager.Impl.ManagerFactory.Instance; + public static IHookFactory HookFactory => Hook.Impl.HookFactory.Instance; + public static IUIFactory UIFactory => UI.UIFactory.Instance; public static INotifier Notifier => TrafficManager.Notifier.Instance; diff --git a/TLM/TLM/Custom/PathFinding/CustomPathFind.cs b/TLM/TLM/Custom/PathFinding/CustomPathFind.cs index d3c807f44..9ce297581 100644 --- a/TLM/TLM/Custom/PathFinding/CustomPathFind.cs +++ b/TLM/TLM/Custom/PathFinding/CustomPathFind.cs @@ -1084,10 +1084,11 @@ ref nextSegmentId.ToSegment(), #if JUNCTIONRESTRICTIONS // next segment does not have pedestrian lanes but cims need to // cross it to reach the next segment - if (!junctionManager.IsPedestrianCrossingAllowed( + if (!junctionManager.GetValueOrDefault( leftSegmentId, leftSegment.m_startNode == - nextNodeId)) { + nextNodeId, + JunctionRestrictionFlags.AllowPedestrianCrossing)) { break; } #endif @@ -1122,10 +1123,11 @@ ref nextSegmentId.ToSegment(), #if JUNCTIONRESTRICTIONS // next segment does not have pedestrian lanes but cims need to // cross it to reach the next segment - if (!junctionManager.IsPedestrianCrossingAllowed( + if (!junctionManager.GetValueOrDefault( rightSegmentId, rightSegment.m_startNode == - nextNodeId)) { + nextNodeId, + JunctionRestrictionFlags.AllowPedestrianCrossing)) { break; } #endif @@ -3167,9 +3169,10 @@ private void ProcessItemPedBicycle( if (Options.junctionRestrictionsEnabled && item.Position.m_segment == nextSegmentId) { // check if pedestrians are not allowed to cross here - if (!junctionManager.IsPedestrianCrossingAllowed( + if (!junctionManager.GetValueOrDefault( nextSegmentId, - nextIsStartNode)) { + nextIsStartNode, + JunctionRestrictionFlags.AllowPedestrianCrossing)) { if (isLogEnabled) { DebugLog( unitId, @@ -3587,7 +3590,7 @@ private bool ProcessItemRouted( prevIsCarLane && // u-turns for road vehicles only (!isHeavyVehicle_ || isStockUturnPoint) && // only small vehicles may perform u-turns OR everyone at stock u-turn points !prevIsOutgoingOneWay && // do not u-turn on one-ways - junctionManager.IsUturnAllowed(prevSegmentId, nextIsStartNode); + junctionManager.GetValueOrDefault(prevSegmentId, nextIsStartNode, JunctionRestrictionFlags.AllowUTurn); if (isLogEnabled) { DebugLog( @@ -3600,7 +3603,7 @@ private bool ProcessItemRouted( $"\tisStockUturnPoint={isStockUturnPoint}\n" + $"\tprevIsOutgoingOneWay={prevIsOutgoingOneWay}\n" + $"\tjManager.IsUturnAllowed(prevSegmentId, " + - $"nextIsStartNode)={junctionManager.IsUturnAllowed(prevSegmentId, nextIsStartNode)}\n" + + $"nextIsStartNode)={junctionManager.GetValueOrDefault(prevSegmentId, nextIsStartNode, JunctionRestrictionFlags.AllowUTurn)}\n" + $"\tm_queueItem.vehicleId={queueItem_.vehicleId}\n" + $"\tm_queueItem.spawned={queueItem_.spawned}\n" + $"\tprevSegmentId={prevSegmentId}\n" + diff --git a/TLM/TLM/Geometry/Impl/SegmentEndId.cs b/TLM/TLM/Geometry/Impl/SegmentEndIdApi.cs similarity index 77% rename from TLM/TLM/Geometry/Impl/SegmentEndId.cs rename to TLM/TLM/Geometry/Impl/SegmentEndIdApi.cs index e30fa811b..e04b3ce93 100644 --- a/TLM/TLM/Geometry/Impl/SegmentEndId.cs +++ b/TLM/TLM/Geometry/Impl/SegmentEndIdApi.cs @@ -1,14 +1,16 @@ namespace TrafficManager.Geometry.Impl { + using System; using TrafficManager.API.Traffic; using TrafficManager.Util.Extensions; - public class SegmentEndId : ISegmentEndId { - public SegmentEndId(ushort segmentId, ushort nodeId) { + [Obsolete("New code should use TrafficManager.Network.Data.SegmentId unless it needs to implement ISegmentEndId. ISegmentEndId should be deprecated in the future, and should be avoided in new APIs.")] + public class SegmentEndIdApi : ISegmentEndId { + public SegmentEndIdApi(ushort segmentId, ushort nodeId) { SegmentId = segmentId; StartNode = segmentId.ToSegment().IsStartNode(nodeId); } - public SegmentEndId(ushort segmentId, bool startNode) { + public SegmentEndIdApi(ushort segmentId, bool startNode) { SegmentId = segmentId; StartNode = startNode; } diff --git a/TLM/TLM/Hook/Impl/HookFactory.cs b/TLM/TLM/Hook/Impl/HookFactory.cs new file mode 100644 index 000000000..ae6930eff --- /dev/null +++ b/TLM/TLM/Hook/Impl/HookFactory.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using TrafficManager.API.Hook; + +namespace TrafficManager.Hook.Impl { + public class HookFactory : IHookFactory { + + public static IHookFactory Instance = new HookFactory(); + + public IJunctionRestrictionsHook JunctionRestrictionsHook => Manager.Impl.JunctionRestrictionsManager.Instance; + } +} diff --git a/TLM/TLM/Manager/Impl/ExtNodeManager.cs b/TLM/TLM/Manager/Impl/ExtNodeManager.cs index 7a75b416c..59e8de237 100644 --- a/TLM/TLM/Manager/Impl/ExtNodeManager.cs +++ b/TLM/TLM/Manager/Impl/ExtNodeManager.cs @@ -90,7 +90,7 @@ public void AddSegment(ushort nodeId, ushort segmentId) { { var replacement = new SegmentEndReplacement { oldSegmentEndId = ExtNodes[nodeId].removedSegmentEndId, - newSegmentEndId = new SegmentEndId(segmentId, nodeId), + newSegmentEndId = new SegmentEndIdApi(segmentId, nodeId), }; ExtNodes[nodeId].removedSegmentEndId = null; @@ -100,7 +100,7 @@ public void AddSegment(ushort nodeId, ushort segmentId) { public void RemoveSegment(ushort nodeId, ushort segmentId) { if (ExtNodes[nodeId].segmentIds.Remove(segmentId)) { - ExtNodes[nodeId].removedSegmentEndId = new SegmentEndId(segmentId, nodeId); + ExtNodes[nodeId].removedSegmentEndId = new SegmentEndIdApi(segmentId, nodeId); } } diff --git a/TLM/TLM/Manager/Impl/JunctionRestrictionsManager.cs b/TLM/TLM/Manager/Impl/JunctionRestrictionsManager.cs index be85b81a8..4a8822564 100644 --- a/TLM/TLM/Manager/Impl/JunctionRestrictionsManager.cs +++ b/TLM/TLM/Manager/Impl/JunctionRestrictionsManager.cs @@ -5,10 +5,12 @@ namespace TrafficManager.Manager.Impl { using System.Collections.Generic; using System; using TrafficManager.API.Geometry; + using TrafficManager.API.Hook; using TrafficManager.API.Manager; using TrafficManager.API.Traffic.Data; using TrafficManager.API.Traffic; using TrafficManager.Geometry; + using TrafficManager.Network.Data; using TrafficManager.State.ConfigData; using TrafficManager.State; using TrafficManager.Traffic; @@ -18,34 +20,63 @@ namespace TrafficManager.Manager.Impl { using TrafficManager.Util.Extensions; using TrafficManager.Lifecycle; using TrafficManager.API.Traffic.Enums; + using TrafficManager.Manager.Impl.LaneConnection; + using static TrafficManager.API.Hook.IJunctionRestrictionsHook; public class JunctionRestrictionsManager : AbstractGeometryObservingManager, ICustomDataManager>, - IJunctionRestrictionsManager + IJunctionRestrictionsManager, + IJunctionRestrictionsHook { public static JunctionRestrictionsManager Instance { get; } = new JunctionRestrictionsManager(); - private readonly SegmentJunctionRestrictions[] invalidSegmentRestrictions; + private readonly SegmentJunctionRestrictions[] orphanedRestrictions; /// /// Holds junction restrictions for each segment end /// private readonly SegmentJunctionRestrictions[] segmentRestrictions; + public event Action GetDefaultsHook; + public event Action GetConfigurableHook; + private JunctionRestrictionsManager() { segmentRestrictions = new SegmentJunctionRestrictions[NetManager.MAX_SEGMENT_COUNT]; - invalidSegmentRestrictions = new SegmentJunctionRestrictions[NetManager.MAX_SEGMENT_COUNT]; + orphanedRestrictions = new SegmentJunctionRestrictions[NetManager.MAX_SEGMENT_COUNT]; + } + + public void InvalidateFlags(ushort segmentId, bool startNode, JunctionRestrictionFlags flags) { + + if (segmentId.ToSegment().IsValid()) { + SegmentEndId segmentEndId = segmentId.AtNode(startNode); + GetJunctionRestrictions(segmentEndId).Invalidate(segmentEndId); + } + } + + public void InvalidateFlags(ushort nodeId, JunctionRestrictionFlags flags) { + + if (nodeId.ToNode().IsValid()) { + foreach (var segmentId in ExtNodeManager.Instance.GetNodeSegmentIds(nodeId, ClockDirection.Clockwise)) { + InvalidateFlags(segmentId, segmentId.ToSegment().IsStartNode(nodeId), flags); + } + } } - private void AddInvalidSegmentJunctionRestrictions(ushort segmentId, + private ref JunctionRestrictions GetJunctionRestrictions(SegmentEndId segmentEndId) { + return ref (segmentEndId.StartNode + ? ref segmentRestrictions[segmentEndId].startNodeRestrictions + : ref segmentRestrictions[segmentEndId].endNodeRestrictions); + } + + private void AddOrphanedSegmentJunctionRestrictions(ushort segmentId, bool startNode, - ref JunctionRestrictions restrictions) { + JunctionRestrictions restrictions) { if (startNode) { - invalidSegmentRestrictions[segmentId].startNodeRestrictions = restrictions; + orphanedRestrictions[segmentId].startNodeRestrictions = restrictions; } else { - invalidSegmentRestrictions[segmentId].endNodeRestrictions = restrictions; + orphanedRestrictions[segmentId].endNodeRestrictions = restrictions; } } @@ -57,30 +88,27 @@ protected override void HandleSegmentEndReplacement(SegmentEndReplacement replac JunctionRestrictions restrictions; if (oldSegmentEndId.StartNode) { - restrictions = invalidSegmentRestrictions[oldSegmentEndId.SegmentId].startNodeRestrictions; - invalidSegmentRestrictions[oldSegmentEndId.SegmentId].startNodeRestrictions.Reset(); + restrictions = orphanedRestrictions[oldSegmentEndId.SegmentId].startNodeRestrictions; + orphanedRestrictions[oldSegmentEndId.SegmentId].startNodeRestrictions.Reset(oldSegmentEndId.FromApi()); } else { - restrictions = invalidSegmentRestrictions[oldSegmentEndId.SegmentId].endNodeRestrictions; - invalidSegmentRestrictions[oldSegmentEndId.SegmentId].endNodeRestrictions.Reset(); + restrictions = orphanedRestrictions[oldSegmentEndId.SegmentId].endNodeRestrictions; + orphanedRestrictions[oldSegmentEndId.SegmentId].endNodeRestrictions.Reset(oldSegmentEndId.FromApi()); } - UpdateDefaults( - ref segEndMan.ExtSegmentEnds[segEndMan.GetIndex(newSegmentEndId.SegmentId, newSegmentEndId.StartNode)], - ref restrictions, - ref segEnd.nodeId.ToNode()); + GetJunctionRestrictions(newSegmentEndId.FromApi()).Invalidate(newSegmentEndId.FromApi()); Log._Debug( $"JunctionRestrictionsManager.HandleSegmentEndReplacement({replacement}): " + $"Segment replacement detected: {oldSegmentEndId.SegmentId} -> {newSegmentEndId.SegmentId} " + $"@ {newSegmentEndId.StartNode}"); - SetSegmentJunctionRestrictions(newSegmentEndId.SegmentId, newSegmentEndId.StartNode, restrictions); + SetSegmentJunctionRestrictions(newSegmentEndId.FromApi(), restrictions); } public override void OnLevelLoading() { base.OnLevelLoading(); - for (uint i = 0; i < NetManager.MAX_SEGMENT_COUNT; ++i) { - ExtSegment seg = Constants.ManagerFactory.ExtSegmentManager.ExtSegments[i]; + for (ushort segmentId = 0; segmentId < NetManager.MAX_SEGMENT_COUNT; ++segmentId) { + ExtSegment seg = Constants.ManagerFactory.ExtSegmentManager.ExtSegments[segmentId]; if (seg.valid) { HandleValidSegment(ref seg); } @@ -91,12 +119,12 @@ protected override void InternalPrintDebugInfo() { base.InternalPrintDebugInfo(); Log._Debug("Junction restrictions:"); - for (int i = 0; i < segmentRestrictions.Length; ++i) { - if (segmentRestrictions[i].IsDefault()) { + for (ushort segmentId = 0; segmentId < segmentRestrictions.Length; ++segmentId) { + if (segmentRestrictions[segmentId].IsDefault(segmentId)) { continue; } - Log._Debug($"Segment {i}: {segmentRestrictions[i]}"); + Log._Debug($"Segment {segmentId}: {segmentRestrictions[segmentId]}"); } } @@ -111,20 +139,15 @@ private bool MayHaveJunctionRestrictions(ushort nodeId) { } public bool HasJunctionRestrictions(ushort nodeId) { - ref NetNode netNode = ref nodeId.ToNode(); - if (!netNode.IsValid()) { + if (!nodeId.ToNode().IsValid()) { return false; } for (int i = 0; i < 8; ++i) { - ushort segmentId = netNode.GetSegment(i); - if (segmentId != 0) { - bool startNode = segmentId.ToSegment().m_startNode == nodeId; - bool isDefault = startNode - ? segmentRestrictions[segmentId].startNodeRestrictions.IsDefault() - : segmentRestrictions[segmentId].endNodeRestrictions.IsDefault(); - - if (!isDefault) { + var segmentEndId = nodeId.GetSegmentEnd(i); + if (segmentEndId != default) { + + if (!GetJunctionRestrictions(segmentEndId).IsDefault(segmentEndId)) { return true; } } @@ -136,15 +159,10 @@ public bool HasJunctionRestrictions(ushort nodeId) { private void RemoveJunctionRestrictions(ushort nodeId) { Log._Debug($"JunctionRestrictionsManager.RemoveJunctionRestrictions({nodeId}) called."); - ref NetNode node = ref nodeId.ToNode(); for (int i = 0; i < 8; ++i) { - ushort segmentId = node.GetSegment(i); - if (segmentId != 0) { - if (segmentId.ToSegment().m_startNode == nodeId) { - segmentRestrictions[segmentId].startNodeRestrictions.Reset(false); - } else { - segmentRestrictions[segmentId].endNodeRestrictions.Reset(false); - } + var segmentEndId = nodeId.GetSegmentEnd(i); + if (segmentEndId != default) { + GetJunctionRestrictions(segmentEndId).Reset(segmentEndId, false); } } } @@ -168,19 +186,22 @@ protected override void HandleInvalidSegment(ref ExtSegment seg) { } private void HandleInvalidSegment(ref ExtSegment seg, bool startNode) { + + var segmentEndId = seg.segmentId.AtNode(startNode); + JunctionRestrictions restrictions = startNode ? segmentRestrictions[seg.segmentId].startNodeRestrictions : segmentRestrictions[seg.segmentId].endNodeRestrictions; - if (!restrictions.IsDefault()) { - AddInvalidSegmentJunctionRestrictions(seg.segmentId, startNode, ref restrictions); + if (!restrictions.IsDefault(segmentEndId)) { + AddOrphanedSegmentJunctionRestrictions(seg.segmentId, startNode, restrictions); } - segmentRestrictions[seg.segmentId].Reset(startNode, true); + segmentRestrictions[seg.segmentId].Reset(segmentEndId); } protected override void HandleValidSegment(ref ExtSegment seg) { - UpdateDefaults(ref seg); + segmentRestrictions[seg.segmentId].Invalidate(seg.segmentId); } /// @@ -188,116 +209,17 @@ protected override void HandleValidSegment(ref ExtSegment seg) { /// TODO [issue #1116]: publish segment changes? if so it should be done only when policy changes not when deserializing. /// public void UpdateAllDefaults() { - ExtSegmentManager extSegmentManager = ExtSegmentManager.Instance; + for (ushort segmentId = 0; segmentId < NetManager.MAX_SEGMENT_COUNT; ++segmentId) { - ref NetSegment netSegment = ref segmentId.ToSegment(); - if (!netSegment.IsValid()) { + if (!segmentId.ToSegment().IsValid()) { continue; } - - UpdateDefaults(ref extSegmentManager.ExtSegments[segmentId]); - } - } - - private void UpdateDefaults(ref ExtSegment seg) { - ushort segmentId = seg.segmentId; - ref NetSegment netSegment = ref segmentId.ToSegment(); - IExtSegmentEndManager segEndMan = Constants.ManagerFactory.ExtSegmentEndManager; - - UpdateDefaults( - ref segEndMan.ExtSegmentEnds[segEndMan.GetIndex(segmentId, true)], - ref segmentRestrictions[segmentId].startNodeRestrictions, - ref netSegment.m_startNode.ToNode()); - - UpdateDefaults( - ref segEndMan.ExtSegmentEnds[segEndMan.GetIndex(segmentId, false)], - ref segmentRestrictions[segmentId].endNodeRestrictions, - ref netSegment.m_endNode.ToNode()); - } - - private void UpdateDefaults(ref ExtSegmentEnd segEnd, - ref JunctionRestrictions restrictions, - ref NetNode node) { - if (!IsUturnAllowedConfigurable(segEnd.segmentId, segEnd.startNode, ref node)) { - restrictions.ClearValue(JunctionRestrictionFlags.AllowUTurn); - } - - if (!IsNearTurnOnRedAllowedConfigurable(segEnd.segmentId, segEnd.startNode, ref node)) { - restrictions.ClearValue(JunctionRestrictionFlags.AllowNearTurnOnRed); - } - - if (!IsFarTurnOnRedAllowedConfigurable(segEnd.segmentId, segEnd.startNode, ref node)) { - restrictions.ClearValue(JunctionRestrictionFlags.AllowFarTurnOnRed); - } - - if (!IsLaneChangingAllowedWhenGoingStraightConfigurable( - segEnd.segmentId, - segEnd.startNode, - ref node)) { - restrictions.ClearValue(JunctionRestrictionFlags.AllowForwardLaneChange); - } - - if (!IsEnteringBlockedJunctionAllowedConfigurable( - segEnd.segmentId, - segEnd.startNode, - ref node)) { - restrictions.ClearValue(JunctionRestrictionFlags.AllowEnterWhenBlocked); - } - - if (!IsPedestrianCrossingAllowedConfigurable( - segEnd.segmentId, - segEnd.startNode, - ref node)) { - restrictions.ClearValue(JunctionRestrictionFlags.AllowPedestrianCrossing); - } - - restrictions.SetDefault(JunctionRestrictionFlags.AllowUTurn, GetDefaultUturnAllowed( - segEnd.segmentId, - segEnd.startNode, - ref node)); - restrictions.SetDefault(JunctionRestrictionFlags.AllowNearTurnOnRed, GetDefaultNearTurnOnRedAllowed( - segEnd.segmentId, - segEnd.startNode, - ref node)); - restrictions.SetDefault(JunctionRestrictionFlags.AllowFarTurnOnRed, GetDefaultFarTurnOnRedAllowed( - segEnd.segmentId, - segEnd.startNode, - ref node)); - restrictions.SetDefault(JunctionRestrictionFlags.AllowForwardLaneChange, - GetDefaultLaneChangingAllowedWhenGoingStraight( - segEnd.segmentId, - segEnd.startNode, - ref node)); - restrictions.SetDefault(JunctionRestrictionFlags.AllowEnterWhenBlocked, GetDefaultEnteringBlockedJunctionAllowed( - segEnd.segmentId, - segEnd.startNode, - ref node)); - restrictions.SetDefault(JunctionRestrictionFlags.AllowPedestrianCrossing, GetDefaultPedestrianCrossingAllowed( - segEnd.segmentId, - segEnd.startNode, - ref node)); - -#if DEBUG - if (DebugSwitch.JunctionRestrictions.Get()) { - Log._DebugFormat( - "JunctionRestrictionsManager.UpdateDefaults({0}, {1}): Set defaults: " + - "defaultUturnAllowed={2}, defaultNearTurnOnRedAllowed={3}, " + - "defaultFarTurnOnRedAllowed={4}, defaultStraightLaneChangingAllowed={5}, " + - "defaultEnterWhenBlockedAllowed={6}, defaultPedestrianCrossingAllowed={7}", - segEnd.segmentId, - segEnd.startNode, - restrictions.GetDefault(JunctionRestrictionFlags.AllowUTurn), - restrictions.GetDefault(JunctionRestrictionFlags.AllowNearTurnOnRed), - restrictions.GetDefault(JunctionRestrictionFlags.AllowFarTurnOnRed), - restrictions.GetDefault(JunctionRestrictionFlags.AllowForwardLaneChange), - restrictions.GetDefault(JunctionRestrictionFlags.AllowEnterWhenBlocked), - restrictions.GetDefault(JunctionRestrictionFlags.AllowPedestrianCrossing)); + segmentRestrictions[segmentId].Invalidate(segmentId); } -#endif - Notifier.Instance.OnNodeModified(segEnd.nodeId, this); } + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool IsUturnAllowedConfigurable(ushort segmentId, bool startNode, ref NetNode node) { ref NetSegment netSegment = ref segmentId.ToSegment(); @@ -327,6 +249,27 @@ public bool IsUturnAllowedConfigurable(ushort segmentId, bool startNode, ref Net return ret; } + /// + /// This is necessary because we can't change the signature of methods known to be patched. + /// It will go away once the Node Controller mods are updated. + /// + private static class CalculationContext { + + [ThreadStatic] + private static bool? _isConfigurable; + + public static bool? IsConfigurable { + get => _isConfigurable; + set { + if (value.HasValue && _isConfigurable.HasValue) + throw new InvalidOperationException("JunctionRestrictionsManager.CalculationContext used recursively"); + + _isConfigurable = value; + } + } + } + + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool GetDefaultUturnAllowed(ushort segmentId, bool startNode, ref NetNode node) { #if DEBUG bool logLogic = DebugSwitch.JunctionRestrictions.Get(); @@ -334,10 +277,8 @@ public bool GetDefaultUturnAllowed(ushort segmentId, bool startNode, ref NetNode const bool logLogic = false; #endif - if (!Constants.ManagerFactory.JunctionRestrictionsManager.IsUturnAllowedConfigurable( - segmentId, - startNode, - ref node)) { + var isConfigurable = CalculationContext.IsConfigurable ?? IsUturnAllowedConfigurable(segmentId, startNode, ref node); + if (!isConfigurable) { bool res = (node.m_flags & (NetNode.Flags.End | NetNode.Flags.OneWayOut)) != NetNode.Flags.None; if (logLogic) { @@ -366,22 +307,21 @@ public bool GetDefaultUturnAllowed(ushort segmentId, bool startNode, ref NetNode return ret; } - public bool IsUturnAllowed(ushort segmentId, bool startNode) { - return segmentRestrictions[segmentId].GetValueOrDefault(JunctionRestrictionFlags.AllowUTurn, startNode); - } - + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool IsNearTurnOnRedAllowedConfigurable(ushort segmentId, bool startNode, ref NetNode node) { return IsTurnOnRedAllowedConfigurable(true, segmentId, startNode, ref node); } + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool IsFarTurnOnRedAllowedConfigurable(ushort segmentId, bool startNode, ref NetNode node) { return IsTurnOnRedAllowedConfigurable(false, segmentId, startNode, ref node); } + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool IsTurnOnRedAllowedConfigurable(bool near, ushort segmentId, bool startNode, @@ -404,18 +344,21 @@ public bool IsTurnOnRedAllowedConfigurable(bool near, return ret; } + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool GetDefaultNearTurnOnRedAllowed(ushort segmentId, bool startNode, ref NetNode node) { return GetDefaultTurnOnRedAllowed(true, segmentId, startNode, ref node); } + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool GetDefaultFarTurnOnRedAllowed(ushort segmentId, bool startNode, ref NetNode node) { return GetDefaultTurnOnRedAllowed(false, segmentId, startNode, ref node); } + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool GetDefaultTurnOnRedAllowed(bool near, ushort segmentId, bool startNode, ref NetNode node) { #if DEBUG bool logLogic = DebugSwitch.JunctionRestrictions.Get(); @@ -423,7 +366,8 @@ public bool GetDefaultTurnOnRedAllowed(bool near, ushort segmentId, bool startNo const bool logLogic = false; #endif - if (!IsTurnOnRedAllowedConfigurable(near, segmentId, startNode, ref node)) { + var isConfigurable = CalculationContext.IsConfigurable ?? IsTurnOnRedAllowedConfigurable(near, segmentId, startNode, ref node); + if (!isConfigurable) { if (logLogic) { Log._Debug( $"JunctionRestrictionsManager.IsTurnOnRedAllowedConfigurable({near}, " + @@ -443,20 +387,7 @@ public bool GetDefaultTurnOnRedAllowed(bool near, ushort segmentId, bool startNo return ret; } - public bool IsTurnOnRedAllowed(bool near, ushort segmentId, bool startNode) { - return near - ? IsNearTurnOnRedAllowed(segmentId, startNode) - : IsFarTurnOnRedAllowed(segmentId, startNode); - } - - public bool IsNearTurnOnRedAllowed(ushort segmentId, bool startNode) { - return segmentRestrictions[segmentId].GetValueOrDefault(JunctionRestrictionFlags.AllowNearTurnOnRed, startNode); - } - - public bool IsFarTurnOnRedAllowed(ushort segmentId, bool startNode) { - return segmentRestrictions[segmentId].GetValueOrDefault(JunctionRestrictionFlags.AllowFarTurnOnRed, startNode); - } - + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool IsLaneChangingAllowedWhenGoingStraightConfigurable( ushort segmentId, bool startNode, @@ -495,6 +426,7 @@ public bool IsLaneChangingAllowedWhenGoingStraightConfigurable( return ret; } + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool GetDefaultLaneChangingAllowedWhenGoingStraight(ushort segmentId, bool startNode, ref NetNode node) { #if DEBUG bool logLogic = DebugSwitch.JunctionRestrictions.Get(); @@ -502,11 +434,8 @@ public bool GetDefaultLaneChangingAllowedWhenGoingStraight(ushort segmentId, boo const bool logLogic = false; #endif - if (!Constants.ManagerFactory.JunctionRestrictionsManager - .IsLaneChangingAllowedWhenGoingStraightConfigurable( - segmentId, - startNode, - ref node)) { + var isConfigurable = CalculationContext.IsConfigurable ?? IsLaneChangingAllowedWhenGoingStraightConfigurable(segmentId, startNode, ref node); + if (!isConfigurable) { if (logLogic) { Log._Debug( "JunctionRestrictionsManager.GetDefaultLaneChangingAllowedWhenGoingStraight" + @@ -527,10 +456,7 @@ public bool GetDefaultLaneChangingAllowedWhenGoingStraight(ushort segmentId, boo return ret; } - public bool IsLaneChangingAllowedWhenGoingStraight(ushort segmentId, bool startNode) { - return segmentRestrictions[segmentId].GetValueOrDefault(JunctionRestrictionFlags.AllowForwardLaneChange, startNode); - } - + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool IsEnteringBlockedJunctionAllowedConfigurable( ushort segmentId, bool startNode, @@ -566,6 +492,7 @@ public bool IsEnteringBlockedJunctionAllowedConfigurable( return ret; } + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool GetDefaultEnteringBlockedJunctionAllowed( ushort segmentId, bool startNode, @@ -581,7 +508,8 @@ public bool GetDefaultEnteringBlockedJunctionAllowed( return false; } - if (!IsEnteringBlockedJunctionAllowedConfigurable(segmentId, startNode, ref node)) { + var isConfigurable = CalculationContext.IsConfigurable ?? IsEnteringBlockedJunctionAllowedConfigurable(segmentId, startNode, ref node); + if (!isConfigurable) { bool res = (node.m_flags & (NetNode.Flags.Junction | NetNode.Flags.OneWayOut | NetNode.Flags.OneWayIn)) != NetNode.Flags.Junction || @@ -628,10 +556,7 @@ public bool GetDefaultEnteringBlockedJunctionAllowed( return ret; } - public bool IsEnteringBlockedJunctionAllowed(ushort segmentId, bool startNode) { - return segmentRestrictions[segmentId].GetValueOrDefault(JunctionRestrictionFlags.AllowEnterWhenBlocked, startNode); - } - + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool IsPedestrianCrossingAllowedConfigurable(ushort segmentId, bool startNode, ref NetNode node) { bool ret = (node.m_flags & (NetNode.Flags.Junction | NetNode.Flags.Bend)) != NetNode.Flags.None && node.Info?.m_class?.m_service != ItemClass.Service.Beautification; @@ -646,6 +571,7 @@ public bool IsPedestrianCrossingAllowedConfigurable(ushort segmentId, bool start return ret; } + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, bool startNode, ref NetNode node) { #if DEBUG bool logLogic = DebugSwitch.JunctionRestrictions.Get(); @@ -653,7 +579,8 @@ public bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, bool startNode const bool logLogic = false; #endif - if (!IsPedestrianCrossingAllowedConfigurable(segmentId, startNode, ref node)) { + var isConfigurable = CalculationContext.IsConfigurable ?? IsPedestrianCrossingAllowedConfigurable(segmentId, startNode, ref node); + if (!isConfigurable) { if (logLogic) { Log._Debug( "JunctionRestrictionsManager.GetDefaultPedestrianCrossingAllowed" + @@ -716,327 +643,48 @@ public bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, bool startNode return ret; } - public bool IsPedestrianCrossingAllowed(ushort segmentId, bool startNode) { - return segmentRestrictions[segmentId].GetValueOrDefault(JunctionRestrictionFlags.AllowPedestrianCrossing, startNode); - } - - public TernaryBool GetUturnAllowed(ushort segmentId, bool startNode) { - return segmentRestrictions[segmentId].GetTernaryBool(JunctionRestrictionFlags.AllowUTurn, startNode); - } - - public TernaryBool GetNearTurnOnRedAllowed(ushort segmentId, bool startNode) { - return segmentRestrictions[segmentId].GetTernaryBool(JunctionRestrictionFlags.AllowNearTurnOnRed, startNode); - } - - public TernaryBool GetFarTurnOnRedAllowed(ushort segmentId, bool startNode) { - return segmentRestrictions[segmentId].GetTernaryBool(JunctionRestrictionFlags.AllowFarTurnOnRed, startNode); - } - - public TernaryBool GetTurnOnRedAllowed(bool near, ushort segmentId, bool startNode) { - return near - ? GetNearTurnOnRedAllowed(segmentId, startNode) - : GetFarTurnOnRedAllowed(segmentId, startNode); - } - - public TernaryBool GetLaneChangingAllowedWhenGoingStraight(ushort segmentId, bool startNode) { - return segmentRestrictions[segmentId].GetTernaryBool(JunctionRestrictionFlags.AllowForwardLaneChange, startNode); - } - - public TernaryBool GetEnteringBlockedJunctionAllowed(ushort segmentId, bool startNode) { - return segmentRestrictions[segmentId].GetTernaryBool(JunctionRestrictionFlags.AllowEnterWhenBlocked, startNode); - } - - public TernaryBool GetPedestrianCrossingAllowed(ushort segmentId, bool startNode) { - return segmentRestrictions[segmentId].GetTernaryBool(JunctionRestrictionFlags.AllowPedestrianCrossing, startNode); - } - - public bool ToggleUturnAllowed(ushort segmentId, bool startNode) { - return SetUturnAllowed(segmentId, startNode, !IsUturnAllowed(segmentId, startNode)); - } - - public bool ToggleNearTurnOnRedAllowed(ushort segmentId, bool startNode) { - return ToggleTurnOnRedAllowed(true, segmentId, startNode); - } - - public bool ToggleFarTurnOnRedAllowed(ushort segmentId, bool startNode) { - return ToggleTurnOnRedAllowed(false, segmentId, startNode); - } - - public bool ToggleTurnOnRedAllowed(bool near, ushort segmentId, bool startNode) { - return SetTurnOnRedAllowed(near, segmentId, startNode, !IsTurnOnRedAllowed(near, segmentId, startNode)); - } - - public bool ToggleLaneChangingAllowedWhenGoingStraight(ushort segmentId, bool startNode) { - return SetLaneChangingAllowedWhenGoingStraight( - segmentId, - startNode, - !IsLaneChangingAllowedWhenGoingStraight(segmentId, startNode)); - } - - public bool ToggleEnteringBlockedJunctionAllowed(ushort segmentId, bool startNode) { - return SetEnteringBlockedJunctionAllowed( - segmentId, - startNode, - !IsEnteringBlockedJunctionAllowed(segmentId, startNode)); - } - - public bool TogglePedestrianCrossingAllowed(ushort segmentId, bool startNode) { - return SetPedestrianCrossingAllowed( - segmentId, - startNode, - !IsPedestrianCrossingAllowed(segmentId, startNode)); - } - - public bool SetUturnAllowed(ushort segmentId, bool startNode, bool value) { - return SetUturnAllowed(segmentId, startNode, ToTernaryBool(value)); - } - - public bool SetNearTurnOnRedAllowed(ushort segmentId, bool startNode, bool value) { - return SetNearTurnOnRedAllowed(segmentId, startNode, ToTernaryBool(value)); - } - - public bool SetFarTurnOnRedAllowed(ushort segmentId, bool startNode, bool value) { - return SetFarTurnOnRedAllowed(segmentId, startNode, ToTernaryBool(value)); - } - - public bool SetTurnOnRedAllowed(bool near, ushort segmentId, bool startNode, bool value) { - return SetTurnOnRedAllowed(near, segmentId, startNode, ToTernaryBool(value)); - } - - public bool SetLaneChangingAllowedWhenGoingStraight(ushort segmentId, bool startNode, bool value) { - return SetLaneChangingAllowedWhenGoingStraight( - segmentId, - startNode, - ToTernaryBool(value)); - } - - public bool SetEnteringBlockedJunctionAllowed(ushort segmentId, bool startNode, bool value) { - return SetEnteringBlockedJunctionAllowed( - segmentId, - startNode, - ToTernaryBool(value)); - } - - public bool SetPedestrianCrossingAllowed(ushort segmentId, bool startNode, bool value) { - return SetPedestrianCrossingAllowed( - segmentId, - startNode, - ToTernaryBool(value)); - } - public bool ClearSegmentEnd(ushort segmentId, bool startNode) { - bool ret = true; - ret |= SetPedestrianCrossingAllowed(segmentId, startNode, TernaryBool.Undefined); - ret |= SetEnteringBlockedJunctionAllowed(segmentId, startNode, TernaryBool.Undefined); - ret |= SetLaneChangingAllowedWhenGoingStraight(segmentId, startNode, TernaryBool.Undefined); - ret |= SetFarTurnOnRedAllowed(segmentId, startNode, TernaryBool.Undefined); - ret |= SetNearTurnOnRedAllowed(segmentId, startNode, TernaryBool.Undefined); - ret |= SetUturnAllowed(segmentId, startNode, TernaryBool.Undefined); - return ret; - } - - private void SetSegmentJunctionRestrictions(ushort segmentId, bool startNode, JunctionRestrictions restrictions) { - if (restrictions.HasValue(JunctionRestrictionFlags.AllowUTurn)) { - SetUturnAllowed(segmentId, startNode, restrictions.GetValueOrDefault(JunctionRestrictionFlags.AllowUTurn)); - } - - if (restrictions.HasValue(JunctionRestrictionFlags.AllowNearTurnOnRed)) { - SetNearTurnOnRedAllowed(segmentId, startNode, restrictions.GetValueOrDefault(JunctionRestrictionFlags.AllowNearTurnOnRed)); - } - - if (restrictions.HasValue(JunctionRestrictionFlags.AllowFarTurnOnRed)) { - SetFarTurnOnRedAllowed(segmentId, startNode, restrictions.GetValueOrDefault(JunctionRestrictionFlags.AllowFarTurnOnRed)); - } - - if (restrictions.HasValue(JunctionRestrictionFlags.AllowForwardLaneChange)) { - SetLaneChangingAllowedWhenGoingStraight( - segmentId, - startNode, - restrictions.GetValueOrDefault(JunctionRestrictionFlags.AllowForwardLaneChange)); - } - - if (restrictions.HasValue(JunctionRestrictionFlags.AllowEnterWhenBlocked)) { - SetEnteringBlockedJunctionAllowed( - segmentId, - startNode, - restrictions.GetValueOrDefault(JunctionRestrictionFlags.AllowEnterWhenBlocked)); - } - - if (restrictions.HasValue(JunctionRestrictionFlags.AllowPedestrianCrossing)) { - SetPedestrianCrossingAllowed( - segmentId, - startNode, - restrictions.GetValueOrDefault(JunctionRestrictionFlags.AllowPedestrianCrossing)); - } - } - - private static ref NetNode GetNode(ushort segmentId, bool startNode) => - ref segmentId.ToSegment().GetNodeId(startNode).ToNode(); - - #region SetAllowed: TernaryBool - - public bool SetUturnAllowed(ushort segmentId, bool startNode, TernaryBool value) { - ref NetSegment netSegment = ref segmentId.ToSegment(); - - if (!netSegment.IsValid()) { - return false; - } - if(GetUturnAllowed(segmentId, startNode) == value) { - return true; - } - if(!IsUturnAllowedConfigurable(segmentId, startNode, ref GetNode(segmentId, startNode))) { - return false; - } - - if (value == TernaryBool.False && Constants.ManagerFactory.LaneConnectionManager.HasUturnConnections( - segmentId, - startNode)) { - return false; - } - - segmentRestrictions[segmentId].SetValue(JunctionRestrictionFlags.AllowUTurn, startNode, value); - OnSegmentChange( - segmentId, - startNode, - ref Constants.ManagerFactory.ExtSegmentManager.ExtSegments[segmentId], - true); - return true; - } - - public bool SetNearTurnOnRedAllowed(ushort segmentId, bool startNode, TernaryBool value) { - return SetTurnOnRedAllowed(true, segmentId, startNode, value); - } - - public bool SetFarTurnOnRedAllowed(ushort segmentId, bool startNode, TernaryBool value) { - return SetTurnOnRedAllowed(false, segmentId, startNode, value); - } - public bool SetTurnOnRedAllowed(bool near, ushort segmentId, bool startNode, TernaryBool value) { - ref NetSegment netSegment = ref segmentId.ToSegment(); - - if (!netSegment.IsValid()) { - return false; - } - if (GetTurnOnRedAllowed(near, segmentId, startNode) == value) { - return true; - } - if (!IsTurnOnRedAllowedConfigurable(near, segmentId, startNode, ref GetNode(segmentId, startNode))) { + if (!segmentId.ToSegment().IsValid()) return false; - } - if (value == TernaryBool.False && Constants.ManagerFactory.LaneConnectionManager.HasUturnConnections( - segmentId, - startNode)) { - return false; - } - - if (near) { - segmentRestrictions[segmentId].SetValue(JunctionRestrictionFlags.AllowNearTurnOnRed, startNode, value); - } else { - segmentRestrictions[segmentId].SetValue(JunctionRestrictionFlags.AllowFarTurnOnRed, startNode, value); - } - OnSegmentChange(segmentId, startNode, ref Constants.ManagerFactory.ExtSegmentManager.ExtSegments[segmentId], true); - return true; + var segmentEndId = segmentId.AtNode(startNode); + return GetJunctionRestrictions(segmentEndId).ClearValue(segmentEndId, JunctionRestrictionFlags.All); } - public bool SetLaneChangingAllowedWhenGoingStraight( - ushort segmentId, - bool startNode, - TernaryBool value) { - ref NetSegment netSegment = ref segmentId.ToSegment(); - - if (!netSegment.IsValid()) { - return false; - } - if (GetLaneChangingAllowedWhenGoingStraight(segmentId, startNode) == value) { - return true; - } - if (!IsLaneChangingAllowedWhenGoingStraightConfigurable(segmentId, startNode, ref GetNode(segmentId, startNode))) { - return false; - } - - segmentRestrictions[segmentId].SetValue(JunctionRestrictionFlags.AllowForwardLaneChange, startNode, value); - OnSegmentChange( - segmentId, - startNode, - ref Constants.ManagerFactory.ExtSegmentManager.ExtSegments[segmentId], - true); - return true; - } - - public bool SetEnteringBlockedJunctionAllowed(ushort segmentId, bool startNode, TernaryBool value) { - ref NetSegment netSegment = ref segmentId.ToSegment(); - - if (!netSegment.IsValid()) { - return false; - } - if (GetEnteringBlockedJunctionAllowed(segmentId, startNode) == value) { - return true; - } - if (!IsEnteringBlockedJunctionAllowedConfigurable(segmentId, startNode, ref GetNode(segmentId, startNode))) { - return false; - } - - segmentRestrictions[segmentId].SetValue(JunctionRestrictionFlags.AllowEnterWhenBlocked, startNode, value); - - // recalculation not needed here because this is a simulation-time feature - OnSegmentChange( - segmentId, - startNode, - ref Constants.ManagerFactory.ExtSegmentManager.ExtSegments[segmentId], - false); - return true; + private void SetSegmentJunctionRestrictions(SegmentEndId segmentEndId, JunctionRestrictions restrictions) { + GetJunctionRestrictions(segmentEndId).Copy(segmentEndId, restrictions); } - public bool SetPedestrianCrossingAllowed(ushort segmentId, bool startNode, TernaryBool value) { - ref NetSegment netSegment = ref segmentId.ToSegment(); - - if (!netSegment.IsValid()) { - return false; - } - if(GetPedestrianCrossingAllowed(segmentId, startNode) == value) { - return true; - } - if(!IsPedestrianCrossingAllowedConfigurable(segmentId, startNode, ref GetNode(segmentId, startNode))) { - return false; - } + private static ref NetNode GetNode(ushort segmentId, bool startNode) => + ref segmentId.ToSegment().GetNodeId(startNode).ToNode(); - segmentRestrictions[segmentId].SetValue(JunctionRestrictionFlags.AllowPedestrianCrossing, startNode, value); - OnSegmentChange( - segmentId, - startNode, - ref Constants.ManagerFactory.ExtSegmentManager.ExtSegments[segmentId], - true); - return true; - } + private void OnSegmentChange(SegmentEndId segmentEndId, + bool requireRecalc) { -#endregion + ref var seg = ref ExtSegmentManager.Instance.ExtSegments[segmentEndId.SegmentId]; - private void OnSegmentChange(ushort segmentId, - bool startNode, - ref ExtSegment seg, - bool requireRecalc) { HandleValidSegment(ref seg); if (requireRecalc) { - RoutingManager.Instance.RequestRecalculation(segmentId); + RoutingManager.Instance.RequestRecalculation(segmentEndId.SegmentId); if (TMPELifecycle.Instance.MayPublishSegmentChanges()) { - ExtSegmentManager.Instance.PublishSegmentChanges(segmentId); + ExtSegmentManager.Instance.PublishSegmentChanges(segmentEndId.SegmentId); } } - Notifier.Instance.OnNodeModified(segmentId.ToSegment().GetNodeId(startNode), this); + Notifier.Instance.OnNodeModified(segmentEndId.GetNodeId(), this); } public override void OnLevelUnloading() { base.OnLevelUnloading(); - for (int i = 0; i < segmentRestrictions.Length; ++i) { - segmentRestrictions[i].Reset(startNode: null, resetDefaults: true); + for (ushort segmentId = 0; segmentId < segmentRestrictions.Length; ++segmentId) { + segmentRestrictions[segmentId].Reset((ushort)segmentId); } - for (int i = 0; i < invalidSegmentRestrictions.Length; ++i) { - invalidSegmentRestrictions[i].Reset(startNode: null, resetDefaults: true); + for (ushort segmentId = 0; segmentId < orphanedRestrictions.Length; ++segmentId) { + orphanedRestrictions[segmentId].Reset(segmentId); } } @@ -1063,71 +711,12 @@ public bool LoadData(List data) { Configuration.SegmentNodeFlags flags = segNodeConf.startNodeFlags; ref NetNode startNode = ref startNodeId.ToNode(); - if (flags.uturnAllowed != null && - IsUturnAllowedConfigurable( - segNodeConf.segmentId, - true, - ref startNode)) { - SetUturnAllowed( - segNodeConf.segmentId, - true, - (bool)flags.uturnAllowed); - } - - if (flags.turnOnRedAllowed != null && - IsNearTurnOnRedAllowedConfigurable( - segNodeConf.segmentId, - true, - ref startNode)) { - SetNearTurnOnRedAllowed( - segNodeConf.segmentId, - true, - (bool)flags.turnOnRedAllowed); - } - - if (flags.farTurnOnRedAllowed != null && - IsFarTurnOnRedAllowedConfigurable( - segNodeConf.segmentId, - true, - ref startNode)) { - SetFarTurnOnRedAllowed( - segNodeConf.segmentId, - true, - (bool)flags.farTurnOnRedAllowed); - } - - if (flags.straightLaneChangingAllowed != null && - IsLaneChangingAllowedWhenGoingStraightConfigurable( - segNodeConf.segmentId, - true, - ref startNode)) { - SetLaneChangingAllowedWhenGoingStraight( - segNodeConf.segmentId, - true, - (bool)flags.straightLaneChangingAllowed); - } - - if (flags.enterWhenBlockedAllowed != null && - IsEnteringBlockedJunctionAllowedConfigurable( - segNodeConf.segmentId, - true, - ref startNode)) { - SetEnteringBlockedJunctionAllowed( - segNodeConf.segmentId, - true, - (bool)flags.enterWhenBlockedAllowed); - } - - if (flags.pedestrianCrossingAllowed != null && - IsPedestrianCrossingAllowedConfigurable( - segNodeConf.segmentId, - true, - ref startNode)) { - SetPedestrianCrossingAllowed( - segNodeConf.segmentId, - true, - (bool)flags.pedestrianCrossingAllowed); - } + SetValue(segNodeConf.segmentId, true, JunctionRestrictionFlags.AllowUTurn, flags.uturnAllowed); + SetValue(segNodeConf.segmentId, true, JunctionRestrictionFlags.AllowNearTurnOnRed, flags.turnOnRedAllowed); + SetValue(segNodeConf.segmentId, true, JunctionRestrictionFlags.AllowFarTurnOnRed, flags.farTurnOnRedAllowed); + SetValue(segNodeConf.segmentId, true, JunctionRestrictionFlags.AllowForwardLaneChange, flags.straightLaneChangingAllowed); + SetValue(segNodeConf.segmentId, true, JunctionRestrictionFlags.AllowEnterWhenBlocked, flags.enterWhenBlockedAllowed); + SetValue(segNodeConf.segmentId, true, JunctionRestrictionFlags.AllowPedestrianCrossing, flags.pedestrianCrossingAllowed); } else { Log.Warning( "JunctionRestrictionsManager.LoadData(): Could not get segment " + @@ -1138,74 +727,15 @@ public bool LoadData(List data) { if (segNodeConf.endNodeFlags != null) { ushort endNodeId = netSegment.m_endNode; if (endNodeId != 0) { - Configuration.SegmentNodeFlags flags1 = segNodeConf.endNodeFlags; + Configuration.SegmentNodeFlags flags = segNodeConf.endNodeFlags; ref NetNode node = ref endNodeId.ToNode(); - if (flags1.uturnAllowed != null && - IsUturnAllowedConfigurable( - segNodeConf.segmentId, - false, - ref node)) { - SetUturnAllowed( - segNodeConf.segmentId, - false, - (bool)flags1.uturnAllowed); - } - - if (flags1.straightLaneChangingAllowed != null && - IsLaneChangingAllowedWhenGoingStraightConfigurable( - segNodeConf.segmentId, - false, - ref node)) { - SetLaneChangingAllowedWhenGoingStraight( - segNodeConf.segmentId, - false, - (bool)flags1.straightLaneChangingAllowed); - } - - if (flags1.enterWhenBlockedAllowed != null && - IsEnteringBlockedJunctionAllowedConfigurable( - segNodeConf.segmentId, - false, - ref node)) { - SetEnteringBlockedJunctionAllowed( - segNodeConf.segmentId, - false, - (bool)flags1.enterWhenBlockedAllowed); - } - - if (flags1.pedestrianCrossingAllowed != null && - IsPedestrianCrossingAllowedConfigurable( - segNodeConf.segmentId, - false, - ref node)) { - SetPedestrianCrossingAllowed( - segNodeConf.segmentId, - false, - (bool)flags1.pedestrianCrossingAllowed); - } - - if (flags1.turnOnRedAllowed != null && - IsNearTurnOnRedAllowedConfigurable( - segNodeConf.segmentId, - false, - ref node)) { - SetNearTurnOnRedAllowed( - segNodeConf.segmentId, - false, - (bool)flags1.turnOnRedAllowed); - } - - if (flags1.farTurnOnRedAllowed != null && - IsFarTurnOnRedAllowedConfigurable( - segNodeConf.segmentId, - false, - ref node)) { - SetFarTurnOnRedAllowed( - segNodeConf.segmentId, - false, - (bool)flags1.farTurnOnRedAllowed); - } + SetValue(segNodeConf.segmentId, false, JunctionRestrictionFlags.AllowUTurn, flags.uturnAllowed); + SetValue(segNodeConf.segmentId, false, JunctionRestrictionFlags.AllowNearTurnOnRed, flags.turnOnRedAllowed); + SetValue(segNodeConf.segmentId, false, JunctionRestrictionFlags.AllowFarTurnOnRed, flags.farTurnOnRedAllowed); + SetValue(segNodeConf.segmentId, false, JunctionRestrictionFlags.AllowForwardLaneChange, flags.straightLaneChangingAllowed); + SetValue(segNodeConf.segmentId, false, JunctionRestrictionFlags.AllowEnterWhenBlocked, flags.enterWhenBlockedAllowed); + SetValue(segNodeConf.segmentId, false, JunctionRestrictionFlags.AllowPedestrianCrossing, flags.pedestrianCrossingAllowed); } else { Log.Warning( "JunctionRestrictionsManager.LoadData(): Could not get segment " + @@ -1228,7 +758,7 @@ public bool LoadData(List data) { ExtSegmentManager extSegmentManager = ExtSegmentManager.Instance; - for (uint segmentId = 0; segmentId < NetManager.MAX_SEGMENT_COUNT; segmentId++) { + for (ushort segmentId = 0; segmentId < NetManager.MAX_SEGMENT_COUNT; segmentId++) { try { ref NetSegment netSegment = ref ((ushort)segmentId).ToSegment(); @@ -1244,21 +774,15 @@ public bool LoadData(List data) { if (startNodeId.ToNode().IsValid()) { JunctionRestrictions endFlags = segmentRestrictions[segmentId].startNodeRestrictions; - if (!endFlags.IsDefault()) { + if (!endFlags.IsDefault(segmentId.AtStartNode())) { startNodeFlags = new Configuration.SegmentNodeFlags(); - startNodeFlags.uturnAllowed = - TernaryBoolUtil.ToOptBool(GetUturnAllowed((ushort)segmentId, true)); - startNodeFlags.turnOnRedAllowed = TernaryBoolUtil.ToOptBool( - GetNearTurnOnRedAllowed((ushort)segmentId, true)); - startNodeFlags.farTurnOnRedAllowed = TernaryBoolUtil.ToOptBool( - GetFarTurnOnRedAllowed((ushort)segmentId, true)); - startNodeFlags.straightLaneChangingAllowed = TernaryBoolUtil.ToOptBool( - GetLaneChangingAllowedWhenGoingStraight((ushort)segmentId, true)); - startNodeFlags.enterWhenBlockedAllowed = TernaryBoolUtil.ToOptBool( - GetEnteringBlockedJunctionAllowed((ushort)segmentId, true)); - startNodeFlags.pedestrianCrossingAllowed = TernaryBoolUtil.ToOptBool( - GetPedestrianCrossingAllowed((ushort)segmentId, true)); + startNodeFlags.uturnAllowed = GetValue(segmentId, true, JunctionRestrictionFlags.AllowUTurn); + startNodeFlags.turnOnRedAllowed = GetValue(segmentId, true, JunctionRestrictionFlags.AllowNearTurnOnRed); + startNodeFlags.farTurnOnRedAllowed = GetValue(segmentId, true, JunctionRestrictionFlags.AllowFarTurnOnRed); + startNodeFlags.straightLaneChangingAllowed = GetValue(segmentId, true, JunctionRestrictionFlags.AllowForwardLaneChange); + startNodeFlags.enterWhenBlockedAllowed = GetValue(segmentId, true, JunctionRestrictionFlags.AllowEnterWhenBlocked); + startNodeFlags.pedestrianCrossingAllowed = GetValue(segmentId, true, JunctionRestrictionFlags.AllowPedestrianCrossing); #if DEBUGSAVE Log._Debug($"JunctionRestrictionsManager.SaveData: Saving start node "+ @@ -1272,22 +796,15 @@ public bool LoadData(List data) { if (endNodeId.ToNode().IsValid()) { JunctionRestrictions restrictions = segmentRestrictions[segmentId].endNodeRestrictions; - if (!restrictions.IsDefault()) { + if (!restrictions.IsDefault(segmentId.AtEndNode())) { endNodeFlags = new Configuration.SegmentNodeFlags(); - endNodeFlags.uturnAllowed = - TernaryBoolUtil.ToOptBool( - GetUturnAllowed((ushort)segmentId, false)); - endNodeFlags.turnOnRedAllowed = TernaryBoolUtil.ToOptBool( - GetNearTurnOnRedAllowed((ushort)segmentId, false)); - endNodeFlags.farTurnOnRedAllowed = TernaryBoolUtil.ToOptBool( - GetFarTurnOnRedAllowed((ushort)segmentId, false)); - endNodeFlags.straightLaneChangingAllowed = TernaryBoolUtil.ToOptBool( - GetLaneChangingAllowedWhenGoingStraight((ushort)segmentId, false)); - endNodeFlags.enterWhenBlockedAllowed = TernaryBoolUtil.ToOptBool( - GetEnteringBlockedJunctionAllowed((ushort)segmentId, false)); - endNodeFlags.pedestrianCrossingAllowed = TernaryBoolUtil.ToOptBool( - GetPedestrianCrossingAllowed((ushort)segmentId, false)); + endNodeFlags.uturnAllowed = GetValue(segmentId, false, JunctionRestrictionFlags.AllowUTurn); + endNodeFlags.turnOnRedAllowed = GetValue(segmentId, false, JunctionRestrictionFlags.AllowNearTurnOnRed); + endNodeFlags.farTurnOnRedAllowed = GetValue(segmentId, false, JunctionRestrictionFlags.AllowFarTurnOnRed); + endNodeFlags.straightLaneChangingAllowed = GetValue(segmentId, false, JunctionRestrictionFlags.AllowForwardLaneChange); + endNodeFlags.enterWhenBlockedAllowed = GetValue(segmentId, false, JunctionRestrictionFlags.AllowEnterWhenBlocked); + endNodeFlags.pedestrianCrossingAllowed = GetValue(segmentId, false, JunctionRestrictionFlags.AllowPedestrianCrossing); #if DEBUGSAVE Log._Debug($"JunctionRestrictionsManager.SaveData: Saving end node junction "+ @@ -1319,37 +836,125 @@ public bool LoadData(List data) { return ret; } + public bool IsConfigurable(ushort segmentId, bool startNode, JunctionRestrictionFlags flags) + => segmentRestrictions[segmentId].IsConfigurable(segmentId.AtNode(startNode), flags); + + public bool GetDefaultValue(ushort segmentId, bool startNode, JunctionRestrictionFlags flags) + => segmentRestrictions[segmentId].GetDefaultValue(segmentId.AtNode(startNode), flags); + + public bool ToggleValue(ushort segmentId, bool startNode, JunctionRestrictionFlags flags) { + + if (flags == default || ((int)flags & ((int)flags - 1)) != 0) + return false; + + return SetValue(segmentId, startNode, flags, !GetValueOrDefault(segmentId, startNode, flags)); + } + + public bool SetValue(ushort segmentId, bool startNode, JunctionRestrictionFlags flags, bool? value) + => segmentId.ToSegment().IsValid() && flags != default && segmentRestrictions[segmentId].SetValue(segmentId.AtNode(startNode), flags, value); + + public bool? GetValue(ushort segmentId, bool startNode, JunctionRestrictionFlags flags) + => segmentRestrictions[segmentId].GetValue(segmentId.AtNode(startNode), flags); + + public bool GetValueOrDefault(ushort segmentId, bool startNode, JunctionRestrictionFlags flags) + => segmentRestrictions[segmentId].GetValueOrDefault(segmentId.AtNode(startNode), flags); + + bool IJunctionRestrictionsManager.IsUturnAllowedConfigurable(ushort segmentId, bool startNode, ref NetNode node) => IsConfigurable(segmentId, startNode, JunctionRestrictionFlags.AllowUTurn); + bool IJunctionRestrictionsManager.IsNearTurnOnRedAllowedConfigurable(ushort segmentId, bool startNode, ref NetNode node) => IsConfigurable(segmentId, startNode, JunctionRestrictionFlags.AllowNearTurnOnRed); + bool IJunctionRestrictionsManager.IsFarTurnOnRedAllowedConfigurable(ushort segmentId, bool startNode, ref NetNode node) => IsConfigurable(segmentId, startNode, JunctionRestrictionFlags.AllowFarTurnOnRed); + bool IJunctionRestrictionsManager.IsTurnOnRedAllowedConfigurable(bool near, ushort segmentId, bool startNode, ref NetNode node) => IsConfigurable(segmentId, startNode, near ? JunctionRestrictionFlags.AllowNearTurnOnRed : JunctionRestrictionFlags.AllowFarTurnOnRed); + bool IJunctionRestrictionsManager.IsLaneChangingAllowedWhenGoingStraightConfigurable(ushort segmentId, bool startNode, ref NetNode node) => IsConfigurable(segmentId, startNode, JunctionRestrictionFlags.AllowForwardLaneChange); + bool IJunctionRestrictionsManager.IsEnteringBlockedJunctionAllowedConfigurable(ushort segmentId, bool startNode, ref NetNode node) => IsConfigurable(segmentId, startNode, JunctionRestrictionFlags.AllowEnterWhenBlocked); + bool IJunctionRestrictionsManager.IsPedestrianCrossingAllowedConfigurable(ushort segmentId, bool startNode, ref NetNode node) => IsConfigurable(segmentId, startNode, JunctionRestrictionFlags.AllowPedestrianCrossing); + bool IJunctionRestrictionsManager.GetDefaultUturnAllowed(ushort segmentId, bool startNode, ref NetNode node) => GetDefaultValue(segmentId, startNode, JunctionRestrictionFlags.AllowUTurn); + bool IJunctionRestrictionsManager.GetDefaultNearTurnOnRedAllowed(ushort segmentId, bool startNode, ref NetNode node) => GetDefaultValue(segmentId, startNode, JunctionRestrictionFlags.AllowNearTurnOnRed); + bool IJunctionRestrictionsManager.GetDefaultFarTurnOnRedAllowed(ushort segmentId, bool startNode, ref NetNode node) => GetDefaultValue(segmentId, startNode, JunctionRestrictionFlags.AllowFarTurnOnRed); + bool IJunctionRestrictionsManager.GetDefaultTurnOnRedAllowed(bool near, ushort segmentId, bool startNode, ref NetNode node) => GetDefaultValue(segmentId, startNode, near ? JunctionRestrictionFlags.AllowNearTurnOnRed : JunctionRestrictionFlags.AllowFarTurnOnRed); + bool IJunctionRestrictionsManager.GetDefaultLaneChangingAllowedWhenGoingStraight(ushort segmentId, bool startNode, ref NetNode node) => GetDefaultValue(segmentId, startNode, JunctionRestrictionFlags.AllowForwardLaneChange); + bool IJunctionRestrictionsManager.GetDefaultEnteringBlockedJunctionAllowed(ushort segmentId, bool startNode, ref NetNode node) => GetDefaultValue(segmentId, startNode, JunctionRestrictionFlags.AllowEnterWhenBlocked); + bool IJunctionRestrictionsManager.GetDefaultPedestrianCrossingAllowed(ushort segmentId, bool startNode, ref NetNode node) => GetDefaultValue(segmentId, startNode, JunctionRestrictionFlags.AllowPedestrianCrossing); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool ToggleUturnAllowed(ushort segmentId, bool startNode) => ToggleValue(segmentId, startNode, JunctionRestrictionFlags.AllowUTurn); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool ToggleNearTurnOnRedAllowed(ushort segmentId, bool startNode) => ToggleValue(segmentId, startNode, JunctionRestrictionFlags.AllowNearTurnOnRed); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool ToggleFarTurnOnRedAllowed(ushort segmentId, bool startNode) => ToggleValue(segmentId, startNode, JunctionRestrictionFlags.AllowFarTurnOnRed); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool ToggleTurnOnRedAllowed(bool near, ushort segmentId, bool startNode) => ToggleValue(segmentId, startNode, near ? JunctionRestrictionFlags.AllowNearTurnOnRed : JunctionRestrictionFlags.AllowFarTurnOnRed); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool ToggleLaneChangingAllowedWhenGoingStraight(ushort segmentId, bool startNode) => ToggleValue(segmentId, startNode, JunctionRestrictionFlags.AllowForwardLaneChange); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool ToggleEnteringBlockedJunctionAllowed(ushort segmentId, bool startNode) => ToggleValue(segmentId, startNode, JunctionRestrictionFlags.AllowEnterWhenBlocked); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool TogglePedestrianCrossingAllowed(ushort segmentId, bool startNode) => ToggleValue(segmentId, startNode, JunctionRestrictionFlags.AllowPedestrianCrossing); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool SetUturnAllowed(ushort segmentId, bool startNode, bool value) => SetValue(segmentId, startNode, JunctionRestrictionFlags.AllowUTurn, value); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool SetNearTurnOnRedAllowed(ushort segmentId, bool startNode, bool value) => SetValue(segmentId, startNode, JunctionRestrictionFlags.AllowNearTurnOnRed, value); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool SetFarTurnOnRedAllowed(ushort segmentId, bool startNode, bool value) => SetValue(segmentId, startNode, JunctionRestrictionFlags.AllowFarTurnOnRed, value); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool SetTurnOnRedAllowed(bool near, ushort segmentId, bool startNode, bool value) => SetValue(segmentId, startNode, near ? JunctionRestrictionFlags.AllowNearTurnOnRed : JunctionRestrictionFlags.AllowFarTurnOnRed, value); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool SetLaneChangingAllowedWhenGoingStraight(ushort segmentId, bool startNode, bool value) => SetValue(segmentId, startNode, JunctionRestrictionFlags.AllowForwardLaneChange, value); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool SetEnteringBlockedJunctionAllowed(ushort segmentId, bool startNode, bool value) => SetValue(segmentId, startNode, JunctionRestrictionFlags.AllowEnterWhenBlocked, value); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool SetPedestrianCrossingAllowed(ushort segmentId, bool startNode, bool value) => SetValue(segmentId, startNode, JunctionRestrictionFlags.AllowPedestrianCrossing, value); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool SetUturnAllowed(ushort segmentId, bool startNode, TernaryBool value) => SetValue(segmentId, startNode, JunctionRestrictionFlags.AllowUTurn, ToOptBool(value)); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool SetNearTurnOnRedAllowed(ushort segmentId, bool startNode, TernaryBool value) => SetValue(segmentId, startNode, JunctionRestrictionFlags.AllowNearTurnOnRed, ToOptBool(value)); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool SetFarTurnOnRedAllowed(ushort segmentId, bool startNode, TernaryBool value) => SetValue(segmentId, startNode, JunctionRestrictionFlags.AllowFarTurnOnRed, ToOptBool(value)); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool SetTurnOnRedAllowed(bool near, ushort segmentId, bool startNode, TernaryBool value) => SetValue(segmentId, startNode, near ? JunctionRestrictionFlags.AllowNearTurnOnRed : JunctionRestrictionFlags.AllowFarTurnOnRed, ToOptBool(value)); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool SetLaneChangingAllowedWhenGoingStraight(ushort segmentId, bool startNode, TernaryBool value) => SetValue(segmentId, startNode, JunctionRestrictionFlags.AllowForwardLaneChange, ToOptBool(value)); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool SetEnteringBlockedJunctionAllowed(ushort segmentId, bool startNode, TernaryBool value) => SetValue(segmentId, startNode, JunctionRestrictionFlags.AllowEnterWhenBlocked, ToOptBool(value)); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool SetPedestrianCrossingAllowed(ushort segmentId, bool startNode, TernaryBool value) => SetValue(segmentId, startNode, JunctionRestrictionFlags.AllowPedestrianCrossing, ToOptBool(value)); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public TernaryBool GetUturnAllowed(ushort segmentId, bool startNode) => ToTernaryBool(GetValue(segmentId, startNode, JunctionRestrictionFlags.AllowUTurn)); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public TernaryBool GetNearTurnOnRedAllowed(ushort segmentId, bool startNode) => ToTernaryBool(GetValue(segmentId, startNode, JunctionRestrictionFlags.AllowNearTurnOnRed)); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public TernaryBool GetFarTurnOnRedAllowed(ushort segmentId, bool startNode) => ToTernaryBool(GetValue(segmentId, startNode, JunctionRestrictionFlags.AllowFarTurnOnRed)); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public TernaryBool GetTurnOnRedAllowed(bool near, ushort segmentId, bool startNode) => ToTernaryBool(GetValue(segmentId, startNode, near ? JunctionRestrictionFlags.AllowNearTurnOnRed : JunctionRestrictionFlags.AllowFarTurnOnRed)); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public TernaryBool GetLaneChangingAllowedWhenGoingStraight(ushort segmentId, bool startNode) => ToTernaryBool(GetValue(segmentId, startNode, JunctionRestrictionFlags.AllowForwardLaneChange)); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public TernaryBool GetEnteringBlockedJunctionAllowed(ushort segmentId, bool startNode) => ToTernaryBool(GetValue(segmentId, startNode, JunctionRestrictionFlags.AllowEnterWhenBlocked)); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public TernaryBool GetPedestrianCrossingAllowed(ushort segmentId, bool startNode) => ToTernaryBool(GetValue(segmentId, startNode, JunctionRestrictionFlags.AllowPedestrianCrossing)); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool IsUturnAllowed(ushort segmentId, bool startNode) => GetValueOrDefault(segmentId, startNode, JunctionRestrictionFlags.AllowUTurn); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool IsNearTurnOnRedAllowed(ushort segmentId, bool startNode) => GetValueOrDefault(segmentId, startNode, JunctionRestrictionFlags.AllowNearTurnOnRed); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool IsFarTurnOnRedAllowed(ushort segmentId, bool startNode) => GetValueOrDefault(segmentId, startNode, JunctionRestrictionFlags.AllowFarTurnOnRed); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool IsTurnOnRedAllowed(bool near, ushort segmentId, bool startNode) => GetValueOrDefault(segmentId, startNode, near ? JunctionRestrictionFlags.AllowNearTurnOnRed : JunctionRestrictionFlags.AllowFarTurnOnRed); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool IsLaneChangingAllowedWhenGoingStraight(ushort segmentId, bool startNode) => GetValueOrDefault(segmentId, startNode, JunctionRestrictionFlags.AllowForwardLaneChange); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool IsEnteringBlockedJunctionAllowed(ushort segmentId, bool startNode) => GetValueOrDefault(segmentId, startNode, JunctionRestrictionFlags.AllowEnterWhenBlocked); + [Obsolete("If you must call this method, please go through IJunctionRestrictionsManager.", true)] public bool IsPedestrianCrossingAllowed(ushort segmentId, bool startNode) => GetValueOrDefault(segmentId, startNode, JunctionRestrictionFlags.AllowPedestrianCrossing); + private struct SegmentJunctionRestrictions { public JunctionRestrictions startNodeRestrictions; public JunctionRestrictions endNodeRestrictions; - public bool GetValueOrDefault(JunctionRestrictionFlags flags, bool startNode) { - return (startNode ? startNodeRestrictions : endNodeRestrictions).GetValueOrDefault(flags); + public bool GetValueOrDefault(SegmentEndId segmentEndId, JunctionRestrictionFlags flags) { + return (segmentEndId.StartNode ? startNodeRestrictions : endNodeRestrictions).GetValueOrDefault(segmentEndId, flags); } - public TernaryBool GetTernaryBool(JunctionRestrictionFlags flags, bool startNode) { - return (startNode ? startNodeRestrictions : endNodeRestrictions).GetTernaryBool(flags); + public bool? GetValue(SegmentEndId segmentEndId, JunctionRestrictionFlags flags) { + return (segmentEndId.StartNode ? startNodeRestrictions : endNodeRestrictions).GetValue(segmentEndId, flags); } - public void SetValue(JunctionRestrictionFlags flags, bool startNode, TernaryBool value) { - if (startNode) - startNodeRestrictions.SetValue(flags, value); + public bool GetDefaultValue(SegmentEndId segmentEndId, JunctionRestrictionFlags flags) { + return (segmentEndId.StartNode ? startNodeRestrictions : endNodeRestrictions).GetDefaultValue(segmentEndId, flags); + } + + public bool IsConfigurable(SegmentEndId segmentEndId, JunctionRestrictionFlags flags) { + return (segmentEndId.StartNode ? startNodeRestrictions : endNodeRestrictions).IsConfigurable(segmentEndId, flags); + } + + public bool SetValue(SegmentEndId segmentEndId, JunctionRestrictionFlags flags, bool? value) { + if (segmentEndId.StartNode) + return startNodeRestrictions.SetValue(segmentEndId, flags, value); else - endNodeRestrictions.SetValue(flags, value); + return endNodeRestrictions.SetValue(segmentEndId, flags, value); } - public bool IsDefault() { - return startNodeRestrictions.IsDefault() && endNodeRestrictions.IsDefault(); + public bool IsDefault(ushort segmentId) { + return startNodeRestrictions.IsDefault(segmentId.AtStartNode()) && endNodeRestrictions.IsDefault(segmentId.AtEndNode()); } - public void Reset(bool? startNode = null, bool resetDefaults = true) { - if (startNode == null || (bool)startNode) { - startNodeRestrictions.Reset(resetDefaults); - } + public void Reset(SegmentEndId segmentEndId) { + if (segmentEndId.StartNode) + startNodeRestrictions.Reset(segmentEndId); + else + endNodeRestrictions.Reset(segmentEndId); + } - if (startNode == null || !(bool)startNode) { - endNodeRestrictions.Reset(resetDefaults); - } + public void Reset(ushort segmentId) { + Reset(segmentId.AtStartNode()); + Reset(segmentId.AtEndNode()); + } + + public void Invalidate(ushort segmentId) { + startNodeRestrictions.Invalidate(segmentId.AtStartNode()); + endNodeRestrictions.Invalidate(segmentId.AtEndNode()); } public override string ToString() { @@ -1368,70 +973,219 @@ private struct JunctionRestrictions { private JunctionRestrictionFlags defaults; + private JunctionRestrictionFlags configurables; - public void ClearValue(JunctionRestrictionFlags flags) { - values &= ~flags; - mask &= ~flags; - } + private JunctionRestrictionFlags valid; + + public bool ClearValue(SegmentEndId segmentEndId, JunctionRestrictionFlags flags) => SetValue(segmentEndId, flags, null); - public void SetDefault(JunctionRestrictionFlags flags, bool value) { + private void SetDefault(SegmentEndId segmentEndId, JunctionRestrictionFlags flags, bool value) { if (value) defaults |= flags; else defaults &= ~flags; } - public bool GetDefault(JunctionRestrictionFlags flags) { + private void SetConfigurable(SegmentEndId segmentEndId, JunctionRestrictionFlags flags, bool value) { + if (value) + configurables |= flags; + else + configurables &= ~flags; + } + + public bool GetDefaultValue(SegmentEndId segmentEndId, JunctionRestrictionFlags flags) { + Recalculate(segmentEndId); return (defaults & flags) == flags; } - public bool HasValue(JunctionRestrictionFlags flags) { + public bool IsConfigurable(SegmentEndId segmentEndId, JunctionRestrictionFlags flags) { + Recalculate(segmentEndId); + return (configurables & flags) == flags; + } + + public bool HasValue(SegmentEndId segmentEndId, JunctionRestrictionFlags flags) { return (mask & flags) == flags; } - public TernaryBool GetTernaryBool(JunctionRestrictionFlags flags) { - return (mask & flags) == flags - ? (values & flags) == flags - ? TernaryBool.True - : TernaryBool.False - : TernaryBool.Undefined; + public bool? GetValue(SegmentEndId segmentEndId, JunctionRestrictionFlags flags) { + + return (mask & flags) != flags ? null + : (values & flags) == flags ? true + : (values & flags) == 0 ? false + : null; } - public bool GetValueOrDefault(JunctionRestrictionFlags flags) { + public bool GetValueOrDefault(SegmentEndId segmentEndId, JunctionRestrictionFlags flags) { + Recalculate(segmentEndId); return ((values & flags & mask) | (defaults & flags & ~mask)) == flags; } - public void SetValue(JunctionRestrictionFlags flags, TernaryBool value) { - switch (value) { - case TernaryBool.True: - values |= flags; - mask |= flags; - break; + public JunctionRestrictionFlags GetFlagsWithDefaults(SegmentEndId segmentEndId) { + return (values & mask) | (defaults & ~mask); + } - case TernaryBool.False: - values &= ~flags; - mask |= flags; - break; + private const JunctionRestrictionFlags routingRecalculationFlags = JunctionRestrictionFlags.All & ~JunctionRestrictionFlags.AllowEnterWhenBlocked; - case TernaryBool.Undefined: - values &= ~flags; - mask &= ~flags; - break; + private bool ValidateSet(SegmentEndId segmentEndId, JunctionRestrictionFlags flags, JunctionRestrictionFlags newValues, JunctionRestrictionFlags newMask) { - default: - throw new ArgumentOutOfRangeException(nameof(value)); - } + const JunctionRestrictionFlags uTurnCheckFlags + = JunctionRestrictionFlags.AllowNearTurnOnRed + | JunctionRestrictionFlags.AllowFarTurnOnRed + | JunctionRestrictionFlags.AllowUTurn; + + if ((newMask & flags & uTurnCheckFlags) != 0 + && (newValues & newMask & flags & uTurnCheckFlags) == 0 + && LaneConnectionManager.Instance.HasUturnConnections(segmentEndId.SegmentId, segmentEndId.StartNode)) + return false; + + return true; + } + + public bool SetValue(SegmentEndId segmentEndId, JunctionRestrictionFlags flags, bool? value) { + + Recalculate(segmentEndId); + + var newValues = value == true ? (values | flags) : (values & ~flags); + var newMask = value.HasValue ? (mask | flags) : (mask & ~flags); + + return Set(segmentEndId, flags, newValues, newMask); } - public bool IsDefault() { + private bool Set(SegmentEndId segmentEndId, JunctionRestrictionFlags flags, JunctionRestrictionFlags newValues, JunctionRestrictionFlags newMask) { + + Recalculate(segmentEndId); + + var changingValues = newValues ^ values; + var changingMask = newMask ^ mask; + + if (changingValues == 0 && changingMask == 0) + return true; + + if ((configurables & changingValues) != changingValues || (configurables & changingMask) != changingMask) + return false; + + if (!ValidateSet(segmentEndId, flags, newValues, newMask)) + return false; + + values = newValues & flags; + mask = newMask & flags; + + return true; + } + + public void Copy(SegmentEndId segmentEndId, JunctionRestrictions other) { + Recalculate(segmentEndId); + Set(segmentEndId, other.mask & configurables, other.values, other.mask); + } + + public bool IsDefault(SegmentEndId segmentEndId) { + Recalculate(segmentEndId); return ((values & mask) | (defaults & ~mask)) == defaults; } - public void Reset(bool resetDefaults = true) { + private delegate bool Calculator(ushort segmentId, bool startNode, ref NetNode node); + + /// + /// This is needed because the methods are annoted to produce a compiler error if referenced directly. + /// + /// + /// + private static Calculator DelegateTo(string methodName) { + return (Calculator)Delegate.CreateDelegate(typeof(Calculator), Instance, methodName); + } + + private static Dictionary configurableCalculators = new Dictionary() { + { JunctionRestrictionFlags.AllowUTurn, DelegateTo(nameof(IsUturnAllowedConfigurable)) }, + { JunctionRestrictionFlags.AllowNearTurnOnRed, DelegateTo(nameof(IsNearTurnOnRedAllowedConfigurable)) }, + { JunctionRestrictionFlags.AllowFarTurnOnRed, DelegateTo(nameof(IsFarTurnOnRedAllowedConfigurable)) }, + { JunctionRestrictionFlags.AllowForwardLaneChange, DelegateTo(nameof(IsLaneChangingAllowedWhenGoingStraightConfigurable)) }, + { JunctionRestrictionFlags.AllowEnterWhenBlocked, DelegateTo(nameof(IsEnteringBlockedJunctionAllowedConfigurable)) }, + { JunctionRestrictionFlags.AllowPedestrianCrossing, DelegateTo(nameof(IsPedestrianCrossingAllowedConfigurable)) }, + }; + + private static Dictionary defaultCalculators = new Dictionary() { + { JunctionRestrictionFlags.AllowUTurn, DelegateTo(nameof(GetDefaultUturnAllowed)) }, + { JunctionRestrictionFlags.AllowNearTurnOnRed, DelegateTo(nameof(GetDefaultNearTurnOnRedAllowed)) }, + { JunctionRestrictionFlags.AllowFarTurnOnRed, DelegateTo(nameof(GetDefaultFarTurnOnRedAllowed)) }, + { JunctionRestrictionFlags.AllowForwardLaneChange, DelegateTo(nameof(GetDefaultLaneChangingAllowedWhenGoingStraight)) }, + { JunctionRestrictionFlags.AllowEnterWhenBlocked, DelegateTo(nameof(GetDefaultEnteringBlockedJunctionAllowed)) }, + { JunctionRestrictionFlags.AllowPedestrianCrossing, DelegateTo(nameof(GetDefaultPedestrianCrossingAllowed)) }, + }; + + private void Recalculate(SegmentEndId segmentEndId) { + + var recalculateFlags = JunctionRestrictionFlags.All & ~valid; + if (recalculateFlags != default) { + ref var node = ref segmentEndId.GetNodeId().ToNode(); + + JunctionRestrictionFlags newConfigurables = default; + + foreach (var c in configurableCalculators) { + if ((recalculateFlags & c.Key) != 0) { + var result = c.Value(segmentEndId.SegmentId, segmentEndId.StartNode, ref node); + if (result) + newConfigurables |= c.Key; + else + newConfigurables &= ~c.Key; + } + } + + if (Instance.GetConfigurableHook != null) { + var args = new FlagsHookArgs(segmentEndId.SegmentId, segmentEndId.StartNode, recalculateFlags, newConfigurables); + Instance.GetConfigurableHook(args); + newConfigurables = args.Result; + } + + JunctionRestrictionFlags newDefaults = default; + + foreach (var c in defaultCalculators) { + if ((recalculateFlags & c.Key) != 0) { + try { + CalculationContext.IsConfigurable = (newConfigurables & c.Key) != 0; + var result = c.Value(segmentEndId.SegmentId, segmentEndId.StartNode, ref node); + if (result) + newDefaults |= c.Key; + else + newDefaults &= ~c.Key; + } + finally { + CalculationContext.IsConfigurable = null; + } + } + } + + if (Instance.GetDefaultsHook != null) { + var args = new FlagsHookArgs(segmentEndId.SegmentId, segmentEndId.StartNode, recalculateFlags, newDefaults); + Instance.GetDefaultsHook(args); + newDefaults = args.Result; + } + + configurables = (configurables & ~recalculateFlags) | (newConfigurables & recalculateFlags); + defaults = (defaults & ~recalculateFlags) | (newDefaults & recalculateFlags); + valid |= recalculateFlags; + + var clearFlags = mask & ~configurables; + if (clearFlags != default) { + values &= configurables; + mask &= configurables; + + Instance.OnSegmentChange(segmentEndId, (clearFlags & routingRecalculationFlags) != 0); + } + } + } + + public void Reset(SegmentEndId segmentEndId, bool resetDefaults = true) { values = mask = default; if (resetDefaults) { - defaults = default; + valid = default; + } + } + + public void Invalidate(SegmentEndId segmentEndId) { + if (valid != default) { + valid = default; + Notifier.Instance.OnNodeModified(segmentEndId.GetNodeId(), Instance); } } @@ -1443,4 +1197,4 @@ public override string ToString() { } } } -} \ No newline at end of file +} diff --git a/TLM/TLM/Manager/Impl/LaneConnection/LaneConnectionSubManager.cs b/TLM/TLM/Manager/Impl/LaneConnection/LaneConnectionSubManager.cs index bf34aa2fe..55074856d 100644 --- a/TLM/TLM/Manager/Impl/LaneConnection/LaneConnectionSubManager.cs +++ b/TLM/TLM/Manager/Impl/LaneConnection/LaneConnectionSubManager.cs @@ -421,9 +421,10 @@ static bool IsDirectionValid(ref NetLane lane, NetInfo.Lane laneInfo, ushort nod } if (sourceSegmentId == targetSegmentId) { - JunctionRestrictionsManager.Instance.SetUturnAllowed( + JunctionRestrictionsManager.Instance.SetValue( sourceSegmentId, sourceStartNode, + JunctionRestrictionFlags.AllowUTurn, true); } diff --git a/TLM/TLM/Manager/Impl/RoutingManager.cs b/TLM/TLM/Manager/Impl/RoutingManager.cs index c8f280003..d7c42ffef 100644 --- a/TLM/TLM/Manager/Impl/RoutingManager.cs +++ b/TLM/TLM/Manager/Impl/RoutingManager.cs @@ -517,7 +517,7 @@ void _ExtendedLogImpl(params object[] lines) => DetailLogger.LogDebug( ExtSegmentEnd segEnd = segEndMan.ExtSegmentEnds[segEndMan.GetIndex(segmentId, startNode)]; if (segEnd.incoming) { ++numIncomingSegents; - laneSwitching |= JunctionRestrictionsManager.Instance.IsLaneChangingAllowedWhenGoingStraight(segmentId, startNode); + laneSwitching |= JunctionRestrictionsManager.Instance.GetValueOrDefault(segmentId, startNode, JunctionRestrictionFlags.AllowForwardLaneChange); } if (segEnd.outgoing) { @@ -829,9 +829,10 @@ void _ExtendedLogImpl(params object[] lines) => DetailLogger.LogDebug( extendedLog?.Invoke(new { _ = "start lane arrow check for ", nextLaneId, nextLaneIndex, hasLeftArrow, hasForwardArrow, hasRightArrow }); - bool hasUTurnRule = JunctionRestrictionsManager.Instance.IsUturnAllowed( + bool hasUTurnRule = JunctionRestrictionsManager.Instance.GetValueOrDefault( nextSegmentId, - isNodeStartNodeOfNextSegment); + isNodeStartNodeOfNextSegment, + JunctionRestrictionFlags.AllowUTurn); bool hasFarTurnArrow = (Shortcuts.LHT && hasRightArrow) || (Shortcuts.RHT && hasLeftArrow); bool canTurn = !nodeIsRealJunction || nodeIsEndOrOneWayOut || hasFarTurnArrow || hasUTurnRule; @@ -925,8 +926,8 @@ void _ExtendedLogImpl(params object[] lines) => DetailLogger.LogDebug( bool laneChangesAllowed = Options.junctionRestrictionsEnabled - && JunctionRestrictionsManager.Instance.IsLaneChangingAllowedWhenGoingStraight( - nextSegmentId, isNodeStartNodeOfNextSegment); + && JunctionRestrictionsManager.Instance.GetValueOrDefault( + nextSegmentId, isNodeStartNodeOfNextSegment, JunctionRestrictionFlags.AllowForwardLaneChange); int nextCompatibleLaneCount = numNextCompatibleTransitionDatas; if (nextCompatibleLaneCount > 0) { diff --git a/TLM/TLM/Manager/Impl/VehicleBehaviorManager.cs b/TLM/TLM/Manager/Impl/VehicleBehaviorManager.cs index 997b1ced5..7aba24eb8 100644 --- a/TLM/TLM/Manager/Impl/VehicleBehaviorManager.cs +++ b/TLM/TLM/Manager/Impl/VehicleBehaviorManager.cs @@ -1699,9 +1699,10 @@ protected bool MustCheckSpace(ushort segmentId, } else { if (Options.junctionRestrictionsEnabled) { checkSpace = - !JunctionRestrictionsManager.Instance.IsEnteringBlockedJunctionAllowed( + !JunctionRestrictionsManager.Instance.GetValueOrDefault( segmentId, - startNode); + startNode, + JunctionRestrictionFlags.AllowEnterWhenBlocked); } else { checkSpace = (node.m_flags & (NetNode.Flags.Junction diff --git a/TLM/TLM/Network/Data/SegmentEndId.cs b/TLM/TLM/Network/Data/SegmentEndId.cs new file mode 100644 index 000000000..9b749e85d --- /dev/null +++ b/TLM/TLM/Network/Data/SegmentEndId.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace TrafficManager.Network.Data { + + /// + /// To help facilitate future migration of this struct into the API, please put + /// implementation-specific methods in . + /// + public struct SegmentEndId { + + public ushort SegmentId; + + public bool StartNode; + + public SegmentEndId(ushort segmentId, bool startNode) { + SegmentId = segmentId; + StartNode = startNode; + } + + public static bool operator ==(SegmentEndId x, SegmentEndId y) => x.Equals(y); + + public static bool operator !=(SegmentEndId x, SegmentEndId y) => !x.Equals(y); + + public static implicit operator ushort(SegmentEndId segmentEndId) => segmentEndId.SegmentId; + + public override string ToString() => $"[SegmentId={SegmentId}, StartNode={StartNode}]"; + } +} diff --git a/TLM/TLM/TLM.csproj b/TLM/TLM/TLM.csproj index 69d877070..313c4c86d 100644 --- a/TLM/TLM/TLM.csproj +++ b/TLM/TLM/TLM.csproj @@ -135,7 +135,8 @@ - + + @@ -148,6 +149,7 @@ + @@ -193,6 +195,7 @@ + diff --git a/TLM/TLM/Traffic/Impl/SegmentEnd.cs b/TLM/TLM/Traffic/Impl/SegmentEnd.cs index 83c9c7522..8e396eb71 100644 --- a/TLM/TLM/Traffic/Impl/SegmentEnd.cs +++ b/TLM/TLM/Traffic/Impl/SegmentEnd.cs @@ -20,7 +20,7 @@ namespace TrafficManager.Traffic.Impl { /// (having custom traffic lights or priority signs). /// [Obsolete("should be removed when implementing issue #240")] - public class SegmentEnd : SegmentEndId, ISegmentEnd { + public class SegmentEnd : SegmentEndIdApi, ISegmentEnd { public SegmentEnd(ushort segmentId, bool startNode) : base(segmentId, startNode) { Update(); diff --git a/TLM/TLM/TrafficLight/Impl/CustomSegmentLights.cs b/TLM/TLM/TrafficLight/Impl/CustomSegmentLights.cs index 33fa2fb21..88f5ae68f 100644 --- a/TLM/TLM/TrafficLight/Impl/CustomSegmentLights.cs +++ b/TLM/TLM/TrafficLight/Impl/CustomSegmentLights.cs @@ -19,7 +19,7 @@ namespace TrafficManager.TrafficLight.Impl { /// Represents the set of custom traffic lights located at a node /// public class CustomSegmentLights - : SegmentEndId + : SegmentEndIdApi { // private static readonly ExtVehicleType[] SINGLE_LANE_VEHICLETYPES // = new ExtVehicleType[] { ExtVehicleType.Tram, ExtVehicleType.Service, diff --git a/TLM/TLM/TrafficLight/Impl/TimedTrafficLights.cs b/TLM/TLM/TrafficLight/Impl/TimedTrafficLights.cs index 5b676d874..d5ebd62b9 100644 --- a/TLM/TLM/TrafficLight/Impl/TimedTrafficLights.cs +++ b/TLM/TLM/TrafficLight/Impl/TimedTrafficLights.cs @@ -1297,7 +1297,7 @@ private void UpdateSegmentEnds(ref NetNode node) { } var startNode = segmentId.ToSegment().IsStartNode(NodeId); - ISegmentEndId endId = new SegmentEndId(segmentId, startNode); + ISegmentEndId endId = new SegmentEndIdApi(segmentId, startNode); if (segmentEndIds.Contains(endId)) { Log._DebugIf( diff --git a/TLM/TLM/UI/SubTools/ManualTrafficLightsTool.cs b/TLM/TLM/UI/SubTools/ManualTrafficLightsTool.cs index 5402a61eb..6ec00ea3f 100644 --- a/TLM/TLM/UI/SubTools/ManualTrafficLightsTool.cs +++ b/TLM/TLM/UI/SubTools/ManualTrafficLightsTool.cs @@ -116,9 +116,10 @@ public override void OnToolGUI(Event e) { } bool showPedLight = segmentLights.PedestrianLightState != null && - junctionRestrictionsManager.IsPedestrianCrossingAllowed( + junctionRestrictionsManager.GetValueOrDefault( segmentLights.SegmentId, - segmentLights.StartNode); + segmentLights.StartNode, + JunctionRestrictionFlags.AllowPedestrianCrossing); bool visible = GeometryUtil.WorldToScreenPoint(position, out Vector3 screenPos); if (!visible) { diff --git a/TLM/TLM/UI/SubTools/TTL/TimedTrafficLightsTool.cs b/TLM/TLM/UI/SubTools/TTL/TimedTrafficLightsTool.cs index 8b8d8e0e7..1443cf634 100644 --- a/TLM/TLM/UI/SubTools/TTL/TimedTrafficLightsTool.cs +++ b/TLM/TLM/UI/SubTools/TTL/TimedTrafficLightsTool.cs @@ -1495,9 +1495,10 @@ private void ShowGUI() { } bool showPedLight = liveSegmentLights.PedestrianLightState != null && - junctionRestrictionsManager.IsPedestrianCrossingAllowed( + junctionRestrictionsManager.GetValueOrDefault( liveSegmentLights.SegmentId, - liveSegmentLights.StartNode); + liveSegmentLights.StartNode, + JunctionRestrictionFlags.AllowPedestrianCrossing); bool timedActive = timedNode.IsStarted(); if (!timedActive) { diff --git a/TLM/TLM/Util/Extensions/NetNodeExtensions.cs b/TLM/TLM/Util/Extensions/NetNodeExtensions.cs index 967cbb95d..0070316aa 100644 --- a/TLM/TLM/Util/Extensions/NetNodeExtensions.cs +++ b/TLM/TLM/Util/Extensions/NetNodeExtensions.cs @@ -1,5 +1,7 @@ namespace TrafficManager.Util.Extensions { using ColossalFramework; + using TrafficManager.Network.Data; + public static class NetNodeExtensions { private static NetNode[] _nodeBuffer = Singleton.instance.m_nodes.m_buffer; diff --git a/TLM/TLM/Util/Extensions/SegmentEndIdExtensions.cs b/TLM/TLM/Util/Extensions/SegmentEndIdExtensions.cs new file mode 100644 index 000000000..b670f2cc9 --- /dev/null +++ b/TLM/TLM/Util/Extensions/SegmentEndIdExtensions.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using TrafficManager.API.Traffic; +using TrafficManager.API.Traffic.Data; +using TrafficManager.Geometry.Impl; +using TrafficManager.Network.Data; + +namespace TrafficManager.Util.Extensions { + /// + /// This class exists so that if we want to move to the API, + /// we've already prepared for that by not including a lot of implementation-specific methods. + /// + internal static class SegmentEndIdExtensions { + + public static ref NetSegment GetSegment(this SegmentEndId segmentEndId) => ref segmentEndId.SegmentId.ToSegment(); + + public static ushort GetNodeId(this SegmentEndId segmentEndId) => + segmentEndId.StartNode ? segmentEndId.GetSegment().m_startNode : segmentEndId.GetSegment().m_endNode; + + public static ref NetNode GetNode(this SegmentEndId segmentEndId) => ref segmentEndId.GetNodeId().ToNode(); + + public static ISegmentEndId ToApi(this SegmentEndId segmentEndId) => + new SegmentEndIdApi(segmentEndId.SegmentId, segmentEndId.StartNode); + + public static SegmentEndId FromApi(this ISegmentEndId segmentEndId) => + new SegmentEndId(segmentEndId.SegmentId, segmentEndId.StartNode); + + public static SegmentEndId AtStartNode(this ushort segmentId) => new SegmentEndId(segmentId, true); + + public static SegmentEndId AtEndNode(this ushort segmentId) => new SegmentEndId(segmentId, false); + + public static SegmentEndId AtNode(this ushort segmentId, bool startNode) => new SegmentEndId(segmentId, startNode); + + public static SegmentEndId AtNode(this ushort segmentId, ushort nodeId) { + if (segmentId == 0) + return default; + ref var segment = ref segmentId.ToSegment(); + if (nodeId == segment.m_startNode) + return segmentId.AtStartNode(); + else if (nodeId == segment.m_endNode) + return segmentId.AtEndNode(); + throw new ArgumentException($"Segment {segmentId} is not on node {nodeId}", nameof(nodeId)); + } + + public static SegmentEndId GetSegmentEnd(this ushort nodeId, int segmentIndex) => + nodeId.ToNode().GetSegment(segmentIndex).AtNode(nodeId); + + public static SegmentEndId GetSegmentEndId(this ExtSegmentEnd extSegmentEnd) => + extSegmentEnd.segmentId.AtNode(extSegmentEnd.startNode); + } +} diff --git a/TLM/TLM/Util/PriorityRoad.cs b/TLM/TLM/Util/PriorityRoad.cs index 39645907b..df438fec6 100644 --- a/TLM/TLM/Util/PriorityRoad.cs +++ b/TLM/TLM/Util/PriorityRoad.cs @@ -412,9 +412,9 @@ private static ArrowDirection GetDirection(ushort segmentId, ushort otherSegment private static void FixMajorSegmentRules(ushort segmentId, ushort nodeId) { Log._Debug($"FixMajorSegmentRules({segmentId}, {nodeId}) was called"); bool startNode = segmentId.ToSegment().IsStartNode(nodeId); - JunctionRestrictionsManager.Instance.SetEnteringBlockedJunctionAllowed(segmentId, startNode, true); + JunctionRestrictionsManager.Instance.SetValue(segmentId, startNode, JunctionRestrictionFlags.AllowEnterWhenBlocked, true); if (!Options.PriorityRoad_CrossMainR) { - JunctionRestrictionsManager.Instance.SetPedestrianCrossingAllowed(segmentId, startNode, false); + JunctionRestrictionsManager.Instance.SetValue(segmentId, startNode, JunctionRestrictionFlags.AllowPedestrianCrossing, false); } TrafficPriorityManager.Instance.SetPrioritySign(segmentId, startNode, PriorityType.Main); } @@ -423,10 +423,10 @@ private static void FixMinorSegmentRules(ushort segmentId, ushort nodeId, List JunctionRestrictionsManager.Instance; public void Record() { - uturnAllowed_ = JRMan.GetUturnAllowed(SegmentId, StartNode); - nearTurnOnRedAllowed_ = JRMan.GetNearTurnOnRedAllowed(SegmentId, StartNode); - farTurnOnRedAllowed_ = JRMan.GetFarTurnOnRedAllowed(SegmentId, StartNode); - laneChangingAllowedWhenGoingStraight_ = JRMan.GetLaneChangingAllowedWhenGoingStraight(SegmentId, StartNode); - enteringBlockedJunctionAllowed_ = JRMan.GetEnteringBlockedJunctionAllowed(SegmentId, StartNode); - pedestrianCrossingAllowed_ = JRMan.GetPedestrianCrossingAllowed(SegmentId, StartNode); + uturnAllowed_ = ToTernaryBool(JRMan.GetValueOrDefault(SegmentId, StartNode, JunctionRestrictionFlags.AllowUTurn)); + nearTurnOnRedAllowed_ = ToTernaryBool(JRMan.GetValueOrDefault(SegmentId, StartNode, JunctionRestrictionFlags.AllowNearTurnOnRed)); + farTurnOnRedAllowed_ = ToTernaryBool(JRMan.GetValueOrDefault(SegmentId, StartNode, JunctionRestrictionFlags.AllowFarTurnOnRed)); + laneChangingAllowedWhenGoingStraight_ = ToTernaryBool(JRMan.GetValueOrDefault(SegmentId, StartNode, JunctionRestrictionFlags.AllowForwardLaneChange)); + enteringBlockedJunctionAllowed_ = ToTernaryBool(JRMan.GetValueOrDefault(SegmentId, StartNode, JunctionRestrictionFlags.AllowEnterWhenBlocked)); + pedestrianCrossingAllowed_ = ToTernaryBool(JRMan.GetValueOrDefault(SegmentId, StartNode, JunctionRestrictionFlags.AllowPedestrianCrossing)); prioirtySign_ = priorityMan.GetPrioritySign(SegmentId, StartNode); @@ -64,12 +65,12 @@ public void Restore() { } // all necessary checks are performed internally. - JRMan.SetUturnAllowed(SegmentId, StartNode, uturnAllowed_); - JRMan.SetNearTurnOnRedAllowed(SegmentId, StartNode, nearTurnOnRedAllowed_); - JRMan.SetFarTurnOnRedAllowed(SegmentId, StartNode, farTurnOnRedAllowed_); - JRMan.SetLaneChangingAllowedWhenGoingStraight(SegmentId, StartNode, laneChangingAllowedWhenGoingStraight_); - JRMan.SetEnteringBlockedJunctionAllowed(SegmentId, StartNode, enteringBlockedJunctionAllowed_); - JRMan.SetPedestrianCrossingAllowed(SegmentId, StartNode, pedestrianCrossingAllowed_); + JRMan.SetValue(SegmentId, StartNode, JunctionRestrictionFlags.AllowUTurn, ToOptBool(uturnAllowed_)); + JRMan.SetValue(SegmentId, StartNode, JunctionRestrictionFlags.AllowNearTurnOnRed, ToOptBool(nearTurnOnRedAllowed_)); + JRMan.SetValue(SegmentId, StartNode, JunctionRestrictionFlags.AllowFarTurnOnRed, ToOptBool(farTurnOnRedAllowed_)); + JRMan.SetValue(SegmentId, StartNode, JunctionRestrictionFlags.AllowForwardLaneChange, ToOptBool(laneChangingAllowedWhenGoingStraight_)); + JRMan.SetValue(SegmentId, StartNode, JunctionRestrictionFlags.AllowEnterWhenBlocked, ToOptBool(enteringBlockedJunctionAllowed_)); + JRMan.SetValue(SegmentId, StartNode, JunctionRestrictionFlags.AllowPedestrianCrossing, ToOptBool(pedestrianCrossingAllowed_)); } public void Transfer(Dictionary map) { @@ -83,12 +84,12 @@ public void Transfer(Dictionary map) { } // all necessary checks are performed internally. - JRMan.SetUturnAllowed(segmentId, StartNode, uturnAllowed_); - JRMan.SetNearTurnOnRedAllowed(segmentId, StartNode, nearTurnOnRedAllowed_); - JRMan.SetFarTurnOnRedAllowed(segmentId, StartNode, farTurnOnRedAllowed_); - JRMan.SetLaneChangingAllowedWhenGoingStraight(segmentId, StartNode, laneChangingAllowedWhenGoingStraight_); - JRMan.SetEnteringBlockedJunctionAllowed(segmentId, StartNode, enteringBlockedJunctionAllowed_); - JRMan.SetPedestrianCrossingAllowed(segmentId, StartNode, pedestrianCrossingAllowed_); + JRMan.SetValue(segmentId, StartNode, JunctionRestrictionFlags.AllowUTurn, ToOptBool(uturnAllowed_)); + JRMan.SetValue(segmentId, StartNode, JunctionRestrictionFlags.AllowNearTurnOnRed, ToOptBool(nearTurnOnRedAllowed_)); + JRMan.SetValue(segmentId, StartNode, JunctionRestrictionFlags.AllowFarTurnOnRed, ToOptBool(farTurnOnRedAllowed_)); + JRMan.SetValue(segmentId, StartNode, JunctionRestrictionFlags.AllowForwardLaneChange, ToOptBool(laneChangingAllowedWhenGoingStraight_)); + JRMan.SetValue(segmentId, StartNode, JunctionRestrictionFlags.AllowEnterWhenBlocked, ToOptBool(enteringBlockedJunctionAllowed_)); + JRMan.SetValue(segmentId, StartNode, JunctionRestrictionFlags.AllowPedestrianCrossing, ToOptBool(pedestrianCrossingAllowed_)); } public void Transfer(uint mappedId) { diff --git a/TLM/TLM/Util/RoundaboutMassEdit.cs b/TLM/TLM/Util/RoundaboutMassEdit.cs index 31906355a..6f15d14fb 100644 --- a/TLM/TLM/Util/RoundaboutMassEdit.cs +++ b/TLM/TLM/Util/RoundaboutMassEdit.cs @@ -122,14 +122,16 @@ private static void FixRulesRoundabout(ushort segmentId, bool startNode) { } if (Options.RoundAboutQuickFix_NoCrossMainR) { - JunctionRestrictionsManager.Instance.SetPedestrianCrossingAllowed( + JunctionRestrictionsManager.Instance.SetValue( segmentId, startNode, + JunctionRestrictionFlags.AllowPedestrianCrossing, false); } - JunctionRestrictionsManager.Instance.SetEnteringBlockedJunctionAllowed( + JunctionRestrictionsManager.Instance.SetValue( segmentId, startNode, + JunctionRestrictionFlags.AllowEnterWhenBlocked, true); } @@ -138,9 +140,10 @@ internal static void FixRulesMinor(ushort segmentId, ushort nodeId) { bool isHighway = ExtNodeManager.JunctionHasOnlyHighwayRoads(nodeId); if (Options.RoundAboutQuickFix_NoCrossYieldR) { - JunctionRestrictionsManager.Instance.SetPedestrianCrossingAllowed( + JunctionRestrictionsManager.Instance.SetValue( segmentId, startNode, + JunctionRestrictionFlags.AllowPedestrianCrossing, false); } if (Options.RoundAboutQuickFix_PrioritySigns) { @@ -152,13 +155,14 @@ internal static void FixRulesMinor(ushort segmentId, ushort nodeId) { if (isHighway) { //ignore highway rules: //TODO remove as part of issue #569 - JunctionRestrictionsManager.Instance.SetLaneChangingAllowedWhenGoingStraight(segmentId, startNode, true); + JunctionRestrictionsManager.Instance.SetValue(segmentId, startNode, JunctionRestrictionFlags.AllowForwardLaneChange, true); } // endif if (Options.RoundAboutQuickFix_KeepClearYieldR) { - JunctionRestrictionsManager.Instance.SetEnteringBlockedJunctionAllowed( + JunctionRestrictionsManager.Instance.SetValue( segmentId, startNode, + JunctionRestrictionFlags.AllowEnterWhenBlocked, false); } } diff --git a/TLM/TMPE.API/Hook/IHookFactory.cs b/TLM/TMPE.API/Hook/IHookFactory.cs new file mode 100644 index 000000000..0cbd2f8a6 --- /dev/null +++ b/TLM/TMPE.API/Hook/IHookFactory.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace TrafficManager.API.Hook { + public interface IHookFactory { + IJunctionRestrictionsHook JunctionRestrictionsHook { get; } + } +} diff --git a/TLM/TMPE.API/Hook/IJunctionRestrictionsHook.cs b/TLM/TMPE.API/Hook/IJunctionRestrictionsHook.cs new file mode 100644 index 000000000..359685468 --- /dev/null +++ b/TLM/TMPE.API/Hook/IJunctionRestrictionsHook.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using TrafficManager.API.Traffic.Enums; + +namespace TrafficManager.API.Hook { + public interface IJunctionRestrictionsHook { + + /// + /// An event that allows a handler to modify the results of a GetDefaultTrafficRule method. + /// + event Action GetDefaultsHook; + + /// + /// An event that allows a handler to modify the results of an IsTrafficRuleConfigurable method. + /// + event Action GetConfigurableHook; + + /// + /// Schedules the specified flags for recalculation. + /// + /// + /// + /// Specifies which flags to invalidate. + public void InvalidateFlags(ushort segmentId, bool startNode, JunctionRestrictionFlags flags); + + /// + /// Schedles the specified flags for recalculation for all segment ends on the specified node. + /// + /// + /// Specifies which flags to invalidate. + public void InvalidateFlags(ushort nodeId, JunctionRestrictionFlags flags); + + public class FlagsHookArgs { + + /// + /// Identifies the segment for which flag data is being returned. + /// + public ushort SegmentId { get; private set; } + + /// + /// Identifies the node on the segment for which flag data is being returned. + /// + public bool StartNode { get; private set; } + + /// + /// Identifies which flags are being returned. Unnecessary computation may be avoided + /// by examining this mask to see which flags are being requested. + /// + public JunctionRestrictionFlags Mask { get; private set; } + + /// + /// The flag return values. Changes to this property alter the outcome of the underlying operation. + /// Any flags that not set in the property are ignored. + /// + public JunctionRestrictionFlags Result { get; set; } + + public FlagsHookArgs(ushort segmentId, bool startNode, JunctionRestrictionFlags mask, JunctionRestrictionFlags result) { + SegmentId = segmentId; + StartNode = startNode; + Mask = mask; + Result = result; + } + } + } +} diff --git a/TLM/TMPE.API/Implementations.cs b/TLM/TMPE.API/Implementations.cs index 6380cdf7c..ea9129a38 100644 --- a/TLM/TMPE.API/Implementations.cs +++ b/TLM/TMPE.API/Implementations.cs @@ -3,15 +3,18 @@ namespace TrafficManager.API { using TrafficManager.API.Manager; using TrafficManager.API.Notifier; using System.Linq; + using TrafficManager.API.Hook; using TrafficManager.API.UI; public static class Implementations { private static Type constantsType_; private static IManagerFactory managerFactory_; + private static IHookFactory hookFactory_; private static INotifier notifier_; private static IUIFactory uiFactory_; public static IManagerFactory ManagerFactory => managerFactory_ ??= GetImplementation(); + public static IHookFactory HookFactory => hookFactory_ ??= GetImplementation(); public static INotifier Notifier => notifier_ ??= GetImplementation(); public static IUIFactory UIFactory => uiFactory_ ??= GetImplementation(); diff --git a/TLM/TMPE.API/Manager/IJunctionRestrictionsManager.cs b/TLM/TMPE.API/Manager/IJunctionRestrictionsManager.cs index 5b4865d18..6336e5db2 100644 --- a/TLM/TMPE.API/Manager/IJunctionRestrictionsManager.cs +++ b/TLM/TMPE.API/Manager/IJunctionRestrictionsManager.cs @@ -1,19 +1,84 @@ namespace TrafficManager.API.Manager { using CSUtil.Commons; + using System; + using TrafficManager.API.Traffic.Enums; public interface IJunctionRestrictionsManager { + + /// + /// Indicates whether the specified flag is configurable. + /// If more than one flag is specified, indicates whether all are configurable. + /// + /// + /// + /// + /// + bool IsConfigurable(ushort segmentId, bool startNode, JunctionRestrictionFlags flags); + + /// + /// Returns the set value (not the default) for the specified flag, or null if no value has been set. + /// If more than one flag is specified, null is returned if they do not all have the same value. + /// + /// + /// + /// + /// + bool? GetValue(ushort segmentId, bool startNode, JunctionRestrictionFlags flags); + + /// + /// Returns the set value of the specified flag, or the default value if no value is set. + /// If more than one flag is specified, returns the logical AND of all results. + /// + /// + /// + /// + /// + bool GetValueOrDefault(ushort segmentId, bool startNode, JunctionRestrictionFlags flags); + + /// + /// Returns the default value for the specified flag. + /// If more than one flag is specified, returns the logical AND of all the results. + /// + /// + /// + /// + /// + bool GetDefaultValue(ushort segmentId, bool startNode, JunctionRestrictionFlags flags); + + /// + /// Sets the value of the specified flag(s). If null, clears the set value so that the default will be used. + /// + /// + /// + /// + /// + /// true if the operation was successful, false if not configurable + bool SetValue(ushort segmentId, bool startNode, JunctionRestrictionFlags flags, bool? value); + + /// + /// Toggles the value of the specified flag. This method fails if more than one flag is specified. + /// + /// + /// + /// + /// true if the operation was successful, false if not configurable or if more than one flag was specified + bool ToggleValue(ushort segmentId, bool startNode, JunctionRestrictionFlags flags); + #region IsConfigurable /// + /// This API is dprecated. Please use .
/// Determines if u-turn behavior may be controlled at the given segment end. ///
/// segment id /// at start node? /// node data /// true if u-turns may be customized, false otherwise + [Obsolete("Please use IsConfigurable(ushort, bool, JunctionRestrictionFlags)")] bool IsUturnAllowedConfigurable(ushort segmentId, bool startNode, ref NetNode node); /// + /// This API is dprecated. Please use .
/// Determines if turn-on-red behavior is enabled for near turns and may be controlled at /// the given segment end. ///
@@ -22,9 +87,11 @@ public interface IJunctionRestrictionsManager { /// node data /// true if turn-on-red may be customized for near turns, /// false otherwise + [Obsolete("Please use IsConfigurable(ushort, bool, JunctionRestrictionFlags)")] bool IsNearTurnOnRedAllowedConfigurable(ushort segmentId, bool startNode, ref NetNode node); /// + /// This API is dprecated. Please use .
/// Determines if turn-on-red behavior is enabled for far turns and may be controlled at /// the given segment end. ///
@@ -33,9 +100,11 @@ public interface IJunctionRestrictionsManager { /// node data /// true if turn-on-red may be customized for far turns, /// false otherwise + [Obsolete("Please use IsConfigurable(ushort, bool, JunctionRestrictionFlags)")] bool IsFarTurnOnRedAllowedConfigurable(ushort segmentId, bool startNode, ref NetNode node); /// + /// This API is dprecated. Please use .
/// Determines if turn-on-red behavior is enabled for the given turn type and that it may /// be controlled at the given segment end. ///
@@ -44,24 +113,28 @@ public interface IJunctionRestrictionsManager { /// at start node? /// node data /// true if turn-on-red may be customized, false otherwise + [Obsolete("Please use IsConfigurable(ushort, bool, JunctionRestrictionFlags)")] bool IsTurnOnRedAllowedConfigurable(bool near, ushort segmentId, bool startNode, ref NetNode node); /// + /// This API is dprecated. Please use .
/// Determines if lane changing behavior may be controlled at the given segment end. ///
/// segment id /// at start node? /// node data /// true if lane changing may be customized, false otherwise + [Obsolete("Please use IsConfigurable(ushort, bool, JunctionRestrictionFlags)")] bool IsLaneChangingAllowedWhenGoingStraightConfigurable( ushort segmentId, bool startNode, ref NetNode node); /// + /// This API is dprecated. Please use .
/// Determines if entering blocked junctions may be controlled at the given segment end. ///
/// segment id @@ -69,11 +142,13 @@ bool IsLaneChangingAllowedWhenGoingStraightConfigurable( /// node data /// true if entering blocked junctions may be customized, /// false otherwise + [Obsolete("Please use IsConfigurable(ushort, bool, JunctionRestrictionFlags)")] bool IsEnteringBlockedJunctionAllowedConfigurable(ushort segmentId, bool startNode, ref NetNode node); /// + /// This API is dprecated. Please use .
/// Determines if pedestrian crossings may be controlled at the given segment end. ///
/// segment id @@ -81,6 +156,7 @@ bool IsEnteringBlockedJunctionAllowedConfigurable(ushort segmentId, /// node data /// true if pedestrian crossings may be customized, false /// otherwise + [Obsolete("Please use IsConfigurable(ushort, bool, JunctionRestrictionFlags)")] bool IsPedestrianCrossingAllowedConfigurable(ushort segmentId, bool startNode, ref NetNode node); @@ -89,6 +165,7 @@ bool IsPedestrianCrossingAllowedConfigurable(ushort segmentId, #region GetDefault /// + /// This API is dprecated. Please use .
/// Determines the default setting for u-turns at the given segment end. ///
/// segment id @@ -96,9 +173,11 @@ bool IsPedestrianCrossingAllowedConfigurable(ushort segmentId, /// node data /// true if u-turns are allowed by default, false /// otherwise + [Obsolete("Please use GetDefaultValue(ushort, bool, JunctionRestrictionFlags)")] bool GetDefaultUturnAllowed(ushort segmentId, bool startNode, ref NetNode node); /// + /// This API is dprecated. Please use .
/// Determines the default setting for near turn-on-red at the given segment end. ///
/// segment id @@ -106,9 +185,11 @@ bool IsPedestrianCrossingAllowedConfigurable(ushort segmentId, /// node data /// true if turn-on-red is allowed for near turns by default, /// false otherwise + [Obsolete("Please use GetDefaultValue(ushort, bool, JunctionRestrictionFlags)")] bool GetDefaultNearTurnOnRedAllowed(ushort segmentId, bool startNode, ref NetNode node); /// + /// This API is dprecated. Please use .
/// Determines the default setting for far turn-on-red at the given segment end. ///
/// segment id @@ -116,9 +197,11 @@ bool IsPedestrianCrossingAllowedConfigurable(ushort segmentId, /// node data /// true if turn-on-red is allowed for far turns by default, /// false otherwise + [Obsolete("Please use GetDefaultValue(ushort, bool, JunctionRestrictionFlags)")] bool GetDefaultFarTurnOnRedAllowed(ushort segmentId, bool startNode, ref NetNode node); /// + /// This API is dprecated. Please use .
/// Determines the default turn-on-red setting for the given turn type at the given segment end. ///
/// for near turns? @@ -127,12 +210,14 @@ bool IsPedestrianCrossingAllowedConfigurable(ushort segmentId, /// node data /// true if turn-on-red is allowed by default, false /// otherwise + [Obsolete("Please use GetDefaultValue(ushort, bool, JunctionRestrictionFlags)")] bool GetDefaultTurnOnRedAllowed(bool near, ushort segmentId, bool startNode, ref NetNode node); /// + /// This API is dprecated. Please use .
/// Determines the default setting for straight lane changes at the given segment end. ///
/// segment id @@ -140,12 +225,14 @@ bool GetDefaultTurnOnRedAllowed(bool near, /// node data /// true if straight lane changes are allowed by default, /// false otherwise + [Obsolete("Please use GetDefaultValue(ushort, bool, JunctionRestrictionFlags)")] bool GetDefaultLaneChangingAllowedWhenGoingStraight( ushort segmentId, bool startNode, ref NetNode node); /// + /// This API is dprecated. Please use .
/// Determines the default setting for entering a blocked junction at the given segment end. ///
/// segment id @@ -153,11 +240,13 @@ bool GetDefaultLaneChangingAllowedWhenGoingStraight( /// node data /// true if entering a blocked junction is allowed by default, /// false otherwise + [Obsolete("Please use GetDefaultValue(ushort, bool, JunctionRestrictionFlags)")] bool GetDefaultEnteringBlockedJunctionAllowed(ushort segmentId, bool startNode, ref NetNode node); /// + /// This API is dprecated. Please use .
/// Determines the default setting for pedestrian crossings at the given segment end. ///
/// segment id @@ -166,6 +255,7 @@ bool GetDefaultEnteringBlockedJunctionAllowed(ushort segmentId, /// true if crossing the road is allowed by default, /// false otherwise /// returns the default value if flag is not set. + [Obsolete("Please use GetDefaultValue(ushort, bool, JunctionRestrictionFlags)")] bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, bool startNode, ref NetNode node); @@ -174,33 +264,40 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, #region IsAllowed /// + /// This API is dprecated. Please use .
/// Determines whether u-turns are allowed at the given segment end. ///
/// segment id /// at start node? /// true if u-turns are allowed, false otherwise /// returns the default value if flag is not set. + [Obsolete("Please use GetValueOrDefault(ushort, bool, JunctionRestrictionFlags)")] bool IsUturnAllowed(ushort segmentId, bool startNode); /// + /// This API is dprecated. Please use .
/// Determines whether turn-on-red is allowed for near turns at the given segment end. ///
/// segment id /// at start node? /// true if turn-on-red is allowed for near turns, false otherwise /// returns the default value if flag is not set. + [Obsolete("Please use GetValueOrDefault(ushort, bool, JunctionRestrictionFlags)")] bool IsNearTurnOnRedAllowed(ushort segmentId, bool startNode); /// + /// This API is dprecated. Please use .
/// Determines whether turn-on-red is allowed for far turns at the given segment end. ///
/// segment id /// at start node? /// true if turn-on-red is allowed for far turns, false otherwise /// returns the default behaviour if flag is not set. + [Obsolete("Please use GetValueOrDefault(ushort, bool, JunctionRestrictionFlags)")] bool IsFarTurnOnRedAllowed(ushort segmentId, bool startNode); /// + /// This API is dprecated. Please use .
/// Determines whether turn-on-red is allowed for the given turn type at the given segment end. ///
/// for near turns? @@ -208,66 +305,80 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// at start node? /// true if turn-on-red is allowed, false otherwise /// returns the default behaviour if flag is not set. + [Obsolete("Please use GetValueOrDefault(ushort, bool, JunctionRestrictionFlags)")] bool IsTurnOnRedAllowed(bool near, ushort segmentId, bool startNode); /// + /// This API is dprecated. Please use .
/// Determines whether lane changing when going straight is allowed at the given segment end. ///
/// segment id /// at start node? /// true if lane changing when going straight is allowed, false otherwise /// returns the default behaviour if flag is not set. + [Obsolete("Please use GetValueOrDefault(ushort, bool, JunctionRestrictionFlags)")] bool IsLaneChangingAllowedWhenGoingStraight(ushort segmentId, bool startNode); /// + /// This API is dprecated. Please use .
/// Determines whether entering a blocked junction is allowed at the given segment end. ///
/// segment id /// at start node? /// true if entering a blocked junction is allowed, false otherwise /// returns the default behaviour if flag is not set. + [Obsolete("Please use GetValueOrDefault(ushort, bool, JunctionRestrictionFlags)")] bool IsEnteringBlockedJunctionAllowed(ushort segmentId, bool startNode); /// + /// This API is dprecated. Please use .
/// Determines whether crossing the road is allowed at the given segment end. ///
/// segment id /// at start node? /// true if crossing the road is allowed, false otherwise. /// returns the default value if flag is not set. + [Obsolete("Please use GetValueOrDefault(ushort, bool, JunctionRestrictionFlags)")] bool IsPedestrianCrossingAllowed(ushort segmentId, bool startNode); #endregion #region Get /// + /// This API is dprecated. Please use .
/// Retrieves the u-turn setting for the given segment end. ///
/// segment id /// at start node? /// ternary u-turn flag. /// returns TernaryBool.Undefined if the flag is not set. + [Obsolete("Please use GetValue(ushort, bool, JunctionRestrictionFlags)")] TernaryBool GetUturnAllowed(ushort segmentId, bool startNode); /// + /// This API is dprecated. Please use .
/// Retrieves the turn-on-red setting for near turns and the given segment end. ///
/// segment id /// at start node? /// ternary turn-on-red flag for near turns. /// returns TernaryBool.Undefined if the flag is not set. + [Obsolete("Please use GetValue(ushort, bool, JunctionRestrictionFlags)")] TernaryBool GetNearTurnOnRedAllowed(ushort segmentId, bool startNode); /// + /// This API is dprecated. Please use .
/// Retrieves the turn-on-red setting for far turns and the given segment end. ///
/// segment id /// at start node? /// ternary turn-on-red flag for far turns. /// returns TernaryBool.Undefined if the flag is not set. + [Obsolete("Please use GetValue(ushort, bool, JunctionRestrictionFlags)")] TernaryBool GetFarTurnOnRedAllowed(ushort segmentId, bool startNode); /// + /// This API is dprecated. Please use .
/// Retrieves the turn-on-red setting for the given turn type and segment end. ///
/// for near turns? @@ -275,39 +386,47 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// at start node? /// ternary turn-on-red flag. /// returns TernaryBool.Undefined if the flag is not set. + [Obsolete("Please use GetValue(ushort, bool, JunctionRestrictionFlags)")] TernaryBool GetTurnOnRedAllowed(bool near, ushort segmentId, bool startNode); /// + /// This API is dprecated. Please use .
/// Retrieves the lane changing setting for the given segment end. ///
/// segment id /// at start node? /// ternary lane changing flag. /// returns TernaryBool.Undefined if the flag is not set. + [Obsolete("Please use GetValue(ushort, bool, JunctionRestrictionFlags)")] TernaryBool GetLaneChangingAllowedWhenGoingStraight(ushort segmentId, bool startNode); /// + /// This API is dprecated. Please use .
/// Retrieves the "enter blocked junction" setting for the given segment end. ///
/// segment id /// at start node? /// ternary "enter blocked junction" flag. /// returns TernaryBool.Undefined if the flag is not set. + [Obsolete("Please use GetValue(ushort, bool, JunctionRestrictionFlags)")] TernaryBool GetEnteringBlockedJunctionAllowed(ushort segmentId, bool startNode); /// + /// This API is dprecated. Please use .
/// Retrieves the pedestrian crossing setting for the given segment end. ///
/// segment id /// at start node? /// ternary pedestrian crossing flag. /// returns TernaryBool.Undefined if the flag is not set. + [Obsolete("Please use GetValue(ushort, bool, JunctionRestrictionFlags)")] TernaryBool GetPedestrianCrossingAllowed(ushort segmentId, bool startNode); #endregion - + #region Toggle /// + /// This API is dprecated. Please use .
/// Switches the u-turn flag for the given segment end. ///
/// segment id @@ -316,9 +435,11 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Silently returns true if the given equals to the flag. /// On failure (including when traffic rule is not configurable) returns false /// + [Obsolete("Please use ToggleValue(ushort, bool, JunctionRestrictionFlags)")] bool ToggleUturnAllowed(ushort segmentId, bool startNode); /// + /// This API is dprecated. Please use .
/// Switches the turn-on-red flag for near turns and given segment end. ///
/// segment id @@ -327,9 +448,11 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Silently returns true if the given equals to the flag. /// On failure (including when traffic rule is not configurable) returns false /// + [Obsolete("Please use ToggleValue(ushort, bool, JunctionRestrictionFlags)")] bool ToggleNearTurnOnRedAllowed(ushort segmentId, bool startNode); /// + /// This API is dprecated. Please use .
/// Switches the turn-on-red flag for far turns and given segment end. ///
/// segment id @@ -338,9 +461,11 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Silently returns true if the given equals to the flag. /// On failure (including when traffic rule is not configurable) returns false /// + [Obsolete("Please use ToggleValue(ushort, bool, JunctionRestrictionFlags)")] bool ToggleFarTurnOnRedAllowed(ushort segmentId, bool startNode); /// + /// This API is dprecated. Please use .
/// Switches the turn-on-red flag for the given turn type and segment end. ///
/// for near turns? @@ -350,9 +475,11 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Silently returns true if the given equals to the flag. /// On failure (including when traffic rule is not configurable) returns false /// + [Obsolete("Please use ToggleValue(ushort, bool, JunctionRestrictionFlags)")] bool ToggleTurnOnRedAllowed(bool near, ushort segmentId, bool startNode); /// + /// This API is dprecated. Please use .
/// Switches the lane changing flag for the given segment end. ///
/// segment id @@ -361,9 +488,11 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Silently returns true if the given equals to the flag. /// On failure (including when traffic rule is not configurable) returns false /// + [Obsolete("Please use ToggleValue(ushort, bool, JunctionRestrictionFlags)")] bool ToggleLaneChangingAllowedWhenGoingStraight(ushort segmentId, bool startNode); /// + /// This API is dprecated. Please use .
/// Switches the "enter blocked junction" flag for the given segment end. ///
/// segment id @@ -372,9 +501,11 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Silently returns true if the given equals to the flag. /// On failure (including when traffic rule is not configurable) returns false /// + [Obsolete("Please use ToggleValue(ushort, bool, JunctionRestrictionFlags)")] bool ToggleEnteringBlockedJunctionAllowed(ushort segmentId, bool startNode); /// + /// This API is dprecated. Please use .
/// Switches the pedestrian crossing flag for the given segment end. ///
/// segment id @@ -383,12 +514,14 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Silently returns true if the given equals to the flag. /// On failure (including when traffic rule is not configurable) returns false /// + [Obsolete("Please use ToggleValue(ushort, bool, JunctionRestrictionFlags)")] bool TogglePedestrianCrossingAllowed(ushort segmentId, bool startNode); #endregion #region Set : bool /// + /// This API is dprecated. Please use .
/// Sets the u-turn flag for the given segment end to the given value. ///
/// segment id @@ -398,9 +531,11 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Silently returns true if the given equals to the flag. /// On failure (including when traffic rule is not configurable) returns false /// + [Obsolete("Please use SetValue(ushort, bool, JunctionRestrictionFlags, bool?)")] bool SetUturnAllowed(ushort segmentId, bool startNode, bool value); /// + /// This API is dprecated. Please use .
/// Sets the turn-on-red flag for near turns at the given segment end to the given value. ///
/// segment id @@ -410,9 +545,11 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Silently returns true if the given equals to the flag. /// On failure (including when traffic rule is not configurable) returns false /// + [Obsolete("Please use SetValue(ushort, bool, JunctionRestrictionFlags, bool?)")] bool SetNearTurnOnRedAllowed(ushort segmentId, bool startNode, bool value); /// + /// This API is dprecated. Please use .
/// Sets the turn-on-red flag for far turns at the given segment end to the given value. ///
/// segment id @@ -422,9 +559,11 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Silently returns true if the given equals to the flag. /// On failure (including when traffic rule is not configurable) returns false /// + [Obsolete("Please use SetValue(ushort, bool, JunctionRestrictionFlags, bool?)")] bool SetFarTurnOnRedAllowed(ushort segmentId, bool startNode, bool value); /// + /// This API is dprecated. Please use .
/// Sets the turn-on-red flag for the given turn type and segment end to the given value. ///
/// for near turns? @@ -435,9 +574,11 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Silently returns true if the given equals to the flag. /// On failure (including when traffic rule is not configurable) returns false /// + [Obsolete("Please use SetValue(ushort, bool, JunctionRestrictionFlags, bool?)")] bool SetTurnOnRedAllowed(bool near, ushort segmentId, bool startNode, bool value); /// + /// This API is dprecated. Please use .
/// Sets the lane changing flag for the given segment end to the given value. ///
/// segment id @@ -447,9 +588,11 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Silently returns true if the given equals to the flag. /// On failure (including when traffic rule is not configurable) returns false /// + [Obsolete("Please use SetValue(ushort, bool, JunctionRestrictionFlags, bool?)")] bool SetLaneChangingAllowedWhenGoingStraight(ushort segmentId, bool startNode, bool value); /// + /// This API is dprecated. Please use .
/// Sets the "enter blocked junction" flag for the given segment end to the given value. ///
/// segment id @@ -459,9 +602,11 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Silently returns true if the given equals to the flag. /// On failure (including when traffic rule is not configurable) returns false /// + [Obsolete("Please use SetValue(ushort, bool, JunctionRestrictionFlags, bool?)")] bool SetEnteringBlockedJunctionAllowed(ushort segmentId, bool startNode, bool value); /// + /// This API is dprecated. Please use .
/// Sets the pedestrian crossing flag for the given segment end to the given value. ///
/// segment id @@ -471,12 +616,14 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Silently returns true if the given equals to the flag. /// On failure (including when traffic rule is not configurable) returns false /// + [Obsolete("Please use SetValue(ushort, bool, JunctionRestrictionFlags, bool?)")] bool SetPedestrianCrossingAllowed(ushort segmentId, bool startNode, bool value); #endregion #region Set : TernaryBool /// + /// This API is dprecated. Please use .
/// Sets the u-turn flag for the given segment end to the given value. ///
/// segment id @@ -486,9 +633,11 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Silently returns true if the given equals to the flag. /// On failure (including when traffic rule is not configurable) returns false /// + [Obsolete("Please use SetValue(ushort, bool, JunctionRestrictionFlags, bool?)")] bool SetUturnAllowed(ushort segmentId, bool startNode, TernaryBool value); /// + /// This API is dprecated. Please use .
/// Sets the turn-on-red flag for near turns at the given segment end to the given value. ///
/// segment id @@ -498,9 +647,11 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Silently returns true if the given equals to the flag. /// On failure (including when traffic rule is not configurable) returns false /// + [Obsolete("Please use SetValue(ushort, bool, JunctionRestrictionFlags, bool?)")] bool SetNearTurnOnRedAllowed(ushort segmentId, bool startNode, TernaryBool value); /// + /// This API is dprecated. Please use .
/// Sets the turn-on-red flag for far turns at the given segment end to the given value. ///
/// segment id @@ -510,9 +661,11 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Silently returns true if the given equals to the flag. /// On failure (including when traffic rule is not configurable) returns false /// + [Obsolete("Please use SetValue(ushort, bool, JunctionRestrictionFlags, bool?)")] bool SetFarTurnOnRedAllowed(ushort segmentId, bool startNode, TernaryBool value); /// + /// This API is dprecated. Please use .
/// Sets the turn-on-red flag for the given turn type and segment end to the given value. ///
/// for near turns? @@ -523,9 +676,11 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Silently returns true if the given equals to the flag. /// On failure (including when traffic rule is not configurable) returns false /// + [Obsolete("Please use SetValue(ushort, bool, JunctionRestrictionFlags, bool?)")] bool SetTurnOnRedAllowed(bool near, ushort segmentId, bool startNode, TernaryBool value); /// + /// This API is dprecated. Please use .
/// Sets the lane changing flag for the given segment end to the given value. ///
/// segment id @@ -535,9 +690,11 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Silently returns true if the given equals to the flag. /// On failure (including when traffic rule is not configurable) returns false /// + [Obsolete("Please use SetValue(ushort, bool, JunctionRestrictionFlags, bool?)")] bool SetLaneChangingAllowedWhenGoingStraight(ushort segmentId, bool startNode, TernaryBool value); /// + /// This API is dprecated. Please use .
/// Sets the "enter blocked junction" flag for the given segment end to the given value. ///
/// segment id @@ -547,9 +704,11 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Silently returns true if the given equals to the flag. /// On failure (including when traffic rule is not configurable) returns false /// + [Obsolete("Please use SetValue(ushort, bool, JunctionRestrictionFlags, bool?)")] bool SetEnteringBlockedJunctionAllowed(ushort segmentId, bool startNode, TernaryBool value); /// + /// This API is dprecated. Please use .
/// Sets the pedestrian crossing flag for the given segment end to the given value. ///
/// segment id @@ -559,6 +718,7 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Silently returns true if the given equals to the flag. /// On failure (including when traffic rule is not configurable) returns false /// + [Obsolete("Please use SetValue(ushort, bool, JunctionRestrictionFlags, bool?)")] bool SetPedestrianCrossingAllowed(ushort segmentId, bool startNode, TernaryBool value); #endregion @@ -574,5 +734,6 @@ bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, /// Updates the default values for all junction restrictions and segments. /// void UpdateAllDefaults(); + } } \ No newline at end of file diff --git a/TLM/TMPE.API/TMPE.API.csproj b/TLM/TMPE.API/TMPE.API.csproj index 0c1b71785..8bcb9f16d 100644 --- a/TLM/TMPE.API/TMPE.API.csproj +++ b/TLM/TMPE.API/TMPE.API.csproj @@ -76,6 +76,8 @@ Properties\SharedAssemblyInfo.cs
+ + diff --git a/TLM/TMPE.API/Traffic/Enums/JunctionRestrictionFlags.cs b/TLM/TMPE.API/Traffic/Enums/JunctionRestrictionFlags.cs index ba8c86698..3a4059e5b 100644 --- a/TLM/TMPE.API/Traffic/Enums/JunctionRestrictionFlags.cs +++ b/TLM/TMPE.API/Traffic/Enums/JunctionRestrictionFlags.cs @@ -1,4 +1,8 @@ +using System; + namespace TrafficManager.API.Traffic.Enums { + + [Flags] public enum JunctionRestrictionFlags { AllowUTurn = 1 << 0, AllowNearTurnOnRed = 1 << 1, @@ -6,5 +10,7 @@ public enum JunctionRestrictionFlags { AllowForwardLaneChange = 1 << 3, AllowEnterWhenBlocked = 1 << 4, AllowPedestrianCrossing = 1 << 5, + + All = (1 << 6) - 1, } -} \ No newline at end of file +}