public bool SetUpTimedTrafficLight(ref TrafficLightSimulation sim,
                                           IEnumerable <ushort> nodeGroup)
        {
            if (sim.IsManualLight())
            {
                DestroyManualTrafficLight(ref sim);
            }

            if (sim.IsTimedLight())
            {
                return(false);
            }

            Constants.ServiceFactory.NetService.ProcessNode(
                sim.nodeId,
                (ushort nId, ref NetNode node) => {
                Constants.ManagerFactory.TrafficLightManager.AddTrafficLight(
                    nId,
                    ref node);
                return(true);
            });

            Constants.ManagerFactory.CustomSegmentLightsManager.AddNodeLights(sim.nodeId);
            sim.timedLight = new TimedTrafficLights(sim.nodeId, nodeGroup);
            sim.type       = TrafficLightSimulationType.Timed;
            return(true);
        }
Example #2
0
        public override void OnPrimaryClickOverlay()
        {
            if (IsCursorInPanel())
            {
                return;
            }
            if (HoveredNodeId == 0)
            {
                return;
            }

            if ((Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_flags & NetNode.Flags.Junction) == NetNode.Flags.None)
            {
                return;
            }

            TrafficLightSimulation sim = TrafficLightSimulationManager.Instance.GetNodeSimulation(HoveredNodeId);

            if (sim != null && sim.IsTimedLight())
            {
                MainTool.ShowTooltip(Translation.GetString("NODE_IS_TIMED_LIGHT"), Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_position);
                return;
            }

            TrafficPriorityManager.Instance.RemovePrioritySegments(HoveredNodeId);
            TrafficLightManager.Instance.ToggleTrafficLight(HoveredNodeId);
        }
        public override void OnPrimaryClickOverlay()
        {
            if (SelectedNodeId != 0)
            {
                return;
            }

            TrafficLightSimulation sim = TrafficLightSimulation.GetNodeSimulation(HoveredNodeId);

            if (sim == null || !sim.IsTimedLight())
            {
                if ((Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_flags & NetNode.Flags.TrafficLights) == NetNode.Flags.None)
                {
                    TrafficPriority.RemovePrioritySegments(HoveredNodeId);
                    Flags.setNodeTrafficLight(HoveredNodeId, true);
                }

                SelectedNodeId = HoveredNodeId;

                sim = TrafficLightSimulation.AddNodeToSimulation(SelectedNodeId);
                sim.SetupManualTrafficLight();

                /*for (var s = 0; s < 8; s++) {
                 *      var segment = Singleton<NetManager>.instance.m_nodes.m_buffer[SelectedNodeId].GetSegment(s);
                 *      if (segment != 0 && !TrafficPriority.IsPrioritySegment(SelectedNodeId, segment)) {
                 *              TrafficPriority.AddPrioritySegment(SelectedNodeId, segment, SegmentEnd.PriorityType.None);
                 *      }
                 * }*/
            }
            else
            {
                MainTool.ShowTooltip(Translation.GetString("NODE_IS_TIMED_LIGHT"), Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_position);
            }
        }
        public bool HasTimedSimulation(ushort nodeId)
        {
            TrafficLightSimulation sim = TrafficLightSimulations[nodeId];

            if (sim == null)
            {
                return(false);
            }
            return(sim.IsTimedLight());
        }
        public bool SetUpManualTrafficLight(ref TrafficLightSimulation sim)
        {
            if (sim.IsTimedLight())
            {
                return(false);
            }

            Constants.ManagerFactory.TrafficLightManager.AddTrafficLight(
                sim.nodeId,
                ref sim.nodeId.ToNode());

            Constants.ManagerFactory.CustomSegmentLightsManager.AddNodeLights(sim.nodeId);
            sim.type = TrafficLightSimulationType.Manual;
            return(true);
        }
        public bool DestroyTimedTrafficLight(ref TrafficLightSimulation sim)
        {
            if (!sim.IsTimedLight())
            {
                return(false);
            }

            sim.type = TrafficLightSimulationType.None;
            ITimedTrafficLights timedLight = sim.timedLight;

            sim.timedLight = null;

            timedLight?.Destroy();

            return(true);
        }
        public bool DestroyManualTrafficLight(ref TrafficLightSimulation sim)
        {
            if (sim.IsTimedLight())
            {
                return(false);
            }

            if (!sim.IsManualLight())
            {
                return(false);
            }

            sim.type = TrafficLightSimulationType.None;
            Constants.ManagerFactory.CustomSegmentLightsManager.RemoveNodeLights(sim.nodeId);
            return(true);
        }
        public bool SetUpManualTrafficLight(ref TrafficLightSimulation sim)
        {
            if (sim.IsTimedLight())
            {
                return(false);
            }

            Constants.ServiceFactory.NetService.ProcessNode(
                sim.nodeId,
                (ushort nId, ref NetNode node) => {
                Constants.ManagerFactory.TrafficLightManager.AddTrafficLight(
                    nId,
                    ref node);
                return(true);
            });

            Constants.ManagerFactory.CustomSegmentLightsManager.AddNodeLights(sim.nodeId);
            sim.type = TrafficLightSimulationType.Manual;
            return(true);
        }
 public override void OnClickOverlay()
 {
     if ((Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_flags & NetNode.Flags.Junction) != NetNode.Flags.None)
     {
         if ((Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_flags & NetNode.Flags.TrafficLights) != NetNode.Flags.None)
         {
             TrafficLightSimulation sim = TrafficLightSimulation.GetNodeSimulation(HoveredNodeId);
             if (sim != null && sim.IsTimedLight())
             {
                 MainTool.ShowTooltip(Translation.GetString("NODE_IS_TIMED_LIGHT"), Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_position);
             }
             else
             {
                 TrafficLightSimulation.RemoveNodeFromSimulation(HoveredNodeId, true);    // TODO refactor!
                 Flags.setNodeTrafficLight(HoveredNodeId, false);                         // TODO refactor!
             }
         }
         else
         {
             TrafficPriority.RemovePrioritySegments(HoveredNodeId);
             Flags.setNodeTrafficLight(HoveredNodeId, true);
         }
     }
 }
Example #10
0
        public void ShowGUI(bool viewOnly)
        {
            try {
                TrafficLightSimulationManager tlsMan  = TrafficLightSimulationManager.Instance;
                TrafficPriorityManager        prioMan = TrafficPriorityManager.Instance;
                TrafficLightManager           tlm     = TrafficLightManager.Instance;

                bool clicked = !viewOnly?MainTool.CheckClicked() : false;

                var hoveredSegment = false;
                //Log.Message("_guiPrioritySigns called. num of prio segments: " + TrafficPriority.PrioritySegments.Count);

                HashSet <ushort> nodeIdsWithSigns = new HashSet <ushort>();
                foreach (ushort segmentId in currentPrioritySegmentIds)
                {
                    var trafficSegment = prioMan.TrafficSegments[segmentId];
                    if (trafficSegment == null)
                    {
                        continue;
                    }
                    SegmentGeometry geometry = SegmentGeometry.Get(segmentId);

                    prioritySegments[0] = null;
                    prioritySegments[1] = null;

                    if (tlsMan.GetNodeSimulation(trafficSegment.Node1) == null)
                    {
                        SegmentEnd tmpSeg1   = prioMan.GetPrioritySegment(trafficSegment.Node1, segmentId);
                        bool       startNode = geometry.StartNodeId() == trafficSegment.Node1;
                        if (tmpSeg1 != null && !geometry.IsOutgoingOneWay(startNode))
                        {
                            prioritySegments[0] = tmpSeg1;
                            nodeIdsWithSigns.Add(trafficSegment.Node1);
                            prioMan.AddPriorityNode(trafficSegment.Node1);
                        }
                    }
                    if (tlsMan.GetNodeSimulation(trafficSegment.Node2) == null)
                    {
                        SegmentEnd tmpSeg2   = prioMan.GetPrioritySegment(trafficSegment.Node2, segmentId);
                        bool       startNode = geometry.StartNodeId() == trafficSegment.Node2;
                        if (tmpSeg2 != null && !geometry.IsOutgoingOneWay(startNode))
                        {
                            prioritySegments[1] = tmpSeg2;
                            nodeIdsWithSigns.Add(trafficSegment.Node2);
                            prioMan.AddPriorityNode(trafficSegment.Node2);
                        }
                    }

                    //Log.Message("init ok");

                    foreach (var prioritySegment in prioritySegments)
                    {
                        if (prioritySegment == null)
                        {
                            continue;
                        }

                        var nodeId = prioritySegment.NodeId;
                        //Log.Message("_guiPrioritySigns: nodeId=" + nodeId);

                        var nodePositionVector3 = Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId].m_position;
                        var camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position;
                        var diff   = nodePositionVector3 - camPos;
                        if (diff.magnitude > TrafficManagerTool.PriorityCloseLod)
                        {
                            continue;                             // do not draw if too distant
                        }
                        if (Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startNode == (ushort)nodeId)
                        {
                            nodePositionVector3.x += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startDirection.x * 10f;
                            nodePositionVector3.y += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startDirection.y * 10f;
                            nodePositionVector3.z += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startDirection.z * 10f;
                        }
                        else
                        {
                            nodePositionVector3.x += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_endDirection.x * 10f;
                            nodePositionVector3.y += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_endDirection.y * 10f;
                            nodePositionVector3.z += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_endDirection.z * 10f;
                        }

                        var nodeScreenPosition = Camera.main.WorldToScreenPoint(nodePositionVector3);
                        nodeScreenPosition.y = Screen.height - nodeScreenPosition.y;
                        if (nodeScreenPosition.z < 0)
                        {
                            continue;
                        }
                        var zoom            = 1.0f / diff.magnitude * 100f * MainTool.GetBaseZoom();
                        var size            = 110f * zoom;
                        var guiColor        = GUI.color;
                        var nodeBoundingBox = new Rect(nodeScreenPosition.x - size / 2, nodeScreenPosition.y - size / 2, size, size);
                        hoveredSegment = !viewOnly && TrafficManagerTool.IsMouseOver(nodeBoundingBox);

                        if (hoveredSegment)
                        {
                            // mouse hovering over sign
                            guiColor.a = 0.8f;
                        }
                        else
                        {
                            guiColor.a = 0.5f;
                            size       = 90f * zoom;
                        }
                        var nodeDrawingBox = new Rect(nodeScreenPosition.x - size / 2, nodeScreenPosition.y - size / 2, size, size);

                        GUI.color = guiColor;

                        bool setUndefinedSignsToMainRoad = false;
                        switch (prioritySegment.Type)
                        {
                        case SegmentEnd.PriorityType.Main:
                            GUI.DrawTexture(nodeDrawingBox, TrafficLightToolTextureResources.SignPriorityTexture2D);
                            if (clicked && hoveredSegment)
                            {
                                //Log._Debug("Click on node " + nodeId + ", segment " + segmentId + " to change prio type (1)");
                                //Log.Message("PrioritySegment.Type = Yield");
                                prioritySegment.Type        = SegmentEnd.PriorityType.Yield;
                                setUndefinedSignsToMainRoad = true;
                                clicked = false;
                            }
                            break;

                        case SegmentEnd.PriorityType.Yield:
                            GUI.DrawTexture(nodeDrawingBox, TrafficLightToolTextureResources.SignYieldTexture2D);
                            if (clicked && hoveredSegment)
                            {
                                //Log._Debug("Click on node " + nodeId + ", segment " + segmentId + " to change prio type (2)");
                                prioritySegment.Type        = SegmentEnd.PriorityType.Stop;
                                setUndefinedSignsToMainRoad = true;
                                clicked = false;
                            }

                            break;

                        case SegmentEnd.PriorityType.Stop:
                            GUI.DrawTexture(nodeDrawingBox, TrafficLightToolTextureResources.SignStopTexture2D);
                            if (clicked && hoveredSegment)
                            {
                                //Log._Debug("Click on node " + nodeId + ", segment " + segmentId + " to change prio type (3)");
                                prioritySegment.Type = SegmentEnd.PriorityType.Main;
                                clicked = false;
                            }
                            break;

                        case SegmentEnd.PriorityType.None:
                            if (viewOnly)
                            {
                                break;
                            }
                            GUI.DrawTexture(nodeDrawingBox, TrafficLightToolTextureResources.SignNoneTexture2D);

                            if (clicked && hoveredSegment)
                            {
                                //Log._Debug("Click on node " + nodeId + ", segment " + segmentId + " to change prio type (4)");
                                //Log.Message("PrioritySegment.Type = None");
                                prioritySegment.Type = GetNumberOfMainRoads(nodeId, ref Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId]) >= 2
                                                                                ? SegmentEnd.PriorityType.Yield
                                                                                : SegmentEnd.PriorityType.Main;
                                if (prioritySegment.Type == SegmentEnd.PriorityType.Yield)
                                {
                                    setUndefinedSignsToMainRoad = true;
                                }
                                clicked = false;
                            }
                            break;
                        }

                        if (setUndefinedSignsToMainRoad)
                        {
                            foreach (var otherPrioritySegment in prioMan.GetPrioritySegments(nodeId))
                            {
                                if (otherPrioritySegment.SegmentId == prioritySegment.SegmentId)
                                {
                                    continue;
                                }
                                if (otherPrioritySegment.Type == SegmentEnd.PriorityType.None)
                                {
                                    otherPrioritySegment.Type = SegmentEnd.PriorityType.Main;
                                }
                            }
                        }
                    }
                }

                if (viewOnly)
                {
                    return;
                }

                ushort hoveredExistingNodeId = 0;
                foreach (ushort nodeId in nodeIdsWithSigns)
                {
                    var nodePositionVector3 = Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId].m_position;
                    var camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position;
                    var diff   = nodePositionVector3 - camPos;
                    if (diff.magnitude > TrafficManagerTool.PriorityCloseLod)
                    {
                        continue;
                    }

                    // draw deletion button
                    var nodeScreenPosition = Camera.main.WorldToScreenPoint(nodePositionVector3);
                    nodeScreenPosition.y = Screen.height - nodeScreenPosition.y;
                    if (nodeScreenPosition.z < 0)
                    {
                        continue;
                    }
                    var zoom            = 1.0f / diff.magnitude * 100f * MainTool.GetBaseZoom();
                    var size            = 90f * zoom;
                    var nodeBoundingBox = new Rect(nodeScreenPosition.x - size / 2, nodeScreenPosition.y - size / 2, size, size);

                    var guiColor          = GUI.color;
                    var nodeCenterHovered = TrafficManagerTool.IsMouseOver(nodeBoundingBox);
                    if (nodeCenterHovered)
                    {
                        hoveredExistingNodeId = nodeId;
                        guiColor.a            = 0.8f;
                    }
                    else
                    {
                        guiColor.a = 0.5f;
                    }
                    GUI.color = guiColor;

                    GUI.DrawTexture(nodeBoundingBox, TrafficLightToolTextureResources.SignRemoveTexture2D);
                }

                // add a new or delete a priority segment node
                if (HoveredNodeId != 0 || hoveredExistingNodeId != 0)
                {
                    bool delete = false;
                    if (hoveredExistingNodeId != 0)
                    {
                        delete = true;
                    }

                    // determine if we may add new priority signs to this node
                    bool ok = false;
                    TrafficLightSimulation nodeSim = tlsMan.GetNodeSimulation(HoveredNodeId);
                    if ((Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_flags & NetNode.Flags.TrafficLights) == NetNode.Flags.None)
                    {
                        // no traffic light set
                        ok = true;
                    }
                    else if (nodeSim == null || !nodeSim.IsTimedLight())
                    {
                        ok = true;
                    }

                    if (!Flags.mayHaveTrafficLight(HoveredNodeId))
                    {
                        ok = false;
                    }

                    if (clicked)
                    {
                        Log._Debug("_guiPrioritySigns: hovered+clicked @ nodeId=" + HoveredNodeId + "/" + hoveredExistingNodeId + " ok=" + ok);

                        if (delete)
                        {
                            prioMan.RemovePrioritySegments(hoveredExistingNodeId);
                            RefreshCurrentPrioritySegmentIds();
                        }
                        else if (ok)
                        {
                            //if (!prioMan.IsPriorityNode(HoveredNodeId)) {
                            Log._Debug("_guiPrioritySigns: adding prio segments @ nodeId=" + HoveredNodeId);
                            tlsMan.RemoveNodeFromSimulation(HoveredNodeId, false, true);
                            tlm.RemoveTrafficLight(HoveredNodeId);
                            prioMan.AddPriorityNode(HoveredNodeId);
                            RefreshCurrentPrioritySegmentIds();
                            //}
                        }
                        else if (nodeSim != null && nodeSim.IsTimedLight())
                        {
                            MainTool.ShowTooltip(Translation.GetString("NODE_IS_TIMED_LIGHT"), Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_position);
                        }
                    }
                }
            } catch (Exception e) {
                Log.Error(e.ToString());
            }
        }
        private static void SaveTimedTrafficLight(ushort i, Configuration configuration)
        {
            try {
                TrafficLightSimulation sim = TrafficLightSimulation.GetNodeSimulation(i);
                if (sim == null || !sim.IsTimedLight())
                {
                    return;
                }

                Log._Debug($"Going to save timed light at node {i}.");

                var timedNode = sim.TimedLight;
                timedNode.handleNewSegments();

                Configuration.TimedTrafficLights cnfTimedLights = new Configuration.TimedTrafficLights();
                configuration.TimedLights.Add(cnfTimedLights);

                cnfTimedLights.nodeId     = timedNode.NodeId;
                cnfTimedLights.nodeGroup  = timedNode.NodeGroup;
                cnfTimedLights.started    = timedNode.IsStarted();
                cnfTimedLights.timedSteps = new List <Configuration.TimedTrafficLightsStep>();

                for (var j = 0; j < timedNode.NumSteps(); j++)
                {
                    Log._Debug($"Saving timed light step {j} at node {i}.");
                    TimedTrafficLightsStep timedStep = timedNode.Steps[j];
                    Configuration.TimedTrafficLightsStep cnfTimedStep = new Configuration.TimedTrafficLightsStep();
                    cnfTimedLights.timedSteps.Add(cnfTimedStep);

                    cnfTimedStep.minTime         = timedStep.minTime;
                    cnfTimedStep.maxTime         = timedStep.maxTime;
                    cnfTimedStep.waitFlowBalance = timedStep.waitFlowBalance;
                    cnfTimedStep.segmentLights   = new Dictionary <ushort, Configuration.CustomSegmentLights>();
                    foreach (KeyValuePair <ushort, CustomSegmentLights> e in timedStep.segmentLights)
                    {
                        Log._Debug($"Saving timed light step {j}, segment {e.Key} at node {i}.");

                        CustomSegmentLights segLights = e.Value;
                        Configuration.CustomSegmentLights cnfSegLights = new Configuration.CustomSegmentLights();
                        cnfTimedStep.segmentLights.Add(e.Key, cnfSegLights);

                        cnfSegLights.nodeId               = segLights.NodeId;
                        cnfSegLights.segmentId            = segLights.SegmentId;
                        cnfSegLights.customLights         = new Dictionary <ExtVehicleType, Configuration.CustomSegmentLight>();
                        cnfSegLights.pedestrianLightState = segLights.PedestrianLightState;
                        cnfSegLights.manualPedestrianMode = segLights.ManualPedestrianMode;

                        Log._Debug($"Saving pedestrian light @ seg. {e.Key}, step {j}: {cnfSegLights.pedestrianLightState} {cnfSegLights.manualPedestrianMode}");

                        foreach (KeyValuePair <Traffic.ExtVehicleType, CustomSegmentLight> e2 in segLights.CustomLights)
                        {
                            Log._Debug($"Saving timed light step {j}, segment {e.Key}, vehicleType {e2.Key} at node {i}.");

                            CustomSegmentLight segLight = e2.Value;
                            Configuration.CustomSegmentLight cnfSegLight = new Configuration.CustomSegmentLight();
                            cnfSegLights.customLights.Add(e2.Key, cnfSegLight);

                            cnfSegLight.nodeId      = segLight.NodeId;
                            cnfSegLight.segmentId   = segLight.SegmentId;
                            cnfSegLight.currentMode = (int)segLight.CurrentMode;
                            cnfSegLight.leftLight   = segLight.LightLeft;
                            cnfSegLight.mainLight   = segLight.LightMain;
                            cnfSegLight.rightLight  = segLight.LightRight;
                        }
                    }
                }
            } catch (Exception e) {
                Log.Error($"Error adding TimedTrafficLights to save {e.Message}");
            }
        }
        public override void OnSaveData()
        {
            Log.Info("Recalculating segment geometries");
            SegmentGeometry.OnBeforeSaveData();
            Log.Info("Saving Mod Data.");
            var configuration = new Configuration();

            if (TrafficPriority.TrafficSegments != null)
            {
                for (ushort i = 0; i < Singleton <NetManager> .instance.m_segments.m_size; i++)
                {
                    try {
                        SavePrioritySegment(i, configuration);
                    } catch (Exception e) {
                        Log.Error($"Exception occurred while saving priority segment @ {i}: {e.ToString()}");
                    }

                    try {
                        SaveSegmentNodeFlags(i, configuration);
                    } catch (Exception e) {
                        Log.Error($"Exception occurred while saving segment node flags @ {i}: {e.ToString()}");
                    }
                }
            }

            for (ushort i = 0; i < Singleton <NetManager> .instance.m_nodes.m_size; i++)
            {
                /*if (TrafficLightSimulation.LightSimulationByNodeId != null) {
                 *      SaveTrafficLightSimulation(i, configuration);
                 * }*/

                /*if (TrafficLightsManual.ManualSegments != null) {
                 *      SaveManualTrafficLight(i, configuration);
                 * }*/

                TrafficLightSimulation sim = TrafficLightSimulation.GetNodeSimulation(i);
                if (sim != null && sim.IsTimedLight())
                {
                    try {
                        SaveTimedTrafficLight(i, configuration);
                    } catch (Exception e) {
                        Log.Error($"Exception occurred while saving timed traffic light @ {i}: {e.ToString()}");
                    }
                    // TODO save new traffic lights
                }

                try {
                    SaveNodeLights(i, configuration);
                } catch (Exception e) {
                    Log.Error($"Exception occurred while saving node traffic light @ {i}: {e.ToString()}");
                }
            }

#if !TAM
            if (LoadingExtension.IsPathManagerCompatible)
            {
#endif
            for (uint i = 0; i < Singleton <NetManager> .instance.m_lanes.m_buffer.Length; i++)
            {
                try {
                    SaveLaneData(i, configuration);
                } catch (Exception e) {
                    Log.Error($"Exception occurred while saving lane data @ {i}: {e.ToString()}");
                }
            }
#if !TAM
        }
#endif

            foreach (KeyValuePair <uint, ushort> e in Flags.getAllLaneSpeedLimits())
            {
                try {
                    SaveLaneSpeedLimit(new Configuration.LaneSpeedLimit(e.Key, e.Value), configuration);
                } catch (Exception ex) {
                    Log.Error($"Exception occurred while saving lane speed limit @ {e.Key}: {ex.ToString()}");
                }
            }

            foreach (KeyValuePair <uint, ExtVehicleType> e in Flags.getAllLaneAllowedVehicleTypes())
            {
                try {
                    SaveLaneAllowedVehicleTypes(new Configuration.LaneVehicleTypes(e.Key, e.Value), configuration);
                } catch (Exception ex) {
                    Log.Error($"Exception occurred while saving lane vehicle restrictions @ {e.Key}: {ex.ToString()}");
                }
            }

            var binaryFormatter = new BinaryFormatter();
            var memoryStream    = new MemoryStream();

            try {
                binaryFormatter.Serialize(memoryStream, configuration);
                memoryStream.Position = 0;
                Log.Info($"Save data byte length {memoryStream.Length}");
                _serializableData.SaveData(DataId, memoryStream.ToArray());

                // save options
                _serializableData.SaveData("TMPE_Options", new byte[] {
                    (byte)Options.simAccuracy,
                    (byte)0,                    //Options.laneChangingRandomization,
                    (byte)Options.recklessDrivers,
                    (byte)(Options.relaxedBusses ? 1 : 0),
                    (byte)(Options.nodesOverlay ? 1 : 0),
                    (byte)(Options.allowEnterBlockedJunctions ? 1 : 0),
                    (byte)(Options.advancedAI ? 1 : 0),
                    (byte)(Options.highwayRules ? 1 : 0),
                    (byte)(Options.prioritySignsOverlay ? 1 : 0),
                    (byte)(Options.timedLightsOverlay ? 1 : 0),
                    (byte)(Options.speedLimitsOverlay ? 1 : 0),
                    (byte)(Options.vehicleRestrictionsOverlay ? 1 : 0),
                    (byte)(Options.strongerRoadConditionEffects ? 1 : 0),
                    (byte)(Options.allowUTurns ? 1 : 0),
                    (byte)(Options.allowLaneChangesWhileGoingStraight ? 1 : 0),
                    (byte)(Options.enableDespawning ? 1 : 0),
                    (byte)(Options.IsDynamicPathRecalculationActive() ? 1 : 0),
                    (byte)(Options.connectedLanesOverlay ? 1 : 0)
                });
            } catch (Exception ex) {
                Log.Error("Unexpected error saving data: " + ex.Message);
            } finally {
                memoryStream.Close();
            }
        }
        /// <summary>
        /// Handles vehicle path information in order to manage special nodes (nodes with priority signs or traffic lights).
        /// Data like "vehicle X is on segment S0 and is going to segment S1" is collected.
        /// </summary>
        /// <param name="vehicleId"></param>
        /// <param name="vehicleData"></param>
        internal static void HandleVehicle(ushort vehicleId, ref Vehicle vehicleData, bool addTraffic, bool realTraffic, byte maxUpcomingPathPositions, bool debug = false)
        {
            if (maxUpcomingPathPositions <= 0)
            {
                maxUpcomingPathPositions = 1;                 // we need at least one upcoming path position
            }
            var netManager          = Singleton <NetManager> .instance;
            var lastFrameData       = vehicleData.GetLastFrameData();
            var lastFrameVehiclePos = lastFrameData.m_position;

#if DEBUGV
            var camPos = Camera.main.transform.position;
            //debug = (lastFrameVehiclePos - camPos).sqrMagnitude < CloseLod;
            debug = false;
            List <String> logBuffer = new List <String>();
            bool          logme     = false;
#endif
            if ((vehicleData.m_flags & Vehicle.Flags.Created) == 0)
            {
                TrafficPriority.RemoveVehicleFromSegments(vehicleId);
                return;
            }

            if (vehicleData.Info.m_vehicleType != VehicleInfo.VehicleType.Car &&
                vehicleData.Info.m_vehicleType != VehicleInfo.VehicleType.Train &&
                vehicleData.Info.m_vehicleType != VehicleInfo.VehicleType.Tram)
            {
                //Log._Debug($"HandleVehicle does not handle vehicles of type {vehicleData.Info.m_vehicleType}");
                return;
            }
#if DEBUGV
            logBuffer.Add("Calculating prio info for vehicleId " + vehicleId);
#endif

            ExtVehicleType?vehicleType = CustomVehicleAI.DetermineVehicleTypeFromVehicle(vehicleId, ref vehicleData);
            if (vehicleType == null)
            {
                Log.Warning($"Could not determine vehicle type of vehicle {vehicleId}!");
            }

            if (vehicleType == null || vehicleType == ExtVehicleType.None)
            {
                return;
            }

            // add vehicle to our vehicle list
            VehiclePosition vehiclePos = TrafficPriority.GetVehiclePosition(vehicleId);

            // we extract the segment information directly from the vehicle
            var                      currentPathUnitId        = vehicleData.m_path;
            List <ushort>            realTimeDestinationNodes = new List <ushort>();            // current and upcoming node ids
            List <PathUnit.Position> realTimePositions        = new List <PathUnit.Position>(); // current and upcoming vehicle positions

#if DEBUGV
            logBuffer.Add("* vehicleId " + vehicleId + ". currentPathId: " + currentPathUnitId + " pathPositionIndex: " + vehicleData.m_pathPositionIndex);
#endif

            if (currentPathUnitId > 0)
            {
                // vehicle has a path...
                if ((Singleton <PathManager> .instance.m_pathUnits.m_buffer[currentPathUnitId].m_pathFindFlags & PathUnit.FLAG_READY) != 0)
                {
                    // The path(unit) is established and is ready for use: get the vehicle's current position in terms of segment and lane
                    realTimePositions.Add(Singleton <PathManager> .instance.m_pathUnits.m_buffer[currentPathUnitId].GetPosition(vehicleData.m_pathPositionIndex >> 1));
                    if (realTimePositions[0].m_offset == 0)
                    {
                        realTimeDestinationNodes.Add(netManager.m_segments.m_buffer[realTimePositions[0].m_segment].m_startNode);
                    }
                    else
                    {
                        realTimeDestinationNodes.Add(netManager.m_segments.m_buffer[realTimePositions[0].m_segment].m_endNode);
                    }

                    if (maxUpcomingPathPositions > 0)
                    {
                        // evaluate upcoming path units
                        byte i          = 0;
                        uint pathUnitId = currentPathUnitId;
                        int  pathPos    = (byte)((vehicleData.m_pathPositionIndex >> 1) + 1);
                        while (true)
                        {
                            if (pathPos > 11)
                            {
                                // go to next path unit
                                pathPos    = 0;
                                pathUnitId = Singleton <PathManager> .instance.m_pathUnits.m_buffer[pathUnitId].m_nextPathUnit;
#if DEBUGV
                                logBuffer.Add("* vehicleId " + vehicleId + ". Going to next path unit (1). pathUnitId=" + pathUnitId);
#endif
                                if (pathUnitId <= 0)
                                {
                                    break;
                                }
                            }

                            PathUnit.Position nextRealTimePosition = default(PathUnit.Position);
                            if (!Singleton <PathManager> .instance.m_pathUnits.m_buffer[pathUnitId].GetPosition(pathPos, out nextRealTimePosition))                             // if this returns false, there is no next path unit
                            {
#if DEBUGV
                                logBuffer.Add("* vehicleId " + vehicleId + ". No next path unit! pathPos=" + pathPos + ", pathUnitId=" + pathUnitId);
#endif
                                break;
                            }

                            ushort destNodeId = 0;
                            if (nextRealTimePosition.m_segment > 0)
                            {
                                if (nextRealTimePosition.m_offset == 0)
                                {
                                    destNodeId = netManager.m_segments.m_buffer[nextRealTimePosition.m_segment].m_startNode;
                                }
                                else
                                {
                                    destNodeId = netManager.m_segments.m_buffer[nextRealTimePosition.m_segment].m_endNode;
                                }
                            }

#if DEBUGV
                            logBuffer.Add("* vehicleId " + vehicleId + ". Next path unit! node " + destNodeId + ", seg. " + nextRealTimePosition.m_segment + ", pathUnitId=" + pathUnitId + ", pathPos: " + pathPos);
#endif

                            realTimePositions.Add(nextRealTimePosition);
                            realTimeDestinationNodes.Add(destNodeId);

                            if (i >= maxUpcomingPathPositions - 1)
                            {
                                break;                                 // we calculate up to 2 upcoming path units at the moment
                            }
                            ++pathPos;
                            ++i;
                        }
                    }

                    // please don't ask why we use "m_pathPositionIndex >> 1" (which equals to "m_pathPositionIndex / 2") here (Though it would
                    // be interesting to know why they used such an ugly indexing scheme!!). I assume the oddness of m_pathPositionIndex relates
                    // to the car's position on the segment. If it is even the car might be in the segment's first half and if it is odd, it might
                    // be in the segment's second half.
#if DEBUGV
                    logBuffer.Add("* vehicleId " + vehicleId + ". *INFO* rtPos.seg=" + realTimePositions[0].m_segment + " nrtPos.seg=" + (realTimePositions.Count > 1 ? "" + realTimePositions[1].m_segment : "n/a"));
#endif
                }
            }

            // we have seen the car!
            vehiclePos.LastFrame = Singleton <SimulationManager> .instance.m_currentFrameIndex;

#if DEBUGV
            logBuffer.Add("* vehicleId " + vehicleId + ". ToNode: " + vehiclePos.ToNode + ". FromSegment: " + vehiclePos.FromSegment /* + ". FromLaneId: " + TrafficPriority.Vehicles[vehicleId].FromLaneId*/);
#endif
            if (addTraffic && vehicleData.m_leadingVehicle == 0 && realTimePositions.Count > 0)
            {
                // add traffic to lane
                uint laneId = PathManager.GetLaneID(realTimePositions[0]);
                CustomRoadAI.AddTraffic(laneId, (ushort)Mathf.RoundToInt(vehicleData.CalculateTotalLength(vehicleId)), (ushort)Mathf.RoundToInt(lastFrameData.m_velocity.magnitude), realTraffic);
            }

#if DEBUGV
            logBuffer.Add("* vehicleId " + vehicleId + ". Real time positions: " + realTimePositions.Count + ", Destination nodes: " + realTimeDestinationNodes.Count);
#endif
            if (realTimePositions.Count >= 1)
            {
                // we found a valid path unit
                var sourceLaneIndex = realTimePositions[0].m_lane;

                if (
                    !vehiclePos.Valid ||
                    vehiclePos.ToNode != realTimeDestinationNodes[0] ||
                    vehiclePos.FromSegment != realTimePositions[0].m_segment ||
                    vehiclePos.FromLaneIndex != sourceLaneIndex)
                {
                    // vehicle information is not up-to-date. remove the car from old priority segments (if existing)...
                    TrafficPriority.RemoveVehicleFromSegments(vehicleId);

                    if (realTimePositions.Count >= 2)
                    {
                        // save vehicle information for priority rule handling
                        vehiclePos.Valid                     = true;
                        vehiclePos.CarState                  = VehicleJunctionTransitState.None;
                        vehiclePos.WaitTime                  = 0;
                        vehiclePos.Stopped                   = false;
                        vehiclePos.ToNode                    = realTimeDestinationNodes[0];
                        vehiclePos.FromSegment               = realTimePositions[0].m_segment;
                        vehiclePos.FromLaneIndex             = realTimePositions[0].m_lane;
                        vehiclePos.ToSegment                 = realTimePositions[1].m_segment;
                        vehiclePos.ToLaneIndex               = realTimePositions[1].m_lane;
                        vehiclePos.ReduceSpeedByValueToYield = UnityEngine.Random.Range(16f, 28f);
                        vehiclePos.OnEmergency               = (vehicleData.m_flags & Vehicle.Flags.Emergency2) != 0;
                        vehiclePos.VehicleType               = (ExtVehicleType)vehicleType;

#if DEBUGV
                        logBuffer.Add($"* vehicleId {vehicleId}. Setting current position to: from {vehiclePos.FromSegment} (lane {vehiclePos.FromLaneIndex}), going over {vehiclePos.ToNode}, to {vehiclePos.ToSegment} (lane {vehiclePos.ToLaneIndex})");
#endif

                        //if (!Options.disableSomething) {
                        // add the vehicle to upcoming priority segments that have timed traffic lights
                        for (int i = 0; i < realTimePositions.Count - 1; ++i)
                        {
                            var prioritySegment = TrafficPriority.GetPrioritySegment(realTimeDestinationNodes[i], realTimePositions[i].m_segment);
                            if (prioritySegment == null)
                            {
                                continue;
                            }

                            // add upcoming segments only if there is a timed traffic light
                            TrafficLightSimulation nodeSim = TrafficLightSimulation.GetNodeSimulation(realTimeDestinationNodes[i]);
                            if (i > 0 && (nodeSim == null || !nodeSim.IsTimedLight() || !nodeSim.IsTimedLightActive()))
                            {
                                continue;
                            }

                            VehiclePosition upcomingVehiclePos = new VehiclePosition();
                            upcomingVehiclePos.Valid                     = true;
                            upcomingVehiclePos.CarState                  = VehicleJunctionTransitState.None;
                            upcomingVehiclePos.LastFrame                 = vehiclePos.LastFrame;
                            upcomingVehiclePos.ToNode                    = realTimeDestinationNodes[i];
                            upcomingVehiclePos.FromSegment               = realTimePositions[i].m_segment;
                            upcomingVehiclePos.FromLaneIndex             = realTimePositions[i].m_lane;
                            upcomingVehiclePos.ToSegment                 = realTimePositions[i + 1].m_segment;
                            upcomingVehiclePos.ToLaneIndex               = realTimePositions[i + 1].m_lane;
                            upcomingVehiclePos.ReduceSpeedByValueToYield = UnityEngine.Random.Range(16f, 28f);
                            upcomingVehiclePos.OnEmergency               = (vehicleData.m_flags & Vehicle.Flags.Emergency2) != 0;
                            upcomingVehiclePos.VehicleType               = (ExtVehicleType)vehicleType;
#if DEBUGV
                            logBuffer.Add($"* vehicleId {vehicleId}. Adding future position: from {upcomingVehiclePos.FromSegment}  (lane {upcomingVehiclePos.FromLaneIndex}), going over {upcomingVehiclePos.ToNode}, to {upcomingVehiclePos.ToSegment} (lane {upcomingVehiclePos.ToLaneIndex})");
#endif

                            prioritySegment.AddVehicle(vehicleId, upcomingVehiclePos);
                        }
                    }
                    //}
                }
                else
                {
#if DEBUGV
                    logBuffer.Add($"* vehicleId {vehicleId}. Nothing has changed. from {vehiclePos.FromSegment} (lane {vehiclePos.FromLaneIndex}), going over {vehiclePos.ToNode}, to {vehiclePos.ToSegment} (lane {vehiclePos.ToLaneIndex})");
                    logme = false;
#endif
                }
            }
            else
            {
#if DEBUGV
                logBuffer.Add($"* vehicleId {vehicleId}. Insufficient path unit positions.");
#endif
                TrafficPriority.RemoveVehicleFromSegments(vehicleId);
            }

#if DEBUGV
            if (logme)
            {
                Log._Debug("vehicleId: " + vehicleId + " ============================================");
                foreach (String logBuf in logBuffer)
                {
                    Log._Debug(logBuf);
                }
                Log._Debug("vehicleId: " + vehicleId + " ============================================");
            }
#endif
        }
        public override void OnSaveData()
        {
            bool error = false;

            /*try {
             *      Log.Info("Recalculating segment geometries");
             *      SegmentGeometry.OnBeforeSaveData();
             * } catch (Exception e) {
             *      Log.Error($"OnSaveData: Exception occurred while calling SegmentGeometry.OnBeforeSaveData: {e.ToString()}");
             *      error = true;
             * }*/

            try {
                Log.Info("Applying all flags");
                Flags.applyAllFlags();
            } catch (Exception e) {
                Log.Error($"OnSaveData: Exception occurred while applying all flags: {e.ToString()}");
                error = true;
            }

            try {
                Log.Info("Saving Mod Data.");
                var configuration = new Configuration();

                TrafficPriorityManager prioMan = TrafficPriorityManager.Instance();

                if (prioMan.TrafficSegments != null)
                {
                    for (ushort i = 0; i < Singleton <NetManager> .instance.m_segments.m_size; i++)
                    {
                        try {
                            SavePrioritySegment(i, configuration);
                        } catch (Exception e) {
                            Log.Error($"Exception occurred while saving priority segment @ {i}: {e.ToString()}");
                            error = true;
                        }

                        try {
                            SaveSegmentNodeFlags(i, configuration);
                        } catch (Exception e) {
                            Log.Error($"Exception occurred while saving segment node flags @ {i}: {e.ToString()}");
                            error = true;
                        }
                    }
                }

                TrafficLightSimulationManager tlsMan = TrafficLightSimulationManager.Instance();

                for (ushort i = 0; i < Singleton <NetManager> .instance.m_nodes.m_size; i++)
                {
                    /*if (TrafficLightSimulation.LightSimulationByNodeId != null) {
                     *      SaveTrafficLightSimulation(i, configuration);
                     * }*/

                    /*if (TrafficLightsManual.ManualSegments != null) {
                     *      SaveManualTrafficLight(i, configuration);
                     * }*/

                    TrafficLightSimulation sim = tlsMan.GetNodeSimulation(i);
                    if (sim != null && sim.IsTimedLight())
                    {
                        try {
                            SaveTimedTrafficLight(i, configuration);
                        } catch (Exception e) {
                            Log.Error($"Exception occurred while saving timed traffic light @ {i}: {e.ToString()}");
                            error = true;
                        }
                        // TODO save new traffic lights
                    }

                    try {
                        SaveNodeLights(i, configuration);
                    } catch (Exception e) {
                        Log.Error($"Exception occurred while saving node traffic light @ {i}: {e.ToString()}");
                        error = true;
                    }
                }

#if !TAM
                if (LoadingExtension.IsPathManagerCompatible)
                {
#endif
                for (uint i = 0; i < Singleton <NetManager> .instance.m_lanes.m_buffer.Length; i++)
                {
                    try {
                        SaveLaneData(i, configuration);
                    } catch (Exception e) {
                        Log.Error($"Exception occurred while saving lane data @ {i}: {e.ToString()}");
                        error = true;
                    }
                }
#if !TAM
            }
#endif

                foreach (KeyValuePair <uint, ushort> e in Flags.getAllLaneSpeedLimits())
                {
                    try {
                        SaveLaneSpeedLimit(new Configuration.LaneSpeedLimit(e.Key, e.Value), configuration);
                    } catch (Exception ex) {
                        Log.Error($"Exception occurred while saving lane speed limit @ {e.Key}: {ex.ToString()}");
                        error = true;
                    }
                }

                foreach (KeyValuePair <uint, ExtVehicleType> e in Flags.getAllLaneAllowedVehicleTypes())
                {
                    try {
                        SaveLaneAllowedVehicleTypes(new Configuration.LaneVehicleTypes(e.Key, e.Value), configuration);
                    } catch (Exception ex) {
                        Log.Error($"Exception occurred while saving lane vehicle restrictions @ {e.Key}: {ex.ToString()}");
                        error = true;
                    }
                }

                var binaryFormatter = new BinaryFormatter();
                var memoryStream    = new MemoryStream();

                try {
                    binaryFormatter.Serialize(memoryStream, configuration);
                    memoryStream.Position = 0;
                    Log.Info($"Save data byte length {memoryStream.Length}");
                    _serializableData.SaveData(DataId, memoryStream.ToArray());
                } catch (Exception ex) {
                    Log.Error("Unexpected error while saving data: " + ex.ToString());
                    error = true;
                } finally {
                    memoryStream.Close();
                }

                try {
                    // save options
                    _serializableData.SaveData("TMPE_Options", new byte[] {
                        (byte)Options.simAccuracy,
                        (byte)0,                        //Options.laneChangingRandomization,
                        (byte)Options.recklessDrivers,
                        (byte)(Options.relaxedBusses ? 1 : 0),
                        (byte)(Options.nodesOverlay ? 1 : 0),
                        (byte)(Options.allowEnterBlockedJunctions ? 1 : 0),
                        (byte)(Options.advancedAI ? 1 : 0),
                        (byte)(Options.highwayRules ? 1 : 0),
                        (byte)(Options.prioritySignsOverlay ? 1 : 0),
                        (byte)(Options.timedLightsOverlay ? 1 : 0),
                        (byte)(Options.speedLimitsOverlay ? 1 : 0),
                        (byte)(Options.vehicleRestrictionsOverlay ? 1 : 0),
                        (byte)(Options.strongerRoadConditionEffects ? 1 : 0),
                        (byte)(Options.allowUTurns ? 1 : 0),
                        (byte)(Options.allowLaneChangesWhileGoingStraight ? 1 : 0),
                        (byte)(Options.enableDespawning ? 1 : 0),
                        (byte)(Options.IsDynamicPathRecalculationActive() ? 1 : 0),
                        (byte)(Options.connectedLanesOverlay ? 1 : 0),
                        (byte)(Options.prioritySignsEnabled ? 1 : 0),
                        (byte)(Options.timedLightsEnabled ? 1 : 0),
                        (byte)(Options.customSpeedLimitsEnabled ? 1 : 0),
                        (byte)(Options.vehicleRestrictionsEnabled ? 1 : 0),
                        (byte)(Options.laneConnectorEnabled ? 1 : 0),
                        (byte)(Options.junctionRestrictionsOverlay ? 1 : 0),
                        (byte)(Options.junctionRestrictionsEnabled ? 1 : 0)
                    });
                } catch (Exception ex) {
                    Log.Error("Unexpected error while saving options: " + ex.Message);
                    error = true;
                }
            } catch (Exception e) {
                error = true;
                Log.Error($"Error occurred while saving data: {e.ToString()}");
                //UIView.library.ShowModal<ExceptionPanel>("ExceptionPanel").SetMessage("An error occurred while saving", "Traffic Manager: President Edition detected an error while saving. To help preventing future errors, please navigate to http://steamcommunity.com/sharedfiles/filedetails/?id=583429740 and follow the steps under 'In case problems arise'.", true);
            }
        }
        public List <Configuration.TimedTrafficLights> SaveData(ref bool success)
        {
            List <Configuration.TimedTrafficLights> ret = new List <Configuration.TimedTrafficLights>();

            for (ushort nodeId = 0; nodeId < NetManager.MAX_NODE_COUNT; ++nodeId)
            {
                try {
                    TrafficLightSimulation sim = GetNodeSimulation(nodeId);
                    if (sim == null || !sim.IsTimedLight())
                    {
                        continue;
                    }

                    Log._Debug($"Going to save timed light at node {nodeId}.");

                    var timedNode = sim.TimedLight;
                    timedNode.handleNewSegments();

                    Configuration.TimedTrafficLights cnfTimedLights = new Configuration.TimedTrafficLights();
                    ret.Add(cnfTimedLights);

                    cnfTimedLights.nodeId     = timedNode.NodeId;
                    cnfTimedLights.nodeGroup  = timedNode.NodeGroup;
                    cnfTimedLights.started    = timedNode.IsStarted();
                    cnfTimedLights.timedSteps = new List <Configuration.TimedTrafficLightsStep>();

                    for (var j = 0; j < timedNode.NumSteps(); j++)
                    {
                        Log._Debug($"Saving timed light step {j} at node {nodeId}.");
                        TimedTrafficLightsStep timedStep = timedNode.Steps[j];
                        Configuration.TimedTrafficLightsStep cnfTimedStep = new Configuration.TimedTrafficLightsStep();
                        cnfTimedLights.timedSteps.Add(cnfTimedStep);

                        cnfTimedStep.minTime         = timedStep.minTime;
                        cnfTimedStep.maxTime         = timedStep.maxTime;
                        cnfTimedStep.waitFlowBalance = timedStep.waitFlowBalance;
                        cnfTimedStep.segmentLights   = new Dictionary <ushort, Configuration.CustomSegmentLights>();
                        foreach (KeyValuePair <ushort, CustomSegmentLights> e in timedStep.segmentLights)
                        {
                            Log._Debug($"Saving timed light step {j}, segment {e.Key} at node {nodeId}.");

                            CustomSegmentLights segLights = e.Value;
                            Configuration.CustomSegmentLights cnfSegLights = new Configuration.CustomSegmentLights();
                            cnfTimedStep.segmentLights.Add(e.Key, cnfSegLights);

                            cnfSegLights.nodeId               = segLights.NodeId;
                            cnfSegLights.segmentId            = segLights.SegmentId;
                            cnfSegLights.customLights         = new Dictionary <ExtVehicleType, Configuration.CustomSegmentLight>();
                            cnfSegLights.pedestrianLightState = segLights.PedestrianLightState;
                            cnfSegLights.manualPedestrianMode = segLights.ManualPedestrianMode;

                            Log._Debug($"Saving pedestrian light @ seg. {e.Key}, step {j}: {cnfSegLights.pedestrianLightState} {cnfSegLights.manualPedestrianMode}");

                            foreach (KeyValuePair <ExtVehicleType, CustomSegmentLight> e2 in segLights.CustomLights)
                            {
                                Log._Debug($"Saving timed light step {j}, segment {e.Key}, vehicleType {e2.Key} at node {nodeId}.");

                                CustomSegmentLight segLight = e2.Value;
                                Configuration.CustomSegmentLight cnfSegLight = new Configuration.CustomSegmentLight();
                                cnfSegLights.customLights.Add(e2.Key, cnfSegLight);

                                cnfSegLight.nodeId      = segLight.NodeId;
                                cnfSegLight.segmentId   = segLight.SegmentId;
                                cnfSegLight.currentMode = (int)segLight.CurrentMode;
                                cnfSegLight.leftLight   = segLight.LightLeft;
                                cnfSegLight.mainLight   = segLight.LightMain;
                                cnfSegLight.rightLight  = segLight.LightRight;
                            }
                        }
                    }
                } catch (Exception e) {
                    Log.Error($"Exception occurred while saving timed traffic light @ {nodeId}: {e.ToString()}");
                    success = false;
                }
            }
            return(ret);
        }