public List <Configuration.LaneVehicleTypes> SaveData(ref bool success) { var ret = new List <Configuration.LaneVehicleTypes>(); foreach (KeyValuePair <uint, ExtVehicleType> e in Flags.GetAllLaneAllowedVehicleTypes()) { try { ret.Add(new Configuration.LaneVehicleTypes(e.Key, LegacyExtVehicleType.ToOld(e.Value))); Log._Trace($"Saving lane vehicle restriction: laneid={e.Key} vehicleType={e.Value}"); } catch (Exception ex) { Log.Error( $"Exception occurred while saving lane vehicle restrictions @ {e.Key}: {ex}"); success = false; } } return(ret); }
private void DrawSpeedLimitHandles(ushort segmentId, ref NetSegment segment, bool viewOnly, ref Vector3 camPos) { if (viewOnly && !Options.speedLimitsOverlay) { return; } Vector3 center = segment.m_bounds.center; NetManager netManager = Singleton <NetManager> .instance; SpeedValue speedLimitToSet = viewOnly ? new SpeedValue(-1f) : currentPaletteSpeedLimit; bool showPerLane = showLimitsPerLane; if (!viewOnly) { showPerLane = showLimitsPerLane ^ (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)); } // US signs are rectangular, all other are round float speedLimitSignVerticalScale = GetVerticalTextureScale(); if (showPerLane) { // show individual speed limit handle per lane int numLanes = TrafficManagerTool.GetSegmentNumVehicleLanes( segmentId, null, out int numDirections, SpeedLimitManager.VEHICLE_TYPES); NetInfo segmentInfo = segment.Info; Vector3 yu = (segment.m_endDirection - segment.m_startDirection).normalized; Vector3 xu = Vector3.Cross(yu, new Vector3(0, 1f, 0)).normalized; // if ((segment.m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) { // xu = -xu; } float f = viewOnly ? 4f : 7f; // reserved sign size in game coordinates Vector3 zero = center - (0.5f * (((numLanes - 1) + numDirections) - 1) * f * xu); uint x = 0; IList <LanePos> sortedLanes = Constants.ServiceFactory.NetService.GetSortedLanes( segmentId, ref segment, null, SpeedLimitManager.LANE_TYPES, SpeedLimitManager.VEHICLE_TYPES); bool onlyMonorailLanes = sortedLanes.Count > 0; if (!viewOnly) { foreach (LanePos laneData in sortedLanes) { byte laneIndex = laneData.laneIndex; NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex]; if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Monorail) == VehicleInfo.VehicleType.None) { onlyMonorailLanes = false; break; } } } var directions = new HashSet <NetInfo.Direction>(); int sortedLaneIndex = -1; foreach (LanePos laneData in sortedLanes) { ++sortedLaneIndex; uint laneId = laneData.laneId; byte laneIndex = laneData.laneIndex; NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex]; if (!directions.Contains(laneInfo.m_finalDirection)) { if (directions.Count > 0) { ++x; // space between different directions } directions.Add(laneInfo.m_finalDirection); } SpeedValue laneSpeedLimit = new SpeedValue( SpeedLimitManager.Instance.GetCustomSpeedLimit(laneId)); bool hoveredHandle = MainTool.DrawGenericOverlayGridTexture( SpeedLimitTextures.GetSpeedLimitTexture(laneSpeedLimit), camPos, zero, f, f, xu, yu, x, 0, speedLimitSignSize, speedLimitSignSize * speedLimitSignVerticalScale, !viewOnly); if (!viewOnly && !onlyMonorailLanes && ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Monorail) != VehicleInfo.VehicleType.None)) { Texture2D tex1 = RoadUITextures.VehicleInfoSignTextures[ LegacyExtVehicleType.ToNew(ExtVehicleType.PassengerTrain)]; MainTool.DrawStaticSquareOverlayGridTexture( tex1, camPos, zero, f, xu, yu, x, 1, speedLimitSignSize); } if (hoveredHandle) { } if (hoveredHandle && Input.GetMouseButton(0) && !IsCursorInPanel()) { SpeedLimitManager.Instance.SetSpeedLimit( segmentId, laneIndex, laneInfo, laneId, speedLimitToSet.GameUnits); if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) { int slIndexCopy = sortedLaneIndex; SegmentLaneTraverser.Traverse( segmentId, SegmentTraverser.TraverseDirection.AnyDirection, SegmentTraverser.TraverseSide.AnySide, SegmentLaneTraverser.LaneStopCriterion.LaneCount, SegmentTraverser.SegmentStopCriterion.Junction, SpeedLimitManager.LANE_TYPES, SpeedLimitManager.VEHICLE_TYPES, data => { if (data.SegVisitData.Initial) { return(true); } if (slIndexCopy != data.SortedLaneIndex) { return(true); } Constants.ServiceFactory.NetService.ProcessSegment( data.SegVisitData.CurSeg.segmentId, (ushort curSegmentId, ref NetSegment curSegment) => { NetInfo.Lane curLaneInfo = curSegment.Info.m_lanes[ data.CurLanePos.laneIndex]; SpeedLimitManager.Instance.SetSpeedLimit( curSegmentId, data.CurLanePos.laneIndex, curLaneInfo, data.CurLanePos.laneId, speedLimitToSet.GameUnits); return(true); }); return(true); }); } } ++x; } } else { // draw speedlimits over mean middle points of lane beziers if (!segmentCenterByDir.TryGetValue( segmentId, out Dictionary <NetInfo.Direction, Vector3> segCenter)) { segCenter = new Dictionary <NetInfo.Direction, Vector3>(); segmentCenterByDir.Add(segmentId, segCenter); TrafficManagerTool.CalculateSegmentCenterByDir(segmentId, segCenter); } foreach (KeyValuePair <NetInfo.Direction, Vector3> e in segCenter) { bool visible = MainTool.WorldToScreenPoint(e.Value, out Vector3 screenPos); if (!visible) { continue; } float zoom = (1.0f / (e.Value - camPos).magnitude) * 100f * MainTool.GetBaseZoom(); float size = (viewOnly ? 0.8f : 1f) * speedLimitSignSize * zoom; Color guiColor = GUI.color; var boundingBox = new Rect(screenPos.x - (size / 2), screenPos.y - (size / 2), size, size * speedLimitSignVerticalScale); bool hoveredHandle = !viewOnly && TrafficManagerTool.IsMouseOver(boundingBox); guiColor.a = TrafficManagerTool.GetHandleAlpha(hoveredHandle); if (hoveredHandle) { // mouse hovering over sign } // Draw something right here, the road sign texture GUI.color = guiColor; 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.GameUnits); if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) { NetInfo.Direction normDir = e.Key; if ((netManager.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None) { normDir = NetInfo.InvertDirection(normDir); } SegmentLaneTraverser.Traverse( segmentId, SegmentTraverser.TraverseDirection.AnyDirection, SegmentTraverser.TraverseSide.AnySide, SegmentLaneTraverser.LaneStopCriterion.LaneCount, SegmentTraverser.SegmentStopCriterion.Junction, SpeedLimitManager.LANE_TYPES, SpeedLimitManager.VEHICLE_TYPES, data => { if (data.SegVisitData.Initial) { return(true); } bool reverse = data.SegVisitData.ViaStartNode == data.SegVisitData.ViaInitialStartNode; ushort otherSegmentId = data.SegVisitData.CurSeg.segmentId; NetInfo otherSegmentInfo = netManager.m_segments.m_buffer[otherSegmentId].Info; byte laneIndex = data.CurLanePos.laneIndex; NetInfo.Lane laneInfo = otherSegmentInfo.m_lanes[laneIndex]; NetInfo.Direction otherNormDir = laneInfo.m_finalDirection; if (((netManager.m_segments.m_buffer[otherSegmentId].m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None) ^ reverse) { otherNormDir = NetInfo.InvertDirection(otherNormDir); } if (otherNormDir == normDir) { SpeedLimitManager.Instance.SetSpeedLimit( otherSegmentId, laneInfo.m_finalDirection, speedLimitToSet.GameUnits); } return(true); }); } } guiColor.a = 1f; GUI.color = guiColor; } } }
public List <Configuration.TimedTrafficLights> SaveData(ref bool success) { var ret = new List <Configuration.TimedTrafficLights>(); for (uint nodeId = 0; nodeId < NetManager.MAX_NODE_COUNT; ++nodeId) { try { if (!TrafficLightSimulations[nodeId].IsTimedLight()) { continue; } #if DEBUGSAVE Log._Debug($"Going to save timed light at node {nodeId}."); #endif ITimedTrafficLights timedNode = TrafficLightSimulations[nodeId].timedLight; timedNode.OnGeometryUpdate(); var cnfTimedLights = new Configuration.TimedTrafficLights { nodeId = timedNode.NodeId, nodeGroup = new List <ushort>(timedNode.NodeGroup), started = timedNode.IsStarted() }; ret.Add(cnfTimedLights); int stepIndex = timedNode.CurrentStep; if (timedNode.IsStarted() && timedNode.GetStep(timedNode.CurrentStep).IsInEndTransition()) { // if in end transition save the next step stepIndex = (stepIndex + 1) % timedNode.NumSteps(); } cnfTimedLights.currentStep = stepIndex; cnfTimedLights.timedSteps = new List <Configuration.TimedTrafficLightsStep>(); for (var j = 0; j < timedNode.NumSteps(); j++) { #if DEBUGSAVE Log._Debug($"Saving timed light step {j} at node {nodeId}."); #endif ITimedTrafficLightsStep timedStep = timedNode.GetStep(j); var cnfTimedStep = new Configuration.TimedTrafficLightsStep { minTime = timedStep.MinTime, maxTime = timedStep.MaxTime, changeMetric = (int)timedStep.ChangeMetric, waitFlowBalance = timedStep.WaitFlowBalance, segmentLights = new Dictionary <ushort, Configuration.CustomSegmentLights>() }; cnfTimedLights.timedSteps.Add(cnfTimedStep); foreach (KeyValuePair <ushort, ICustomSegmentLights> e in timedStep.CustomSegmentLights) { #if DEBUGSAVE Log._Debug($"Saving timed light step {j}, segment {e.Key} at node {nodeId}."); #endif ICustomSegmentLights segLights = e.Value; ushort lightsNodeId = segLights.NodeId; var cnfSegLights = new Configuration.CustomSegmentLights { nodeId = lightsNodeId, // TODO not needed segmentId = segLights.SegmentId, // TODO not needed customLights = new Dictionary <ExtVehicleType, Configuration.CustomSegmentLight>(), pedestrianLightState = segLights.PedestrianLightState, manualPedestrianMode = segLights.ManualPedestrianMode }; if (lightsNodeId == 0 || lightsNodeId != timedNode.NodeId) { Log.Warning( "Inconsistency detected: Timed traffic light @ node " + $"{timedNode.NodeId} contains custom traffic lights for the invalid " + $"segment ({segLights.SegmentId}) at step {j}: nId={lightsNodeId}"); continue; } cnfTimedStep.segmentLights.Add(e.Key, cnfSegLights); #if DEBUGSAVE Log._Debug($"Saving pedestrian light @ seg. {e.Key}, step {j}: " + $"{cnfSegLights.pedestrianLightState} {cnfSegLights.manualPedestrianMode}"); #endif foreach (KeyValuePair <API.Traffic.Enums.ExtVehicleType, ICustomSegmentLight> e2 in segLights.CustomLights) { #if DEBUGSAVE Log._Debug($"Saving timed light step {j}, segment {e.Key}, vehicleType " + $"{e2.Key} at node {nodeId}."); #endif ICustomSegmentLight segLight = e2.Value; var cnfSegLight = new Configuration.CustomSegmentLight { nodeId = lightsNodeId, // TODO not needed segmentId = segLights.SegmentId, // TODO not needed currentMode = (int)segLight.CurrentMode, leftLight = segLight.LightLeft, mainLight = segLight.LightMain, rightLight = segLight.LightRight }; cnfSegLights.customLights.Add( LegacyExtVehicleType.ToOld(e2.Key), cnfSegLight); } } } } catch (Exception e) { Log.Error( $"Exception occurred while saving timed traffic light @ {nodeId}: {e}"); success = false; } } return(ret); }
public bool LoadData(List <Configuration.TimedTrafficLights> data) { bool success = true; Log.Info($"Loading {data.Count} timed traffic lights (new method)"); var nodesWithSimulation = new HashSet <ushort>(); foreach (Configuration.TimedTrafficLights cnfTimedLights in data) { nodesWithSimulation.Add(cnfTimedLights.nodeId); } var masterNodeIdBySlaveNodeId = new Dictionary <ushort, ushort>(); var nodeGroupByMasterNodeId = new Dictionary <ushort, List <ushort> >(); foreach (Configuration.TimedTrafficLights cnfTimedLights in data) { try { // TODO most of this should not be necessary at all if the classes around TimedTrafficLights class were properly designed // enforce uniqueness of node ids List <ushort> currentNodeGroup = cnfTimedLights.nodeGroup.Distinct().ToList(); if (!currentNodeGroup.Contains(cnfTimedLights.nodeId)) { currentNodeGroup.Add(cnfTimedLights.nodeId); } // remove any nodes that are not configured to have a simulation currentNodeGroup = new List <ushort>( currentNodeGroup.Intersect(nodesWithSimulation)); // remove invalid nodes from the group; find if any of the nodes in the group is already a master node ushort masterNodeId = 0; int foundMasterNodes = 0; for (int i = 0; i < currentNodeGroup.Count;) { ushort nodeId = currentNodeGroup[i]; if (!Services.NetService.IsNodeValid(currentNodeGroup[i])) { currentNodeGroup.RemoveAt(i); continue; } if (nodeGroupByMasterNodeId.ContainsKey(nodeId)) { // this is a known master node if (foundMasterNodes > 0) { // we already found another master node. ignore this node. currentNodeGroup.RemoveAt(i); continue; } // we found the first master node masterNodeId = nodeId; ++foundMasterNodes; } ++i; } if (masterNodeId == 0) { // no master node defined yet, set the first node as a master node masterNodeId = currentNodeGroup[0]; } // ensure the master node is the first node in the list (TimedTrafficLights // depends on this at the moment...) currentNodeGroup.Remove(masterNodeId); currentNodeGroup.Insert(0, masterNodeId); // update the saved node group and master-slave info nodeGroupByMasterNodeId[masterNodeId] = currentNodeGroup; foreach (ushort nodeId in currentNodeGroup) { masterNodeIdBySlaveNodeId[nodeId] = masterNodeId; } } catch (Exception e) { Log.WarningFormat( "Error building timed traffic light group for TimedNode {0} (NodeGroup: {1}): {2}", cnfTimedLights.nodeId, string.Join(", ", cnfTimedLights.nodeGroup.Select(x => x.ToString()).ToArray()), e); success = false; } } foreach (Configuration.TimedTrafficLights cnfTimedLights in data) { try { if (!masterNodeIdBySlaveNodeId.ContainsKey(cnfTimedLights.nodeId)) { continue; } ushort masterNodeId = masterNodeIdBySlaveNodeId[cnfTimedLights.nodeId]; List <ushort> nodeGroup = nodeGroupByMasterNodeId[masterNodeId]; #if DEBUGLOAD Log._Debug($"Adding timed light at node {cnfTimedLights.nodeId}. NodeGroup: " + $"{string.Join(", ", nodeGroup.Select(x => x.ToString()).ToArray())}"); #endif SetUpTimedTrafficLight(cnfTimedLights.nodeId, nodeGroup); int j = 0; foreach (Configuration.TimedTrafficLightsStep cnfTimedStep in cnfTimedLights.timedSteps) { #if DEBUGLOAD Log._Debug($"Loading timed step {j} at node {cnfTimedLights.nodeId}"); #endif ITimedTrafficLightsStep step = TrafficLightSimulations[cnfTimedLights.nodeId].timedLight.AddStep( cnfTimedStep.minTime, cnfTimedStep.maxTime, (StepChangeMetric)cnfTimedStep.changeMetric, cnfTimedStep.waitFlowBalance); foreach (KeyValuePair <ushort, Configuration.CustomSegmentLights> e in cnfTimedStep.segmentLights) { if (!Services.NetService.IsSegmentValid(e.Key)) { continue; } e.Value.nodeId = cnfTimedLights.nodeId; #if DEBUGLOAD Log._Debug($"Loading timed step {j}, segment {e.Key} at node {cnfTimedLights.nodeId}"); #endif ICustomSegmentLights lights = null; if (!step.CustomSegmentLights.TryGetValue(e.Key, out lights)) { #if DEBUGLOAD Log._Debug($"No segment lights found at timed step {j} for segment " + $"{e.Key}, node {cnfTimedLights.nodeId}"); #endif continue; } Configuration.CustomSegmentLights cnfLights = e.Value; #if DEBUGLOAD Log._Debug($"Loading pedestrian light @ seg. {e.Key}, step {j}: " + $"{cnfLights.pedestrianLightState} {cnfLights.manualPedestrianMode}"); #endif lights.ManualPedestrianMode = cnfLights.manualPedestrianMode; lights.PedestrianLightState = cnfLights.pedestrianLightState; bool first = true; // v1.10.2 transitional code foreach (KeyValuePair <ExtVehicleType, Configuration.CustomSegmentLight> e2 in cnfLights.customLights) { #if DEBUGLOAD Log._Debug($"Loading timed step {j}, segment {e.Key}, vehicleType " + $"{e2.Key} at node {cnfTimedLights.nodeId}"); #endif if (!lights.CustomLights.TryGetValue( LegacyExtVehicleType.ToNew(e2.Key), out ICustomSegmentLight light)) { #if DEBUGLOAD Log._Debug($"No segment light found for timed step {j}, segment " + $"{e.Key}, vehicleType {e2.Key} at node {cnfTimedLights.nodeId}"); #endif // v1.10.2 transitional code START if (first) { first = false; if (!lights.CustomLights.TryGetValue( CustomSegmentLights .DEFAULT_MAIN_VEHICLETYPE, out light)) { #if DEBUGLOAD Log._Debug($"No segment light found for timed step {j}, " + $"segment {e.Key}, DEFAULT vehicleType {CustomSegmentLights.DEFAULT_MAIN_VEHICLETYPE} " + $"at node {cnfTimedLights.nodeId}"); #endif continue; } } else { // v1.10.2 transitional code END continue; // v1.10.2 transitional code START } // v1.10.2 transitional code END } Configuration.CustomSegmentLight cnfLight = e2.Value; light.InternalCurrentMode = (LightMode)cnfLight.currentMode; // TODO improve & remove light.SetStates( cnfLight.mainLight, cnfLight.leftLight, cnfLight.rightLight, false); } } ++j; } } catch (Exception e) { // ignore, as it's probably corrupt save data. it'll be culled on next save Log.Warning($"Error loading data from TimedNode (new method): {e}"); success = false; } } foreach (Configuration.TimedTrafficLights cnfTimedLights in data) { try { ITimedTrafficLights timedNode = TrafficLightSimulations[cnfTimedLights.nodeId].timedLight; timedNode.Housekeeping(); if (cnfTimedLights.started) { timedNode.Start(cnfTimedLights.currentStep); } } catch (Exception e) { Log.Warning($"Error starting timed light @ {cnfTimedLights.nodeId}: {e}"); success = false; } } return(success); }