From a1bdb90596fee8509684d92c8bb0de8c8c542091 Mon Sep 17 00:00:00 2001 From: dmytro lytovchenko Date: Thu, 1 Aug 2019 01:08:33 +0200 Subject: [PATCH 1/8] Moved SpeedLimit class and its contents; New SpeedValue, KmphValue and MphValue structs --- TLM/TLM/Constants.cs | 15 ++-- TLM/TLM/Custom/AI/CustomCarAI.cs | 1 - TLM/TLM/Custom/AI/CustomHumanAI.cs | 1 - TLM/TLM/Custom/PathFinding/CustomPathFind.cs | 1 - .../Custom/PathFinding/CustomPathManager.cs | 1 - .../AbstractGeometryObservingManager.cs | 1 - .../Manager/Impl/AdvancedParkingManager.cs | 1 - .../Impl/CustomSegmentLightsManager.cs | 1 - TLM/TLM/Manager/Impl/ExtBuildingManager.cs | 1 - .../Manager/Impl/ExtCitizenInstanceManager.cs | 1 - TLM/TLM/Manager/Impl/ExtCitizenManager.cs | 2 +- TLM/TLM/Manager/Impl/ExtNodeManager.cs | 1 - TLM/TLM/Manager/Impl/ExtSegmentEndManager.cs | 1 - TLM/TLM/Manager/Impl/ExtSegmentManager.cs | 1 - TLM/TLM/Manager/Impl/ExtVehicleManager.cs | 5 +- TLM/TLM/Manager/Impl/GeometryManager.cs | 1 - .../Impl/JunctionRestrictionsManager.cs | 1 - TLM/TLM/Manager/Impl/LaneArrowManager.cs | 1 - TLM/TLM/Manager/Impl/LaneConnectionManager.cs | 1 - .../Impl/ParkingRestrictionsManager.cs | 1 - TLM/TLM/Manager/Impl/RoutingManager.cs | 1 - TLM/TLM/Manager/Impl/SpeedLimitManager.cs | 23 +++-- .../Manager/Impl/TrafficMeasurementManager.cs | 1 - .../Manager/Impl/TrafficPriorityManager.cs | 1 - TLM/TLM/Manager/Impl/TurnOnRedManager.cs | 1 - .../Manager/Impl/VehicleBehaviorManager.cs | 44 ++++++---- .../Impl/VehicleRestrictionsManager.cs | 1 - .../State/ConfigData/DynamicLaneSelection.cs | 13 ++- TLM/TLM/State/ConfigData/Main.cs | 2 +- TLM/TLM/State/Configuration.cs | 8 +- .../State/OptionsTabs/OptionsGeneralTab.cs | 2 +- TLM/TLM/TLM.csproj | 8 +- .../TrafficLight/Impl/CustomSegmentLight.cs | 1 - .../TrafficLight/Impl/CustomSegmentLights.cs | 1 - .../Impl/TimedTrafficLightsStep.cs | 2 +- .../UI/SubTools/ManualTrafficLightsTool.cs | 1 - TLM/TLM/UI/SubTools/PrioritySignsTool.cs | 1 - .../SubTools/SpeedLimits}/SpeedLimit.cs | 83 ++++++++----------- .../{ => SpeedLimits}/SpeedLimitsTool.cs | 12 ++- TLM/TLM/UI/SubTools/TimedTrafficLightsTool.cs | 1 - TLM/TLM/UI/Textures/JunctionUITextures.cs | 1 - TLM/TLM/UI/Textures/SpeedLimitTextures.cs | 2 +- TLM/TLM/UI/TrafficManagerTool.cs | 2 +- TLM/TLM/Util/FloatUtil.cs | 28 +++++++ TLM/TLM/Util/SegmentTraverser.cs | 1 - TLM/TMPE.API/TMPE.API.csproj | 2 + TLM/TMPE.API/Traffic/ApiConstants.cs | 13 +++ TLM/TMPE.API/Traffic/Data/SpeedValue.cs | 35 ++++++++ 48 files changed, 197 insertions(+), 133 deletions(-) rename TLM/TLM/{Traffic/Data => UI/SubTools/SpeedLimits}/SpeedLimit.cs (79%) rename TLM/TLM/UI/SubTools/{ => SpeedLimits}/SpeedLimitsTool.cs (99%) create mode 100644 TLM/TLM/Util/FloatUtil.cs create mode 100644 TLM/TMPE.API/Traffic/ApiConstants.cs create mode 100644 TLM/TMPE.API/Traffic/Data/SpeedValue.cs diff --git a/TLM/TLM/Constants.cs b/TLM/TLM/Constants.cs index a47afa2d8..be7bdb589 100644 --- a/TLM/TLM/Constants.cs +++ b/TLM/TLM/Constants.cs @@ -3,11 +3,6 @@ using GenericGameBridge.Factory; public static class Constants { - /// - /// A very small value for float comparisons to zero - /// - public const float VERY_SMALL_FLOAT = 1e-12f; - /// /// Used where a 0..1f value has to be scaled to byte or a byte to 0..1f /// @@ -18,6 +13,16 @@ public static class Constants { /// public static readonly bool[] ALL_BOOL = { false, true }; + /// + /// Conversion rate from km/h to game speed (also exists in TrafficManager.API.Constants) + /// + public const float SPEED_TO_KMPH = 50.0f; // 1.0f equals 50 km/h + + /// + /// Conversion rate from MPH to game speed (also exists in TrafficManager.API.Constants) + /// + public const float SPEED_TO_MPH = 32.06f; // 50 km/h converted to mph + public static float ByteToFloat(byte b) { return b * BYTE_TO_FLOAT_SCALE; } diff --git a/TLM/TLM/Custom/AI/CustomCarAI.cs b/TLM/TLM/Custom/AI/CustomCarAI.cs index 58319f165..798be1808 100644 --- a/TLM/TLM/Custom/AI/CustomCarAI.cs +++ b/TLM/TLM/Custom/AI/CustomCarAI.cs @@ -16,7 +16,6 @@ namespace TrafficManager.Custom.AI { using RedirectionFramework.Attributes; using State; using State.ConfigData; - using Traffic.Data; using UnityEngine; using System.Diagnostics.CodeAnalysis; using CSUtil.Commons.Benchmark; diff --git a/TLM/TLM/Custom/AI/CustomHumanAI.cs b/TLM/TLM/Custom/AI/CustomHumanAI.cs index b4fbafdb8..de9ab52c2 100644 --- a/TLM/TLM/Custom/AI/CustomHumanAI.cs +++ b/TLM/TLM/Custom/AI/CustomHumanAI.cs @@ -13,7 +13,6 @@ namespace TrafficManager.Custom.AI { using RedirectionFramework.Attributes; using State; using State.ConfigData; - using Traffic.Data; using UnityEngine; [TargetType(typeof(HumanAI))] diff --git a/TLM/TLM/Custom/PathFinding/CustomPathFind.cs b/TLM/TLM/Custom/PathFinding/CustomPathFind.cs index 8ac119676..6a61cdc0d 100644 --- a/TLM/TLM/Custom/PathFinding/CustomPathFind.cs +++ b/TLM/TLM/Custom/PathFinding/CustomPathFind.cs @@ -15,7 +15,6 @@ using Manager.Impl; using RedirectionFramework.Attributes; using State; - using Traffic.Data; using UnityEngine; #if DEBUG diff --git a/TLM/TLM/Custom/PathFinding/CustomPathManager.cs b/TLM/TLM/Custom/PathFinding/CustomPathManager.cs index cb1db874c..adb2d919e 100644 --- a/TLM/TLM/Custom/PathFinding/CustomPathManager.cs +++ b/TLM/TLM/Custom/PathFinding/CustomPathManager.cs @@ -13,7 +13,6 @@ namespace TrafficManager.Custom.PathFinding { using Manager.Impl; using RedirectionFramework.Attributes; using State; - using Traffic.Data; using UnityEngine; #if !PF_DIJKSTRA diff --git a/TLM/TLM/Manager/AbstractGeometryObservingManager.cs b/TLM/TLM/Manager/AbstractGeometryObservingManager.cs index cc7797f7c..66fdfdd27 100644 --- a/TLM/TLM/Manager/AbstractGeometryObservingManager.cs +++ b/TLM/TLM/Manager/AbstractGeometryObservingManager.cs @@ -8,7 +8,6 @@ using Geometry; using JetBrains.Annotations; using State.ConfigData; - using Traffic.Data; using Util; public abstract class AbstractGeometryObservingManager : AbstractCustomManager, IObserver { diff --git a/TLM/TLM/Manager/Impl/AdvancedParkingManager.cs b/TLM/TLM/Manager/Impl/AdvancedParkingManager.cs index 048321f9a..3a9b06235 100644 --- a/TLM/TLM/Manager/Impl/AdvancedParkingManager.cs +++ b/TLM/TLM/Manager/Impl/AdvancedParkingManager.cs @@ -13,7 +13,6 @@ using JetBrains.Annotations; using State; using State.ConfigData; - using Traffic.Data; using UI; using UnityEngine; using Util; diff --git a/TLM/TLM/Manager/Impl/CustomSegmentLightsManager.cs b/TLM/TLM/Manager/Impl/CustomSegmentLightsManager.cs index d08f992ae..29814b7e4 100644 --- a/TLM/TLM/Manager/Impl/CustomSegmentLightsManager.cs +++ b/TLM/TLM/Manager/Impl/CustomSegmentLightsManager.cs @@ -6,7 +6,6 @@ namespace TrafficManager.Manager.Impl { using API.TrafficLight; using ColossalFramework; using CSUtil.Commons; - using Traffic.Data; using TrafficLight; using TrafficLight.Impl; diff --git a/TLM/TLM/Manager/Impl/ExtBuildingManager.cs b/TLM/TLM/Manager/Impl/ExtBuildingManager.cs index e5cfce1ca..86335526a 100644 --- a/TLM/TLM/Manager/Impl/ExtBuildingManager.cs +++ b/TLM/TLM/Manager/Impl/ExtBuildingManager.cs @@ -5,7 +5,6 @@ using ColossalFramework; using CSUtil.Commons; using State; - using Traffic.Data; using UnityEngine; public class ExtBuildingManager diff --git a/TLM/TLM/Manager/Impl/ExtCitizenInstanceManager.cs b/TLM/TLM/Manager/Impl/ExtCitizenInstanceManager.cs index aef90f456..e175cb2dc 100644 --- a/TLM/TLM/Manager/Impl/ExtCitizenInstanceManager.cs +++ b/TLM/TLM/Manager/Impl/ExtCitizenInstanceManager.cs @@ -11,7 +11,6 @@ using Custom.PathFinding; using State; using State.ConfigData; - using Traffic.Data; using UnityEngine; public class ExtCitizenInstanceManager diff --git a/TLM/TLM/Manager/Impl/ExtCitizenManager.cs b/TLM/TLM/Manager/Impl/ExtCitizenManager.cs index 332fb868e..28836daa1 100644 --- a/TLM/TLM/Manager/Impl/ExtCitizenManager.cs +++ b/TLM/TLM/Manager/Impl/ExtCitizenManager.cs @@ -6,7 +6,7 @@ using API.Traffic.Enums; using ColossalFramework; using CSUtil.Commons; - using Traffic.Data; + #if DEBUG using State.ConfigData; #endif diff --git a/TLM/TLM/Manager/Impl/ExtNodeManager.cs b/TLM/TLM/Manager/Impl/ExtNodeManager.cs index 722a0371b..7fd274ec6 100644 --- a/TLM/TLM/Manager/Impl/ExtNodeManager.cs +++ b/TLM/TLM/Manager/Impl/ExtNodeManager.cs @@ -5,7 +5,6 @@ using CSUtil.Commons; using Geometry; using Geometry.Impl; - using Traffic.Data; public class ExtNodeManager : AbstractCustomManager, diff --git a/TLM/TLM/Manager/Impl/ExtSegmentEndManager.cs b/TLM/TLM/Manager/Impl/ExtSegmentEndManager.cs index e414ace47..3f517b902 100644 --- a/TLM/TLM/Manager/Impl/ExtSegmentEndManager.cs +++ b/TLM/TLM/Manager/Impl/ExtSegmentEndManager.cs @@ -5,7 +5,6 @@ using ColossalFramework; using CSUtil.Commons; using State.ConfigData; - using Traffic.Data; using UnityEngine; public class ExtSegmentEndManager diff --git a/TLM/TLM/Manager/Impl/ExtSegmentManager.cs b/TLM/TLM/Manager/Impl/ExtSegmentManager.cs index bc82082ea..006a754a0 100644 --- a/TLM/TLM/Manager/Impl/ExtSegmentManager.cs +++ b/TLM/TLM/Manager/Impl/ExtSegmentManager.cs @@ -4,7 +4,6 @@ using ColossalFramework; using CSUtil.Commons; using State.ConfigData; - using Traffic.Data; public class ExtSegmentManager : AbstractCustomManager, diff --git a/TLM/TLM/Manager/Impl/ExtVehicleManager.cs b/TLM/TLM/Manager/Impl/ExtVehicleManager.cs index a228b4ff4..c15f7ab63 100644 --- a/TLM/TLM/Manager/Impl/ExtVehicleManager.cs +++ b/TLM/TLM/Manager/Impl/ExtVehicleManager.cs @@ -9,7 +9,6 @@ using JetBrains.Annotations; using State; using State.ConfigData; - using Traffic.Data; using UnityEngine; public class ExtVehicleManager @@ -816,8 +815,8 @@ public void UpdateDynamicLaneSelectionParameters(ref ExtVehicle extVehicle) { dls.MaxMaxOptLaneChanges, egoism); extVehicle.minSafeSpeedImprovement = Mathf.Lerp( - dls.MinMinSafeSpeedImprovement, - dls.MaxMinSafeSpeedImprovement, + dls.MinMinSafeSpeedImprovement.GameSpeed, + dls.MaxMinSafeSpeedImprovement.GameSpeed, altruism); extVehicle.minSafeTrafficImprovement = Mathf.Lerp( dls.MinMinSafeTrafficImprovement, diff --git a/TLM/TLM/Manager/Impl/GeometryManager.cs b/TLM/TLM/Manager/Impl/GeometryManager.cs index de91664dd..d63269554 100644 --- a/TLM/TLM/Manager/Impl/GeometryManager.cs +++ b/TLM/TLM/Manager/Impl/GeometryManager.cs @@ -10,7 +10,6 @@ using CSUtil.Commons; using State.ConfigData; using Geometry; - using Traffic.Data; using Util; public class GeometryManager diff --git a/TLM/TLM/Manager/Impl/JunctionRestrictionsManager.cs b/TLM/TLM/Manager/Impl/JunctionRestrictionsManager.cs index 4ec57aa68..3cfdfee11 100644 --- a/TLM/TLM/Manager/Impl/JunctionRestrictionsManager.cs +++ b/TLM/TLM/Manager/Impl/JunctionRestrictionsManager.cs @@ -12,7 +12,6 @@ namespace TrafficManager.Manager.Impl { using State; using State.ConfigData; using Traffic; - using Traffic.Data; public class JunctionRestrictionsManager : AbstractGeometryObservingManager, diff --git a/TLM/TLM/Manager/Impl/LaneArrowManager.cs b/TLM/TLM/Manager/Impl/LaneArrowManager.cs index 229b58134..e1e42912d 100644 --- a/TLM/TLM/Manager/Impl/LaneArrowManager.cs +++ b/TLM/TLM/Manager/Impl/LaneArrowManager.cs @@ -8,7 +8,6 @@ using ColossalFramework; using CSUtil.Commons; using State; - using Traffic.Data; public class LaneArrowManager : AbstractGeometryObservingManager, diff --git a/TLM/TLM/Manager/Impl/LaneConnectionManager.cs b/TLM/TLM/Manager/Impl/LaneConnectionManager.cs index 12148b3cc..d34999148 100644 --- a/TLM/TLM/Manager/Impl/LaneConnectionManager.cs +++ b/TLM/TLM/Manager/Impl/LaneConnectionManager.cs @@ -10,7 +10,6 @@ using JetBrains.Annotations; using State; using State.ConfigData; - using Traffic.Data; using UnityEngine; public class LaneConnectionManager diff --git a/TLM/TLM/Manager/Impl/ParkingRestrictionsManager.cs b/TLM/TLM/Manager/Impl/ParkingRestrictionsManager.cs index 3af033dc8..f175befb3 100644 --- a/TLM/TLM/Manager/Impl/ParkingRestrictionsManager.cs +++ b/TLM/TLM/Manager/Impl/ParkingRestrictionsManager.cs @@ -4,7 +4,6 @@ using API.Manager; using API.Traffic.Data; using CSUtil.Commons; - using Traffic.Data; public class ParkingRestrictionsManager : AbstractGeometryObservingManager, diff --git a/TLM/TLM/Manager/Impl/RoutingManager.cs b/TLM/TLM/Manager/Impl/RoutingManager.cs index fb991c0f4..31ad71987 100644 --- a/TLM/TLM/Manager/Impl/RoutingManager.cs +++ b/TLM/TLM/Manager/Impl/RoutingManager.cs @@ -11,7 +11,6 @@ using JetBrains.Annotations; using State.ConfigData; using State; - using Traffic.Data; public class RoutingManager : AbstractGeometryObservingManager, diff --git a/TLM/TLM/Manager/Impl/SpeedLimitManager.cs b/TLM/TLM/Manager/Impl/SpeedLimitManager.cs index 855628acb..5749b0511 100644 --- a/TLM/TLM/Manager/Impl/SpeedLimitManager.cs +++ b/TLM/TLM/Manager/Impl/SpeedLimitManager.cs @@ -8,8 +8,9 @@ using CSUtil.Commons; using JetBrains.Annotations; using State; - using Traffic.Data; + using UI.SubTools.SpeedLimits; using UnityEngine; + using Util; public class SpeedLimitManager : AbstractGeometryObservingManager, @@ -27,6 +28,9 @@ public class SpeedLimitManager /// Ingame speed units, max possible speed public const float MAX_SPEED = 10f * 2f; // 1000 km/h + /// Ingame speed units, minimal speed + private const float MIN_SPEED = 0.1f; // 5 km/h + // For each NetInfo (by name) and lane index: game default speed limit private Dictionary vanillaLaneSpeedLimitsByNetInfoName; @@ -307,7 +311,7 @@ public float GetLockFreeGameSpeedLimit(ushort segmentId, /// Custom speed limit which can be zero /// Speed limit in game speed units public float ToGameSpeedLimit(float customSpeedLimit) { - return SpeedLimit.IsZero(customSpeedLimit) + return FloatUtil.IsZero(customSpeedLimit) ? MAX_SPEED : customSpeedLimit; } @@ -552,7 +556,7 @@ public bool SetSpeedLimit(ushort segmentId, return false; } - if (!SpeedLimit.IsValidRange(speedLimit)) { + if (!IsValidRange(speedLimit)) { return false; } @@ -578,7 +582,7 @@ public bool SetSpeedLimit(ushort segmentId, NetInfo.Direction finalDir, float sp return false; } - if (!SpeedLimit.IsValidRange(speedLimit)) { + if (!IsValidRange(speedLimit)) { return false; } @@ -615,7 +619,7 @@ public bool SetSpeedLimit(ushort segmentId, NetInfo.Direction finalDir, float sp #if DEBUG Log._Debug( $"SpeedLimitManager: Setting speed limit of lane {curLaneId} " + - $"to {speedLimit * SpeedLimit.SPEED_TO_KMPH}"); + $"to {speedLimit * Constants.SPEED_TO_KMPH}"); #endif Flags.SetLaneSpeedLimit(curLaneId, speedLimit); @@ -828,7 +832,7 @@ public bool LoadData(List data) { $"lanes={info?.m_lanes} is {customSpeedLimit}"); #endif - if (SpeedLimit.IsValidRange(customSpeedLimit)) { + if (IsValidRange(customSpeedLimit)) { // lane speed limit differs from default speed limit #if DEBUGLOAD Log._Debug($"SpeedLimitManager.LoadData: Loading lane speed limit: lane "+ @@ -839,7 +843,7 @@ public bool LoadData(List data) { $"SpeedLimitManager.LoadData: Loading lane speed limit: " + $"lane {laneSpeedLimit.laneId} = {laneSpeedLimit.speedLimit} km/h"); float kmph = laneSpeedLimit.speedLimit / - SpeedLimit.SPEED_TO_KMPH; // convert to game units + Constants.SPEED_TO_KMPH; // convert to game units Flags.SetLaneSpeedLimit(laneSpeedLimit.laneId, kmph); } else { #if DEBUGLOAD @@ -955,6 +959,9 @@ Dictionary ICustomDataManager>.SaveData public static ICustomDataManager> AsCustomDefaultSpeedLimitsDM() { return Instance; } - } + public static bool IsValidRange(float speed) { + return FloatUtil.IsZero(speed) || (speed >= MIN_SPEED && speed <= MAX_SPEED); + } + } // end class } \ No newline at end of file diff --git a/TLM/TLM/Manager/Impl/TrafficMeasurementManager.cs b/TLM/TLM/Manager/Impl/TrafficMeasurementManager.cs index b2d3c5a16..369432f52 100644 --- a/TLM/TLM/Manager/Impl/TrafficMeasurementManager.cs +++ b/TLM/TLM/Manager/Impl/TrafficMeasurementManager.cs @@ -5,7 +5,6 @@ using ColossalFramework; using CSUtil.Commons; using State; - using Traffic.Data; using UnityEngine; public class TrafficMeasurementManager : AbstractCustomManager, ITrafficMeasurementManager { diff --git a/TLM/TLM/Manager/Impl/TrafficPriorityManager.cs b/TLM/TLM/Manager/Impl/TrafficPriorityManager.cs index 9cc6981e4..78585512a 100644 --- a/TLM/TLM/Manager/Impl/TrafficPriorityManager.cs +++ b/TLM/TLM/Manager/Impl/TrafficPriorityManager.cs @@ -14,7 +14,6 @@ namespace TrafficManager.Manager.Impl { using State; using State.ConfigData; using Traffic; - using Traffic.Data; using TrafficLight; using UnityEngine; diff --git a/TLM/TLM/Manager/Impl/TurnOnRedManager.cs b/TLM/TLM/Manager/Impl/TurnOnRedManager.cs index efdd07115..d03d79a55 100644 --- a/TLM/TLM/Manager/Impl/TurnOnRedManager.cs +++ b/TLM/TLM/Manager/Impl/TurnOnRedManager.cs @@ -3,7 +3,6 @@ namespace TrafficManager.Manager.Impl { using API.Traffic.Data; using CSUtil.Commons; using State.ConfigData; - using Traffic.Data; public class TurnOnRedManager : AbstractGeometryObservingManager, diff --git a/TLM/TLM/Manager/Impl/VehicleBehaviorManager.cs b/TLM/TLM/Manager/Impl/VehicleBehaviorManager.cs index 6a8d58839..8af986e4a 100644 --- a/TLM/TLM/Manager/Impl/VehicleBehaviorManager.cs +++ b/TLM/TLM/Manager/Impl/VehicleBehaviorManager.cs @@ -10,8 +10,9 @@ using JetBrains.Annotations; using State; using State.ConfigData; - using Traffic.Data; + using UI.SubTools.SpeedLimits; using UnityEngine; + using Util; public class VehicleBehaviorManager : AbstractCustomManager, IVehicleBehaviorManager { public const float MIN_SPEED = 8f * 0.2f; // 10 km/h @@ -1507,7 +1508,7 @@ ref segEndMan.ExtSegmentEnds[segEndMan.GetIndex(prevPos.m_segment, isTargetStart Log._DebugIf( logPriority, () => $"VehicleBehaviorManager.MayChangeSegment({frontVehicleId}): " + - $"Setting JunctionTransitState to APPROACH (prio)"); + "Setting JunctionTransitState to APPROACH (prio)"); transitState = VehicleJunctionTransitState.Approach; } @@ -2016,7 +2017,7 @@ LaneTransitionData[] next1FwdTransitions if (next2FwdRoutingIndex >= RoutingManager.Instance.LaneEndForwardRoutings.Length) { Log._DebugOnlyError( $"Invalid array index: next2FwdRoutingIndex={next2FwdRoutingIndex}, " + - $"RoutingManager.Instance.laneEndForwardRoutings.Length=" + + "RoutingManager.Instance.laneEndForwardRoutings.Length=" + $"{RoutingManager.Instance.LaneEndForwardRoutings.Length} " + $"(next1FwdTransitions[j].laneId={next1FwdTransitions[j].laneId}, " + $"!next1FwdTransitions[j].startNode={!next1FwdTransitions[j].startNode})"); @@ -2161,7 +2162,7 @@ LaneTransitionData[] next2FwdTransitions Log._Debug( $"VehicleBehaviorManager.FindBestLane({vehicleId}): " + $"Skipping next3 transition {next3FwdTransitions[l]} " + - $"(distance too large)"); + "(distance too large)"); } continue; } @@ -2387,7 +2388,7 @@ LaneTransitionData[] next1BackTransitions #if DEBUG if (currentFwdTransitions[i].laneIndex >= next1SegInfo.m_lanes.Length) { Log.Error( - $"Invalid array index: currentFwdTransitions[i].laneIndex=" + + "Invalid array index: currentFwdTransitions[i].laneIndex=" + $"{currentFwdTransitions[i].laneIndex}, " + $"next1SegInfo.m_lanes.Length={next1SegInfo.m_lanes.Length}"); } @@ -2587,7 +2588,7 @@ LaneTransitionData[] next1BackTransitions return bestStayNext1LaneIndex; } - bool isBssDiffZero = Math.Abs(bestStaySpeedDiff) < Constants.VERY_SMALL_FLOAT; + bool isBssDiffZero = Math.Abs(bestStaySpeedDiff) < FloatUtil.VERY_SMALL_FLOAT; if (isBssDiffZero || bestOptMeanSpeed < 0.1f) { //--------------------------------------- // edge cases: @@ -2636,20 +2637,27 @@ LaneTransitionData[] next1BackTransitions return bestStayNext1LaneIndex; } - if (bestStaySpeedDiff < 0 && bestOptSpeedDiff > bestStaySpeedDiff) { + if (bestStaySpeedDiff < 0 + && bestOptSpeedDiff > bestStaySpeedDiff) + { // found a lane change that improves vehicle speed // float improvement = 100f * ((bestOptSpeedDiff - bestStaySpeedDiff) // / ((bestStayMeanSpeed + bestOptMeanSpeed) / 2f)); - var speedDiff = Mathf.Abs(bestOptMeanSpeed - vehicleCurSpeed); - var optImprovementSpeed = - SpeedLimit.ToKmphRounded(bestOptSpeedDiff - bestStaySpeedDiff); + float speedDiff = Mathf.Abs(bestOptMeanSpeed - vehicleCurSpeed); + float optImprovementSpeed = bestOptSpeedDiff - bestStaySpeedDiff; - Log._DebugIf( - logLaneSelection, - () => $"VehicleBehaviorManager.FindBestLane({vehicleId}): a lane change for " + - $"speed improvement is possible. optImprovementInKmH={optImprovementSpeed} km/h " + - $"speedDiff={speedDiff} (bestOptMeanSpeed={bestOptMeanSpeed}, " + - $"vehicleCurVelocity={vehicleCurSpeed}, foundSafeLaneChange={foundSafeLaneChange})"); + if (logLaneSelection) { + Log._DebugFormat( + "VehicleBehaviorManager.FindBestLane({0}): a lane change for speed " + + "improvement is possible. optImprovementInKmH={1} km/h speedDiff={2} " + + "(bestOptMeanSpeed={3}, vehicleCurVelocity={4}, foundSafeLaneChange={5})", + vehicleId, + SpeedLimit.ToKmphPrecise(optImprovementSpeed), + speedDiff, + bestOptMeanSpeed, + vehicleCurSpeed, + foundSafeLaneChange); + } if (optImprovementSpeed >= vehicleState.minSafeSpeedImprovement && (foundSafeLaneChange || (speedDiff <= vehicleState.maxUnsafeSpeedDiff))) @@ -2669,7 +2677,7 @@ LaneTransitionData[] next1BackTransitions Log._DebugIf( logLaneSelection, () => $"VehicleBehaviorManager.FindBestLane({vehicleId}): ===> found a faster " + - $"lane to change to but speed improvement is NOT significant OR lane change " + + "lane to change to but speed improvement is NOT significant OR lane change " + $"is unsafe -- selecting bestStayNext1LaneIndex={bestStayNext1LaneIndex} " + $"(foundSafeLaneChange={foundSafeLaneChange})"); @@ -2703,7 +2711,7 @@ LaneTransitionData[] next1BackTransitions Log._DebugIf( logLaneSelection, () => $"VehicleBehaviorManager.FindBestLane({vehicleId}): ===> found a lane " + - $"that optimizes overall traffic but optimization is NOT significant -- selecting " + + "that optimizes overall traffic but optimization is NOT significant -- selecting " + $"bestStayNext1LaneIndex={bestStayNext1LaneIndex}"); return bestOptNext1LaneIndex; diff --git a/TLM/TLM/Manager/Impl/VehicleRestrictionsManager.cs b/TLM/TLM/Manager/Impl/VehicleRestrictionsManager.cs index a71f183c5..2cad277f9 100644 --- a/TLM/TLM/Manager/Impl/VehicleRestrictionsManager.cs +++ b/TLM/TLM/Manager/Impl/VehicleRestrictionsManager.cs @@ -9,7 +9,6 @@ using JetBrains.Annotations; using State; using Traffic; - using Traffic.Data; using Util; using ExtVehicleType = global::TrafficManager.API.Traffic.Enums.ExtVehicleType; diff --git a/TLM/TLM/State/ConfigData/DynamicLaneSelection.cs b/TLM/TLM/State/ConfigData/DynamicLaneSelection.cs index 282000192..974fc5cbb 100644 --- a/TLM/TLM/State/ConfigData/DynamicLaneSelection.cs +++ b/TLM/TLM/State/ConfigData/DynamicLaneSelection.cs @@ -1,4 +1,7 @@ namespace TrafficManager.State.ConfigData { + using API.Traffic.Data; + using UI.SubTools.SpeedLimits; + public class DynamicLaneSelection { /// /// Maximum allowed reserved space on previous vehicle lane @@ -123,14 +126,16 @@ public class DynamicLaneSelection { */ /// - /// Minimum minimum required speed improvement for safe lane changes (in km/h) + /// Minimum minimum required speed improvement for safe lane changes (in game units). + /// Set to 5 km/h in game units. /// - public float MinMinSafeSpeedImprovement = 5f; + public SpeedValue MinMinSafeSpeedImprovement = SpeedValue.FromKmph(5f); /// - /// Maximum minimum required speed improvement for safe lane changes (in km/h) + /// Maximum minimum required speed improvement for safe lane changes (in game units) + /// Set to 30 km/h in game units. /// - public float MaxMinSafeSpeedImprovement = 30f; + public SpeedValue MaxMinSafeSpeedImprovement = SpeedValue.FromKmph(30f); /* * min. required traffic flow improvement for safe lane changes diff --git a/TLM/TLM/State/ConfigData/Main.cs b/TLM/TLM/State/ConfigData/Main.cs index de4152520..021d5aa16 100644 --- a/TLM/TLM/State/ConfigData/Main.cs +++ b/TLM/TLM/State/ConfigData/Main.cs @@ -1,8 +1,8 @@ namespace TrafficManager.State.ConfigData { using System.Collections.Generic; using System.Linq; - using Traffic.Data; using UI.MainMenu; + using UI.SubTools.SpeedLimits; public class Main { /// diff --git a/TLM/TLM/State/Configuration.cs b/TLM/TLM/State/Configuration.cs index 29037d33e..d8a6affbd 100644 --- a/TLM/TLM/State/Configuration.cs +++ b/TLM/TLM/State/Configuration.cs @@ -5,18 +5,22 @@ namespace TrafficManager { using JetBrains.Annotations; using State; using Traffic; - using Traffic.Data; + using UI.SubTools.SpeedLimits; [Serializable] public class Configuration { [Serializable] public class LaneSpeedLimit { public uint laneId; + + /// + /// Unit: km/h. + /// public ushort speedLimit; public LaneSpeedLimit(uint laneId, float speedLimit) { this.laneId = laneId; - this.speedLimit = (ushort)(speedLimit * SpeedLimit.SPEED_TO_KMPH); + this.speedLimit = (ushort)(speedLimit * Constants.SPEED_TO_KMPH); } } diff --git a/TLM/TLM/State/OptionsTabs/OptionsGeneralTab.cs b/TLM/TLM/State/OptionsTabs/OptionsGeneralTab.cs index babc6e9eb..982da413c 100644 --- a/TLM/TLM/State/OptionsTabs/OptionsGeneralTab.cs +++ b/TLM/TLM/State/OptionsTabs/OptionsGeneralTab.cs @@ -4,8 +4,8 @@ namespace TrafficManager.State { using CSUtil.Commons; using ICities; using JetBrains.Annotations; - using Traffic.Data; using UI; + using UI.SubTools.SpeedLimits; using UnityEngine; public static class OptionsGeneralTab { diff --git a/TLM/TLM/TLM.csproj b/TLM/TLM/TLM.csproj index 58985b06f..d866bc1a3 100644 --- a/TLM/TLM/TLM.csproj +++ b/TLM/TLM/TLM.csproj @@ -204,7 +204,6 @@ - @@ -241,6 +240,8 @@ + + @@ -250,7 +251,6 @@ - @@ -264,6 +264,7 @@ + @@ -519,6 +520,9 @@ + + + rem set "DEPLOYDIR=D:\Games\Steam\steamapps\workshop\content\255710\1637663252\" diff --git a/TLM/TLM/TrafficLight/Impl/CustomSegmentLight.cs b/TLM/TLM/TrafficLight/Impl/CustomSegmentLight.cs index 0ea359d0b..1f391b878 100644 --- a/TLM/TLM/TrafficLight/Impl/CustomSegmentLight.cs +++ b/TLM/TLM/TrafficLight/Impl/CustomSegmentLight.cs @@ -10,7 +10,6 @@ namespace TrafficManager.TrafficLight.Impl { using CSUtil.Commons; using JetBrains.Annotations; using State.ConfigData; - using Traffic.Data; /// /// Represents the traffic light (left, forward, right) at a specific segment end diff --git a/TLM/TLM/TrafficLight/Impl/CustomSegmentLights.cs b/TLM/TLM/TrafficLight/Impl/CustomSegmentLights.cs index 00e819da1..d850caea6 100644 --- a/TLM/TLM/TrafficLight/Impl/CustomSegmentLights.cs +++ b/TLM/TLM/TrafficLight/Impl/CustomSegmentLights.cs @@ -12,7 +12,6 @@ namespace TrafficManager.TrafficLight.Impl { using Geometry.Impl; using JetBrains.Annotations; using State.ConfigData; - using Traffic.Data; using Util; /// diff --git a/TLM/TLM/TrafficLight/Impl/TimedTrafficLightsStep.cs b/TLM/TLM/TrafficLight/Impl/TimedTrafficLightsStep.cs index 3e0f76249..ab6ebd0b5 100644 --- a/TLM/TLM/TrafficLight/Impl/TimedTrafficLightsStep.cs +++ b/TLM/TLM/TrafficLight/Impl/TimedTrafficLightsStep.cs @@ -736,7 +736,7 @@ public bool ShouldGoToNextStep(float flow, float wait, out float metric) { metric = GetMetric(flow, wait); return ChangeMetric == StepChangeMetric.Default ? metric < 0 - : Math.Abs(metric) < Constants.VERY_SMALL_FLOAT; + : Math.Abs(metric) < FloatUtil.VERY_SMALL_FLOAT; } /// diff --git a/TLM/TLM/UI/SubTools/ManualTrafficLightsTool.cs b/TLM/TLM/UI/SubTools/ManualTrafficLightsTool.cs index e7c172202..35aa5b889 100644 --- a/TLM/TLM/UI/SubTools/ManualTrafficLightsTool.cs +++ b/TLM/TLM/UI/SubTools/ManualTrafficLightsTool.cs @@ -7,7 +7,6 @@ using JetBrains.Annotations; using Manager.Impl; using Textures; - using Traffic.Data; using TrafficLight; using UnityEngine; diff --git a/TLM/TLM/UI/SubTools/PrioritySignsTool.cs b/TLM/TLM/UI/SubTools/PrioritySignsTool.cs index 371a12eb7..219c08b85 100644 --- a/TLM/TLM/UI/SubTools/PrioritySignsTool.cs +++ b/TLM/TLM/UI/SubTools/PrioritySignsTool.cs @@ -9,7 +9,6 @@ using Manager.Impl; using State; using Textures; - using Traffic.Data; using UnityEngine; using Util; using static Util.SegmentTraverser; diff --git a/TLM/TLM/Traffic/Data/SpeedLimit.cs b/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimit.cs similarity index 79% rename from TLM/TLM/Traffic/Data/SpeedLimit.cs rename to TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimit.cs index 8285cffa4..277120fb7 100644 --- a/TLM/TLM/Traffic/Data/SpeedLimit.cs +++ b/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimit.cs @@ -1,46 +1,43 @@ -namespace TrafficManager.Traffic.Data { - using System; +namespace TrafficManager.UI.SubTools.SpeedLimits { using System.Collections.Generic; using State; - using UI; using UnityEngine; + using Util; - public enum SpeedUnit { - CurrentlyConfigured, // Currently selected in the options menu - Kmph, - Mph - } - + /// + /// Defines styles available for road signs + /// public enum MphSignStyle { SquareUS = 0, RoundUK = 1, RoundGerman = 2, } + public enum SpeedUnit { + CurrentlyConfigured, // Currently selected in the options menu + Kmph, + Mph + } + /// - /// Defines a speed limit value with default Kmph and display value of Mph - /// for when the option is set to display Mph. The engine still uses kmph. + /// Contains constants and implements algorithms for building the speed limit palette and + /// selecting speeds from the palette. /// - public struct SpeedLimit { - public const float SPEED_TO_KMPH = 50.0f; // 1.0f equals 50 km/h + public class SpeedLimit { + public const int + BREAK_PALETTE_COLUMN_KMPH = 8; // palette shows N in a row, then break and another row + + public const int + BREAK_PALETTE_COLUMN_MPH = 10; // palette shows M in a row, then break and another row + private const ushort LOWER_KMPH = 10; public const ushort UPPER_KMPH = 140; private const ushort KMPH_STEP = 10; - public const int - BREAK_PALETTE_COLUMN_KMPH = 8; // palette shows N in a row, then break and another row - - private const float SPEED_TO_MPH = 32.06f; // 50 km/h converted to mph private const ushort LOWER_MPH = 5; public const ushort UPPER_MPH = 90; private const ushort MPH_STEP = 5; - public const int - BREAK_PALETTE_COLUMN_MPH = 10; // palette shows M in a row, then break and another row - - private const float LOWER_SPEED = 0.1f; - private const float UPPER_SPEED = 2 * 10.0f; // 1000 km/h - /// /// Produces list of speed limits to offer user in the palette /// @@ -52,13 +49,13 @@ public static List EnumerateSpeedLimits(SpeedUnit unit) { switch (unit) { case SpeedUnit.Kmph: for (var km = LOWER_KMPH; km <= UPPER_KMPH; km += KMPH_STEP) { - result.Add(km / SPEED_TO_KMPH); + result.Add(km / Constants.SPEED_TO_KMPH); } break; case SpeedUnit.Mph: for (var mi = LOWER_MPH; mi <= UPPER_MPH; mi += MPH_STEP) { - result.Add(mi / SPEED_TO_MPH); + result.Add(mi / Constants.SPEED_TO_MPH); } break; @@ -73,7 +70,7 @@ public static List EnumerateSpeedLimits(SpeedUnit unit) { } public static string ToMphPreciseString(float speed) { - if (IsZero(speed)) { + if (FloatUtil.IsZero(speed)) { return Translation.GetString("Speed_limit_unlimited"); } @@ -81,37 +78,25 @@ public static string ToMphPreciseString(float speed) { } public static string ToKmphPreciseString(float speed) { - if (IsZero(speed)) { + if (FloatUtil.IsZero(speed)) { return Translation.GetString("Speed_limit_unlimited"); } return ToKmphPrecise(speed) + " km/h"; } - public static bool NearlyEqual(float a, float b) { - return Mathf.Abs(a - b) < 0.001f; - } - - public static bool IsZero(float speed) { - return Math.Abs(speed) < Constants.VERY_SMALL_FLOAT; - } - - public static bool IsValidRange(float speed) { - return IsZero(speed) || (speed >= LOWER_SPEED && speed <= UPPER_SPEED); - } - /// /// Convert float game speed to mph and round to nearest STEP /// /// Speed, scale: 1f=32 MPH /// Speed in MPH rounded to nearest 5 MPH public static ushort ToMphRounded(float speed) { - var mph = speed * SPEED_TO_MPH; + var mph = speed * Constants.SPEED_TO_MPH; return (ushort)(Mathf.Round(mph / MPH_STEP) * MPH_STEP); } public static ushort ToMphPrecise(float speed) { - return (ushort)Mathf.Round(speed * SPEED_TO_MPH); + return (ushort)Mathf.Round(speed * Constants.SPEED_TO_MPH); } /// @@ -120,12 +105,12 @@ public static ushort ToMphPrecise(float speed) { /// Speed, scale: 1f=50km/h /// Speed in km/h rounded to nearest 10 km/h public static ushort ToKmphRounded(float speed) { - var kmph = speed * SPEED_TO_KMPH; + var kmph = speed * Constants.SPEED_TO_KMPH; return (ushort)(Mathf.Round(kmph / KMPH_STEP) * KMPH_STEP); } public static ushort ToKmphPrecise(float speed) { - return (ushort)Mathf.Round(speed * SPEED_TO_KMPH); + return (ushort)Mathf.Round(speed * Constants.SPEED_TO_KMPH); } /// @@ -146,10 +131,10 @@ public static float GetPrevious(float speed) { } if (rounded == 0) { - return UPPER_MPH / SPEED_TO_MPH; + return UPPER_MPH / Constants.SPEED_TO_MPH; } - return (rounded > LOWER_MPH ? rounded - MPH_STEP : LOWER_MPH) / SPEED_TO_MPH; + return (rounded > LOWER_MPH ? rounded - MPH_STEP : LOWER_MPH) / Constants.SPEED_TO_MPH; } else { ushort rounded = ToKmphRounded(speed); if (rounded == LOWER_KMPH) { @@ -157,10 +142,10 @@ public static float GetPrevious(float speed) { } if (rounded == 0) { - return UPPER_KMPH / SPEED_TO_KMPH; + return UPPER_KMPH / Constants.SPEED_TO_KMPH; } - return (rounded > LOWER_KMPH ? rounded - KMPH_STEP : LOWER_KMPH) / SPEED_TO_KMPH; + return (rounded > LOWER_KMPH ? rounded - KMPH_STEP : LOWER_KMPH) / Constants.SPEED_TO_KMPH; } } @@ -183,7 +168,7 @@ public static float GetNext(float speed) { rounded = 0; } - return rounded / SPEED_TO_MPH; + return rounded / Constants.SPEED_TO_MPH; } else { ushort rounded = ToKmphRounded(speed); rounded += KMPH_STEP; @@ -192,7 +177,7 @@ public static float GetNext(float speed) { rounded = 0; } - return rounded / SPEED_TO_KMPH; + return rounded / Constants.SPEED_TO_KMPH; } } diff --git a/TLM/TLM/UI/SubTools/SpeedLimitsTool.cs b/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimitsTool.cs similarity index 99% rename from TLM/TLM/UI/SubTools/SpeedLimitsTool.cs rename to TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimitsTool.cs index 2e0466668..0c9794728 100644 --- a/TLM/TLM/UI/SubTools/SpeedLimitsTool.cs +++ b/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimitsTool.cs @@ -1,18 +1,16 @@ -namespace TrafficManager.UI.SubTools { +namespace TrafficManager.UI.SubTools.SpeedLimits { using System; using System.Collections.Generic; using ColossalFramework; + using ColossalFramework.UI; using CSUtil.Commons; using GenericGameBridge.Service; using Manager.Impl; using State; using Textures; using Traffic; - using Traffic.Data; using UnityEngine; using Util; - using static ColossalFramework.UI.UITextureAtlas; - using static Util.SegmentLaneTraverser; public class SpeedLimitsTool : SubTool { /// Visible sign size, slightly reduced from 100 to accomodate another column for MPH @@ -380,7 +378,7 @@ private void UpdateRoadTex(NetInfo info) { info.m_Atlas.material.mainTexture != null && info.m_Atlas.material.mainTexture is Texture2D mainTex) { - SpriteInfo spriteInfo = info.m_Atlas[info.m_Thumbnail]; + UITextureAtlas.SpriteInfo spriteInfo = info.m_Atlas[info.m_Thumbnail]; if (spriteInfo != null && spriteInfo.texture != null && spriteInfo.texture.width > 0 && spriteInfo.texture.height > 0) { @@ -436,7 +434,7 @@ private void GuiSpeedLimitsWindow(int num) { foreach (float speedLimit in allSpeedLimits) { // Highlight palette item if it is very close to its float speed - if (SpeedLimit.NearlyEqual(currentPaletteSpeedLimit, speedLimit)) { + if (FloatUtil.NearlyEqual(currentPaletteSpeedLimit, speedLimit)) { GUI.color = Color.gray; } @@ -802,5 +800,5 @@ private bool drawSpeedLimitHandles(ushort segmentId, return hovered; } - } + } // end class } \ No newline at end of file diff --git a/TLM/TLM/UI/SubTools/TimedTrafficLightsTool.cs b/TLM/TLM/UI/SubTools/TimedTrafficLightsTool.cs index 1b06cd234..c0dc52cc3 100644 --- a/TLM/TLM/UI/SubTools/TimedTrafficLightsTool.cs +++ b/TLM/TLM/UI/SubTools/TimedTrafficLightsTool.cs @@ -11,7 +11,6 @@ using Manager.Impl; using State; using Textures; - using Traffic.Data; using TrafficLight; using UnityEngine; diff --git a/TLM/TLM/UI/Textures/JunctionUITextures.cs b/TLM/TLM/UI/Textures/JunctionUITextures.cs index 58dfeb25d..d6c2d8be4 100644 --- a/TLM/TLM/UI/Textures/JunctionUITextures.cs +++ b/TLM/TLM/UI/Textures/JunctionUITextures.cs @@ -2,7 +2,6 @@ namespace TrafficManager.UI.Textures { using System; using System.Collections.Generic; using State; - using Traffic.Data; using UnityEngine; using Util; using static TextureResources; diff --git a/TLM/TLM/UI/Textures/SpeedLimitTextures.cs b/TLM/TLM/UI/Textures/SpeedLimitTextures.cs index 080847053..9d6da3df3 100644 --- a/TLM/TLM/UI/Textures/SpeedLimitTextures.cs +++ b/TLM/TLM/UI/Textures/SpeedLimitTextures.cs @@ -2,7 +2,7 @@ namespace TrafficManager.UI.Textures { using System; using System.Collections.Generic; using State; - using Traffic.Data; + using SubTools.SpeedLimits; using UnityEngine; using Util; using static TextureResources; diff --git a/TLM/TLM/UI/TrafficManagerTool.cs b/TLM/TLM/UI/TrafficManagerTool.cs index 97d395b63..c7c93560f 100644 --- a/TLM/TLM/UI/TrafficManagerTool.cs +++ b/TLM/TLM/UI/TrafficManagerTool.cs @@ -15,9 +15,9 @@ using Manager.Impl; using State; using State.ConfigData; - using Traffic.Data; using MainMenu; using SubTools; + using SubTools.SpeedLimits; using Util; using UnityEngine; diff --git a/TLM/TLM/Util/FloatUtil.cs b/TLM/TLM/Util/FloatUtil.cs new file mode 100644 index 000000000..aeb83ea45 --- /dev/null +++ b/TLM/TLM/Util/FloatUtil.cs @@ -0,0 +1,28 @@ +namespace TrafficManager.Util { + using System; + using UnityEngine; + + /// + /// Provides static functions for handling floating point values. + /// + public class FloatUtil { + /// + /// A very small value for float comparisons to zero + /// + public const float VERY_SMALL_FLOAT = 1e-12f; + + /// + /// Checks whether two floats are very close to each other + /// + /// One float + /// Another float + /// Are really closed + public static bool NearlyEqual(float a, float b) { + return Mathf.Abs(a - b) < VERY_SMALL_FLOAT; + } + + public static bool IsZero(float speed) { + return Math.Abs(speed) < VERY_SMALL_FLOAT; + } + } +} \ No newline at end of file diff --git a/TLM/TLM/Util/SegmentTraverser.cs b/TLM/TLM/Util/SegmentTraverser.cs index 7d669b05a..2293d33c1 100644 --- a/TLM/TLM/Util/SegmentTraverser.cs +++ b/TLM/TLM/Util/SegmentTraverser.cs @@ -4,7 +4,6 @@ using API.Manager; using API.Traffic.Data; using CSUtil.Commons; - using Traffic.Data; public class SegmentTraverser { [Flags] diff --git a/TLM/TMPE.API/TMPE.API.csproj b/TLM/TMPE.API/TMPE.API.csproj index fd806e2b1..87afdcfbe 100644 --- a/TLM/TMPE.API/TMPE.API.csproj +++ b/TLM/TMPE.API/TMPE.API.csproj @@ -97,6 +97,7 @@ + @@ -111,6 +112,7 @@ + diff --git a/TLM/TMPE.API/Traffic/ApiConstants.cs b/TLM/TMPE.API/Traffic/ApiConstants.cs new file mode 100644 index 000000000..aa7e5f13a --- /dev/null +++ b/TLM/TMPE.API/Traffic/ApiConstants.cs @@ -0,0 +1,13 @@ +namespace TrafficManager.API.Traffic { + public static class ApiConstants { + /// + /// Conversion rate from km/h to game speed (also exists in TrafficManager.Constants) + /// + public const float SPEED_TO_KMPH = 50.0f; // 1.0f equals 50 km/h + + /// + /// Conversion rate from MPH to game speed (also exists in TrafficManager.Constants) + /// + private const float SPEED_TO_MPH = 32.06f; // 50 km/h converted to mph + } +} \ No newline at end of file diff --git a/TLM/TMPE.API/Traffic/Data/SpeedValue.cs b/TLM/TMPE.API/Traffic/Data/SpeedValue.cs new file mode 100644 index 000000000..d23e9bec6 --- /dev/null +++ b/TLM/TMPE.API/Traffic/Data/SpeedValue.cs @@ -0,0 +1,35 @@ +namespace TrafficManager.API.Traffic.Data { + using System; + + /// + /// Represents a speed value expressed in km/hour. + /// + [Serializable] + public struct KmphValue { + public float Kmph { get; } + } + + /// + /// Represents a speed value expressed in miles/hour. + /// + [Serializable] + public struct MphValue { + public float Mph { get; } + } + + /// + /// Represents a speed value expressed in game units where 1f = 50 km/h or 32 MPH. + /// + [Serializable] + public struct SpeedValue { + public SpeedValue(float gameSpeed) { + GameSpeed = gameSpeed; + } + + public float GameSpeed { get; } + + public static SpeedValue FromKmph(float f) { + return new SpeedValue(f / ApiConstants.SPEED_TO_KMPH); + } + } +} From 136fa7c60f88c627fd27d124b9521364999ea244 Mon Sep 17 00:00:00 2001 From: dmytro lytovchenko Date: Thu, 1 Aug 2019 21:32:28 +0200 Subject: [PATCH 2/8] #438 Use speed values with units; Remove SpeedLimit class --- TLM/TLM/Constants.cs | 2 + TLM/TLM/Manager/Impl/ExtVehicleManager.cs | 4 +- .../Manager/Impl/VehicleBehaviorManager.cs | 4 +- .../State/ConfigData/DynamicLaneSelection.cs | 4 +- TLM/TLM/TLM.csproj | 3 +- .../UI/SubTools/SpeedLimits/MphSignStyle.cs | 11 + TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimit.cs | 196 ----------------- .../SubTools/SpeedLimits/SpeedLimitsTool.cs | 208 +++++++++++++++--- TLM/TLM/UI/SubTools/SpeedLimits/SpeedUnit.cs | 7 + TLM/TLM/UI/Textures/SpeedLimitTextures.cs | 17 +- TLM/TLM/UI/TrafficManagerTool.cs | 7 +- TLM/TMPE.API/Traffic/ApiConstants.cs | 7 +- TLM/TMPE.API/Traffic/Data/SpeedValue.cs | 83 ++++++- 13 files changed, 302 insertions(+), 251 deletions(-) create mode 100644 TLM/TLM/UI/SubTools/SpeedLimits/MphSignStyle.cs delete mode 100644 TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimit.cs create mode 100644 TLM/TLM/UI/SubTools/SpeedLimits/SpeedUnit.cs diff --git a/TLM/TLM/Constants.cs b/TLM/TLM/Constants.cs index be7bdb589..28e594b2d 100644 --- a/TLM/TLM/Constants.cs +++ b/TLM/TLM/Constants.cs @@ -1,6 +1,7 @@ namespace TrafficManager { using API.Manager; using GenericGameBridge.Factory; + using JetBrains.Annotations; public static class Constants { /// @@ -21,6 +22,7 @@ public static class Constants { /// /// Conversion rate from MPH to game speed (also exists in TrafficManager.API.Constants) /// + [UsedImplicitly] public const float SPEED_TO_MPH = 32.06f; // 50 km/h converted to mph public static float ByteToFloat(byte b) { diff --git a/TLM/TLM/Manager/Impl/ExtVehicleManager.cs b/TLM/TLM/Manager/Impl/ExtVehicleManager.cs index c15f7ab63..ad4afdd16 100644 --- a/TLM/TLM/Manager/Impl/ExtVehicleManager.cs +++ b/TLM/TLM/Manager/Impl/ExtVehicleManager.cs @@ -815,8 +815,8 @@ public void UpdateDynamicLaneSelectionParameters(ref ExtVehicle extVehicle) { dls.MaxMaxOptLaneChanges, egoism); extVehicle.minSafeSpeedImprovement = Mathf.Lerp( - dls.MinMinSafeSpeedImprovement.GameSpeed, - dls.MaxMinSafeSpeedImprovement.GameSpeed, + dls.MinMinSafeSpeedImprovement.GameUnits, + dls.MaxMinSafeSpeedImprovement.GameUnits, altruism); extVehicle.minSafeTrafficImprovement = Mathf.Lerp( dls.MinMinSafeTrafficImprovement, diff --git a/TLM/TLM/Manager/Impl/VehicleBehaviorManager.cs b/TLM/TLM/Manager/Impl/VehicleBehaviorManager.cs index 8af986e4a..98b0b7cf6 100644 --- a/TLM/TLM/Manager/Impl/VehicleBehaviorManager.cs +++ b/TLM/TLM/Manager/Impl/VehicleBehaviorManager.cs @@ -2649,10 +2649,10 @@ LaneTransitionData[] next1BackTransitions if (logLaneSelection) { Log._DebugFormat( "VehicleBehaviorManager.FindBestLane({0}): a lane change for speed " + - "improvement is possible. optImprovementInKmH={1} km/h speedDiff={2} " + + "improvement is possible. optImprovementInKmH={1} speedDiff={2} " + "(bestOptMeanSpeed={3}, vehicleCurVelocity={4}, foundSafeLaneChange={5})", vehicleId, - SpeedLimit.ToKmphPrecise(optImprovementSpeed), + new SpeedValue(optImprovementSpeed).ToKmphPrecise(), speedDiff, bestOptMeanSpeed, vehicleCurSpeed, diff --git a/TLM/TLM/State/ConfigData/DynamicLaneSelection.cs b/TLM/TLM/State/ConfigData/DynamicLaneSelection.cs index 974fc5cbb..01a2b8e8a 100644 --- a/TLM/TLM/State/ConfigData/DynamicLaneSelection.cs +++ b/TLM/TLM/State/ConfigData/DynamicLaneSelection.cs @@ -129,13 +129,13 @@ public class DynamicLaneSelection { /// Minimum minimum required speed improvement for safe lane changes (in game units). /// Set to 5 km/h in game units. /// - public SpeedValue MinMinSafeSpeedImprovement = SpeedValue.FromKmph(5f); + public readonly SpeedValue MinMinSafeSpeedImprovement = SpeedValue.FromKmph(5); /// /// Maximum minimum required speed improvement for safe lane changes (in game units) /// Set to 30 km/h in game units. /// - public SpeedValue MaxMinSafeSpeedImprovement = SpeedValue.FromKmph(30f); + public readonly SpeedValue MaxMinSafeSpeedImprovement = SpeedValue.FromKmph(30); /* * min. required traffic flow improvement for safe lane changes diff --git a/TLM/TLM/TLM.csproj b/TLM/TLM/TLM.csproj index d866bc1a3..5f5898097 100644 --- a/TLM/TLM/TLM.csproj +++ b/TLM/TLM/TLM.csproj @@ -240,8 +240,9 @@ - + + diff --git a/TLM/TLM/UI/SubTools/SpeedLimits/MphSignStyle.cs b/TLM/TLM/UI/SubTools/SpeedLimits/MphSignStyle.cs new file mode 100644 index 000000000..07d245179 --- /dev/null +++ b/TLM/TLM/UI/SubTools/SpeedLimits/MphSignStyle.cs @@ -0,0 +1,11 @@ +namespace TrafficManager.UI.SubTools.SpeedLimits { + /// + /// Defines styles available for road signs + /// + public enum MphSignStyle { + SquareUS = 0, + RoundUK = 1, + RoundGerman = 2, + } + +} \ No newline at end of file diff --git a/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimit.cs b/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimit.cs deleted file mode 100644 index 277120fb7..000000000 --- a/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimit.cs +++ /dev/null @@ -1,196 +0,0 @@ -namespace TrafficManager.UI.SubTools.SpeedLimits { - using System.Collections.Generic; - using State; - using UnityEngine; - using Util; - - /// - /// Defines styles available for road signs - /// - public enum MphSignStyle { - SquareUS = 0, - RoundUK = 1, - RoundGerman = 2, - } - - public enum SpeedUnit { - CurrentlyConfigured, // Currently selected in the options menu - Kmph, - Mph - } - - /// - /// Contains constants and implements algorithms for building the speed limit palette and - /// selecting speeds from the palette. - /// - public class SpeedLimit { - public const int - BREAK_PALETTE_COLUMN_KMPH = 8; // palette shows N in a row, then break and another row - - public const int - BREAK_PALETTE_COLUMN_MPH = 10; // palette shows M in a row, then break and another row - - private const ushort LOWER_KMPH = 10; - public const ushort UPPER_KMPH = 140; - private const ushort KMPH_STEP = 10; - - private const ushort LOWER_MPH = 5; - public const ushort UPPER_MPH = 90; - private const ushort MPH_STEP = 5; - - /// - /// Produces list of speed limits to offer user in the palette - /// - /// What kind of speed limit list is required - /// List from smallest to largest speed with the given unit. Zero (no limit) is not added to the list. - /// The values are in-game speeds as float. - public static List EnumerateSpeedLimits(SpeedUnit unit) { - var result = new List(); - switch (unit) { - case SpeedUnit.Kmph: - for (var km = LOWER_KMPH; km <= UPPER_KMPH; km += KMPH_STEP) { - result.Add(km / Constants.SPEED_TO_KMPH); - } - - break; - case SpeedUnit.Mph: - for (var mi = LOWER_MPH; mi <= UPPER_MPH; mi += MPH_STEP) { - result.Add(mi / Constants.SPEED_TO_MPH); - } - - break; - case SpeedUnit.CurrentlyConfigured: - // Automatically choose from the config - return GlobalConfig.Instance.Main.DisplaySpeedLimitsMph - ? EnumerateSpeedLimits(SpeedUnit.Mph) - : EnumerateSpeedLimits(SpeedUnit.Kmph); - } - - return result; - } - - public static string ToMphPreciseString(float speed) { - if (FloatUtil.IsZero(speed)) { - return Translation.GetString("Speed_limit_unlimited"); - } - - return ToMphPrecise(speed) + " MPH"; - } - - public static string ToKmphPreciseString(float speed) { - if (FloatUtil.IsZero(speed)) { - return Translation.GetString("Speed_limit_unlimited"); - } - - return ToKmphPrecise(speed) + " km/h"; - } - - /// - /// Convert float game speed to mph and round to nearest STEP - /// - /// Speed, scale: 1f=32 MPH - /// Speed in MPH rounded to nearest 5 MPH - public static ushort ToMphRounded(float speed) { - var mph = speed * Constants.SPEED_TO_MPH; - return (ushort)(Mathf.Round(mph / MPH_STEP) * MPH_STEP); - } - - public static ushort ToMphPrecise(float speed) { - return (ushort)Mathf.Round(speed * Constants.SPEED_TO_MPH); - } - - /// - /// Convert float game speed to km/h and round to nearest STEP - /// - /// Speed, scale: 1f=50km/h - /// Speed in km/h rounded to nearest 10 km/h - public static ushort ToKmphRounded(float speed) { - var kmph = speed * Constants.SPEED_TO_KMPH; - return (ushort)(Mathf.Round(kmph / KMPH_STEP) * KMPH_STEP); - } - - public static ushort ToKmphPrecise(float speed) { - return (ushort)Mathf.Round(speed * Constants.SPEED_TO_KMPH); - } - - /// - /// Based on the MPH/KMPH settings round the current speed to the nearest STEP and - /// then decrease by STEP. - /// - /// Ingame speed - /// Ingame speed decreased by the increment for MPH or KMPH - public static float GetPrevious(float speed) { - if (speed < 0f) { - return -1f; - } - - if (GlobalConfig.Instance.Main.DisplaySpeedLimitsMph) { - ushort rounded = ToMphRounded(speed); - if (rounded == LOWER_MPH) { - return 0; - } - - if (rounded == 0) { - return UPPER_MPH / Constants.SPEED_TO_MPH; - } - - return (rounded > LOWER_MPH ? rounded - MPH_STEP : LOWER_MPH) / Constants.SPEED_TO_MPH; - } else { - ushort rounded = ToKmphRounded(speed); - if (rounded == LOWER_KMPH) { - return 0; - } - - if (rounded == 0) { - return UPPER_KMPH / Constants.SPEED_TO_KMPH; - } - - return (rounded > LOWER_KMPH ? rounded - KMPH_STEP : LOWER_KMPH) / Constants.SPEED_TO_KMPH; - } - } - - /// - /// Based on the MPH/KMPH settings round the current speed to the nearest STEP and - /// then increase by STEP. - /// - /// Ingame speed - /// Ingame speed increased by the increment for MPH or KMPH - public static float GetNext(float speed) { - if (speed < 0f) { - return -1f; - } - - if (GlobalConfig.Instance.Main.DisplaySpeedLimitsMph) { - ushort rounded = ToMphRounded(speed); - rounded += MPH_STEP; - - if (rounded > UPPER_MPH) { - rounded = 0; - } - - return rounded / Constants.SPEED_TO_MPH; - } else { - ushort rounded = ToKmphRounded(speed); - rounded += KMPH_STEP; - - if (rounded > UPPER_KMPH) { - rounded = 0; - } - - return rounded / Constants.SPEED_TO_KMPH; - } - } - - /// - /// For US signs and MPH enabled, scale textures vertically by 1.25f. - /// Other signs are round. - /// - /// Multiplier for horizontal sign size - public static float GetVerticalTextureScale() { - return (GlobalConfig.Instance.Main.DisplaySpeedLimitsMph && - GlobalConfig.Instance.Main.MphRoadSignStyle == MphSignStyle.SquareUS) - ? 1.25f - : 1.0f; - } - } -} \ No newline at end of file diff --git a/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimitsTool.cs b/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimitsTool.cs index 0c9794728..1143268c3 100644 --- a/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimitsTool.cs +++ b/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimitsTool.cs @@ -1,6 +1,7 @@ namespace TrafficManager.UI.SubTools.SpeedLimits { using System; using System.Collections.Generic; + using API.Traffic.Data; using ColossalFramework; using ColossalFramework.UI; using CSUtil.Commons; @@ -13,6 +14,20 @@ using Util; public class SpeedLimitsTool : SubTool { + public const int + BREAK_PALETTE_COLUMN_KMPH = 8; // palette shows N in a row, then break and another row + + public const int + BREAK_PALETTE_COLUMN_MPH = 10; // palette shows M in a row, then break and another row + + private const ushort LOWER_KMPH = 10; + public const ushort UPPER_KMPH = 140; + public const ushort KMPH_STEP = 10; + + private const ushort LOWER_MPH = 5; + public const ushort UPPER_MPH = 90; + public const ushort MPH_STEP = 5; + /// Visible sign size, slightly reduced from 100 to accomodate another column for MPH private const int GUI_SPEED_SIGN_SIZE = 80; private readonly float speedLimitSignSize = 70f; @@ -20,7 +35,7 @@ public class SpeedLimitsTool : SubTool { private bool cursorInSecondaryPanel; /// Currently selected speed limit on the limits palette - private float currentPaletteSpeedLimit = -1f; + private SpeedValue currentPaletteSpeedLimit = new SpeedValue(-1f); private readonly Dictionary> segmentCenterByDir = new Dictionary>(); @@ -32,7 +47,7 @@ public class SpeedLimitsTool : SubTool { private readonly HashSet currentlyVisibleSegmentIds; private bool defaultsWindowVisible; private int currentInfoIndex = -1; - private float currentSpeedLimit = -1f; + private SpeedValue currentSpeedLimit = new SpeedValue(-1f); private Texture2D RoadTexture { get { @@ -115,7 +130,7 @@ public override void Cleanup() { lastCamPos = null; lastCamRot = null; currentInfoIndex = -1; - currentSpeedLimit = -1f; + currentSpeedLimit = new SpeedValue(-1f); } private Quaternion? lastCamRot; @@ -222,8 +237,8 @@ private void _guiDefaultsWindow(int num) { UpdateRoadTex(info); } - if (currentSpeedLimit < 0f) { - currentSpeedLimit = SpeedLimitManager.Instance.GetCustomNetInfoSpeedLimit(info); + if (currentSpeedLimit.GameUnits < 0f) { + currentSpeedLimit.GameUnits = SpeedLimitManager.Instance.GetCustomNetInfoSpeedLimit(info); Log._Debug($"set currentSpeedLimit to {currentSpeedLimit}"); } @@ -244,7 +259,7 @@ private void _guiDefaultsWindow(int num) { currentInfoIndex = (currentInfoIndex + mainNetInfos.Count - 1) % mainNetInfos.Count; info = mainNetInfos[currentInfoIndex]; - currentSpeedLimit = SpeedLimitManager.Instance.GetCustomNetInfoSpeedLimit(info); + currentSpeedLimit.GameUnits = SpeedLimitManager.Instance.GetCustomNetInfoSpeedLimit(info); UpdateRoadTex(info); } @@ -268,7 +283,7 @@ private void _guiDefaultsWindow(int num) { if (GUILayout.Button("→", GUILayout.Width(50))) { currentInfoIndex = (currentInfoIndex + 1) % mainNetInfos.Count; info = mainNetInfos[currentInfoIndex]; - currentSpeedLimit = SpeedLimitManager.Instance.GetCustomNetInfoSpeedLimit(info); + currentSpeedLimit.GameUnits = SpeedLimitManager.Instance.GetCustomNetInfoSpeedLimit(info); UpdateRoadTex(info); } @@ -297,7 +312,7 @@ private void _guiDefaultsWindow(int num) { // currentSpeedLimit = (currentSpeedLimitIndex + // SpeedLimitManager.Instance.AvailableSpeedLimits.Count - 1) // % SpeedLimitManager.Instance.AvailableSpeedLimits.Count; - currentSpeedLimit = SpeedLimit.GetPrevious(currentSpeedLimit); + currentSpeedLimit = GetPrevious(currentSpeedLimit); } GUILayout.FlexibleSpace(); @@ -327,7 +342,7 @@ private void _guiDefaultsWindow(int num) { if (GUILayout.Button("→", GUILayout.Width(50))) { // currentSpeedLimitIndex = (currentSpeedLimitIndex + 1) % // SpeedLimitManager.Instance.AvailableSpeedLimits.Count; - currentSpeedLimit = SpeedLimit.GetNext(currentSpeedLimit); + currentSpeedLimit = GetNext(currentSpeedLimit); } GUILayout.FlexibleSpace(); @@ -352,7 +367,7 @@ private void _guiDefaultsWindow(int num) { if (GUILayout.Button(Translation.GetString("Save"), GUILayout.Width(70))) { SpeedLimitManager.Instance.FixCurrentSpeedLimits(info); - SpeedLimitManager.Instance.SetCustomNetInfoSpeedLimit(info, currentSpeedLimit); + SpeedLimitManager.Instance.SetCustomNetInfoSpeedLimit(info, currentSpeedLimit.GameUnits); } GUILayout.FlexibleSpace(); @@ -360,7 +375,7 @@ private void _guiDefaultsWindow(int num) { if (GUILayout.Button( Translation.GetString("Save") + " & " + Translation.GetString("Apply"), GUILayout.Width(160))) { - SpeedLimitManager.Instance.SetCustomNetInfoSpeedLimit(info, currentSpeedLimit); + SpeedLimitManager.Instance.SetCustomNetInfoSpeedLimit(info, currentSpeedLimit.GameUnits); SpeedLimitManager.Instance.ClearCurrentSpeedLimits(info); } @@ -424,17 +439,16 @@ private void GuiSpeedLimitsWindow(int num) { GUILayout.FlexibleSpace(); Color oldColor = GUI.color; - List allSpeedLimits = SpeedLimit.EnumerateSpeedLimits(SpeedUnit.CurrentlyConfigured); - allSpeedLimits.Add(0); // add last item: no limit + List allSpeedLimits = EnumerateSpeedLimits(SpeedUnit.CurrentlyConfigured); + allSpeedLimits.Add(new SpeedValue(0)); // add last item: no limit bool showMph = GlobalConfig.Instance.Main.DisplaySpeedLimitsMph; var column = 0u; // break palette to a new line at breakColumn - int breakColumn = showMph ? SpeedLimit.BREAK_PALETTE_COLUMN_MPH - : SpeedLimit.BREAK_PALETTE_COLUMN_KMPH; + int breakColumn = showMph ? BREAK_PALETTE_COLUMN_MPH : BREAK_PALETTE_COLUMN_KMPH; - foreach (float speedLimit in allSpeedLimits) { + foreach (SpeedValue speedLimit in allSpeedLimits) { // Highlight palette item if it is very close to its float speed - if (FloatUtil.NearlyEqual(currentPaletteSpeedLimit, speedLimit)) { + if (FloatUtil.NearlyEqual(currentPaletteSpeedLimit.GameUnits, speedLimit.GameUnits)) { GUI.color = Color.gray; } @@ -497,7 +511,7 @@ private void GuiSpeedLimitsWindow(int num) { /// Helper to create speed limit sign + label below converted to the opposite unit /// Config value from GlobalConfig.I.M.ShowMPH /// The float speed to show - private void GuiSpeedLimitsWindow_AddButton(bool showMph, float speedLimit) { + private void GuiSpeedLimitsWindow_AddButton(bool showMph, SpeedValue speedLimit) { // The button is wrapped in vertical sub-layout and a label for MPH/KMPH is added GUILayout.BeginVertical(); @@ -507,7 +521,7 @@ private void GuiSpeedLimitsWindow_AddButton(bool showMph, float speedLimit) { if (GUILayout.Button( SpeedLimitTextures.GetSpeedLimitTexture(speedLimit), GUILayout.Width(signSize), - GUILayout.Height(signSize * SpeedLimit.GetVerticalTextureScale()))) { + GUILayout.Height(signSize * GetVerticalTextureScale()))) { currentPaletteSpeedLimit = speedLimit; } @@ -519,8 +533,8 @@ private void GuiSpeedLimitsWindow_AddButton(bool showMph, float speedLimit) { GUILayout.FlexibleSpace(); GUILayout.Label( showMph - ? SpeedLimit.ToKmphPreciseString(speedLimit) - : SpeedLimit.ToMphPreciseString(speedLimit)); + ? ToKmphPreciseString(speedLimit) + : ToMphPreciseString(speedLimit)); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); @@ -539,7 +553,9 @@ private bool drawSpeedLimitHandles(ushort segmentId, Vector3 center = segment.m_bounds.center; NetManager netManager = Singleton.instance; var hovered = false; - float speedLimitToSet = viewOnly ? -1f : currentPaletteSpeedLimit; + SpeedValue speedLimitToSet = viewOnly + ? new SpeedValue(-1f) + : currentPaletteSpeedLimit; bool showPerLane = showLimitsPerLane; if (!viewOnly) { @@ -549,7 +565,7 @@ private bool drawSpeedLimitHandles(ushort segmentId, } // US signs are rectangular, all other are round - float speedLimitSignVerticalScale = SpeedLimit.GetVerticalTextureScale(); + float speedLimitSignVerticalScale = GetVerticalTextureScale(); if (showPerLane) { // show individual speed limit handle per lane @@ -607,7 +623,9 @@ private bool drawSpeedLimitHandles(ushort segmentId, directions.Add(laneInfo.m_finalDirection); } - float laneSpeedLimit = SpeedLimitManager.Instance.GetCustomSpeedLimit(laneId); + SpeedValue laneSpeedLimit = new SpeedValue( + SpeedLimitManager.Instance.GetCustomSpeedLimit(laneId)); + bool hoveredHandle = MainTool.DrawGenericOverlayGridTexture( SpeedLimitTextures.GetSpeedLimitTexture(laneSpeedLimit), camPos, @@ -651,7 +669,7 @@ private bool drawSpeedLimitHandles(ushort segmentId, laneIndex, laneInfo, laneId, - speedLimitToSet); + speedLimitToSet.GameUnits); if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) { int slIndexCopy = sortedLaneIndex; @@ -685,7 +703,7 @@ private bool drawSpeedLimitHandles(ushort segmentId, data.CurLanePos.laneIndex, curLaneInfo, data.CurLanePos.laneId, - speedLimitToSet); + speedLimitToSet.GameUnits); return true; }); @@ -732,15 +750,19 @@ private bool drawSpeedLimitHandles(ushort segmentId, // Draw something right here, the road sign texture GUI.color = guiColor; - float displayLimit = SpeedLimitManager.Instance.GetCustomSpeedLimit(segmentId, e.Key); + SpeedValue displayLimit = new SpeedValue( + SpeedLimitManager.Instance.GetCustomSpeedLimit(segmentId, e.Key)); Texture2D tex = SpeedLimitTextures.GetSpeedLimitTexture(displayLimit); + GUI.DrawTexture(boundingBox, tex); if (hoveredHandle && Input.GetMouseButton(0) && !IsCursorInPanel()) { // change the speed limit to the selected one // Log._Debug($"Setting speed limit of segment {segmentId}, dir {e.Key.ToString()} // to {speedLimitToSet}"); - SpeedLimitManager.Instance.SetSpeedLimit(segmentId, e.Key, currentPaletteSpeedLimit); + SpeedLimitManager.Instance.SetSpeedLimit(segmentId, + e.Key, + currentPaletteSpeedLimit.GameUnits); if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) { NetInfo.Direction normDir = e.Key; @@ -785,7 +807,7 @@ private bool drawSpeedLimitHandles(ushort segmentId, SpeedLimitManager.Instance.SetSpeedLimit( otherSegmentId, laneInfo.m_finalDirection, - speedLimitToSet); + speedLimitToSet.GameUnits); } return true; @@ -800,5 +822,133 @@ private bool drawSpeedLimitHandles(ushort segmentId, return hovered; } + + public static string ToMphPreciseString(SpeedValue speed) { + return FloatUtil.IsZero(speed.GameUnits) + ? Translation.GetString("Speed_limit_unlimited") + : speed.ToMphPrecise().ToString(); + } + + public static string ToKmphPreciseString(SpeedValue speed) { + return FloatUtil.IsZero(speed.GameUnits) + ? Translation.GetString("Speed_limit_unlimited") + : speed.ToKmphPrecise().ToString(); + } + + /// + /// Produces list of speed limits to offer user in the palette + /// + /// What kind of speed limit list is required + /// List from smallest to largest speed with the given unit. Zero (no limit) is not added to the list. + /// The values are in-game speeds as float. + public static List EnumerateSpeedLimits(SpeedUnit unit) { + var result = new List(); + switch (unit) { + case SpeedUnit.Kmph: + for (var km = LOWER_KMPH; km <= UPPER_KMPH; km += KMPH_STEP) { + result.Add(SpeedValue.FromKmph(km)); + } + + break; + case SpeedUnit.Mph: + for (var mi = LOWER_MPH; mi <= UPPER_MPH; mi += MPH_STEP) { + result.Add(SpeedValue.FromMph(mi)); + } + + break; + case SpeedUnit.CurrentlyConfigured: + // Automatically choose from the config + return GlobalConfig.Instance.Main.DisplaySpeedLimitsMph + ? EnumerateSpeedLimits(SpeedUnit.Mph) + : EnumerateSpeedLimits(SpeedUnit.Kmph); + } + + return result; + } + + /// + /// Based on the MPH/KMPH settings round the current speed to the nearest STEP and + /// then decrease by STEP. + /// + /// Ingame speed + /// Ingame speed decreased by the increment for MPH or KMPH + public static SpeedValue GetPrevious(SpeedValue speed) { + if (speed.GameUnits < 0f) { + return new SpeedValue(-1f); + } + + if (GlobalConfig.Instance.Main.DisplaySpeedLimitsMph) { + MphValue rounded = speed.ToMphRounded(MPH_STEP); + if (rounded.Mph == LOWER_MPH) { + return new SpeedValue(0); + } + + if (rounded.Mph == 0) { + return SpeedValue.FromMph(UPPER_MPH); + } + + return SpeedValue.FromMph(rounded.Mph > LOWER_MPH + ? (ushort)(rounded.Mph - MPH_STEP) + : LOWER_MPH); + } else { + KmphValue rounded = speed.ToKmphRounded(KMPH_STEP); + if (rounded.Kmph == LOWER_KMPH) { + return new SpeedValue(0); + } + + if (rounded.Kmph == 0) { + return SpeedValue.FromKmph(UPPER_KMPH); + } + + return SpeedValue.FromKmph(rounded.Kmph > LOWER_KMPH + ? (ushort)(rounded.Kmph - KMPH_STEP) + : LOWER_KMPH); + } + } + + /// + /// Based on the MPH/KMPH settings round the current speed to the nearest STEP and + /// then increase by STEP. + /// + /// Ingame speed + /// Ingame speed increased by the increment for MPH or KMPH + public static SpeedValue GetNext(SpeedValue speed) { + if (speed.GameUnits < 0f) { + return new SpeedValue(-1f); + } + + if (GlobalConfig.Instance.Main.DisplaySpeedLimitsMph) { + MphValue rounded = speed.ToMphRounded(MPH_STEP); + rounded.Mph += MPH_STEP; + + if (rounded.Mph > UPPER_MPH) { + rounded.Mph = 0; + } + + return SpeedValue.FromMph(rounded); + } else { + KmphValue rounded = speed.ToKmphRounded(KMPH_STEP); + rounded.Kmph += KMPH_STEP; + + if (rounded.Kmph > UPPER_KMPH) { + rounded.Kmph = 0; + } + + return SpeedValue.FromKmph(rounded); + } + } + + /// + /// For US signs and MPH enabled, scale textures vertically by 1.25f. + /// Other signs are round. + /// + /// Multiplier for horizontal sign size + public static float GetVerticalTextureScale() { + return (GlobalConfig.Instance.Main.DisplaySpeedLimitsMph && + GlobalConfig.Instance.Main.MphRoadSignStyle == MphSignStyle.SquareUS) + ? 1.25f + : 1.0f; + } + } // end class } \ No newline at end of file diff --git a/TLM/TLM/UI/SubTools/SpeedLimits/SpeedUnit.cs b/TLM/TLM/UI/SubTools/SpeedLimits/SpeedUnit.cs new file mode 100644 index 000000000..953154426 --- /dev/null +++ b/TLM/TLM/UI/SubTools/SpeedLimits/SpeedUnit.cs @@ -0,0 +1,7 @@ +namespace TrafficManager.UI.SubTools.SpeedLimits { + public enum SpeedUnit { + CurrentlyConfigured, // Currently selected in the options menu + Kmph, + Mph + } +} diff --git a/TLM/TLM/UI/Textures/SpeedLimitTextures.cs b/TLM/TLM/UI/Textures/SpeedLimitTextures.cs index 9d6da3df3..f45d96b2f 100644 --- a/TLM/TLM/UI/Textures/SpeedLimitTextures.cs +++ b/TLM/TLM/UI/Textures/SpeedLimitTextures.cs @@ -1,6 +1,7 @@ namespace TrafficManager.UI.Textures { using System; using System.Collections.Generic; + using API.Traffic.Data; using State; using SubTools.SpeedLimits; using UnityEngine; @@ -38,11 +39,11 @@ static SpeedLimitTextures() { /// /// Given the float speed, style and MPH option return a texture to render. /// - /// float speed + /// float speed /// Signs theme /// Mph or km/h /// - public static Texture2D GetSpeedLimitTexture(float speedLimit, MphSignStyle mphStyle, SpeedUnit unit) { + public static Texture2D GetSpeedLimitTexture(SpeedValue spd, MphSignStyle mphStyle, SpeedUnit unit) { // Select the source for the textures based on unit and the theme bool mph = unit == SpeedUnit.Mph; IDictionary textures = TexturesKmph; @@ -61,10 +62,12 @@ public static Texture2D GetSpeedLimitTexture(float speedLimit, MphSignStyle mphS } // Round to nearest 5 MPH or nearest 10 km/h - ushort index = mph ? SpeedLimit.ToMphRounded(speedLimit) : SpeedLimit.ToKmphRounded(speedLimit); + ushort index = mph ? spd.ToMphRounded(SpeedLimitsTool.MPH_STEP).Mph + : spd.ToKmphRounded(SpeedLimitsTool.KMPH_STEP).Kmph; // Trim the index since 140 km/h / 90 MPH is the max sign we have - ushort upper = mph ? SpeedLimit.UPPER_MPH : SpeedLimit.UPPER_KMPH; + ushort upper = mph ? SpeedLimitsTool.UPPER_MPH + : SpeedLimitsTool.UPPER_KMPH; // Show unlimited if the speed cannot be represented by the available sign textures if (index == 0 || index > upper) { @@ -80,12 +83,12 @@ public static Texture2D GetSpeedLimitTexture(float speedLimit, MphSignStyle mphS /// /// Given speed limit, round it up to nearest Kmph or Mph and produce a texture /// - /// Ingame speed + /// Ingame speed /// The texture, hopefully it existed - public static Texture2D GetSpeedLimitTexture(float speedLimit) { + public static Texture2D GetSpeedLimitTexture(SpeedValue spd) { var m = GlobalConfig.Instance.Main; var unit = m.DisplaySpeedLimitsMph ? SpeedUnit.Mph : SpeedUnit.Kmph; - return GetSpeedLimitTexture(speedLimit, m.MphRoadSignStyle, unit); + return GetSpeedLimitTexture(spd, m.MphRoadSignStyle, unit); } } } \ No newline at end of file diff --git a/TLM/TLM/UI/TrafficManagerTool.cs b/TLM/TLM/UI/TrafficManagerTool.cs index c7c93560f..4cfd67d8e 100644 --- a/TLM/TLM/UI/TrafficManagerTool.cs +++ b/TLM/TLM/UI/TrafficManagerTool.cs @@ -1315,8 +1315,7 @@ private void GuiDisplayVehicles() { // ushort segmentId = vState.currentSegmentId; // Converting magnitudes into game speed float, and then into km/h - float vehSpeed = SpeedLimit.ToKmphPrecise( - vehicleManager.m_vehicles.m_buffer[i].GetLastFrameVelocity().magnitude / 8f); + SpeedValue vehSpeed = SpeedValue.FromVelocity(vehicleManager.m_vehicles.m_buffer[i].GetLastFrameVelocity().magnitude); #if DEBUG if (GlobalConfig.Instance.Debug.ExtPathMode != ExtPathMode.None && driverInst.pathMode != GlobalConfig.Instance.Debug.ExtPathMode) { @@ -1324,7 +1323,7 @@ private void GuiDisplayVehicles() { } #endif string labelStr = string.Format( - "V #{0} is a {1}{2} {3} @ ~{4:0.0} km/h (len: {5:0.0}, {6} @ {7} ({8}), l. {9} " + + "V #{0} is a {1}{2} {3} @ ~{4} (len: {5:0.0}, {6} @ {7} ({8}), l. {9} " + "-> {10}, l. {11}), w: {12}\n" + "di: {13} dc: {14} m: {15} f: {16} l: {17} lid: {18} ltsu: {19} lpu: {20} " + "als: {21} srnd: {22} trnd: {23}", @@ -1332,7 +1331,7 @@ private void GuiDisplayVehicles() { vState.recklessDriver ? "reckless " : string.Empty, vState.flags, vState.vehicleType, - vehSpeed, + vehSpeed.ToKmphPrecise().ToString(), vState.totalLength, vState.junctionTransitState, vState.currentSegmentId, diff --git a/TLM/TMPE.API/Traffic/ApiConstants.cs b/TLM/TMPE.API/Traffic/ApiConstants.cs index aa7e5f13a..c17febb26 100644 --- a/TLM/TMPE.API/Traffic/ApiConstants.cs +++ b/TLM/TMPE.API/Traffic/ApiConstants.cs @@ -8,6 +8,11 @@ public static class ApiConstants { /// /// Conversion rate from MPH to game speed (also exists in TrafficManager.Constants) /// - private const float SPEED_TO_MPH = 32.06f; // 50 km/h converted to mph + public const float SPEED_TO_MPH = 32.06f; // 50 km/h converted to mph + + /// + /// Multiplier used to convert between game speedlimits and velocities (directed speeds) + /// + public const float SPEED_TO_VELOCITY = 8f; } } \ No newline at end of file diff --git a/TLM/TMPE.API/Traffic/Data/SpeedValue.cs b/TLM/TMPE.API/Traffic/Data/SpeedValue.cs index d23e9bec6..13364ca33 100644 --- a/TLM/TMPE.API/Traffic/Data/SpeedValue.cs +++ b/TLM/TMPE.API/Traffic/Data/SpeedValue.cs @@ -1,12 +1,21 @@ namespace TrafficManager.API.Traffic.Data { using System; + using UnityEngine; /// /// Represents a speed value expressed in km/hour. /// [Serializable] public struct KmphValue { - public float Kmph { get; } + public KmphValue(ushort kmph) { + Kmph = kmph; + } + + public override string ToString() { + return $"{Kmph:0.0} km/h"; + } + + public ushort Kmph { get; set; } } /// @@ -14,7 +23,15 @@ public struct KmphValue { /// [Serializable] public struct MphValue { - public float Mph { get; } + public MphValue(ushort mph) { + Mph = mph; + } + + public override string ToString() { + return $"{Mph} MPH"; + } + + public ushort Mph { get; set; } } /// @@ -22,14 +39,66 @@ public struct MphValue { /// [Serializable] public struct SpeedValue { - public SpeedValue(float gameSpeed) { - GameSpeed = gameSpeed; + public SpeedValue(float gameUnits) { + GameUnits = gameUnits; + } + + public float GameUnits { get; set; } + + public float ToVelocity() { + return GameUnits * ApiConstants.SPEED_TO_VELOCITY; + } + + public static SpeedValue FromKmph(ushort kmph) { + return new SpeedValue(kmph / ApiConstants.SPEED_TO_KMPH); + } + + public static SpeedValue FromVelocity(float vel) { + return new SpeedValue(vel / ApiConstants.SPEED_TO_VELOCITY); + } + + public static SpeedValue FromKmph(KmphValue kmph) { + return new SpeedValue(kmph.Kmph / ApiConstants.SPEED_TO_KMPH); + } + + public static SpeedValue operator -(SpeedValue x, SpeedValue y) { + return new SpeedValue(x.GameUnits - y.GameUnits); + } + + public static SpeedValue FromMph(ushort mph) { + return new SpeedValue(mph / ApiConstants.SPEED_TO_MPH); } - public float GameSpeed { get; } + public static SpeedValue FromMph(MphValue mph) { + return new SpeedValue(mph.Mph / ApiConstants.SPEED_TO_MPH); + } + + /// + /// Convert float game speed to mph and round to nearest STEP + /// + /// Rounds to the nearest step units + /// Speed in MPH rounded to nearest step (5 MPH) + public MphValue ToMphRounded(float step) { + float mph = GameUnits * ApiConstants.SPEED_TO_MPH; + return new MphValue((ushort)(Mathf.Round(mph / step) * step)); + } + + /// + /// Convert float game speed to km/h and round to nearest STEP + /// + /// Speed, scale: 1f=50km/h + /// Speed in km/h rounded to nearest 10 km/h + public KmphValue ToKmphRounded(float step) { + float kmph = GameUnits * ApiConstants.SPEED_TO_KMPH; + return new KmphValue((ushort)(Mathf.Round(kmph / step) * step)); + } + + public MphValue ToMphPrecise() { + return new MphValue((ushort)Mathf.Round(GameUnits * ApiConstants.SPEED_TO_MPH)); + } - public static SpeedValue FromKmph(float f) { - return new SpeedValue(f / ApiConstants.SPEED_TO_KMPH); + public KmphValue ToKmphPrecise() { + return new KmphValue((ushort)Mathf.Round(GameUnits * ApiConstants.SPEED_TO_KMPH)); } } } From 4b3cab01f21c66e875709bb0193f3e0806465bd8 Mon Sep 17 00:00:00 2001 From: dmytro lytovchenko Date: Thu, 1 Aug 2019 22:58:07 +0200 Subject: [PATCH 3/8] Add xmldoc to SpeedValue --- TLM/TMPE.API/Traffic/Data/SpeedValue.cs | 68 ++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 8 deletions(-) diff --git a/TLM/TMPE.API/Traffic/Data/SpeedValue.cs b/TLM/TMPE.API/Traffic/Data/SpeedValue.cs index 13364ca33..a466eaecb 100644 --- a/TLM/TMPE.API/Traffic/Data/SpeedValue.cs +++ b/TLM/TMPE.API/Traffic/Data/SpeedValue.cs @@ -1,5 +1,6 @@ namespace TrafficManager.API.Traffic.Data { using System; + using JetBrains.Annotations; using UnityEngine; /// @@ -39,40 +40,83 @@ public override string ToString() { /// [Serializable] public struct SpeedValue { + /// + /// Constructs a SpeedValue from game units float + /// + /// The value in game speed units public SpeedValue(float gameUnits) { GameUnits = gameUnits; } + /// + /// Sets or returns stored value in game units (no conversion) + /// public float GameUnits { get; set; } + /// + /// Converts stored value in game units into velocity magnitude (8x the game units) + /// + /// + [UsedImplicitly] public float ToVelocity() { return GameUnits * ApiConstants.SPEED_TO_VELOCITY; } - public static SpeedValue FromKmph(ushort kmph) { - return new SpeedValue(kmph / ApiConstants.SPEED_TO_KMPH); - } - + /// + /// Constructs a SpeedValue from velocity magnitude (8x the game units) + /// + /// The velocity value originating from a vehicle velocity + /// A new SpeedValue downscaled to game units public static SpeedValue FromVelocity(float vel) { return new SpeedValue(vel / ApiConstants.SPEED_TO_VELOCITY); } - public static SpeedValue FromKmph(KmphValue kmph) { - return new SpeedValue(kmph.Kmph / ApiConstants.SPEED_TO_KMPH); + /// + /// Constructs a SpeedValue from km/hour given as an integer + /// + /// A speed in kilometres/hour + /// A new speedvalue converted to the game units + public static SpeedValue FromKmph(ushort kmph) { + return new SpeedValue(kmph / ApiConstants.SPEED_TO_KMPH); } - public static SpeedValue operator -(SpeedValue x, SpeedValue y) { - return new SpeedValue(x.GameUnits - y.GameUnits); + /// + /// Constructs a speed value from km/hour given as a KmphValue + /// + /// Km/hour typed value + /// A new SpeedValue scaled to the game units + public static SpeedValue FromKmph(KmphValue kmph) { + return new SpeedValue(kmph.Kmph / ApiConstants.SPEED_TO_KMPH); } + /// + /// Constructs a SpeedValue from miles/hour given as an integer + /// + /// A speed in miles/hour + /// A new speedvalue converted to the game units public static SpeedValue FromMph(ushort mph) { return new SpeedValue(mph / ApiConstants.SPEED_TO_MPH); } + /// + /// Constructs a speed value from miles/hour given as a MphValue + /// + /// Miles/hour typed value + /// A new SpeedValue scaled to the game units public static SpeedValue FromMph(MphValue mph) { return new SpeedValue(mph.Mph / ApiConstants.SPEED_TO_MPH); } + /// + /// Subtracts two speed values + /// + /// First value + /// Second value + /// A new SpeedValue which is a difference between x and y + public static SpeedValue operator -(SpeedValue x, SpeedValue y) { + return new SpeedValue(x.GameUnits - y.GameUnits); + } + /// /// Convert float game speed to mph and round to nearest STEP /// @@ -93,10 +137,18 @@ public KmphValue ToKmphRounded(float step) { return new KmphValue((ushort)(Mathf.Round(kmph / step) * step)); } + /// + /// Converts this SpeedValue into miles/hour + /// + /// A typed mph value with integer miles/hour public MphValue ToMphPrecise() { return new MphValue((ushort)Mathf.Round(GameUnits * ApiConstants.SPEED_TO_MPH)); } + /// + /// Converts this SpeedValue into km/hour + /// + /// A typed km/h value with integer km/hour public KmphValue ToKmphPrecise() { return new KmphValue((ushort)Mathf.Round(GameUnits * ApiConstants.SPEED_TO_KMPH)); } From 456d56a5d3490e6b38383efb4f30e4d8ace81d8d Mon Sep 17 00:00:00 2001 From: dmytro lytovchenko Date: Thu, 1 Aug 2019 23:39:35 +0200 Subject: [PATCH 4/8] FloatUtil is marked as static --- TLM/TLM/Util/FloatUtil.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TLM/TLM/Util/FloatUtil.cs b/TLM/TLM/Util/FloatUtil.cs index aeb83ea45..29ab7235d 100644 --- a/TLM/TLM/Util/FloatUtil.cs +++ b/TLM/TLM/Util/FloatUtil.cs @@ -5,7 +5,7 @@ namespace TrafficManager.Util { /// /// Provides static functions for handling floating point values. /// - public class FloatUtil { + public static class FloatUtil { /// /// A very small value for float comparisons to zero /// From 1e6a510fa5214d7b71e40ee34ec1ea45cb1b9c98 Mon Sep 17 00:00:00 2001 From: dmytro lytovchenko Date: Fri, 2 Aug 2019 00:00:09 +0200 Subject: [PATCH 5/8] SpeedValue, Mph and KmphValue are now readonly --- .../UI/SubTools/SpeedLimits/SpeedLimitsTool.cs | 17 ++++++++++------- TLM/TMPE.API/Traffic/Data/SpeedValue.cs | 6 +++--- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimitsTool.cs b/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimitsTool.cs index 1143268c3..6ec095977 100644 --- a/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimitsTool.cs +++ b/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimitsTool.cs @@ -238,7 +238,8 @@ private void _guiDefaultsWindow(int num) { } if (currentSpeedLimit.GameUnits < 0f) { - currentSpeedLimit.GameUnits = SpeedLimitManager.Instance.GetCustomNetInfoSpeedLimit(info); + currentSpeedLimit = new SpeedValue( + SpeedLimitManager.Instance.GetCustomNetInfoSpeedLimit(info)); Log._Debug($"set currentSpeedLimit to {currentSpeedLimit}"); } @@ -259,7 +260,8 @@ private void _guiDefaultsWindow(int num) { currentInfoIndex = (currentInfoIndex + mainNetInfos.Count - 1) % mainNetInfos.Count; info = mainNetInfos[currentInfoIndex]; - currentSpeedLimit.GameUnits = SpeedLimitManager.Instance.GetCustomNetInfoSpeedLimit(info); + currentSpeedLimit = new SpeedValue( + SpeedLimitManager.Instance.GetCustomNetInfoSpeedLimit(info)); UpdateRoadTex(info); } @@ -283,7 +285,8 @@ private void _guiDefaultsWindow(int num) { if (GUILayout.Button("→", GUILayout.Width(50))) { currentInfoIndex = (currentInfoIndex + 1) % mainNetInfos.Count; info = mainNetInfos[currentInfoIndex]; - currentSpeedLimit.GameUnits = SpeedLimitManager.Instance.GetCustomNetInfoSpeedLimit(info); + currentSpeedLimit = new SpeedValue( + SpeedLimitManager.Instance.GetCustomNetInfoSpeedLimit(info)); UpdateRoadTex(info); } @@ -919,19 +922,19 @@ public static SpeedValue GetNext(SpeedValue speed) { if (GlobalConfig.Instance.Main.DisplaySpeedLimitsMph) { MphValue rounded = speed.ToMphRounded(MPH_STEP); - rounded.Mph += MPH_STEP; + rounded = new MphValue((ushort)(rounded.Mph + MPH_STEP)); if (rounded.Mph > UPPER_MPH) { - rounded.Mph = 0; + rounded = new MphValue(0); } return SpeedValue.FromMph(rounded); } else { KmphValue rounded = speed.ToKmphRounded(KMPH_STEP); - rounded.Kmph += KMPH_STEP; + rounded = new KmphValue((ushort)(rounded.Kmph + KMPH_STEP)); if (rounded.Kmph > UPPER_KMPH) { - rounded.Kmph = 0; + rounded = new KmphValue(0); } return SpeedValue.FromKmph(rounded); diff --git a/TLM/TMPE.API/Traffic/Data/SpeedValue.cs b/TLM/TMPE.API/Traffic/Data/SpeedValue.cs index a466eaecb..05f36f02b 100644 --- a/TLM/TMPE.API/Traffic/Data/SpeedValue.cs +++ b/TLM/TMPE.API/Traffic/Data/SpeedValue.cs @@ -16,7 +16,7 @@ public override string ToString() { return $"{Kmph:0.0} km/h"; } - public ushort Kmph { get; set; } + public ushort Kmph { get; } } /// @@ -32,7 +32,7 @@ public override string ToString() { return $"{Mph} MPH"; } - public ushort Mph { get; set; } + public ushort Mph { get; } } /// @@ -51,7 +51,7 @@ public SpeedValue(float gameUnits) { /// /// Sets or returns stored value in game units (no conversion) /// - public float GameUnits { get; set; } + public float GameUnits { get; } /// /// Converts stored value in game units into velocity magnitude (8x the game units) From 5d3f7eaece15c44f03b4006e527200b37a1fc874 Mon Sep 17 00:00:00 2001 From: dmytro lytovchenko Date: Fri, 2 Aug 2019 00:23:35 +0200 Subject: [PATCH 6/8] Speed value structs are readonly now. Added operator + (K|mphValue, ushort) for convenience --- .../SubTools/SpeedLimits/SpeedLimitsTool.cs | 4 +- TLM/TMPE.API/Traffic/Data/SpeedValue.cs | 66 +++++++++---------- 2 files changed, 32 insertions(+), 38 deletions(-) diff --git a/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimitsTool.cs b/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimitsTool.cs index 6ec095977..4ecf97150 100644 --- a/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimitsTool.cs +++ b/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimitsTool.cs @@ -922,7 +922,7 @@ public static SpeedValue GetNext(SpeedValue speed) { if (GlobalConfig.Instance.Main.DisplaySpeedLimitsMph) { MphValue rounded = speed.ToMphRounded(MPH_STEP); - rounded = new MphValue((ushort)(rounded.Mph + MPH_STEP)); + rounded += MPH_STEP; if (rounded.Mph > UPPER_MPH) { rounded = new MphValue(0); @@ -931,7 +931,7 @@ public static SpeedValue GetNext(SpeedValue speed) { return SpeedValue.FromMph(rounded); } else { KmphValue rounded = speed.ToKmphRounded(KMPH_STEP); - rounded = new KmphValue((ushort)(rounded.Kmph + KMPH_STEP)); + rounded += KMPH_STEP; if (rounded.Kmph > UPPER_KMPH) { rounded = new KmphValue(0); diff --git a/TLM/TMPE.API/Traffic/Data/SpeedValue.cs b/TLM/TMPE.API/Traffic/Data/SpeedValue.cs index 05f36f02b..2595888c4 100644 --- a/TLM/TMPE.API/Traffic/Data/SpeedValue.cs +++ b/TLM/TMPE.API/Traffic/Data/SpeedValue.cs @@ -7,39 +7,43 @@ namespace TrafficManager.API.Traffic.Data { /// Represents a speed value expressed in km/hour. /// [Serializable] - public struct KmphValue { + public readonly struct KmphValue { public KmphValue(ushort kmph) { Kmph = kmph; } - public override string ToString() { - return $"{Kmph:0.0} km/h"; - } + public override string ToString() => $"{Kmph:0.0} km/h"; public ushort Kmph { get; } + + /// A new KmphValue increased by right + public static KmphValue operator +(KmphValue left, ushort right) + => new KmphValue((ushort)(left.Kmph + right)); } /// /// Represents a speed value expressed in miles/hour. /// [Serializable] - public struct MphValue { + public readonly struct MphValue { public MphValue(ushort mph) { Mph = mph; } - public override string ToString() { - return $"{Mph} MPH"; - } + public override string ToString() => $"{Mph} MPH"; public ushort Mph { get; } + + /// A new MphValue increased by right + public static MphValue operator +(MphValue left, ushort right) + => new MphValue((ushort)(left.Mph + right)); } /// /// Represents a speed value expressed in game units where 1f = 50 km/h or 32 MPH. /// [Serializable] - public struct SpeedValue { + public readonly struct SpeedValue { /// /// Constructs a SpeedValue from game units float /// @@ -58,54 +62,47 @@ public SpeedValue(float gameUnits) { /// /// [UsedImplicitly] - public float ToVelocity() { - return GameUnits * ApiConstants.SPEED_TO_VELOCITY; - } + public float ToVelocity() => GameUnits * ApiConstants.SPEED_TO_VELOCITY; /// /// Constructs a SpeedValue from velocity magnitude (8x the game units) /// /// The velocity value originating from a vehicle velocity /// A new SpeedValue downscaled to game units - public static SpeedValue FromVelocity(float vel) { - return new SpeedValue(vel / ApiConstants.SPEED_TO_VELOCITY); - } + public static SpeedValue FromVelocity(float vel) + => new SpeedValue(vel / ApiConstants.SPEED_TO_VELOCITY); /// /// Constructs a SpeedValue from km/hour given as an integer /// /// A speed in kilometres/hour /// A new speedvalue converted to the game units - public static SpeedValue FromKmph(ushort kmph) { - return new SpeedValue(kmph / ApiConstants.SPEED_TO_KMPH); - } + public static SpeedValue FromKmph(ushort kmph) + => new SpeedValue(kmph / ApiConstants.SPEED_TO_KMPH); /// /// Constructs a speed value from km/hour given as a KmphValue /// /// Km/hour typed value /// A new SpeedValue scaled to the game units - public static SpeedValue FromKmph(KmphValue kmph) { - return new SpeedValue(kmph.Kmph / ApiConstants.SPEED_TO_KMPH); - } + public static SpeedValue FromKmph(KmphValue kmph) + => new SpeedValue(kmph.Kmph / ApiConstants.SPEED_TO_KMPH); /// /// Constructs a SpeedValue from miles/hour given as an integer /// /// A speed in miles/hour /// A new speedvalue converted to the game units - public static SpeedValue FromMph(ushort mph) { - return new SpeedValue(mph / ApiConstants.SPEED_TO_MPH); - } + public static SpeedValue FromMph(ushort mph) + => new SpeedValue(mph / ApiConstants.SPEED_TO_MPH); /// /// Constructs a speed value from miles/hour given as a MphValue /// /// Miles/hour typed value /// A new SpeedValue scaled to the game units - public static SpeedValue FromMph(MphValue mph) { - return new SpeedValue(mph.Mph / ApiConstants.SPEED_TO_MPH); - } + public static SpeedValue FromMph(MphValue mph) + => new SpeedValue(mph.Mph / ApiConstants.SPEED_TO_MPH); /// /// Subtracts two speed values @@ -113,9 +110,8 @@ public static SpeedValue FromMph(MphValue mph) { /// First value /// Second value /// A new SpeedValue which is a difference between x and y - public static SpeedValue operator -(SpeedValue x, SpeedValue y) { - return new SpeedValue(x.GameUnits - y.GameUnits); - } + public static SpeedValue operator -(SpeedValue x, SpeedValue y) + => new SpeedValue(x.GameUnits - y.GameUnits); /// /// Convert float game speed to mph and round to nearest STEP @@ -141,16 +137,14 @@ public KmphValue ToKmphRounded(float step) { /// Converts this SpeedValue into miles/hour /// /// A typed mph value with integer miles/hour - public MphValue ToMphPrecise() { - return new MphValue((ushort)Mathf.Round(GameUnits * ApiConstants.SPEED_TO_MPH)); - } + public MphValue ToMphPrecise() + => new MphValue((ushort)Mathf.Round(GameUnits * ApiConstants.SPEED_TO_MPH)); /// /// Converts this SpeedValue into km/hour /// /// A typed km/h value with integer km/hour - public KmphValue ToKmphPrecise() { - return new KmphValue((ushort)Mathf.Round(GameUnits * ApiConstants.SPEED_TO_KMPH)); - } + public KmphValue ToKmphPrecise() + => new KmphValue((ushort)Mathf.Round(GameUnits * ApiConstants.SPEED_TO_KMPH)); } } From 0b218866128e9982e66c0dc3caa5b5847fb794cd Mon Sep 17 00:00:00 2001 From: dmytro lytovchenko Date: Sat, 3 Aug 2019 00:14:15 +0200 Subject: [PATCH 7/8] Remove KM/gameunits conversion from Configuration.cs --- TLM/TLM/Manager/Impl/SpeedLimitManager.cs | 2 +- TLM/TLM/State/Configuration.cs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/TLM/TLM/Manager/Impl/SpeedLimitManager.cs b/TLM/TLM/Manager/Impl/SpeedLimitManager.cs index 5749b0511..3ae07d321 100644 --- a/TLM/TLM/Manager/Impl/SpeedLimitManager.cs +++ b/TLM/TLM/Manager/Impl/SpeedLimitManager.cs @@ -868,7 +868,7 @@ public bool LoadData(List data) { var ret = new List(); foreach (KeyValuePair e in Flags.GetAllLaneSpeedLimits()) { try { - var laneSpeedLimit = new Configuration.LaneSpeedLimit(e.Key, e.Value); + var laneSpeedLimit = new Configuration.LaneSpeedLimit(e.Key, new SpeedValue(e.Value)); #if DEBUGSAVE Log._Debug($"Saving speed limit of lane {laneSpeedLimit.laneId}: " + $"{laneSpeedLimit.speedLimit*SpeedLimit.SPEED_TO_KMPH} km/h"); diff --git a/TLM/TLM/State/Configuration.cs b/TLM/TLM/State/Configuration.cs index d8a6affbd..f15685a8e 100644 --- a/TLM/TLM/State/Configuration.cs +++ b/TLM/TLM/State/Configuration.cs @@ -2,6 +2,7 @@ namespace TrafficManager { using System; using System.Collections.Generic; + using API.Traffic.Data; using JetBrains.Annotations; using State; using Traffic; @@ -18,9 +19,9 @@ public class LaneSpeedLimit { /// public ushort speedLimit; - public LaneSpeedLimit(uint laneId, float speedLimit) { + public LaneSpeedLimit(uint laneId, SpeedValue speed) { this.laneId = laneId; - this.speedLimit = (ushort)(speedLimit * Constants.SPEED_TO_KMPH); + this.speedLimit = speed.ToKmphPrecise().Kmph; } } From 6b90824a0f7bf4861efad60fe1b78fad24121b4d Mon Sep 17 00:00:00 2001 From: dmytro lytovchenko Date: Sat, 3 Aug 2019 00:26:39 +0200 Subject: [PATCH 8/8] Remove 1 unused import --- TLM/TLM/State/Configuration.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/TLM/TLM/State/Configuration.cs b/TLM/TLM/State/Configuration.cs index f15685a8e..c2cf13371 100644 --- a/TLM/TLM/State/Configuration.cs +++ b/TLM/TLM/State/Configuration.cs @@ -6,7 +6,6 @@ namespace TrafficManager { using JetBrains.Annotations; using State; using Traffic; - using UI.SubTools.SpeedLimits; [Serializable] public class Configuration {