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); }