diff --git a/TLM/SharedAssemblyInfo.cs b/TLM/SharedAssemblyInfo.cs index 050b42ab7..3a0de65f5 100644 --- a/TLM/SharedAssemblyInfo.cs +++ b/TLM/SharedAssemblyInfo.cs @@ -20,4 +20,4 @@ // Minor Version // Build Number // Revision -[assembly: AssemblyVersion("11.5.0.*")] +[assembly: AssemblyVersion("11.5.1.*")] diff --git a/TLM/TLM/Manager/Impl/AdvancedParkingManager.cs b/TLM/TLM/Manager/Impl/AdvancedParkingManager.cs index d738359f4..a8aca6101 100644 --- a/TLM/TLM/Manager/Impl/AdvancedParkingManager.cs +++ b/TLM/TLM/Manager/Impl/AdvancedParkingManager.cs @@ -2883,6 +2883,50 @@ public bool FindParkingSpaceBuilding(VehicleInfo vehicleInfo, out parkOffset) != 0; } + public bool VanillaFindParkingSpaceWithoutRestrictions(bool isElectric, + ushort homeId, + Vector3 refPos, + Vector3 searchDir, + ushort segment, + float width, + float length, + out Vector3 parkPos, + out Quaternion parkRot, + out float parkOffset) { + if (!CustomPassengerCarAI.FindParkingSpace(isElectric, + homeId, + refPos, + searchDir, + segment, + width, + length, + out parkPos, + out parkRot, + out parkOffset)) { + return false; + } + + // in vanilla parkOffset is always >= 0 for RoadSideParkingSpace + if (Options.parkingRestrictionsEnabled && parkOffset >= 0) { + if (Singleton.instance.m_segments.m_buffer[segment].GetClosestLanePosition( + refPos, + NetInfo.LaneType.Parking, + VehicleInfo.VehicleType.Car, + out _, + out _, + out int laneIndex, + out _)) { + NetInfo.Direction direction + = Singleton.instance.m_segments.m_buffer[segment].Info.m_lanes[laneIndex].m_finalDirection; + if (!ParkingRestrictionsManager.Instance.IsParkingAllowed(segment, direction)) { + return false; + } + } + } + + return true; + } + public bool GetBuildingInfoViewColor(ushort buildingId, ref Building buildingData, ref ExtBuilding extBuilding, diff --git a/TLM/TLM/Manager/Impl/ExtSegmentEndManager.cs b/TLM/TLM/Manager/Impl/ExtSegmentEndManager.cs index 6e5a9b207..1254a841d 100644 --- a/TLM/TLM/Manager/Impl/ExtSegmentEndManager.cs +++ b/TLM/TLM/Manager/Impl/ExtSegmentEndManager.cs @@ -12,17 +12,10 @@ public class ExtSegmentEndManager : AbstractCustomManager, IExtSegmentEndManager { - public static ExtSegmentEndManager Instance { get; } - static ExtSegmentEndManager() { Instance = new ExtSegmentEndManager(); } - /// - /// All additional data for segment ends - /// - public ExtSegmentEnd[] ExtSegmentEnds { get; } - private ExtSegmentEndManager() { ExtSegmentEnds = new ExtSegmentEnd[NetManager.MAX_SEGMENT_COUNT * 2]; for (uint i = 0; i < NetManager.MAX_SEGMENT_COUNT; ++i) { @@ -31,6 +24,13 @@ private ExtSegmentEndManager() { } } + public static ExtSegmentEndManager Instance { get; } + + /// + /// All additional data for segment ends + /// + public ExtSegmentEnd[] ExtSegmentEnds { get; } + #if DEBUG public string GenerateVehicleChainDebugInfo(ushort segmentId, bool startNode) { int index = GetIndex(segmentId, startNode); @@ -298,23 +298,33 @@ private void Recalculate(ref ExtSegmentEnd segEnd) { public void CalculateCorners(ushort segmentId, bool startNode) { if (!Shortcuts.netService.IsSegmentValid(segmentId)) return; - ref ExtSegmentEnd segEnd = ref ExtSegmentEnds[GetIndex(segmentId, startNode)]; - segmentId.ToSegment().CalculateCorner( - segmentID: segmentId, - heightOffset: true, - start: startNode, - leftSide: false, - cornerPos: out segEnd.RightCorner, - cornerDirection: out segEnd.RightCornerDir, - smooth: out _); - segmentId.ToSegment().CalculateCorner( - segmentID: segmentId, - heightOffset: true, - start: startNode, - leftSide: true, - cornerPos: out segEnd.LeftCorner, - cornerDirection: out segEnd.LeftCornerDir, - smooth: out _); + if (!segmentId.ToSegment().Info) { + Log.Warning($"segment {segmentId} has null info"); + return; + } + + try { + ref ExtSegmentEnd segEnd = ref ExtSegmentEnds[GetIndex(segmentId, startNode)]; + segmentId.ToSegment().CalculateCorner( + segmentID: segmentId, + heightOffset: true, + start: startNode, + leftSide: false, + cornerPos: out segEnd.RightCorner, + cornerDirection: out segEnd.RightCornerDir, + smooth: out _); + segmentId.ToSegment().CalculateCorner( + segmentID: segmentId, + heightOffset: true, + start: startNode, + leftSide: true, + cornerPos: out segEnd.LeftCorner, + cornerDirection: out segEnd.LeftCornerDir, + smooth: out _); + } catch (Exception e) { + Log.Error($"failed calculating corner for segment:{segmentId}, info={segmentId.ToSegment().Info}\n" + + e.Message); + } } private void CalculateIncomingOutgoing(ushort segmentId, diff --git a/TLM/TLM/Manager/Impl/VehicleBehaviorManager.cs b/TLM/TLM/Manager/Impl/VehicleBehaviorManager.cs index e7e5ef3f2..d0bca5b33 100644 --- a/TLM/TLM/Manager/Impl/VehicleBehaviorManager.cs +++ b/TLM/TLM/Manager/Impl/VehicleBehaviorManager.cs @@ -241,16 +241,16 @@ bool citizenDebug } if (!searchedParkingSpace) { + bool isElectric = vehicleInfo.m_class.m_subService != ItemClass.SubService.ResidentialLow; foundParkingSpace = - Constants.ManagerFactory.AdvancedParkingManager.FindParkingSpaceInVicinity( + Constants.ManagerFactory.AdvancedParkingManager.VanillaFindParkingSpaceWithoutRestrictions( + isElectric, + homeID, refPos, searchDir, - vehicleInfo, - homeID, - vehicleID, - GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance, - out ExtParkingSpaceLocation parkLoc, - out ushort parkId, + pathPos.m_segment, + vehicleInfo.m_generatedInfo.m_size.x, + vehicleInfo.m_generatedInfo.m_size.z, out parkPos, out parkRot, out parkOffset); diff --git a/TLM/TLM/Resources/RoadSelectionPanel/Clear-fg-disabled.png b/TLM/TLM/Resources/RoadSelectionPanel/Clear-fg-disabled.png index e1cc1a312..33a10fb32 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/Clear-fg-disabled.png and b/TLM/TLM/Resources/RoadSelectionPanel/Clear-fg-disabled.png differ diff --git a/TLM/TLM/Resources/RoadSelectionPanel/Clear-fg-normal.png b/TLM/TLM/Resources/RoadSelectionPanel/Clear-fg-normal.png index 3e8845788..681a27f03 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/Clear-fg-normal.png and b/TLM/TLM/Resources/RoadSelectionPanel/Clear-fg-normal.png differ diff --git a/TLM/TLM/Resources/RoadSelectionPanel/HighPriority_LHT-fg-disabled.png b/TLM/TLM/Resources/RoadSelectionPanel/HighPriority_LHT-fg-disabled.png index c5113ef96..631bc727e 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/HighPriority_LHT-fg-disabled.png and b/TLM/TLM/Resources/RoadSelectionPanel/HighPriority_LHT-fg-disabled.png differ diff --git a/TLM/TLM/Resources/RoadSelectionPanel/HighPriority_LHT-fg-normal.png b/TLM/TLM/Resources/RoadSelectionPanel/HighPriority_LHT-fg-normal.png index 5a3bdc314..e1533e941 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/HighPriority_LHT-fg-normal.png and b/TLM/TLM/Resources/RoadSelectionPanel/HighPriority_LHT-fg-normal.png differ diff --git a/TLM/TLM/Resources/RoadSelectionPanel/HighPriority_RHT-fg-disabled.png b/TLM/TLM/Resources/RoadSelectionPanel/HighPriority_RHT-fg-disabled.png index 0f441a8af..f2d6aa9c0 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/HighPriority_RHT-fg-disabled.png and b/TLM/TLM/Resources/RoadSelectionPanel/HighPriority_RHT-fg-disabled.png differ diff --git a/TLM/TLM/Resources/RoadSelectionPanel/HighPriority_RHT-fg-normal.png b/TLM/TLM/Resources/RoadSelectionPanel/HighPriority_RHT-fg-normal.png index c7fce5a09..e96f59d08 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/HighPriority_RHT-fg-normal.png and b/TLM/TLM/Resources/RoadSelectionPanel/HighPriority_RHT-fg-normal.png differ diff --git a/TLM/TLM/Resources/RoadSelectionPanel/RoundButton-bg-active.png b/TLM/TLM/Resources/RoadSelectionPanel/RoundButton-bg-active.png index d08b5583d..efcc9c49e 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/RoundButton-bg-active.png and b/TLM/TLM/Resources/RoadSelectionPanel/RoundButton-bg-active.png differ diff --git a/TLM/TLM/Resources/RoadSelectionPanel/RoundButton-bg-disabled.png b/TLM/TLM/Resources/RoadSelectionPanel/RoundButton-bg-disabled.png index 6aacb026a..a194720e1 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/RoundButton-bg-disabled.png and b/TLM/TLM/Resources/RoadSelectionPanel/RoundButton-bg-disabled.png differ diff --git a/TLM/TLM/Resources/RoadSelectionPanel/RoundButton-bg-hovered.png b/TLM/TLM/Resources/RoadSelectionPanel/RoundButton-bg-hovered.png index 7b562e7d7..15a33b342 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/RoundButton-bg-hovered.png and b/TLM/TLM/Resources/RoadSelectionPanel/RoundButton-bg-hovered.png differ diff --git a/TLM/TLM/Resources/RoadSelectionPanel/RoundButton-bg-normal.png b/TLM/TLM/Resources/RoadSelectionPanel/RoundButton-bg-normal.png index 81f981b7a..9da7dc4e4 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/RoundButton-bg-normal.png and b/TLM/TLM/Resources/RoadSelectionPanel/RoundButton-bg-normal.png differ diff --git a/TLM/TLM/Resources/RoadSelectionPanel/Roundabout_LHT-fg-disabled.png b/TLM/TLM/Resources/RoadSelectionPanel/Roundabout_LHT-fg-disabled.png index 4a2982e5e..5f557502d 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/Roundabout_LHT-fg-disabled.png and b/TLM/TLM/Resources/RoadSelectionPanel/Roundabout_LHT-fg-disabled.png differ diff --git a/TLM/TLM/Resources/RoadSelectionPanel/Roundabout_LHT-fg-normal.png b/TLM/TLM/Resources/RoadSelectionPanel/Roundabout_LHT-fg-normal.png index 7c0dd48e3..2d5d895bd 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/Roundabout_LHT-fg-normal.png and b/TLM/TLM/Resources/RoadSelectionPanel/Roundabout_LHT-fg-normal.png differ diff --git a/TLM/TLM/Resources/RoadSelectionPanel/Roundabout_RHT-fg-disabled.png b/TLM/TLM/Resources/RoadSelectionPanel/Roundabout_RHT-fg-disabled.png index 3fc4e20e0..c2858aa55 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/Roundabout_RHT-fg-disabled.png and b/TLM/TLM/Resources/RoadSelectionPanel/Roundabout_RHT-fg-disabled.png differ diff --git a/TLM/TLM/Resources/RoadSelectionPanel/Roundabout_RHT-fg-normal.png b/TLM/TLM/Resources/RoadSelectionPanel/Roundabout_RHT-fg-normal.png index ab7b3203b..7f55b2098 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/Roundabout_RHT-fg-normal.png and b/TLM/TLM/Resources/RoadSelectionPanel/Roundabout_RHT-fg-normal.png differ diff --git a/TLM/TLM/Resources/RoadSelectionPanel/Stop_LHT-fg-disabled.png b/TLM/TLM/Resources/RoadSelectionPanel/Stop_LHT-fg-disabled.png index 3151b24a6..e3ae3027d 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/Stop_LHT-fg-disabled.png and b/TLM/TLM/Resources/RoadSelectionPanel/Stop_LHT-fg-disabled.png differ diff --git a/TLM/TLM/Resources/RoadSelectionPanel/Stop_LHT-fg-normal.png b/TLM/TLM/Resources/RoadSelectionPanel/Stop_LHT-fg-normal.png index 3d48550ef..81078d537 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/Stop_LHT-fg-normal.png and b/TLM/TLM/Resources/RoadSelectionPanel/Stop_LHT-fg-normal.png differ diff --git a/TLM/TLM/Resources/RoadSelectionPanel/Stop_RHT-fg-disabled.png b/TLM/TLM/Resources/RoadSelectionPanel/Stop_RHT-fg-disabled.png index 5e7c6156b..6d255b8d8 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/Stop_RHT-fg-disabled.png and b/TLM/TLM/Resources/RoadSelectionPanel/Stop_RHT-fg-disabled.png differ diff --git a/TLM/TLM/Resources/RoadSelectionPanel/Stop_RHT-fg-normal.png b/TLM/TLM/Resources/RoadSelectionPanel/Stop_RHT-fg-normal.png index 6996a746b..ce0d20d48 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/Stop_RHT-fg-normal.png and b/TLM/TLM/Resources/RoadSelectionPanel/Stop_RHT-fg-normal.png differ diff --git a/TLM/TLM/Resources/RoadSelectionPanel/Yield_LHT-fg-disabled.png b/TLM/TLM/Resources/RoadSelectionPanel/Yield_LHT-fg-disabled.png index 20bdb818d..2e95d4643 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/Yield_LHT-fg-disabled.png and b/TLM/TLM/Resources/RoadSelectionPanel/Yield_LHT-fg-disabled.png differ diff --git a/TLM/TLM/Resources/RoadSelectionPanel/Yield_LHT-fg-normal.png b/TLM/TLM/Resources/RoadSelectionPanel/Yield_LHT-fg-normal.png index 782698fb0..57edeceee 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/Yield_LHT-fg-normal.png and b/TLM/TLM/Resources/RoadSelectionPanel/Yield_LHT-fg-normal.png differ diff --git a/TLM/TLM/Resources/RoadSelectionPanel/Yield_RHT-fg-disabled.png b/TLM/TLM/Resources/RoadSelectionPanel/Yield_RHT-fg-disabled.png index 42a2cec05..2590f08c4 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/Yield_RHT-fg-disabled.png and b/TLM/TLM/Resources/RoadSelectionPanel/Yield_RHT-fg-disabled.png differ diff --git a/TLM/TLM/Resources/RoadSelectionPanel/Yield_RHT-fg-normal.png b/TLM/TLM/Resources/RoadSelectionPanel/Yield_RHT-fg-normal.png index dd8ee54eb..31e5396c9 100644 Binary files a/TLM/TLM/Resources/RoadSelectionPanel/Yield_RHT-fg-normal.png and b/TLM/TLM/Resources/RoadSelectionPanel/Yield_RHT-fg-normal.png differ diff --git a/TLM/TLM/State/GlobalConfig.cs b/TLM/TLM/State/GlobalConfig.cs index 4a104d9ed..7377f5586 100644 --- a/TLM/TLM/State/GlobalConfig.cs +++ b/TLM/TLM/State/GlobalConfig.cs @@ -17,8 +17,8 @@ public static GlobalConfig Instance { get => instance; private set { if (value != null && instance != null) { - value.Observers = instance.Observers; - value.ObserverLock = instance.ObserverLock; + value._observers = instance._observers; + value._lock = instance._lock; } instance = value; diff --git a/TLM/TLM/UI/SubTools/JunctionRestrictionsTool.cs b/TLM/TLM/UI/SubTools/JunctionRestrictionsTool.cs index 2dc7e7f49..3cc977216 100644 --- a/TLM/TLM/UI/SubTools/JunctionRestrictionsTool.cs +++ b/TLM/TLM/UI/SubTools/JunctionRestrictionsTool.cs @@ -164,8 +164,12 @@ public override void OnPrimaryClickOverlay() { } public override void OnSecondaryClickOverlay() { - SelectedNodeId = 0; - MainTool.RequestOnscreenDisplayUpdate(); + if (SelectedNodeId != 0) { + SelectedNodeId = 0; + MainTool.RequestOnscreenDisplayUpdate(); + } else { + MainTool.SetToolMode(ToolMode.None); + } } public override void OnActivate() { diff --git a/TLM/TLM/UI/SubTools/LaneConnectorTool.cs b/TLM/TLM/UI/SubTools/LaneConnectorTool.cs index bb8a1a0cc..f82c24e87 100644 --- a/TLM/TLM/UI/SubTools/LaneConnectorTool.cs +++ b/TLM/TLM/UI/SubTools/LaneConnectorTool.cs @@ -553,7 +553,7 @@ public static bool GetSortedSegments(ushort nodeId, out List segments) { /// /// /// determines for which side to connect lanes. - /// false if there is only one incomming/outgoing lane, true otherwise + /// true if any lanes were connectde, false otherwise public static bool StayInLane(ushort nodeId, StayInLaneMode mode = StayInLaneMode.None) { Log._Debug($"Stay In Lane called node:{nodeId} mode:{mode}"); LaneConnectionManager.Instance.RemoveLaneConnectionsFromNode(nodeId); @@ -629,12 +629,12 @@ private static bool StayInLane( // count relavent source(going toward the junction) lanes and // target (going aginst the junction) lanes on each segment. - int laneCountMinorSource = minorSegmentId == 0 ? 0 : PriorityRoad.CountLanesTowardJunction(minorSegmentId, nodeId); - int laneCountMinorTarget = minorSegmentId == 0 ? 0 : PriorityRoad.CountLanesAgainstJunction(minorSegmentId, nodeId); - int laneCountMinor2Source = minorSegment2Id == 0 ? 0 : PriorityRoad.CountLanesTowardJunction(minorSegment2Id, nodeId); - int laneCountMinor2Target = minorSegment2Id == 0 ? 0 : PriorityRoad.CountLanesAgainstJunction(minorSegment2Id, nodeId); - int laneCountMainSource = PriorityRoad.CountLanesTowardJunction(mainSegmentSourceId, nodeId); - int laneCountMainTarget = PriorityRoad.CountLanesAgainstJunction(mainSegmentTargetId, nodeId); + int laneCountMinorSource = minorSegmentId == 0 ? 0 : CountLanesTowardJunction(minorSegmentId, nodeId); + int laneCountMinorTarget = minorSegmentId == 0 ? 0 : CountLanesAgainstJunction(minorSegmentId, nodeId); + int laneCountMinor2Source = minorSegment2Id == 0 ? 0 : CountLanesTowardJunction(minorSegment2Id, nodeId); + int laneCountMinor2Target = minorSegment2Id == 0 ? 0 : CountLanesAgainstJunction(minorSegment2Id, nodeId); + int laneCountMainSource = CountLanesTowardJunction(mainSegmentSourceId, nodeId); + int laneCountMainTarget = CountLanesAgainstJunction(mainSegmentTargetId, nodeId); int totalSource = laneCountMinorSource + laneCountMainSource + laneCountMinor2Source; int totalTarget = laneCountMinorTarget + laneCountMainTarget + laneCountMinor2Target; @@ -779,6 +779,20 @@ bool ConnectToMinor2(int sourceIdx, int targetIdx) { return true; } + private static int CountLanes(ushort segmentId, ushort nodeId, bool toward) { + return netService.GetSortedLanes( + segmentId, + ref segmentId.ToSegment(), + netService.IsStartNode(segmentId, nodeId) ^ (!toward), + LaneConnectionManager.LANE_TYPES, + LaneConnectionManager.VEHICLE_TYPES, + true + ).Count; + } + internal static int CountLanesTowardJunction(ushort segmentId, ushort nodeId) => CountLanes(segmentId, nodeId, true); + internal static int CountLanesAgainstJunction(ushort segmentId, ushort nodeId) => CountLanes(segmentId, nodeId, false); + + public override void OnPrimaryClickOverlay() { #if DEBUG bool logLaneConn = DebugSwitch.LaneConnections.Get(); @@ -952,6 +966,10 @@ public override void OnSecondaryClickOverlay() { break; } } + + if (GetSelectionMode() == SelectionMode.None) { + MainTool.SetToolMode(ToolMode.None); + } } public override void OnActivate() { diff --git a/TLM/TLM/UI/SubTools/ManualTrafficLightsTool.cs b/TLM/TLM/UI/SubTools/ManualTrafficLightsTool.cs index b6f05ae07..098fa434f 100644 --- a/TLM/TLM/UI/SubTools/ManualTrafficLightsTool.cs +++ b/TLM/TLM/UI/SubTools/ManualTrafficLightsTool.cs @@ -27,9 +27,13 @@ public override void OnSecondaryClickOverlay() { return; } - Cleanup(); - SelectedNodeId = 0; - MainTool.RequestOnscreenDisplayUpdate(); + if (SelectedNodeId != 0) { + Cleanup(); + SelectedNodeId = 0; + MainTool.RequestOnscreenDisplayUpdate(); + } else { + MainTool.SetToolMode(ToolMode.None); + } } public override void OnPrimaryClickOverlay() { diff --git a/TLM/TLM/UI/SubTools/ParkingRestrictionsTool.cs b/TLM/TLM/UI/SubTools/ParkingRestrictionsTool.cs index 5b022569f..8540b8dc7 100644 --- a/TLM/TLM/UI/SubTools/ParkingRestrictionsTool.cs +++ b/TLM/TLM/UI/SubTools/ParkingRestrictionsTool.cs @@ -66,6 +66,10 @@ public override void OnActivate() { public override void OnPrimaryClickOverlay() { } + public override void OnSecondaryClickOverlay() { + MainTool.SetToolMode(ToolMode.None); + } + private void RenderSegmentParkings(RenderManager.CameraInfo cameraInfo) { bool allowed = parkingManager.IsParkingAllowed(renderInfo_.SegmentId, renderInfo_.FinalDirection); bool pressed = Input.GetMouseButton(0); diff --git a/TLM/TLM/UI/SubTools/PrioritySigns/PrioritySignsTool.cs b/TLM/TLM/UI/SubTools/PrioritySigns/PrioritySignsTool.cs index c08da5371..ac34d1552 100644 --- a/TLM/TLM/UI/SubTools/PrioritySigns/PrioritySignsTool.cs +++ b/TLM/TLM/UI/SubTools/PrioritySigns/PrioritySignsTool.cs @@ -76,7 +76,7 @@ public override void OnPrimaryClickOverlay() { if (!isRoundabout) { record_ = PriorityRoad.FixRoad(HoveredSegmentId); } - // TODO: benchmark why bulk setup takes a long time. + // TODO: benchmark why bulk setup takes a long time. Log.Info("After FixRoundabout/FixRoad. Before RefreshMassEditOverlay"); // log time for benchmarking. RefreshMassEditOverlay(); Log.Info("After RefreshMassEditOverlay."); // log time for benchmarking. @@ -125,7 +125,7 @@ public override void OnPrimaryClickOverlay() { massEditMode = PrioritySignsMassEditMode.Min; } } - + // refresh cache if(ControlIsPressed) RefreshMassEditOverlay(); @@ -133,6 +133,10 @@ public override void OnPrimaryClickOverlay() { RefreshCurrentPriorityNodeIds(); } + public override void OnSecondaryClickOverlay() { + MainTool.SetToolMode(ToolMode.None); + } + public override void OnToolGUI(Event e) { } /// diff --git a/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimitsTool.cs b/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimitsTool.cs index 9ff9e56f8..3ddcc598c 100644 --- a/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimitsTool.cs +++ b/TLM/TLM/UI/SubTools/SpeedLimits/SpeedLimitsTool.cs @@ -43,7 +43,7 @@ public const int /// 0 = no limit /// null = default /// - private SpeedValue ?currentPaletteSpeedLimit = new SpeedValue(-1f); + private SpeedValue? currentPaletteSpeedLimit = new SpeedValue(-1f); private readonly Dictionary> segmentCenterByDir = new Dictionary>(); @@ -96,12 +96,21 @@ private struct RenderData { private RenderData renderData_; public SpeedLimitsTool(TrafficManagerTool mainTool) - : base(mainTool) - { + : base(mainTool) { CachedVisibleSegmentIds = new GenericArrayCache(NetManager.MAX_SEGMENT_COUNT); LastCachedCamera = new CameraTransformValue(); } + internal static void SetSpeedLimit(LanePos lane, SpeedValue? speed) { + ushort segmentId = lane.laneId.ToLane().m_segment; + SpeedLimitManager.Instance.SetSpeedLimit( + segmentId: segmentId, + laneIndex: lane.laneIndex, + laneInfo: segmentId.ToSegment().Info.m_lanes[lane.laneIndex], + laneId: lane.laneId, + speedLimit: speed?.GameUnits); + } + public override bool IsCursorInPanel() { return base.IsCursorInPanel() || cursorInSecondaryPanel; } @@ -113,6 +122,10 @@ public override void OnActivate() { public override void OnPrimaryClickOverlay() { } + public override void OnSecondaryClickOverlay() { + MainTool.SetToolMode(ToolMode.None); + } + public override void OnToolGUI(Event e) { base.OnToolGUI(e); @@ -156,17 +169,21 @@ public override void OnToolGUI(Event e) { private void RenderLaneOverlay(RenderManager.CameraInfo cameraInfo, uint laneId) { var marker = new SegmentLaneMarker(laneBuffer[laneId].m_bezier); bool pressed = Input.GetMouseButton(0); - Color color = MainTool.GetToolColor(pressed,false); + Color color = MainTool.GetToolColor(pressed, false); if (!ShowLimitsPerLane) { marker.Size = 3f; // lump the lanes together. } marker.RenderOverlay(cameraInfo, color, pressed); } + /// + /// Renders all lanes with the given + /// if NetInfo.Direction.None, all lanes are rendered. + /// private int RenderSegmentSideOverlay( RenderManager.CameraInfo cameraInfo, ushort segmentId, - NetInfo.Direction finalDirection) { + NetInfo.Direction finalDirection = NetInfo.Direction.None) { int count = 0; bool pressed = Input.GetMouseButton(0); Color color = MainTool.GetToolColor(pressed, false); @@ -180,7 +197,7 @@ private int RenderSegmentSideOverlay( byte laneIndex) => { bool render = (laneInfo.m_laneType & SpeedLimitManager.LANE_TYPES) != 0; render &= (laneInfo.m_vehicleType & SpeedLimitManager.VEHICLE_TYPES) != 0; - render &= laneInfo.m_finalDirection == finalDirection; + render &= laneInfo.m_finalDirection == finalDirection || finalDirection == NetInfo.Direction.None; if (render) { RenderLaneOverlay(cameraInfo, laneId); count++; @@ -193,6 +210,10 @@ private int RenderSegmentSideOverlay( private void RenderLanes(RenderManager.CameraInfo cameraInfo) { if (!MultiSegmentMode) { RenderLaneOverlay(cameraInfo, renderData_.LaneId); + } else if (RoundaboutMassEdit.Instance.TraverseLoop(renderData_.SegmentId, out var segmentList)) { + var lanes = FollowRoundaboutLane(segmentList, renderData_.SegmentId, renderData_.SortedLaneIndex); + foreach (var lane in lanes) + RenderLaneOverlay(cameraInfo, lane.laneId); } else { bool LaneVisitorFun(SegmentLaneTraverser.SegmentLaneVisitData data) { if (data.SortedLaneIndex == renderData_.SortedLaneIndex) { @@ -200,6 +221,7 @@ bool LaneVisitorFun(SegmentLaneTraverser.SegmentLaneVisitData data) { } return true; } + { SegmentLaneTraverser.Traverse( renderData_.SegmentId, SegmentTraverser.TraverseDirection.AnyDirection, @@ -211,10 +233,53 @@ bool LaneVisitorFun(SegmentLaneTraverser.SegmentLaneVisitData data) { LaneVisitorFun); } } + } + + /// + /// iterates through the given roundabout returning an enumeration + /// of all lanes with a matching based on + /// + /// input list of roundabout segments (must be oneway, and in the same direction). + /// The segment to match lane agaisnt + /// + private IEnumerable FollowRoundaboutLane(List segmentList, ushort segmentId0, int sortedLaneIndex) { + bool invert0 = segmentId0.ToSegment().m_flags.IsFlagSet(NetSegment.Flags.Invert); + int count0 = netService.GetSortedLanes( + segmentId: segmentId0, + segment: ref segmentId0.ToSegment(), + startNode: null, + laneTypeFilter: SpeedLimitManager.LANE_TYPES, + vehicleTypeFilter: SpeedLimitManager.VEHICLE_TYPES, + sort: false).Count; + foreach (ushort segmentId in segmentList) { + bool invert = segmentId.ToSegment().m_flags.IsFlagSet(NetSegment.Flags.Invert); + var lanes = netService.GetSortedLanes( + segmentId: segmentId, + segment: ref segmentId.ToSegment(), + startNode: null, + laneTypeFilter: SpeedLimitManager.LANE_TYPES, + vehicleTypeFilter: SpeedLimitManager.VEHICLE_TYPES, + reverse: invert != invert0, + sort: true); + int index = sortedLaneIndex; + + // if lane count does not match, assume segments are connected from outer side of the roundabout. + if (invert0) { + int diff = lanes.Count - count0; + index += diff; + } + if (0 <= index && index < lanes.Count) { + yield return lanes[index]; + } + } // foreach + } private void RenderSegmentsSide(RenderManager.CameraInfo cameraInfo) { if (!MultiSegmentMode) { RenderSegmentSideOverlay(cameraInfo, renderData_.SegmentId, renderData_.FinalDirection); + } else if (RoundaboutMassEdit.Instance.TraverseLoop(renderData_.SegmentId, out var segmentList)) { + foreach (ushort segmentId in segmentList) + RenderSegmentSideOverlay(cameraInfo, segmentId); } else { SegmentTraverser.Traverse( renderData_.SegmentId, @@ -305,8 +370,7 @@ private void ShowSigns(bool viewOnly) { bool hover = false; for (int segmentIdIndex = CachedVisibleSegmentIds.Size - 1; segmentIdIndex >= 0; - segmentIdIndex--) - { + segmentIdIndex--) { ushort segmentId = CachedVisibleSegmentIds.Values[segmentIdIndex]; // draw speed limits if ((MainTool.GetToolMode() == ToolMode.VehicleRestrictions) && @@ -315,7 +379,7 @@ private void ShowSigns(bool viewOnly) { } // no speed limit overlay on selected segment when in vehicle restrictions mode - hover|= DrawSpeedLimitHandles( + hover |= DrawSpeedLimitHandles( segmentId, ref netManager.m_segments.m_buffer[segmentId], viewOnly, @@ -485,8 +549,7 @@ private void GuiDefaultsWindow(int num) { GUILayout.FlexibleSpace(); if (GUILayout.Button(Translation.SpeedLimits.Get("Button:Save"), - GUILayout.Width(70))) - { + GUILayout.Width(70))) { SpeedLimitManager.Instance.FixCurrentSpeedLimits(info); SpeedLimitManager.Instance.SetCustomNetInfoSpeedLimit(info, currentSpeedLimit.GameUnits); } @@ -512,8 +575,7 @@ private void UpdateRoadTex(NetInfo info) { if (info != null) { if ((info.m_Atlas != null) && (info.m_Atlas.material != null) && (info.m_Atlas.material.mainTexture != null) && - info.m_Atlas.material.mainTexture is Texture2D mainTex) - { + info.m_Atlas.material.mainTexture is Texture2D mainTex) { UITextureAtlas.SpriteInfo spriteInfo = info.m_Atlas[info.m_Thumbnail]; if ((spriteInfo != null) && (spriteInfo.texture != null) && @@ -569,7 +631,7 @@ private void GuiSpeedLimitsWindow(int num) { foreach (SpeedValue speedLimit in allSpeedLimits) { // Highlight palette item if it is very close to its float speed - if (currentPaletteSpeedLimit !=null && + if (currentPaletteSpeedLimit != null && FloatUtil.NearlyEqual( (float)currentPaletteSpeedLimit?.GameUnits, speedLimit.GameUnits)) { @@ -589,7 +651,7 @@ private void GuiSpeedLimitsWindow(int num) { } } { - if (currentPaletteSpeedLimit == null ) { + if (currentPaletteSpeedLimit == null) { GUI.color = Color.gray; } GuiSpeedLimitsWindow_AddClearButton(); @@ -606,7 +668,7 @@ private void GuiSpeedLimitsWindow(int num) { if (GUILayout.Button(Translation.SpeedLimits.Get("Window.Title:Default speed limits"), GUILayout.Width(200))) { - TrafficManagerTool.ShowAdvisor(this.GetType().Name + "_Defaults"); + TrafficManagerTool.ShowAdvisor(GetType().Name + "_Defaults"); defaultsWindowVisible = true; } @@ -728,7 +790,7 @@ private bool DrawSpeedLimitHandles(ushort segmentId, Vector3 center = segment.m_bounds.center; NetManager netManager = Singleton.instance; - SpeedValue ?speedLimitToSet = viewOnly + SpeedValue? speedLimitToSet = viewOnly ? new SpeedValue(-1f) : currentPaletteSpeedLimit; @@ -812,8 +874,7 @@ private bool DrawSpeedLimitHandles(ushort segmentId, if (!viewOnly && !onlyMonorailLanes && ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Monorail) != - VehicleInfo.VehicleType.None)) - { + VehicleInfo.VehicleType.None)) { Texture2D tex1 = RoadUI.VehicleInfoSignTextures[ LegacyExtVehicleType.ToNew(ExtVehicleType.PassengerTrain)]; MainTool.DrawStaticSquareOverlayGridTexture( @@ -845,8 +906,15 @@ private bool DrawSpeedLimitHandles(ushort segmentId, speedLimitToSet?.GameUnits); if (MultiSegmentMode) { + if (new RoundaboutMassEdit().TraverseLoop(segmentId, out var segmentList)) { + var lanes = FollowRoundaboutLane(segmentList, segmentId, sortedLaneIndex); + foreach (var lane in lanes) { + if (lane.laneId == laneId) // the speed limit for this lane has already been set. + continue; + SetSpeedLimit(lane, speedLimitToSet); + } + } else { int slIndexCopy = sortedLaneIndex; - SegmentLaneTraverser.Traverse( segmentId, SegmentTraverser.TraverseDirection.AnyDirection, @@ -883,6 +951,7 @@ private bool DrawSpeedLimitHandles(ushort segmentId, }); } } + } ++x; } @@ -897,7 +966,7 @@ private bool DrawSpeedLimitHandles(ushort segmentId, GeometryUtil.CalculateSegmentCenterByDir( segmentId, segCenter, - speedLimitSignSize*TrafficManagerTool.MAX_ZOOM); + speedLimitSignSize * TrafficManagerTool.MAX_ZOOM); } foreach (KeyValuePair e in segCenter) { @@ -941,6 +1010,13 @@ private bool DrawSpeedLimitHandles(ushort segmentId, currentPaletteSpeedLimit?.GameUnits); if (MultiSegmentMode) { + if (new RoundaboutMassEdit().TraverseLoop(segmentId, out var segmentList)) { + foreach (ushort segId in segmentList) { + SpeedLimitManager.Instance.SetSpeedLimit( + segId, + currentPaletteSpeedLimit?.GameUnits); + } + } else { NetInfo.Direction normDir = e.Key; if ((netManager.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None) { normDir = NetInfo.InvertDirection(normDir); @@ -954,8 +1030,7 @@ private bool DrawSpeedLimitHandles(ushort segmentId, SegmentTraverser.SegmentStopCriterion.Junction, SpeedLimitManager.LANE_TYPES, SpeedLimitManager.VEHICLE_TYPES, - data => - { + data => { if (data.SegVisitData.Initial) { return true; } @@ -974,8 +1049,7 @@ private bool DrawSpeedLimitHandles(ushort segmentId, if (((netManager.m_segments.m_buffer[otherSegmentId].m_flags & NetSegment.Flags.Invert) - != NetSegment.Flags.None) ^ reverse) - { + != NetSegment.Flags.None) ^ reverse) { otherNormDir = NetInfo.InvertDirection(otherNormDir); } @@ -988,6 +1062,7 @@ private bool DrawSpeedLimitHandles(ushort segmentId, return true; }); + } } } @@ -1124,6 +1199,5 @@ public static float GetVerticalTextureScale() { ? 1.25f : 1.0f; } - } // end class } diff --git a/TLM/TLM/UI/SubTools/TimedTrafficLights/TimedTrafficLightsTool.cs b/TLM/TLM/UI/SubTools/TimedTrafficLights/TimedTrafficLightsTool.cs index 036f1ad6c..1c8a3cbff 100644 --- a/TLM/TLM/UI/SubTools/TimedTrafficLights/TimedTrafficLightsTool.cs +++ b/TLM/TLM/UI/SubTools/TimedTrafficLights/TimedTrafficLightsTool.cs @@ -106,8 +106,12 @@ public override void OnActivate() { public override void OnSecondaryClickOverlay() { if (!IsCursorInPanel()) { - Cleanup(); - this.SetToolMode(TTLToolMode.SelectNode); + if (ttlToolMode_ != TTLToolMode.SelectNode) { + Cleanup(); + this.SetToolMode(TTLToolMode.SelectNode); + } else { + MainTool.SetToolMode(ToolMode.None); + } } } diff --git a/TLM/TLM/UI/SubTools/ToggleTrafficLightsTool.cs b/TLM/TLM/UI/SubTools/ToggleTrafficLightsTool.cs index a5e92d3ab..ae19e4eb4 100644 --- a/TLM/TLM/UI/SubTools/ToggleTrafficLightsTool.cs +++ b/TLM/TLM/UI/SubTools/ToggleTrafficLightsTool.cs @@ -51,6 +51,10 @@ public override void OnPrimaryClickOverlay() { }); } + public override void OnSecondaryClickOverlay() { + MainTool.SetToolMode(ToolMode.None); + } + public void ToggleTrafficLight(ushort nodeId, ref NetNode node, bool showMessageOnError = true) { diff --git a/TLM/TLM/UI/SubTools/VehicleRestrictionsTool.cs b/TLM/TLM/UI/SubTools/VehicleRestrictionsTool.cs index b531e4b3c..2b07ea1ce 100644 --- a/TLM/TLM/UI/SubTools/VehicleRestrictionsTool.cs +++ b/TLM/TLM/UI/SubTools/VehicleRestrictionsTool.cs @@ -122,8 +122,12 @@ public override void OnPrimaryClickOverlay() { public override void OnSecondaryClickOverlay() { if (!IsCursorInPanel()) { - SelectedSegmentId = 0; - MainTool.RequestOnscreenDisplayUpdate(); + if (SelectedSegmentId != 0) { + SelectedSegmentId = 0; + MainTool.RequestOnscreenDisplayUpdate(); + } else { + MainTool.SetToolMode(ToolMode.None); + } } } @@ -195,7 +199,6 @@ public override void RenderOverlay(RenderManager.CameraInfo cameraInfo) { RenderRoadLane(cameraInfo); } else { RenderLaneOverlay(cameraInfo, renderData_.laneId); - } } } diff --git a/TLM/TLM/UI/TrafficManagerTool.cs b/TLM/TLM/UI/TrafficManagerTool.cs index 69cf6b13e..d8cb114b7 100644 --- a/TLM/TLM/UI/TrafficManagerTool.cs +++ b/TLM/TLM/UI/TrafficManagerTool.cs @@ -286,6 +286,8 @@ public void SetToolMode(ToolMode newToolMode) { toolMode_ = ToolMode.None; Log._Debug($"SetToolMode: reset because toolmode not found {newToolMode}"); + OnscreenDisplay.DisplayIdle(); + ModUI.Instance.MainMenu.UpdateButtons(); return; } @@ -329,6 +331,10 @@ private void SetToolMode_Activate(ToolMode newToolMode) { // Overridden to disable base class behavior protected override void OnEnable() { + // If TMPE was enabled by switching back from another tool (eg: buldozer, free camera), show main menue panel. + if (ModUI.Instance != null && !ModUI.Instance.IsVisible()) + ModUI.Instance.ShowMainMenu(); + if (legacySubTools_ != null) { Log._Debug("TrafficManagerTool.OnEnable(): Performing cleanup"); foreach (KeyValuePair e in legacySubTools_) { @@ -339,7 +345,10 @@ protected override void OnEnable() { } protected override void OnDisable() { - // Overridden to disable base class behavior + // If TMPE was disabled by switching to another tool, hide main menue panel. + if (ModUI.Instance != null && ModUI.Instance.IsVisible()) + ModUI.Instance.CloseMainMenu(); + // no call to base method to disable base class behavior } public override void RenderGeometry(RenderManager.CameraInfo cameraInfo) { @@ -459,7 +468,7 @@ protected override void OnToolUpdate() { } bool primaryMouseClicked = Input.GetMouseButtonDown(0); - bool secondaryMouseClicked = Input.GetMouseButtonDown(1); + bool secondaryMouseClicked = Input.GetMouseButtonUp(1); // check if clicked if (!primaryMouseClicked && !secondaryMouseClicked) { @@ -485,8 +494,17 @@ protected override void OnToolUpdate() { } if (secondaryMouseClicked) { - activeLegacySubTool_?.OnSecondaryClickOverlay(); - activeSubTool_?.OnToolRightClick(); + if (GetToolMode() == ToolMode.None) { + RoadSelectionPanels roadSelectionPanels = UIView.GetAView().GetComponent(); + if (roadSelectionPanels && roadSelectionPanels.RoadWorldInfoPanelExt && roadSelectionPanels.RoadWorldInfoPanelExt.isVisible) { + RoadSelectionPanels.RoadWorldInfoPanel.Hide(); + } else { + ModUI.Instance.CloseMainMenu(); + } + } else { + activeLegacySubTool_?.OnSecondaryClickOverlay(); + activeSubTool_?.OnToolRightClick(); + } } } } @@ -510,6 +528,9 @@ public void OnToolGUIImpl(Event e) { if (!Input.GetMouseButtonDown(0)) { _mouseClickProcessed = false; } + if (e.type == EventType.keyDown && e.keyCode == KeyCode.Escape) { + ModUI.Instance.CloseMainMenu(); + } if (Options.nodesOverlay) { DebugGuiDisplaySegments(); @@ -575,8 +596,6 @@ void DefaultOnToolGUI(Event e) { instanceID, HitPos); }); - } else if (e.type == EventType.MouseDown && e.button == 1) { - SimulationManager.instance.m_ThreadingWrapper.QueueMainThread(RoadSelectionPanels.RoadWorldInfoPanel.Hide); } } diff --git a/TLM/TLM/Util/GenericObservable.cs b/TLM/TLM/Util/GenericObservable.cs index 0ea46eb77..58b283229 100644 --- a/TLM/TLM/Util/GenericObservable.cs +++ b/TLM/TLM/Util/GenericObservable.cs @@ -1,8 +1,7 @@ -namespace TrafficManager.Util { +namespace TrafficManager.Util { using CSUtil.Commons; - using System.Collections.Generic; - using System.Threading; using System; + using System.Collections.Generic; using TrafficManager.API.Util; public abstract class GenericObservable : IObservable { @@ -10,12 +9,12 @@ public abstract class GenericObservable : IObservable { /// Holds a list of observers which are being notified as soon as the managed node's /// geometry is updated (but not neccessarily modified) /// - protected List> Observers = new List>(); + protected List> _observers = new List>(); /// /// Lock object. Acquire this before accessing the HashSets. /// - protected object ObserverLock = new object(); + protected object _lock = new object(); /// /// Registers an observer. @@ -23,33 +22,26 @@ public abstract class GenericObservable : IObservable { /// /// An unsubscriber public IDisposable Subscribe(IObserver observer) { - // Log._Debug($"GenericObserable.Subscribe: Subscribing observer {observer} to observable {this}"); - try { - Monitor.Enter(ObserverLock); - Observers.Add(observer); - } - finally { - Monitor.Exit(ObserverLock); + lock (_lock) { + _observers.Add(observer); } - return new GenericUnsubscriber(Observers, observer, ObserverLock); + return new GenericUnsubscriber(_observers, observer, _lock); } /// /// Notifies all observers that the observable object' state has changed /// public virtual void NotifyObservers(T subject) { - // Log._Debug($"GenericObserable.NotifyObservers: Notifying observers of observable {this}"); - // in case somebody unsubscribes while iterating over subscribers - var myObservers = new List>(Observers); - - foreach (IObserver observer in myObservers) { - try { - observer.OnUpdate(subject); - } - catch (Exception e) { - Log.Error("GenericObserable.NotifyObservers: An exception occured while " + - $"notifying an observer of observable {this}: {e}"); + lock (_lock) { + foreach (IObserver observer in _observers) { + try { + observer.OnUpdate(subject); + } + catch (Exception e) { + Log.Error("GenericObserable.NotifyObservers: An exception occured while " + + $"notifying an observer of observable {this}: {e}"); + } } } } diff --git a/TLM/TMPE.API/Manager/IAdvancedParkingManager.cs b/TLM/TMPE.API/Manager/IAdvancedParkingManager.cs index d2778ce15..ea3be4c3a 100644 --- a/TLM/TMPE.API/Manager/IAdvancedParkingManager.cs +++ b/TLM/TMPE.API/Manager/IAdvancedParkingManager.cs @@ -367,5 +367,30 @@ bool FindParkingSpacePropAtBuilding(VehicleInfo vehicleInfo, out Vector3 parkPos, out Quaternion parkRot, out float parkOffset); + + /// + /// Tries to find parking space using vanilla code, preserving parking restrictions + /// + /// Is electric vehicle + /// Home building id of the citizen (citizens are not allowed to park their car on foreign residential premises) + /// Target position that is used as a center point for the search procedure + /// Search direction + /// If != 0, the building is forced to be "accessible" from this segment (where accessible means "close enough") + /// Vehicle width + /// Vehicle length + /// Identified parking space position (only valid if method returns true) + /// Identified parking space rotation (only valid if method returns true) + /// Identified parking space offset (only valid if method returns true and a segment id was given) + /// + bool VanillaFindParkingSpaceWithoutRestrictions(bool isElectric, + ushort homeId, + Vector3 refPos, + Vector3 searchDir, + ushort segment, + float width, + float length, + out Vector3 parkPos, + out Quaternion parkRot, + out float parkOffset); } } \ No newline at end of file