private void RefreshCurrentRestrictedSegmentIds() { currentRestrictedSegmentIds.Clear(); for (ushort segmentId = 1; segmentId < NetManager.MAX_SEGMENT_COUNT; ++segmentId) { if ((Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Created) == NetSegment.Flags.None) { continue; } if (VehicleRestrictionsManager.Instance().HasSegmentRestrictions(segmentId)) { currentRestrictedSegmentIds.Add(segmentId); } } }
private bool drawVehicleRestrictionHandles(ushort segmentId, bool viewOnly, out bool stateUpdated) { stateUpdated = false; if (!LoadingExtension.IsPathManagerCompatible) { return(false); } if (viewOnly && !Options.vehicleRestrictionsOverlay && TrafficManagerTool.GetToolMode() != ToolMode.VehicleRestrictions) { return(false); } Vector3 center = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_bounds.center; var screenPos = Camera.main.WorldToScreenPoint(center); screenPos.y = Screen.height - screenPos.y; if (screenPos.z < 0) { return(false); } var camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position; var diff = center - camPos; if (diff.magnitude > TrafficManagerTool.PriorityCloseLod) { return(false); // do not draw if too distant } int numDirections; int numLanes = TrafficManagerTool.GetSegmentNumVehicleLanes(segmentId, null, out numDirections); // draw vehicle restrictions over each lane NetInfo segmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].Info; Vector3 yu = (Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_endDirection - Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startDirection).normalized; if ((Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) { yu = -yu; } Vector3 xu = Vector3.Cross(yu, new Vector3(0, 1f, 0)).normalized; float f = viewOnly ? 4f : 7f; // reserved sign size in game coordinates ItemClass connectionClass = segmentInfo.GetConnectionClass(); int maxNumSigns = 0; if (connectionClass.m_service == ItemClass.Service.Road) { maxNumSigns = roadVehicleTypes.Length; } else if (connectionClass.m_service == ItemClass.Service.PublicTransport && connectionClass.m_subService == ItemClass.SubService.PublicTransportTrain) { maxNumSigns = railVehicleTypes.Length; } //Vector3 zero = center - 0.5f * (float)(numLanes + numDirections - 1) * f * (xu + yu); // "bottom left" Vector3 zero = center - 0.5f * (float)(numLanes - 1 + numDirections - 1) * f * xu - 0.5f * (float)maxNumSigns * f * yu; // "bottom left" /*if (!viewOnly) * Log._Debug($"xu: {xu.ToString()} yu: {yu.ToString()} center: {center.ToString()} zero: {zero.ToString()} numLanes: {numLanes} numDirections: {numDirections}");*/ uint x = 0; var guiColor = GUI.color; List <object[]> sortedLanes = TrafficManagerTool.GetSortedVehicleLanes(segmentId, segmentInfo, null); bool hovered = false; HashSet <NetInfo.Direction> directions = new HashSet <NetInfo.Direction>(); int sortedLaneIndex = -1; foreach (object[] laneData in sortedLanes) { ++sortedLaneIndex; uint laneId = (uint)laneData[0]; uint laneIndex = (uint)laneData[2]; NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex]; if (!directions.Contains(laneInfo.m_direction)) { if (directions.Count > 0) { ++x; // space between different directions } directions.Add(laneInfo.m_direction); } ExtVehicleType[] possibleVehicleTypes = null; if (VehicleRestrictionsManager.Instance().IsRoadLane(laneInfo)) { possibleVehicleTypes = roadVehicleTypes; } else if (VehicleRestrictionsManager.Instance().IsRailLane(laneInfo)) { possibleVehicleTypes = railVehicleTypes; } else { ++x; continue; } ExtVehicleType allowedTypes = VehicleRestrictionsManager.Instance().GetAllowedVehicleTypes(segmentId, segmentInfo, laneIndex, laneInfo); uint y = 0; #if DEBUGx Vector3 labelCenter = zero + f * (float)x * xu + f * (float)y * yu; // in game coordinates var labelScreenPos = Camera.main.WorldToScreenPoint(labelCenter); labelScreenPos.y = Screen.height - labelScreenPos.y; diff = labelCenter - camPos; var labelZoom = 1.0f / diff.magnitude * 100f; _counterStyle.fontSize = (int)(11f * labelZoom); _counterStyle.normal.textColor = new Color(1f, 1f, 0f); string labelStr = $"Idx {laneIndex}"; Vector2 dim = _counterStyle.CalcSize(new GUIContent(labelStr)); Rect labelRect = new Rect(labelScreenPos.x - dim.x / 2f, labelScreenPos.y, dim.x, dim.y); GUI.Label(labelRect, labelStr, _counterStyle); ++y; #endif foreach (ExtVehicleType vehicleType in possibleVehicleTypes) { bool allowed = VehicleRestrictionsManager.Instance().IsAllowed(allowedTypes, vehicleType); if (allowed && viewOnly) { continue; // do not draw allowed vehicles in view-only mode } bool hoveredHandle; DrawRestrictionsSign(viewOnly, camPos, out diff, xu, yu, f, zero, x, y, ref guiColor, TrafficLightToolTextureResources.VehicleRestrictionTextures[vehicleType][allowed], out hoveredHandle); if (hoveredHandle) { hovered = true; } if (hoveredHandle && MainTool.CheckClicked()) { // toggle vehicle restrictions //Log._Debug($"Setting vehicle restrictions of segment {segmentId}, lane idx {laneIndex}, {vehicleType.ToString()} to {!allowed}"); VehicleRestrictionsManager.Instance().ToggleAllowedType(segmentId, segmentInfo, laneIndex, laneId, laneInfo, vehicleType, !allowed); stateUpdated = true; // TODO use SegmentTraverser if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) { ApplyRestrictionsToAllSegments(sortedLaneIndex); } } ++y; } ++x; } guiColor.a = 1f; GUI.color = guiColor; return(hovered); }
private void ApplyRestrictionsToAllSegments(int?sortedLaneIndex = null) { NetInfo selectedSegmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].Info; List <object[]> selectedSortedLanes = TrafficManagerTool.GetSortedVehicleLanes(SelectedSegmentId, selectedSegmentInfo, null); LinkedList <ushort> nodesToProcess = new LinkedList <ushort>(); HashSet <ushort> processedNodes = new HashSet <ushort>(); HashSet <ushort> processedSegments = new HashSet <ushort>(); processedSegments.Add(SelectedSegmentId); ushort selectedStartNodeId = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].m_startNode; ushort selectedEndNodeId = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].m_endNode; if (selectedStartNodeId != 0) { nodesToProcess.AddFirst(selectedStartNodeId); } if (selectedEndNodeId != 0) { nodesToProcess.AddFirst(selectedEndNodeId); } while (nodesToProcess.First != null) { ushort nodeId = nodesToProcess.First.Value; nodesToProcess.RemoveFirst(); processedNodes.Add(nodeId); if (Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId].CountSegments() > 2) { continue; // junction. stop. } // explore segments at node for (var s = 0; s < 8; s++) { var segmentId = Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId].GetSegment(s); if (segmentId <= 0 || processedSegments.Contains(segmentId)) { continue; } processedSegments.Add(segmentId); NetInfo segmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].Info; List <object[]> sortedLanes = TrafficManagerTool.GetSortedVehicleLanes(segmentId, segmentInfo, null); if (sortedLanes.Count == selectedSortedLanes.Count) { // number of lanes matches selected segment int sli = -1; for (int i = 0; i < sortedLanes.Count; ++i) { ++sli; if (sortedLaneIndex != null && sli != sortedLaneIndex) { continue; } object[] selectedLaneData = selectedSortedLanes[i]; object[] laneData = sortedLanes[i]; uint selectedLaneId = (uint)selectedLaneData[0]; uint selectedLaneIndex = (uint)selectedLaneData[2]; NetInfo.Lane selectedLaneInfo = segmentInfo.m_lanes[selectedLaneIndex]; uint laneId = (uint)laneData[0]; uint laneIndex = (uint)laneData[2]; NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex]; // apply restrictions of selected segment & lane VehicleRestrictionsManager.Instance().SetAllowedVehicleTypes(segmentId, segmentInfo, laneIndex, laneInfo, laneId, VehicleRestrictionsManager.Instance().GetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, selectedLaneIndex, selectedLaneInfo)); } // add nodes to explore ushort startNodeId = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startNode; ushort endNodeId = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_endNode; if (startNodeId != 0 && !processedNodes.Contains(startNodeId)) { nodesToProcess.AddFirst(startNodeId); } if (endNodeId != 0 && !processedNodes.Contains(endNodeId)) { nodesToProcess.AddFirst(endNodeId); } } } } }
private void _guiVehicleRestrictionsWindow(int num) { if (GUILayout.Button(Translation.GetString("Invert"))) { // invert pattern NetInfo selectedSegmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].Info; List <object[]> sortedLanes = TrafficManagerTool.GetSortedVehicleLanes(SelectedSegmentId, selectedSegmentInfo, null); // TODO does not need to be sorted, but every lane should be a vehicle lane foreach (object[] laneData in sortedLanes) { uint laneId = (uint)laneData[0]; uint laneIndex = (uint)laneData[2]; NetInfo.Lane laneInfo = selectedSegmentInfo.m_lanes[laneIndex]; ExtVehicleType baseMask = VehicleRestrictionsManager.Instance().GetBaseMask(laneInfo); if (baseMask == ExtVehicleType.None) { continue; } ExtVehicleType allowedTypes = VehicleRestrictionsManager.Instance().GetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo); allowedTypes = ~allowedTypes & baseMask; VehicleRestrictionsManager.Instance().SetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo, laneId, allowedTypes); } RefreshCurrentRestrictedSegmentIds(); } GUILayout.BeginHorizontal(); if (GUILayout.Button(Translation.GetString("Allow_all_vehicles"))) { // allow all vehicle types NetInfo selectedSegmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].Info; List <object[]> sortedLanes = TrafficManagerTool.GetSortedVehicleLanes(SelectedSegmentId, selectedSegmentInfo, null); // TODO does not need to be sorted, but every lane should be a vehicle lane foreach (object[] laneData in sortedLanes) { uint laneId = (uint)laneData[0]; uint laneIndex = (uint)laneData[2]; NetInfo.Lane laneInfo = selectedSegmentInfo.m_lanes[laneIndex]; ExtVehicleType baseMask = VehicleRestrictionsManager.Instance().GetBaseMask(laneInfo); if (baseMask == ExtVehicleType.None) { continue; } VehicleRestrictionsManager.Instance().SetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo, laneId, baseMask); } RefreshCurrentRestrictedSegmentIds(); } if (GUILayout.Button(Translation.GetString("Ban_all_vehicles"))) { // ban all vehicle types NetInfo selectedSegmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].Info; List <object[]> sortedLanes = TrafficManagerTool.GetSortedVehicleLanes(SelectedSegmentId, selectedSegmentInfo, null); // TODO does not need to be sorted, but every lane should be a vehicle lane foreach (object[] laneData in sortedLanes) { uint laneId = (uint)laneData[0]; uint laneIndex = (uint)laneData[2]; NetInfo.Lane laneInfo = selectedSegmentInfo.m_lanes[laneIndex]; VehicleRestrictionsManager.Instance().SetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo, laneId, ExtVehicleType.None); } RefreshCurrentRestrictedSegmentIds(); } GUILayout.EndHorizontal(); if (GUILayout.Button(Translation.GetString("Apply_vehicle_restrictions_to_all_road_segments_between_two_junctions"))) { ApplyRestrictionsToAllSegments(); RefreshCurrentRestrictedSegmentIds(); } GUI.DragWindow(); }
private static void LoadDataState(out bool error) { error = false; Log.Info("Loading State from Config"); if (_configuration == null) { Log.Warning("Configuration NULL, Couldn't load save data. Possibly a new game?"); return; } TrafficPriorityManager prioMan = TrafficPriorityManager.Instance(); // load priority segments if (_configuration.PrioritySegments != null) { Log.Info($"Loading {_configuration.PrioritySegments.Count()} priority segments"); foreach (var segment in _configuration.PrioritySegments) { try { if (segment.Length < 3) { continue; } #if DEBUG bool debug = segment[0] == 13630; #endif if ((SegmentEnd.PriorityType)segment[2] == SegmentEnd.PriorityType.None) { #if DEBUG if (debug) { Log._Debug($"Loading priority segment: Not adding 'None' priority segment: {segment[1]} @ node {segment[0]}"); } #endif continue; } if (!NetUtil.IsNodeValid((ushort)segment[0])) { #if DEBUG if (debug) { Log._Debug($"Loading priority segment: node {segment[0]} is invalid"); } #endif continue; } if (!NetUtil.IsSegmentValid((ushort)segment[1])) { #if DEBUG if (debug) { Log._Debug($"Loading priority segment: segment {segment[1]} @ node {segment[0]} is invalid"); } #endif continue; } if (prioMan.IsPrioritySegment((ushort)segment[0], (ushort)segment[1])) { #if DEBUG if (debug) { Log._Debug($"Loading priority segment: segment {segment[1]} @ node {segment[0]} is already a priority segment"); } #endif prioMan.GetPrioritySegment((ushort)segment[0], (ushort)segment[1]).Type = (SegmentEnd.PriorityType)segment[2]; continue; } #if DEBUG Log._Debug($"Adding Priority Segment of type: {segment[2].ToString()} to segment {segment[1]} @ node {segment[0]}"); #endif prioMan.AddPrioritySegment((ushort)segment[0], (ushort)segment[1], (SegmentEnd.PriorityType)segment[2]); } catch (Exception e) { // ignore, as it's probably corrupt save data. it'll be culled on next save Log.Warning("Error loading data from Priority segments: " + e.ToString()); error = true; } } } else { Log.Warning("Priority segments data structure undefined!"); } // load vehicle restrictions (warning: has to be done before loading timed lights!) if (_configuration.LaneAllowedVehicleTypes != null) { Log.Info($"Loading lane vehicle restriction data. {_configuration.LaneAllowedVehicleTypes.Count} elements"); foreach (Configuration.LaneVehicleTypes laneVehicleTypes in _configuration.LaneAllowedVehicleTypes) { try { ExtVehicleType baseMask = VehicleRestrictionsManager.Instance().GetBaseMask(laneVehicleTypes.laneId); ExtVehicleType maskedType = laneVehicleTypes.vehicleTypes & baseMask; Log._Debug($"Loading lane vehicle restriction: lane {laneVehicleTypes.laneId} = {laneVehicleTypes.vehicleTypes}, masked = {maskedType}"); if (maskedType != baseMask) { Flags.setLaneAllowedVehicleTypes(laneVehicleTypes.laneId, maskedType); } else { Log._Debug($"Masked type does not differ from base type. Ignoring."); } } catch (Exception e) { // ignore, as it's probably corrupt save data. it'll be culled on next save Log.Warning("Error loading data from vehicle restrictions: " + e.ToString()); error = true; } } } else { Log.Warning("Vehicle restrctions structure undefined!"); } NetManager netManager = Singleton <NetManager> .instance; TrafficLightSimulationManager tlsMan = TrafficLightSimulationManager.Instance(); if (_configuration.TimedLights != null) { Log.Info($"Loading {_configuration.TimedLights.Count()} timed traffic lights (new method)"); foreach (Configuration.TimedTrafficLights cnfTimedLights in _configuration.TimedLights) { try { if (!NetUtil.IsNodeValid(cnfTimedLights.nodeId)) { continue; } Flags.setNodeTrafficLight(cnfTimedLights.nodeId, true); Log._Debug($"Adding Timed Node at node {cnfTimedLights.nodeId}"); TrafficLightSimulation sim = tlsMan.AddNodeToSimulation(cnfTimedLights.nodeId); sim.SetupTimedTrafficLight(cnfTimedLights.nodeGroup); var timedNode = sim.TimedLight; int j = 0; foreach (Configuration.TimedTrafficLightsStep cnfTimedStep in cnfTimedLights.timedSteps) { Log._Debug($"Loading timed step {j} at node {cnfTimedLights.nodeId}"); TimedTrafficLightsStep step = timedNode.AddStep(cnfTimedStep.minTime, cnfTimedStep.maxTime, cnfTimedStep.waitFlowBalance); foreach (KeyValuePair <ushort, Configuration.CustomSegmentLights> e in cnfTimedStep.segmentLights) { Log._Debug($"Loading timed step {j}, segment {e.Key} at node {cnfTimedLights.nodeId}"); CustomSegmentLights lights = null; if (!step.segmentLights.TryGetValue(e.Key, out lights)) { Log._Debug($"No segment lights found at timed step {j} for segment {e.Key}, node {cnfTimedLights.nodeId}"); continue; } Configuration.CustomSegmentLights cnfLights = e.Value; Log._Debug($"Loading pedestrian light @ seg. {e.Key}, step {j}: {cnfLights.pedestrianLightState} {cnfLights.manualPedestrianMode}"); lights.ManualPedestrianMode = cnfLights.manualPedestrianMode; lights.PedestrianLightState = cnfLights.pedestrianLightState; foreach (KeyValuePair <ExtVehicleType, Configuration.CustomSegmentLight> e2 in cnfLights.customLights) { Log._Debug($"Loading timed step {j}, segment {e.Key}, vehicleType {e2.Key} at node {cnfTimedLights.nodeId}"); CustomSegmentLight light = null; if (!lights.CustomLights.TryGetValue(e2.Key, out light)) { Log._Debug($"No segment light found for timed step {j}, segment {e.Key}, vehicleType {e2.Key} at node {cnfTimedLights.nodeId}"); continue; } Configuration.CustomSegmentLight cnfLight = e2.Value; light.CurrentMode = (CustomSegmentLight.Mode)cnfLight.currentMode; light.LightLeft = cnfLight.leftLight; light.LightMain = cnfLight.mainLight; light.LightRight = cnfLight.rightLight; } } ++j; } if (cnfTimedLights.started) { timedNode.Start(); } } 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.ToString()); error = true; } } } else { Log.Warning("Timed traffic lights data structure undefined!"); } if (_configuration.NodeTrafficLights != null) { var trafficLightDefs = _configuration.NodeTrafficLights.Split(','); Log.Info($"Loading junction traffic light data"); // new method foreach (var split in trafficLightDefs.Select(def => def.Split(':')).Where(split => split.Length > 1)) { try { Log._Debug($"Traffic light split data: {split[0]} , {split[1]}"); var nodeId = Convert.ToUInt16(split[0]); uint flag = Convert.ToUInt16(split[1]); Flags.setNodeTrafficLight(nodeId, flag > 0); } catch (Exception e) { // ignore as it's probably bad save data. Log.Error($"Error setting the NodeTrafficLights: " + e.ToString()); error = true; } } } else { Log.Warning("Junction traffic lights data structure undefined!"); } if (_configuration.LaneFlags != null) { Log.Info($"Loading lane arrow data"); #if DEBUG Log._Debug($"LaneFlags: {_configuration.LaneFlags}"); #endif var lanes = _configuration.LaneFlags.Split(','); if (lanes.Length > 1) { foreach (var split in lanes.Select(lane => lane.Split(':')).Where(split => split.Length > 1)) { try { Log._Debug($"Split Data: {split[0]} , {split[1]}"); var laneId = Convert.ToUInt32(split[0]); uint flags = Convert.ToUInt32(split[1]); //make sure we don't cause any overflows because of bad save data. if (Singleton <NetManager> .instance.m_lanes.m_buffer.Length <= laneId) { continue; } if (flags > ushort.MaxValue) { continue; } if (!NetUtil.IsLaneValid(laneId)) { continue; } //Singleton<NetManager>.instance.m_lanes.m_buffer[laneId].m_flags = fixLaneFlags(Singleton<NetManager>.instance.m_lanes.m_buffer[laneId].m_flags); uint laneArrowFlags = flags & Flags.lfr; uint origFlags = (Singleton <NetManager> .instance.m_lanes.m_buffer[laneId].m_flags & Flags.lfr); #if DEBUG Log._Debug("Setting flags for lane " + laneId + " to " + flags + " (" + ((Flags.LaneArrows)(laneArrowFlags)).ToString() + ")"); if ((origFlags | laneArrowFlags) == origFlags) // only load if setting differs from default { Log._Debug("Flags for lane " + laneId + " are original (" + ((NetLane.Flags)(origFlags)).ToString() + ")"); } #endif Flags.setLaneArrowFlags(laneId, (Flags.LaneArrows)(laneArrowFlags)); } catch (Exception e) { Log.Error($"Error loading Lane Split data. Length: {split.Length} value: {split}\nError: {e.ToString()}"); error = true; } } } } else { Log.Warning("Lane arrow data structure undefined!"); } // load lane connections if (_configuration.LaneConnections != null) { Log.Info($"Loading {_configuration.LaneConnections.Count()} lane connections"); foreach (Configuration.LaneConnection conn in _configuration.LaneConnections) { try { Log._Debug($"Loading lane connection: lane {conn.lowerLaneId} -> {conn.higherLaneId}"); LaneConnectionManager.Instance().AddLaneConnection(conn.lowerLaneId, conn.higherLaneId, conn.lowerStartNode); } catch (Exception e) { // ignore, as it's probably corrupt save data. it'll be culled on next save Log.Error("Error loading data from lane connection: " + e.ToString()); error = true; } } } else { Log.Warning("Lane connection data structure undefined!"); } // load speed limits if (_configuration.LaneSpeedLimits != null) { Log.Info($"Loading lane speed limit data. {_configuration.LaneSpeedLimits.Count} elements"); foreach (Configuration.LaneSpeedLimit laneSpeedLimit in _configuration.LaneSpeedLimits) { try { Log._Debug($"Loading lane speed limit: lane {laneSpeedLimit.laneId} = {laneSpeedLimit.speedLimit}"); Flags.setLaneSpeedLimit(laneSpeedLimit.laneId, laneSpeedLimit.speedLimit); } catch (Exception e) { // ignore, as it's probably corrupt save data. it'll be culled on next save Log.Warning("Error loading speed limits: " + e.ToString()); error = true; } } } else { Log.Warning("Lane speed limit structure undefined!"); } // Load segment-at-node flags if (_configuration.SegmentNodeConfs != null) { Log.Info($"Loading segment-at-node data. {_configuration.SegmentNodeConfs.Count} elements"); foreach (Configuration.SegmentNodeConf segNodeConf in _configuration.SegmentNodeConfs) { try { if (!NetUtil.IsSegmentValid(segNodeConf.segmentId)) { continue; } Flags.setSegmentNodeFlags(segNodeConf.segmentId, true, segNodeConf.startNodeFlags); Flags.setSegmentNodeFlags(segNodeConf.segmentId, false, segNodeConf.endNodeFlags); } catch (Exception e) { // ignore, as it's probably corrupt save data. it'll be culled on next save Log.Warning("Error loading segment-at-node config: " + e.ToString()); error = true; } } } else { Log.Warning("Segment-at-node structure undefined!"); } }
internal void housekeeping(bool mayDelete, RoadBaseAI.TrafficLightState mainState = RoadBaseAI.TrafficLightState.Red, RoadBaseAI.TrafficLightState leftState = RoadBaseAI.TrafficLightState.Red, RoadBaseAI.TrafficLightState rightState = RoadBaseAI.TrafficLightState.Red, RoadBaseAI.TrafficLightState pedState = RoadBaseAI.TrafficLightState.Red) { #if TRACE Singleton <CodeProfiler> .instance.Start("CustomSegmentLights.housekeeping"); #endif // we intentionally never delete vehicle types (because we may want to retain traffic light states if a segment is upgraded or replaced) HashSet <ExtVehicleType> setupLights = new HashSet <ExtVehicleType>(); Dictionary <byte, ExtVehicleType> allAllowedTypes = VehicleRestrictionsManager.Instance().GetAllowedVehicleTypesAsDict(segmentId, nodeId); ExtVehicleType allAllowedMask = VehicleRestrictionsManager.Instance().GetAllowedVehicleTypes(segmentId, nodeId); SeparateVehicleTypes = ExtVehicleType.None; #if DEBUGHK Log._Debug($"CustomSegmentLights: housekeeping @ seg. {segmentId}, node {nodeId}, allAllowedTypes={string.Join(", ", allAllowedTypes.Select(x => x.ToString()).ToArray())}"); #endif bool addPedestrianLight = false; uint numLights = 0; VehicleTypeByLaneIndex.Clear(); HashSet <byte> laneIndicesWithoutSeparateLights = new HashSet <byte>(allAllowedTypes.Keys); foreach (KeyValuePair <byte, ExtVehicleType> e in allAllowedTypes) { byte laneIndex = e.Key; ExtVehicleType allowedTypes = e.Value; foreach (ExtVehicleType mask in singleLaneVehicleTypes) { if (setupLights.Contains(mask)) { break; } if ((allowedTypes & mask) != ExtVehicleType.None && (allowedTypes & ~(mask | ExtVehicleType.Emergency)) == ExtVehicleType.None) { #if DEBUGHK Log._Debug($"CustomSegmentLights: housekeeping @ seg. {segmentId}, node {nodeId}: adding {mask} light"); #endif if (!CustomLights.ContainsKey(mask)) { CustomLights.Add(mask, new TrafficLight.CustomSegmentLight(this, nodeId, segmentId, mainState, leftState, rightState)); VehicleTypes.AddFirst(mask); } VehicleTypeByLaneIndex[laneIndex] = mask; laneIndicesWithoutSeparateLights.Remove(laneIndex); ++numLights; addPedestrianLight = true; autoPedestrianVehicleType = mask; mainSegmentLight = CustomLights[mask]; setupLights.Add(mask); SeparateVehicleTypes |= mask; break; } } } if (allAllowedTypes.Count > numLights) { #if DEBUGHK Log._Debug($"CustomSegmentLights: housekeeping @ seg. {segmentId}, node {nodeId}: adding main vehicle light: {mainVehicleType}"); #endif // traffic lights for cars if (!CustomLights.ContainsKey(mainVehicleType)) { CustomLights.Add(mainVehicleType, new TrafficLight.CustomSegmentLight(this, nodeId, segmentId, mainState, leftState, rightState)); VehicleTypes.AddFirst(mainVehicleType); } autoPedestrianVehicleType = mainVehicleType; mainSegmentLight = CustomLights[mainVehicleType]; foreach (byte laneIndex in laneIndicesWithoutSeparateLights) { VehicleTypeByLaneIndex[laneIndex] = ExtVehicleType.None; } addPedestrianLight = allAllowedMask == ExtVehicleType.None || (allAllowedMask & ~ExtVehicleType.RailVehicle) != ExtVehicleType.None; } else { addPedestrianLight = true; } #if DEBUGHK if (addPedestrianLight) { Log._Debug($"CustomSegmentLights: housekeeping @ seg. {segmentId}, node {nodeId}: adding ped. light"); } #endif if (mayDelete) { // delete traffic lights for non-existing configurations HashSet <ExtVehicleType> vehicleTypesToDelete = new HashSet <ExtVehicleType>(); foreach (KeyValuePair <ExtVehicleType, CustomSegmentLight> e in CustomLights) { if (e.Key == mainVehicleType) { continue; } if (!setupLights.Contains(e.Key)) { vehicleTypesToDelete.Add(e.Key); } } foreach (ExtVehicleType vehicleType in vehicleTypesToDelete) { #if DEBUGHK Log._Debug($"Deleting traffic light for {vehicleType} at segment {segmentId}, node {nodeId}"); #endif CustomLights.Remove(vehicleType); VehicleTypes.Remove(vehicleType); } } if (CustomLights.ContainsKey(mainVehicleType) && VehicleTypes.First.Value != mainVehicleType) { VehicleTypes.Remove(mainVehicleType); VehicleTypes.AddFirst(mainVehicleType); } if (addPedestrianLight) { #if DEBUGHK Log._Debug($"CustomSegmentLights: housekeeping @ seg. {segmentId}, node {nodeId}: adding pedestrian light"); #endif if (pedestrianLightState == null) { pedestrianLightState = pedState; } } else { pedestrianLightState = null; } #if DEBUGHK Log._Debug($"CustomSegmentLights: housekeeping @ seg. {segmentId}, node {nodeId}: Housekeeping complete. VehicleTypeByLaneIndex={string.Join("; ", VehicleTypeByLaneIndex.Select(x => x.Key + "=" + x.Value).ToArray())} CustomLights={string.Join("; ", CustomLights.Select(x => x.Key.ToString()).ToArray())}"); #endif #if TRACE Singleton <CodeProfiler> .instance.Stop("CustomSegmentLights.housekeeping"); #endif }
/// <summary> /// Calculates the current metrics for flowing and waiting vehicles /// </summary> /// <param name="wait"></param> /// <param name="flow"></param> /// <returns>true if the values could be calculated, false otherwise</returns> public bool calcWaitFlow(out float wait, out float flow) { #if TRACE Singleton <CodeProfiler> .instance.Start("TimedTrafficLightsStep.calcWaitFlow"); #endif #if DEBUGMETRIC bool debug = timedNode.NodeId == 3201; #else bool debug = false; #endif #if DEBUGMETRIC if (debug) { Log.Warning($"TimedTrafficLightsStep.calcWaitFlow: ***START*** @ node {timedNode.NodeId}"); } #endif uint numFlows = 0; uint numWaits = 0; uint curMeanFlow = 0; uint curMeanWait = 0; TrafficLightSimulationManager tlsMan = TrafficLightSimulationManager.Instance(); TrafficPriorityManager prioMan = TrafficPriorityManager.Instance(); // we are the master node. calculate traffic data foreach (ushort timedNodeId in timedNode.NodeGroup) { TrafficLightSimulation sim = tlsMan.GetNodeSimulation(timedNodeId); if (sim == null || !sim.IsTimedLight()) { continue; } TimedTrafficLights slaveTimedNode = sim.TimedLight; TimedTrafficLightsStep slaveStep = slaveTimedNode.Steps[timedNode.CurrentStep]; //List<int> segmentIdsToDelete = new List<int>(); // minimum time reached. check traffic! foreach (KeyValuePair <ushort, CustomSegmentLights> e in slaveStep.segmentLights) { var fromSegmentId = e.Key; var segLights = e.Value; // one of the traffic lights at this segment is green: count minimum traffic flowing through SegmentEnd fromSeg = prioMan.GetPrioritySegment(timedNodeId, fromSegmentId); if (fromSeg == null) { #if DEBUGMETRIC if (debug) { Log.Warning($"TimedTrafficLightsStep.calcWaitFlow: No priority segment @ seg. {fromSegmentId} found!"); } #endif //Log.Warning("stepDone(): prioSeg is null"); //segmentIdsToDelete.Add(fromSegmentId); continue; // skip invalid segment } //bool startPhase = getCurrentFrame() <= startFrame + minTime + 2; // during start phase all vehicles on "green" segments are counted as flowing ExtVehicleType validVehicleTypes = VehicleRestrictionsManager.Instance().GetAllowedVehicleTypes(fromSegmentId, timedNode.NodeId); foreach (KeyValuePair <byte, ExtVehicleType> e2 in segLights.VehicleTypeByLaneIndex) { byte laneIndex = e2.Key; ExtVehicleType vehicleType = e2.Value; if (vehicleType != ExtVehicleType.None && (validVehicleTypes & vehicleType) == ExtVehicleType.None) { continue; } CustomSegmentLight segLight = segLights.GetCustomLight(laneIndex); if (segLight == null) { Log.Warning($"Timed traffic light step: Failed to get custom light for vehicleType {vehicleType} @ seg. {fromSegmentId}, node {timedNode.NodeId}!"); continue; } #if DEBUGMETRIC if (debug) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Checking lane {laneIndex} @ seg. {fromSegmentId}. Vehicle types: {vehicleType}"); } #endif Dictionary <ushort, uint> carsFlowingToSegmentMetric = null; Dictionary <ushort, uint> allCarsToSegmentMetric = null; try { carsFlowingToSegmentMetric = fromSeg.GetVehicleMetricGoingToSegment(false, laneIndex, debug); } catch (Exception ex) { Log.Warning("calcWaitFlow (1): " + ex.ToString()); } try { allCarsToSegmentMetric = fromSeg.GetVehicleMetricGoingToSegment(true, laneIndex, debug); } catch (Exception ex) { Log.Warning("calcWaitFlow (2): " + ex.ToString()); } if (carsFlowingToSegmentMetric == null) { continue; } // build directions from toSegment to fromSegment Dictionary <ushort, ArrowDirection> directions = new Dictionary <ushort, ArrowDirection>(); foreach (KeyValuePair <ushort, uint> f in allCarsToSegmentMetric) { var toSegmentId = f.Key; SegmentGeometry geometry = SegmentGeometry.Get(fromSegmentId); ArrowDirection dir = geometry.GetDirection(toSegmentId, timedNodeId == geometry.StartNodeId()); directions[toSegmentId] = dir; #if DEBUGMETRIC if (debug) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Calculated direction for seg. {fromSegmentId} -> seg. {toSegmentId}: {dir}"); } #endif } // calculate waiting/flowing traffic foreach (KeyValuePair <ushort, uint> f in allCarsToSegmentMetric) { ushort toSegmentId = f.Key; uint totalNormCarLength = f.Value; uint totalFlowingNormCarLength = carsFlowingToSegmentMetric[f.Key]; #if DEBUGMETRIC if (debug) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Total norm. car length of vehicles on lane {laneIndex} going to seg. {toSegmentId}: {totalNormCarLength}"); } #endif bool addToFlow = false; switch (directions[toSegmentId]) { case ArrowDirection.Turn: addToFlow = TrafficPriorityManager.IsLeftHandDrive() ? segLight.isRightGreen() : segLight.isLeftGreen(); break; case ArrowDirection.Left: addToFlow = segLight.isLeftGreen(); break; case ArrowDirection.Right: addToFlow = segLight.isRightGreen(); break; case ArrowDirection.Forward: default: addToFlow = segLight.isForwardGreen(); break; } if (addToFlow) { ++numFlows; curMeanFlow += totalFlowingNormCarLength; } else { ++numWaits; curMeanWait += totalNormCarLength; } #if DEBUGMETRIC if (debug) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Vehicles on lane {laneIndex} on seg. {fromSegmentId} going to seg. {toSegmentId} flowing? {addToFlow} curMeanFlow={curMeanFlow}, curMeanWait={curMeanWait}"); } #endif } } } // delete invalid segments from step /*foreach (int segmentId in segmentIdsToDelete) { * slaveStep.segmentLightStates.Remove(segmentId); * }*/ } #if DEBUGMETRIC if (debug) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: ### Calculation completed. numFlows={numFlows}, numWaits={numWaits}, curMeanFlow={curMeanFlow}, curMeanWait={curMeanWait}"); } wait = curMeanWait; flow = curMeanFlow; #else if (numFlows > 0) { curMeanFlow /= numFlows; } if (numWaits > 0) { curMeanWait /= numWaits; } float fCurMeanFlow = curMeanFlow; fCurMeanFlow /= waitFlowBalance; // a value smaller than 1 rewards steady traffic currents wait = (float)curMeanWait; flow = fCurMeanFlow; #endif #if TRACE Singleton <CodeProfiler> .instance.Stop("TimedTrafficLightsStep.calcWaitFlow"); #endif return(true); }