public void TmCalculateSegmentPosition(ushort vehicleId, ref Vehicle vehicleData, PathUnit.Position nextPosition,
                                               PathUnit.Position position, uint laneID, byte offset, PathUnit.Position prevPos, uint prevLaneID,
                                               byte prevOffset, out Vector3 pos, out Vector3 dir, out float maxSpeed)
        {
            var netManager = Singleton <NetManager> .instance;

            //var vehicleManager = Singleton<VehicleManager>.instance;
            netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].CalculatePositionAndDirection(offset * 0.003921569f, out pos, out dir);

            var lastFrameData       = vehicleData.GetLastFrameData();
            var lastFrameVehiclePos = lastFrameData.m_position;

            if (vehicleData.Info.m_vehicleType == VehicleInfo.VehicleType.Car)
            {
                // add vehicle to our vehicle list
                if (!TrafficPriority.VehicleList.ContainsKey(vehicleId))
                {
                    TrafficPriority.VehicleList.Add(vehicleId, new PriorityCar());
                }
            }

            HandleVehicle(vehicleId, ref vehicleData);

            // I think this is supposed to be the lane position?
            // [VN, 12/23/2015] It's the 3D car position on the Bezier curve of the lane.
            // This crazy 0.003921569f equals to 1f/255 and prevOffset is the byte value (0..255) of the car position.
            var vehiclePosOnBezier = netManager.m_lanes.m_buffer[(int)((UIntPtr)prevLaneID)].CalculatePosition(prevOffset * 0.003921569f);
            //ushort currentSegmentId = netManager.m_lanes.m_buffer[(int)((UIntPtr)prevLaneID)].m_segment;

            ushort destinationNodeId;
            ushort sourceNodeId;

            if (offset < position.m_offset)
            {
                destinationNodeId = netManager.m_segments.m_buffer[position.m_segment].m_startNode;
                sourceNodeId      = netManager.m_segments.m_buffer[position.m_segment].m_endNode;
            }
            else
            {
                destinationNodeId = netManager.m_segments.m_buffer[position.m_segment].m_endNode;
                sourceNodeId      = netManager.m_segments.m_buffer[position.m_segment].m_startNode;
            }
            var interestingNodeId = prevOffset == 0 ? netManager.m_segments.m_buffer[prevPos.m_segment].m_startNode :
                                    netManager.m_segments.m_buffer[prevPos.m_segment].m_endNode;

            // this seems to be like the required braking force in order to stop the vehicle within its half length.
            var crazyValue = 0.5f * lastFrameData.m_velocity.sqrMagnitude / m_info.m_braking + m_info.m_generatedInfo.m_size.z * 0.5f;

            // Essentially, this is true if the car has enough time and space to brake (e.g. for a red traffic light)
            if (destinationNodeId == interestingNodeId)
            {
                if (Vector3.Distance(lastFrameVehiclePos, vehiclePosOnBezier) >= crazyValue - 1f)
                {
                    var currentFrameIndex = Singleton <SimulationManager> .instance.m_currentFrameIndex;
                    var num5 = (uint)((interestingNodeId << 8) / 32768);
                    var num6 = currentFrameIndex - num5 & 255u;

                    var nodeFlags        = netManager.m_nodes.m_buffer[destinationNodeId].m_flags;
                    var prevLaneFlags    = (NetLane.Flags)netManager.m_lanes.m_buffer[(int)((UIntPtr)prevLaneID)].m_flags;
                    var hasTrafficLight  = (nodeFlags & NetNode.Flags.TrafficLights) != NetNode.Flags.None;
                    var hasCrossing      = (nodeFlags & NetNode.Flags.LevelCrossing) != NetNode.Flags.None;
                    var isJoinedJunction = (prevLaneFlags & NetLane.Flags.JoinedJunction) != NetLane.Flags.None;
                    if ((nodeFlags & (NetNode.Flags.Junction | NetNode.Flags.OneWayOut | NetNode.Flags.OneWayIn)) ==
                        NetNode.Flags.Junction && netManager.m_nodes.m_buffer[destinationNodeId].CountSegments() != 2)
                    {
                        var len = vehicleData.CalculateTotalLength(vehicleId) + 2f;
                        if (!netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].CheckSpace(len))
                        {
                            var sufficientSpace = false;
                            if (nextPosition.m_segment != 0 &&
                                netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_length < 30f)
                            {
                                var flags3 = netManager.m_nodes.m_buffer[sourceNodeId].m_flags;
                                if ((flags3 &
                                     (NetNode.Flags.Junction | NetNode.Flags.OneWayOut | NetNode.Flags.OneWayIn)) !=
                                    NetNode.Flags.Junction || netManager.m_nodes.m_buffer[sourceNodeId].CountSegments() == 2)
                                {
                                    var laneId2 = PathManager.GetLaneID(nextPosition);
                                    if (laneId2 != 0u)
                                    {
                                        sufficientSpace = netManager.m_lanes.m_buffer[(int)((UIntPtr)laneId2)].CheckSpace(len);
                                    }
                                }
                            }
                            if (!sufficientSpace)
                            {
                                maxSpeed = 0f;
                                return;
                            }
                        }
                    }

                    if (vehicleData.Info.m_vehicleType == VehicleInfo.VehicleType.Car)
                    {
                        if (hasTrafficLight && (!isJoinedJunction || hasCrossing))
                        {
                            var nodeSimulation = TrafficPriority.GetNodeSimulation(interestingNodeId);

                            var destinationInfo = netManager.m_nodes.m_buffer[destinationNodeId].Info;
                            RoadBaseAI.TrafficLightState vehicleLightState;
                            ManualSegmentLight           light = TrafficLightsManual.GetSegmentLight(interestingNodeId, prevPos.m_segment);                   // TODO rework

                            if (light == null || nodeSimulation == null ||
                                (nodeSimulation.FlagTimedTrafficLights && !nodeSimulation.TimedTrafficLightsActive))
                            {
                                RoadBaseAI.TrafficLightState pedestrianLightState;
                                bool flag5;
                                bool pedestrians;
                                RoadBaseAI.GetTrafficLightState(interestingNodeId,
                                                                ref netManager.m_segments.m_buffer[prevPos.m_segment],
                                                                currentFrameIndex - num5, out vehicleLightState, out pedestrianLightState, out flag5,
                                                                out pedestrians);
                                if (!flag5 && num6 >= 196u)
                                {
                                    flag5 = true;
                                    RoadBaseAI.SetTrafficLightState(interestingNodeId,
                                                                    ref netManager.m_segments.m_buffer[prevPos.m_segment], currentFrameIndex - num5,
                                                                    vehicleLightState, pedestrianLightState, flag5, pedestrians);
                                }

                                if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.None ||
                                    destinationInfo.m_class.m_service != ItemClass.Service.Road)
                                {
                                    switch (vehicleLightState)
                                    {
                                    case RoadBaseAI.TrafficLightState.RedToGreen:
                                        if (num6 < 60u)
                                        {
                                            maxSpeed = 0f;
                                            return;
                                        }
                                        break;

                                    case RoadBaseAI.TrafficLightState.Red:
                                        maxSpeed = 0f;
                                        return;

                                    case RoadBaseAI.TrafficLightState.GreenToRed:
                                        if (num6 >= 30u)
                                        {
                                            maxSpeed = 0f;
                                            return;
                                        }
                                        break;
                                    }
                                }
                            }
                            else
                            {
                                // traffic light simulation is active
                                var stopCar = false;

                                // determine responsible traffic light (left, right or main)
                                if (TrafficPriority.IsLeftSegment(prevPos.m_segment, position.m_segment, destinationNodeId))
                                {
                                    vehicleLightState = light.GetLightLeft();
                                }
                                else if (TrafficPriority.IsRightSegment(prevPos.m_segment, position.m_segment, destinationNodeId))
                                {
                                    vehicleLightState = light.GetLightRight();
                                }
                                else
                                {
                                    vehicleLightState = light.GetLightMain();
                                }

                                if (vehicleLightState == RoadBaseAI.TrafficLightState.Green)
                                {
                                    var hasIncomingCars = TrafficPriority.HasIncomingVehicles(vehicleId, destinationNodeId);

                                    if (hasIncomingCars)
                                    {
                                        // green light but other cars are incoming: slow approach
                                        maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f) * 0.01f;
                                        //stopCar = true;
                                    }
                                }

                                if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.None ||
                                    destinationInfo.m_class.m_service != ItemClass.Service.Road)
                                {
                                    switch (vehicleLightState)
                                    {
                                    case RoadBaseAI.TrafficLightState.RedToGreen:
                                        if (num6 < 60u)
                                        {
                                            stopCar = true;
                                        }
                                        break;

                                    case RoadBaseAI.TrafficLightState.Red:
                                        stopCar = true;
                                        break;

                                    case RoadBaseAI.TrafficLightState.GreenToRed:
                                        if (num6 >= 30u)
                                        {
                                            stopCar = true;
                                        }
                                        break;
                                    }
                                }

                                if (stopCar)
                                {
                                    maxSpeed = 0f;
                                    return;
                                }
                            }
                        }
                        else
                        {
                            if (TrafficPriority.VehicleList.ContainsKey(vehicleId) &&
                                TrafficPriority.IsPrioritySegment(destinationNodeId, prevPos.m_segment))
                            {
                                var currentFrameIndex2 = Singleton <SimulationManager> .instance.m_currentFrameIndex;
                                var frame = currentFrameIndex2 >> 4;

                                var prioritySegment = TrafficPriority.GetPrioritySegment(destinationNodeId, prevPos.m_segment);

                                if (TrafficPriority.VehicleList[vehicleId].CarState == CarState.None)
                                {
                                    TrafficPriority.VehicleList[vehicleId].CarState = CarState.Enter;
                                }

                                if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.None &&
                                    TrafficPriority.VehicleList[vehicleId].CarState != CarState.Leave)
                                {
                                    bool hasIncomingCars;
                                    switch (prioritySegment.Type)
                                    {
                                    case PrioritySegment.PriorityType.Stop:
                                        if (TrafficPriority.VehicleList[vehicleId].WaitTime < 75)
                                        {
                                            TrafficPriority.VehicleList[vehicleId].CarState = CarState.Stop;

                                            if (lastFrameData.m_velocity.sqrMagnitude < 0.1f ||
                                                TrafficPriority.VehicleList[vehicleId].Stopped)
                                            {
                                                TrafficPriority.VehicleList[vehicleId].Stopped = true;
                                                TrafficPriority.VehicleList[vehicleId].WaitTime++;

                                                if (TrafficPriority.VehicleList[vehicleId].WaitTime > 2)
                                                {
                                                    hasIncomingCars = TrafficPriority.HasIncomingVehicles(vehicleId, destinationNodeId);

                                                    if (hasIncomingCars)
                                                    {
                                                        maxSpeed = 0f;
                                                        return;
                                                    }
                                                    TrafficPriority.VehicleList[vehicleId].CarState =
                                                        CarState.Leave;
                                                }
                                                else
                                                {
                                                    maxSpeed = 0f;
                                                    return;
                                                }
                                            }
                                            else
                                            {
                                                maxSpeed = 0f;
                                                return;
                                            }
                                        }
                                        else
                                        {
                                            TrafficPriority.VehicleList[vehicleId].CarState = CarState.Leave;
                                        }
                                        break;

                                    case PrioritySegment.PriorityType.Yield:
                                        if (TrafficPriority.VehicleList[vehicleId].WaitTime < 75)
                                        {
                                            TrafficPriority.VehicleList[vehicleId].WaitTime++;
                                            TrafficPriority.VehicleList[vehicleId].CarState = CarState.Stop;
                                            maxSpeed = 0f;

                                            if (lastFrameData.m_velocity.sqrMagnitude <
                                                TrafficPriority.VehicleList[vehicleId].ReduceSpeedByValueToYield)
                                            {
                                                hasIncomingCars = TrafficPriority.HasIncomingVehicles(vehicleId, destinationNodeId);

                                                if (hasIncomingCars)
                                                {
                                                    return;
                                                }
                                            }
                                            else
                                            {
                                                maxSpeed = lastFrameData.m_velocity.sqrMagnitude -
                                                           TrafficPriority.VehicleList[vehicleId]
                                                           .ReduceSpeedByValueToYield;
                                                return;
                                            }
                                        }
                                        else
                                        {
                                            TrafficPriority.VehicleList[vehicleId].CarState = CarState.Leave;
                                        }
                                        break;

                                    case PrioritySegment.PriorityType.Main:
                                        TrafficPriority.VehicleList[vehicleId].WaitTime++;
                                        TrafficPriority.VehicleList[vehicleId].CarState = CarState.Stop;
                                        maxSpeed = 0f;

                                        hasIncomingCars = TrafficPriority.HasIncomingVehicles(vehicleId, destinationNodeId);

                                        if (hasIncomingCars)
                                        {
                                            TrafficPriority.VehicleList[vehicleId].Stopped = true;
                                            return;
                                        }
                                        TrafficPriority.VehicleList[vehicleId].Stopped = false;

                                        var info3 = netManager.m_segments.m_buffer[position.m_segment].Info;
                                        if (info3.m_lanes != null && info3.m_lanes.Length > position.m_lane)
                                        {
                                            maxSpeed =
                                                CalculateTargetSpeed(vehicleId, ref vehicleData,
                                                                     info3.m_lanes[position.m_lane].m_speedLimit,
                                                                     netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_curve) * 0.8f;
                                        }
                                        else
                                        {
                                            maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f) *
                                                       0.8f;
                                        }
                                        return;
                                    }
                                }
                                else
                                {
                                    TrafficPriority.VehicleList[vehicleId].CarState = CarState.Transit;
                                }
                            }
                        }
                    }
                }
            }

            var info2 = netManager.m_segments.m_buffer[position.m_segment].Info;

            if (info2.m_lanes != null && info2.m_lanes.Length > position.m_lane)
            {
                var laneSpeedLimit = info2.m_lanes[position.m_lane].m_speedLimit;

                if (TrafficRoadRestrictions.IsSegment(position.m_segment))
                {
                    var restrictionSegment = TrafficRoadRestrictions.GetSegment(position.m_segment);

                    if (restrictionSegment.SpeedLimits[position.m_lane] > 0.1f)
                    {
                        laneSpeedLimit = restrictionSegment.SpeedLimits[position.m_lane];
                    }
                }

                maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, laneSpeedLimit,
                                                netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_curve);
            }
            else
            {
                maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f);
            }
        }
        internal void handleNewSegments()
        {
            if (Steps.Count <= 0)
            {
                return;
            }

            NetNode node = Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId];

            for (int s = 0; s < 8; ++s)
            {
                ushort segmentId = node.GetSegment(s);
                if (segmentId <= 0)
                {
                    continue;
                }
                NetSegment segment = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId];

                List <ushort> invalidSegmentIds = new List <ushort>();
                bool          isNewSegment      = true;

                foreach (KeyValuePair <ushort, ManualSegmentLight> e in Steps[0].segmentLightStates)
                {
                    var fromSegmentId = e.Key;
                    var segLightState = e.Value;

                    if (fromSegmentId == segmentId)
                    {
                        isNewSegment = false;
                    }

                    if (!TrafficPriority.IsPrioritySegment(nodeId, fromSegmentId))
                    {
                        invalidSegmentIds.Add(fromSegmentId);
                    }
                }

                if (isNewSegment)
                {
                    Log.Message($"New segment detected: {segmentId} @ {nodeId}");
                    // segment was created
                    TrafficLightsManual.AddLiveSegmentLight(nodeId, segmentId);
                    TrafficPriority.AddPrioritySegment(nodeId, segmentId, PrioritySegment.PriorityType.None);

                    if (invalidSegmentIds.Count > 0)
                    {
                        var oldSegmentId = invalidSegmentIds[0];
                        Log.Message($"Replacing old segment {oldSegmentId} @ {nodeId} with new segment {segmentId}");

                        // replace the old segment with the newly created one
                        for (int i = 0; i < Steps.Count; ++i)
                        {
                            ManualSegmentLight segmentLight = Steps[i].segmentLightStates[oldSegmentId];
                            Steps[i].segmentIds.Remove(oldSegmentId);
                            Steps[i].segmentLightStates.Remove(oldSegmentId);
                            segmentLight.SegmentId = segmentId;
                            Steps[i].segmentLightStates.Add(segmentId, segmentLight);
                            Steps[i].segmentIds.Add(segmentId);
                            Steps[i].rebuildSegmentIds();
                        }
                    }
                    else
                    {
                        Log.Message($"Adding new segment {segmentId} to node {nodeId}");

                        // create a new manual light
                        for (int i = 0; i < Steps.Count; ++i)
                        {
                            Steps[i].addSegment(segmentId);
                            Steps[i].rebuildSegmentIds();
                        }
                    }
                }
            }
        }
示例#3
0
        /*public static TimedTrafficLights AddTimedLight(ushort nodeid, List<ushort> nodeGroup, bool vehiclesMayEnterBlockedJunctions) {
         *      TimedScripts.Add(nodeid, new TimedTrafficLights(nodeid, nodeGroup, vehiclesMayEnterBlockedJunctions));
         *      return TimedScripts[nodeid];
         * }
         *
         * public static void RemoveTimedLight(ushort nodeid) {
         *      TimedScripts.Remove(nodeid);
         * }
         *
         * public static bool IsTimedLight(ushort nodeid) {
         *      return TimedScripts.ContainsKey(nodeid);
         * }
         *
         * public static TimedTrafficLights GetTimedLight(ushort nodeid) {
         *      if (!IsTimedLight(nodeid))
         *              return null;
         *      return TimedScripts[nodeid];
         * }
         *
         * internal static void OnLevelUnloading() {
         *      TimedScripts.Clear();
         * }*/

        internal void handleNewSegments()
        {
            if (NumSteps() <= 0)
            {
                // no steps defined, just create live traffic lights
                for (int s = 0; s < 8; ++s)
                {
                    ushort segmentId = Singleton <NetManager> .instance.m_nodes.m_buffer[NodeId].GetSegment(s);
                    if (segmentId <= 0)
                    {
                        continue;
                    }
                    CustomTrafficLights.AddLiveSegmentLights(NodeId, segmentId);
                }

                return;
            }

            for (int s = 0; s < 8; ++s)
            {
                ushort segmentId = Singleton <NetManager> .instance.m_nodes.m_buffer[NodeId].GetSegment(s);
                if (segmentId <= 0)
                {
                    continue;
                }

                List <ushort> invalidSegmentIds = new List <ushort>();
                bool          isNewSegment      = true;

                foreach (KeyValuePair <ushort, CustomSegmentLights> e in Steps[0].segmentLights)
                {
                    var fromSegmentId = e.Key;

                    if (fromSegmentId == segmentId)
                    {
                        isNewSegment = false;
                    }

                    if (!TrafficPriority.IsPrioritySegment(NodeId, fromSegmentId))
                    {
                        invalidSegmentIds.Add(fromSegmentId);
                    }
                }

                if (isNewSegment)
                {
                    Log._Debug($"New segment detected: {segmentId} @ {NodeId}");
                    // segment was created
                    CustomTrafficLights.AddLiveSegmentLights(NodeId, segmentId);
                    TrafficPriority.AddPrioritySegment(NodeId, segmentId, SegmentEnd.PriorityType.None);

                    if (invalidSegmentIds.Count > 0)
                    {
                        var oldSegmentId = invalidSegmentIds[0];
                        TrafficPriority.RemovePrioritySegment(NodeId, oldSegmentId);
                        Log._Debug($"Replacing old segment {oldSegmentId} @ {NodeId} with new segment {segmentId}");

                        // replace the old segment with the newly created one
                        for (int i = 0; i < NumSteps(); ++i)
                        {
                            CustomSegmentLights segmentLights = Steps[i].segmentLights[oldSegmentId];
                            Steps[i].segmentLights.Remove(oldSegmentId);
                            segmentLights.SegmentId = segmentId;
                            Steps[i].segmentLights.Add(segmentId, segmentLights);
                            Steps[i].calcMaxSegmentLength();
                            CustomSegmentLights liveSegLights = CustomTrafficLights.GetSegmentLights(NodeId, segmentId);
                            foreach (KeyValuePair <ExtVehicleType, CustomSegmentLight> e in segmentLights.CustomLights)
                            {
                                CustomSegmentLight liveSegLight = liveSegLights.GetCustomLight(e.Key);
                                if (liveSegLight == null)
                                {
                                    continue;
                                }
                                liveSegLight.CurrentMode = e.Value.CurrentMode;
                            }
                        }
                    }
                    else
                    {
                        Log._Debug($"Adding new segment {segmentId} to node {NodeId}");

                        // create a new manual light
                        for (int i = 0; i < NumSteps(); ++i)
                        {
                            Steps[i].addSegment(segmentId, true);
                            Steps[i].calcMaxSegmentLength();
                        }
                    }
                }
            }
        }
示例#4
0
        private static void LoadDataState()
        {
            Log.Info("Loading State from Config");
            if (_configuration == null)
            {
                Log.Warning("Configuration NULL, Couldn't load save data. Possibly a new game?");
                return;
            }

            // load priority segments
            if (_configuration.PrioritySegments != null)
            {
                Log.Info($"Loading {_configuration.PrioritySegments.Count()} priority segments");
                foreach (var segment in _configuration.PrioritySegments)
                {
                    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 ((Singleton <NetManager> .instance.m_nodes.m_buffer[segment[0]].m_flags & NetNode.Flags.Created) == NetNode.Flags.None)
                    {
#if DEBUG
                        if (debug)
                        {
                            Log._Debug($"Loading priority segment: node {segment[0]} is invalid");
                        }
#endif
                        continue;
                    }
                    if ((Singleton <NetManager> .instance.m_segments.m_buffer[segment[1]].m_flags & NetSegment.Flags.Created) == NetSegment.Flags.None)
                    {
#if DEBUG
                        if (debug)
                        {
                            Log._Debug($"Loading priority segment: segment {segment[1]} @ node {segment[0]} is invalid");
                        }
#endif
                        continue;
                    }
                    if (TrafficPriority.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
                        TrafficPriority.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
                    TrafficPriority.AddPrioritySegment((ushort)segment[0], (ushort)segment[1], (SegmentEnd.PriorityType)segment[2]);
                }
            }
            else
            {
                Log.Warning("Priority segments data structure undefined!");
            }

            // load nodes with traffic light simulation

            /*if (_configuration.NodeDictionary != null) {
             *      Log.Info($"Loading {_configuration.NodeDictionary.Count()} traffic light simulations");
             *      foreach (var node in _configuration.NodeDictionary) {
             *              if (node.Length < 4)
             *                      continue;
             *              if (TrafficLightSimulation.GetNodeSimulation((ushort)node[0]) != null)
             *                      continue;
             *              if ((Singleton<NetManager>.instance.m_nodes.m_buffer[node[0]].m_flags & NetNode.Flags.Created) == NetNode.Flags.None)
             *                      continue;
             #if DEBUG
             *              Log._Debug($"Adding node simulation {node[0]}");
             #endif
             *              try {
             *                      TrafficLightSimulation.AddNodeToSimulation((ushort)node[0]);
             *                      var nodeDict = TrafficLightSimulation.GetNodeSimulation((ushort)node[0]);
             *
             *                      nodeDict.ManualTrafficLights = Convert.ToBoolean(node[1]);
             *                      nodeDict.TimedTrafficLights = Convert.ToBoolean(node[2]);
             *                      nodeDict.TimedTrafficLightsActive = Convert.ToBoolean(node[3]);
             *              } catch (Exception e) {
             *                      // if we failed, just means it's old corrupt data. Ignore it and continue.
             *                      Log.Warning("Error loading data from the NodeDictionary: " + e.Message);
             *              }
             *      }
             * } else {
             *      Log.Warning("Traffic light simulation data structure undefined!");
             * }*/

            // Load live traffic lights

            /*if (_configuration.ManualSegments != null) {
             *      Log.Message($"Loading {_configuration.ManualSegments.Count()} live traffic lights");
             *      foreach (var segmentData in _configuration.ManualSegments) {
             *              if (segmentData.Length < 10)
             *                      continue;
             *
             *              if ((Singleton<NetManager>.instance.m_nodes.m_buffer[segmentData[0]].m_flags & NetNode.Flags.Created) == NetNode.Flags.None)
             *                      continue;
             *              if ((Singleton<NetManager>.instance.m_segments.m_buffer[segmentData[1]].m_flags & NetSegment.Flags.Created) == NetSegment.Flags.None)
             *                      continue;
             *              if (TrafficLightsManual.IsSegmentLight((ushort)segmentData[0], (ushort)segmentData[1]))
             *                      continue;
             #if DEBUG
             *              Log.Message($"Adding Light to node {segmentData[0]}, segment {segmentData[1]}");
             #endif
             *              try {
             *                      Flags.setNodeTrafficLight((ushort)segmentData[0], true);
             *                      TrafficLightsManual.AddSegmentLight((ushort)segmentData[0], (ushort)segmentData[1], RoadBaseAI.TrafficLightState.Green);
             *                      var segment = TrafficLightsManual.GetSegmentLight((ushort)segmentData[0], (ushort)segmentData[1]);
             *                      segment.CurrentMode = (ManualSegmentLight.Mode)segmentData[2];
             *                      segment.LightLeft = (RoadBaseAI.TrafficLightState)segmentData[3];
             *                      segment.LightMain = (RoadBaseAI.TrafficLightState)segmentData[4];
             *                      segment.LightRight = (RoadBaseAI.TrafficLightState)segmentData[5];
             *                      segment.LightPedestrian = (RoadBaseAI.TrafficLightState)segmentData[6];
             *                      segment.LastChange = (uint)segmentData[7];
             *                      segment.LastChangeFrame = (uint)segmentData[8];
             *                      segment.PedestrianEnabled = Convert.ToBoolean(segmentData[9]);
             *              } catch (Exception e) {
             *                      // if we failed, just means it's old corrupt data. Ignore it and continue.
             *                      Log.Warning("Error loading data from the ManualSegments: " + e.Message);
             *              }
             *      }
             * } else {
             *      Log.Warning("Live traffic lights data structure undefined!");
             * }*/

            var timedStepCount        = 0;
            var timedStepSegmentCount = 0;

            NetManager netManager = Singleton <NetManager> .instance;

            if (_configuration.TimedLights != null)
            {
                Log.Info($"Loading {_configuration.TimedLights.Count()} timed traffic lights (new method)");

                foreach (Configuration.TimedTrafficLights cnfTimedLights in _configuration.TimedLights)
                {
                    if ((Singleton <NetManager> .instance.m_nodes.m_buffer[cnfTimedLights.nodeId].m_flags & NetNode.Flags.Created) == NetNode.Flags.None)
                    {
                        continue;
                    }
                    Flags.setNodeTrafficLight(cnfTimedLights.nodeId, true);

                    Log._Debug($"Adding Timed Node at node {cnfTimedLights.nodeId}");

                    TrafficLightSimulation sim = TrafficLightSimulation.AddNodeToSimulation(cnfTimedLights.nodeId);
                    sim.SetupTimedTrafficLight(cnfTimedLights.nodeGroup);
                    var timedNode = sim.TimedLight;

                    int j = 0;
                    foreach (Configuration.TimedTrafficLightsStep cnfTimedStep in cnfTimedLights.timedSteps)
                    {
                        TimedTrafficLightsStep step = timedNode.AddStep(cnfTimedStep.minTime, cnfTimedStep.maxTime, cnfTimedStep.waitFlowBalance);

                        foreach (KeyValuePair <ushort, Configuration.CustomSegmentLights> e in cnfTimedStep.segmentLights)
                        {
                            CustomSegmentLights lights = null;
                            if (!step.segmentLights.TryGetValue(e.Key, out lights))
                            {
                                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)
                            {
                                CustomSegmentLight light = null;
                                if (!lights.CustomLights.TryGetValue(e2.Key, out light))
                                {
                                    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();
                    }
                }
            }
            else if (_configuration.TimedNodes != null && _configuration.TimedNodeGroups != null)
            {
                Log.Info($"Loading {_configuration.TimedNodes.Count()} timed traffic lights (old method)");
                for (var i = 0; i < _configuration.TimedNodes.Count; i++)
                {
                    try {
                        var nodeid = (ushort)_configuration.TimedNodes[i][0];
                        if ((Singleton <NetManager> .instance.m_nodes.m_buffer[nodeid].m_flags & NetNode.Flags.Created) == NetNode.Flags.None)
                        {
                            continue;
                        }
                        Flags.setNodeTrafficLight(nodeid, true);

                        Log._Debug($"Adding Timed Node {i} at node {nodeid}");

                        var nodeGroup = new List <ushort>();
                        for (var j = 0; j < _configuration.TimedNodeGroups[i].Length; j++)
                        {
                            nodeGroup.Add(_configuration.TimedNodeGroups[i][j]);
                        }

                        TrafficLightSimulation sim = TrafficLightSimulation.AddNodeToSimulation(nodeid);
                        sim.SetupTimedTrafficLight(nodeGroup);
                        var timedNode = sim.TimedLight;

                        timedNode.CurrentStep = _configuration.TimedNodes[i][1];

                        for (var j = 0; j < _configuration.TimedNodes[i][2]; j++)
                        {
                            var cfgstep = _configuration.TimedNodeSteps[timedStepCount];
                            // old (pre 1.3.0):
                            //   cfgstep[0]: time of step
                            //   cfgstep[1]: number of segments
                            // new (post 1.3.0):
                            //   cfgstep[0]: min. time of step
                            //   cfgstep[1]: max. time of step
                            //   cfgstep[2]: number of segments

                            int minTime = 1;
                            int maxTime = 1;
                            //int numSegments = 0;
                            float waitFlowBalance = 1f;

                            if (cfgstep.Length == 2)
                            {
                                minTime = cfgstep[0];
                                maxTime = cfgstep[0];
                                //numSegments = cfgstep[1];
                            }
                            else if (cfgstep.Length >= 3)
                            {
                                minTime = cfgstep[0];
                                maxTime = cfgstep[1];
                                //numSegments = cfgstep[2];
                                if (cfgstep.Length == 4)
                                {
                                    waitFlowBalance = Convert.ToSingle(cfgstep[3]) / 10f;
                                }
                                if (cfgstep.Length == 5)
                                {
                                    waitFlowBalance = Convert.ToSingle(cfgstep[4]) / 1000f;
                                }
                            }

                            Log._Debug($"Adding timed step to node {nodeid}: min/max: {minTime}/{maxTime}, waitFlowBalance: {waitFlowBalance}");

                            timedNode.AddStep(minTime, maxTime, waitFlowBalance);
                            var step = timedNode.Steps[j];

                            for (var s = 0; s < 8; s++)
                            {
                                var segmentId = netManager.m_nodes.m_buffer[nodeid].GetSegment(s);
                                if (segmentId <= 0)
                                {
                                    continue;
                                }

                                bool tooFewSegments = (timedStepSegmentCount >= _configuration.TimedNodeStepSegments.Count);

                                var leftLightState           = tooFewSegments ? RoadBaseAI.TrafficLightState.Red : (RoadBaseAI.TrafficLightState)_configuration.TimedNodeStepSegments[timedStepSegmentCount][0];
                                var mainLightState           = tooFewSegments ? RoadBaseAI.TrafficLightState.Red : (RoadBaseAI.TrafficLightState)_configuration.TimedNodeStepSegments[timedStepSegmentCount][1];
                                var rightLightState          = tooFewSegments ? RoadBaseAI.TrafficLightState.Red : (RoadBaseAI.TrafficLightState)_configuration.TimedNodeStepSegments[timedStepSegmentCount][2];
                                var pedLightState            = tooFewSegments ? RoadBaseAI.TrafficLightState.Red : (RoadBaseAI.TrafficLightState)_configuration.TimedNodeStepSegments[timedStepSegmentCount][3];
                                CustomSegmentLight.Mode?mode = null;
                                if (_configuration.TimedNodeStepSegments[timedStepSegmentCount].Length >= 5)
                                {
                                    mode = (CustomSegmentLight.Mode)_configuration.TimedNodeStepSegments[timedStepSegmentCount][4];
                                }

                                foreach (KeyValuePair <ExtVehicleType, CustomSegmentLight> e in step.segmentLights[segmentId].CustomLights)
                                {
                                    //ManualSegmentLight segmentLight = new ManualSegmentLight(step.NodeId, step.segmentIds[k], mainLightState, leftLightState, rightLightState, pedLightState);
                                    e.Value.LightLeft  = leftLightState;
                                    e.Value.LightMain  = mainLightState;
                                    e.Value.LightRight = rightLightState;
                                    if (mode != null)
                                    {
                                        e.Value.CurrentMode = (CustomSegmentLight.Mode)mode;
                                    }
                                }

                                if (step.segmentLights[segmentId].PedestrianLightState != null)
                                {
                                    step.segmentLights[segmentId].PedestrianLightState = pedLightState;
                                }

                                timedStepSegmentCount++;
                            }
                            timedStepCount++;
                        }

                        if (Convert.ToBoolean(_configuration.TimedNodes[i][3]))
                        {
                            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 the TimedNodes: " + e.ToString());
                    }
                }
            }
            else
            {
                Log.Warning("Timed traffic lights data structure undefined!");
            }

            var trafficLightDefs = _configuration.NodeTrafficLights.Split(',');

            Log.Info($"Loading junction traffic light data");
            if (trafficLightDefs.Length <= 1)
            {
                // old method
                Log.Info($"Using old method to load traffic light data");

                var saveDataIndex = 0;
                for (var i = 0; i < Singleton <NetManager> .instance.m_nodes.m_buffer.Length; i++)
                {
                    //Log.Message($"Adding NodeTrafficLights iteration: {i1}");
                    try {
                        if ((Singleton <NetManager> .instance.m_nodes.m_buffer[i].Info.m_class.m_service != ItemClass.Service.Road &&
                             Singleton <NetManager> .instance.m_nodes.m_buffer[i].Info.m_class.m_service != ItemClass.Service.PublicTransport) ||
                            (Singleton <NetManager> .instance.m_nodes.m_buffer[i].m_flags & NetNode.Flags.Created) == NetNode.Flags.None)
                        {
                            continue;
                        }

                        // prevent overflow
                        if (_configuration.NodeTrafficLights.Length > saveDataIndex)
                        {
                            var trafficLight = _configuration.NodeTrafficLights[saveDataIndex];
#if DEBUG
                            Log._Debug("Setting traffic light flag for node " + i + ": " + (trafficLight == '1'));
#endif
                            Flags.setNodeTrafficLight((ushort)i, trafficLight == '1');
                        }
                        ++saveDataIndex;
                    } catch (Exception e) {
                        // ignore as it's probably bad save data.
                        Log.Warning("Error setting the NodeTrafficLights (old): " + e.Message);
                    }
                }
            }
            else
            {
                // new method
                foreach (var split in trafficLightDefs.Select(def => def.Split(':')).Where(split => split.Length > 1))
                {
                    try {
                        Log.Info($"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.Warning("Error setting the NodeTrafficLights (new): " + e.Message);
                    }
                }
            }

            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.Info($"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 ((Singleton <NetManager> .instance.m_lanes.m_buffer[laneId].m_flags & (ushort)NetLane.Flags.Created) == 0 || Singleton <NetManager> .instance.m_lanes.m_buffer[laneId].m_segment == 0)
                            {
                                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.Message}");
                        }
                    }
                }
            }
            else
            {
                Log.Warning("Lane arrow 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)
                {
                    Log._Debug($"Loading lane speed limit: lane {laneSpeedLimit.laneId} = {laneSpeedLimit.speedLimit}");
                    Flags.setLaneSpeedLimit(laneSpeedLimit.laneId, laneSpeedLimit.speedLimit);
                }
            }
            else
            {
                Log.Warning("Lane speed limit structure undefined!");
            }

            // load vehicle restrictions
            if (_configuration.LaneAllowedVehicleTypes != null)
            {
                Log.Info($"Loading lane vehicle restriction data. {_configuration.LaneAllowedVehicleTypes.Count} elements");
                foreach (Configuration.LaneVehicleTypes laneVehicleTypes in _configuration.LaneAllowedVehicleTypes)
                {
                    Log._Debug($"Loading lane vehicle restriction: lane {laneVehicleTypes.laneId} = {laneVehicleTypes.vehicleTypes}");
                    Flags.setLaneAllowedVehicleTypes(laneVehicleTypes.laneId, laneVehicleTypes.vehicleTypes);
                }
            }
            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)
                {
                    if ((Singleton <NetManager> .instance.m_segments.m_buffer[segNodeConf.segmentId].m_flags & NetSegment.Flags.Created) == NetSegment.Flags.None)
                    {
                        continue;
                    }
                    Flags.setSegmentNodeFlags(segNodeConf.segmentId, true, segNodeConf.startNodeFlags);
                    Flags.setSegmentNodeFlags(segNodeConf.segmentId, false, segNodeConf.endNodeFlags);
                }
            }
            else
            {
                Log.Warning("Segment-at-node structure undefined!");
            }
        }
        internal void handleNewSegments()
        {
            if (NumSteps() <= 0)
            {
                // no steps defined, just create live traffic lights

                /*for (int s = 0; s < 8; ++s) {
                 *      ushort segmentId = Singleton<NetManager>.instance.m_nodes.m_buffer[NodeId].GetSegment(s);
                 *      if (segmentId <= 0)
                 *              continue;
                 *      if (! CustomTrafficLights.IsSegmentLight(NodeId, segmentId))
                 *              CustomTrafficLights.AddSegmentLights(NodeId, segmentId);
                 * }*/


                return;
            }

            for (int s = 0; s < 8; ++s)
            {
                ushort segmentId = Singleton <NetManager> .instance.m_nodes.m_buffer[NodeId].GetSegment(s);
                if (segmentId <= 0)
                {
                    continue;
                }

                List <ushort> invalidSegmentIds = new List <ushort>();
                bool          isNewSegment      = !Steps[0].segmentLights.ContainsKey(segmentId);

                if (isNewSegment)
                {
                    // segment was created
                    Log._Debug($"New segment detected: {segmentId} @ {NodeId}");

                    foreach (KeyValuePair <ushort, CustomSegmentLights> e in Steps[0].segmentLights)
                    {
                        var fromSegmentId = e.Key;

                        if (!TrafficPriority.IsPrioritySegment(NodeId, fromSegmentId))
                        {
                            Log._Debug($"Identified old segment {fromSegmentId} @ {NodeId}");
                            invalidSegmentIds.Add(fromSegmentId);
                        }
                    }

                    Log._Debug($"Setting up segment end for new segment {segmentId} @ {NodeId}");
                    SetupSegmentEnd(segmentId);

                    if (invalidSegmentIds.Count > 0)
                    {
                        var oldSegmentId = invalidSegmentIds[0];
                        TrafficPriority.RemovePrioritySegment(NodeId, oldSegmentId);
                        Log._Debug($"Replacing old segment {oldSegmentId} @ {NodeId} with new segment {segmentId}");

                        // replace the old segment with the newly created one
                        for (int i = 0; i < NumSteps(); ++i)
                        {
                            if (!Steps[i].segmentLights.ContainsKey(oldSegmentId))
                            {
                                Log.Error($"Step {i} at node {NodeId} does not contain step lights for old segment {oldSegmentId}");
                                Steps[i].addSegment(segmentId, true);
                                Steps[i].calcMaxSegmentLength();
                                continue;
                            }

                            CustomSegmentLights customLights = Steps[i].segmentLights[oldSegmentId];
                            Log._Debug($"Removing old segment {oldSegmentId} @ {NodeId} from step {i}");
                            Steps[i].segmentLights.Remove(oldSegmentId);
                            Log._Debug($"Setting new segment id {segmentId} at custom light from step {i}");
                            customLights.SegmentId = segmentId;
                            Steps[i].segmentLights.Add(segmentId, customLights);
                            Steps[i].calcMaxSegmentLength();
                            Log._Debug($"Getting live segment lights of new segment {segmentId} @ {NodeId} and applying mode @ step {i}");
                            CustomSegmentLights liveSegLights = CustomTrafficLights.GetSegmentLights(NodeId, segmentId);
                            if (liveSegLights == null)
                            {
                                Log.Error($"No live segment lights for seg. {segmentId} @ node {NodeId} found!");
                                CustomTrafficLights.AddSegmentLights(NodeId, segmentId);
                                liveSegLights = CustomTrafficLights.GetSegmentLights(NodeId, segmentId);
                            }

                            foreach (KeyValuePair <ExtVehicleType, CustomSegmentLight> e in customLights.CustomLights)
                            {
                                CustomSegmentLight liveSegLight = liveSegLights.GetCustomLight(e.Key);
                                if (liveSegLight == null)
                                {
                                    continue;
                                }
                                Log._Debug($"Updating live segment light mode of new segment {segmentId} @ {NodeId} for vehicle type {e.Key} @ step {i}");
                                liveSegLight.CurrentMode = e.Value.CurrentMode;
                            }
                            Log._Debug($"Finished applying new segment {segmentId} @ {NodeId} @ step {i}");
                        }
                    }
                    else
                    {
                        Log._Debug($"Adding new segment {segmentId} to node {NodeId}");

                        // create a new manual light
                        for (int i = 0; i < NumSteps(); ++i)
                        {
                            Steps[i].addSegment(segmentId, true);
                            Steps[i].calcMaxSegmentLength();
                        }
                    }
                }
            }
        }