public override void RenderOverlay(RenderManager.CameraInfo cameraInfo)
        {
            if (MainTool.GetToolController().IsInsideUI || !Cursor.visible)
            {
                return;
            }

            // no highlight for existing priority node in sign mode
            if (TrafficPriority.IsPriorityNode(HoveredNodeId))
            {
                return;
            }

            if (HoveredNodeId == 0)
            {
                return;
            }

            if (!Flags.mayHaveTrafficLight(HoveredNodeId))
            {
                return;
            }

            MainTool.DrawNodeCircle(cameraInfo, HoveredNodeId);
        }
Example #2
0
        private static void DeserializeData(byte[] data)
        {
            try {
                if (data != null && data.Length != 0)
                {
                    Log.Info("Loading Data from New Load Routine!");
                    var memoryStream = new MemoryStream();
                    memoryStream.Write(data, 0, data.Length);
                    memoryStream.Position = 0;

                    var binaryFormatter = new BinaryFormatter();
                    _configuration = (Configuration)binaryFormatter.Deserialize(memoryStream);
                }
                else
                {
                    Log.Warning("No data to deserialize!");
                }
            } catch (Exception e) {
                Log.Error($"Error deserializing data: {e.Message}");
            }

            LoadDataState();
            Flags.clearHighwayLaneArrows();
            Flags.applyAllFlags();
            TrafficPriority.HandleAllVehicles();
        }
Example #3
0
        // this implements the Update method of MonoBehaviour
        public void Update()
        {
            //Log.Warning("CustomRoadAI: Update called");
            var currentFrameIndex = Singleton <SimulationManager> .instance.m_currentFrameIndex >> 6;

            if (_lastFrame < currentFrameIndex)
            {
                _lastFrame = currentFrameIndex;

                if (TrafficLightTool.getToolMode() != ToolMode.AddPrioritySigns)
                {
                    TrafficPriority.housekeeping();
                }
            }

            try {
                foreach (KeyValuePair <ushort, TrafficLightSimulation> e in TrafficPriority.LightSimByNodeId)
                {
                    var nodeSim = e.Value;
                    nodeSim.SimulationStep();
                }
            } catch (Exception) {
                // TODO the dictionary was modified (probably a segment connected to a traffic light was changed/removed). rework this
            }
        }
        public bool CheckCurrentStep()
        {
            if (!IsStarted())
            {
                return(true);
            }

            if (!Steps[CurrentStep].isValid())
            {
                TrafficPriority.RemoveNodeFromSimulation(nodeId);
                return(false);
            }

            var currentFrameIndex = Singleton <SimulationManager> .instance.m_currentFrameIndex;

            Steps[CurrentStep].SetLights();
            if (!Steps[CurrentStep].StepDone())
            {
                return(false);
            }
            // step is done
            if (!Steps[CurrentStep].isEndTransitionDone())
            {
                return(false);
            }
            // ending transition (yellow) finished
            CurrentStep = (CurrentStep + 1) % Steps.Count;

            Steps[CurrentStep].Start();
            Steps[CurrentStep].SetLights();
            return(true);
        }
Example #5
0
        public void CustomNodeSimulationStep(ushort nodeId, ref NetNode data)
        {
            if (simStartFrame == 0)
            {
                simStartFrame = Singleton <SimulationManager> .instance.m_currentFrameIndex;
            }

            try {
                if (TrafficLightTool.getToolMode() != ToolMode.AddPrioritySigns)
                {
                    try {
                        TrafficPriority.nodeHousekeeping(nodeId);
                    } catch (Exception e) {
                        Log.Error($"Error occured while housekeeping node {nodeId}: " + e.ToString());
                    }
                }

                TrafficPriority.TrafficLightSimulationStep();

                var nodeSim = TrafficLightSimulation.GetNodeSimulation(nodeId);
                if (nodeSim == null || !nodeSim.IsSimulationActive())
                {
                    OriginalSimulationStep(nodeId, ref data);
                }
            } catch (Exception e) {
                Log.Warning($"CustomNodeSimulationStep: An error occurred: {e.ToString()}");
            }
        }
Example #6
0
        /// <summary>
        /// build outgoing segment lists
        /// </summary>
        private void rebuildOutSegments()
        {
            var node = Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId];

            leftOutSegmentIds    = new List <int>();
            forwardOutSegmentIds = new List <int>();
            rightOutSegmentIds   = new List <int>();

            for (var s = 0; s < 8; s++)
            {
                var toSegmentId = node.GetSegment(s);
                if (toSegmentId == 0)
                {
                    continue;
                }

                if (TrafficPriority.IsLeftSegment(segmentId, toSegmentId, nodeId))
                {
                    leftOutSegmentIds.Add(toSegmentId);
                }
                else if (TrafficPriority.IsRightSegment(segmentId, toSegmentId, nodeId))
                {
                    rightOutSegmentIds.Add(toSegmentId);
                }
                else
                {
                    forwardOutSegmentIds.Add(toSegmentId);
                }
            }
        }
        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 TrafficLightsTimed(ushort nodeId, IEnumerable <ushort> nodeGroup)
        {
            this.nodeId  = nodeId;
            NodeGroup    = new List <ushort>(nodeGroup);
            masterNodeId = NodeGroup[0];

            TrafficPriority.GetNodeSimulation(nodeId).TimedTrafficLightsActive = false;
        }
        public void Start()
        {
            CurrentStep = 0;
            Steps[0].SetLights();
            Steps[0].Start();

            TrafficPriority.GetNodeSimulation(nodeId).TimedTrafficLightsActive = true;
        }
 private void DestroySegmentEnd(ushort segmentId)
 {
     if (segmentId <= 0)
     {
         return;
     }
     TrafficPriority.RemovePrioritySegment(NodeId, segmentId);
     //CustomTrafficLights.RemoveSegmentLights(segmentId);
 }
        /// <summary>
        /// Displays vehicle ids over vehicles
        /// </summary>
        private void _guiVehicles()
        {
            GUIStyle          _counterStyle = new GUIStyle();
            Array16 <Vehicle> vehicles      = Singleton <VehicleManager> .instance.m_vehicles;

            for (int i = 1; i < vehicles.m_size; ++i)
            {
                Vehicle vehicle = vehicles.m_buffer[i];
                if (vehicle.m_flags == Vehicle.Flags.None)                 // node is unused
                {
                    continue;
                }

                Vector3 pos       = vehicle.GetLastFramePosition();
                var     screenPos = Camera.main.WorldToScreenPoint(pos);
                screenPos.y = Screen.height - screenPos.y;

                if (screenPos.z < 0)
                {
                    continue;
                }

                var camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position;
                var diff   = pos - camPos;
                if (diff.magnitude > DebugCloseLod)
                {
                    continue;                     // do not draw if too distant
                }
                var zoom = 1.0f / diff.magnitude * 150f;

                _counterStyle.fontSize         = (int)(10f * zoom);
                _counterStyle.normal.textColor = new Color(1f, 1f, 1f);
                //_counterStyle.normal.background = MakeTex(1, 1, new Color(0f, 0f, 0f, 0.4f));

                VehiclePosition vPos     = TrafficPriority.GetVehiclePosition((ushort)i);
                String          labelStr = "Veh. " + i + " @ " + String.Format("{0:0.##}", vehicle.GetLastFrameVelocity().magnitude) + ", len: " + vehicle.CalculateTotalLength((ushort)i) + ", state: " + vPos.CarState;
                // add current path info

                /*var currentPathId = vehicle.m_path;
                 * if (currentPathId > 0) {
                 *      var vehiclePathUnit = Singleton<PathManager>.instance.m_pathUnits.m_buffer[currentPathId];
                 *      if ((vehiclePathUnit.m_pathFindFlags & PathUnit.FLAG_READY) != 0) {
                 *              var realTimePosition = vehiclePathUnit.GetPosition(vehicle.m_pathPositionIndex >> 1);
                 *              labelStr += "\n@ seg " + realTimePosition.m_segment + "\nlane " + realTimePosition.m_lane + "\noff " + realTimePosition.m_offset;
                 *      }
                 * }*/

                Vector2 dim       = _counterStyle.CalcSize(new GUIContent(labelStr));
                Rect    labelRect = new Rect(screenPos.x - dim.x / 2f, screenPos.y - dim.y - 50f, dim.x, dim.y);

                GUI.Box(labelRect, labelStr, _counterStyle);

                //_counterStyle.normal.background = null;
            }
        }
        internal static bool mayHaveLaneArrows(uint laneId, bool?startNode = null)
        {
            if (laneId <= 0)
            {
                return(false);
            }
            NetManager netManager = Singleton <NetManager> .instance;

            if (((NetLane.Flags)Singleton <NetManager> .instance.m_lanes.m_buffer[laneId].m_flags & (NetLane.Flags.Created | NetLane.Flags.Deleted)) != NetLane.Flags.Created)
            {
                return(false);
            }

            ushort segmentId = netManager.m_lanes.m_buffer[laneId].m_segment;

            var dir  = NetInfo.Direction.Forward;
            var dir2 = ((netManager.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) ? dir : NetInfo.InvertDirection(dir);
            var dir3 = TrafficPriority.IsLeftHandDrive() ? NetInfo.InvertDirection(dir2) : dir2;

            NetInfo segmentInfo = netManager.m_segments.m_buffer[segmentId].Info;
            uint    curLaneId   = netManager.m_segments.m_buffer[segmentId].m_lanes;
            int     numLanes    = segmentInfo.m_lanes.Length;
            int     laneIndex   = 0;
            int     wIter       = 0;

            while (laneIndex < numLanes && curLaneId != 0u)
            {
                ++wIter;
                if (wIter >= 20)
                {
                    Log.Error("Too many iterations in Flags.mayHaveLaneArrows!");
                    break;
                }

                if (curLaneId == laneId)
                {
                    NetInfo.Lane laneInfo    = segmentInfo.m_lanes[laneIndex];
                    bool         isStartNode = laneInfo.m_direction != dir3;
                    if (startNode != null && isStartNode != startNode)
                    {
                        return(false);
                    }
                    ushort nodeId = isStartNode ? netManager.m_segments.m_buffer[segmentId].m_startNode : netManager.m_segments.m_buffer[segmentId].m_endNode;

                    if ((netManager.m_nodes.m_buffer[nodeId].m_flags & (NetNode.Flags.Created | NetNode.Flags.Deleted)) != NetNode.Flags.Created)
                    {
                        return(false);
                    }
                    return((netManager.m_nodes.m_buffer[nodeId].m_flags & NetNode.Flags.Junction) != NetNode.Flags.None);
                }
                curLaneId = netManager.m_lanes.m_buffer[curLaneId].m_nextLane;
                ++laneIndex;
            }
            return(false);
        }
        public static bool ShouldRecalculatePath(ushort vehicleId, ref Vehicle vehicleData, int maxBlockCounter)
        {
            if (vehicleData.m_leadingVehicle != 0)
            {
                return(false);
            }
            if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.None)
            {
                return(false);
            }
            if (!Options.dynamicPathRecalculation)
            {
                return(false);
            }
            if (TrafficPriority.GetVehiclePosition(vehicleId).LastPathRecalculation >= GetVehiclePathRecalculationFrame())
            {
                return(false);
            }
            if (vehicleData.m_path != 0)
            {
                PathUnit.Position pos = Singleton <PathManager> .instance.m_pathUnits.m_buffer[vehicleData.m_path].GetPosition(vehicleData.m_pathPositionIndex >> 1);
                if (pos.m_segment != 0)
                {
                    bool isHighway = CustomRoadAI.GetSegmentGeometry(pos.m_segment).IsHighway();
                    if (isHighway)
                    {
                        return(false);                        // no recalculation on highways
                    }
                }
            }

            return(vehicleData.m_blockCounter >= MIN_BLOCK_COUNTER_PATH_RECALC_VALUE);

            /*float recalcDecisionValue = Math.Max(0.005f, ((float)vehicleData.m_blockCounter - (float)MIN_BLOCK_RECALC_VALUE) / ((float)maxBlockCounter - (float)MIN_BLOCK_RECALC_VALUE));
             * float bias = 1f;
             * switch (Options.simAccuracy) {
             *      case 1:
             *              bias = 1.25f;
             *              break;
             *      case 2:
             *              bias = 1.5f;
             *              break;
             *      case 3:
             *              bias = 2f;
             *              break;
             *      case 4:
             *              bias = 3f;
             *              break;
             * }
             * //Log._Debug($"Path recalculation for vehicle {vehicleId}: recalcDecisionValue={recalcDecisionValue} bias={bias}");
             * recalcDecisionValue *= bias;
             * return UnityEngine.Random.Range(0f, 1f) < recalcDecisionValue;*/
        }
 public static void resetTrafficLights(bool all)
 {
     for (ushort i = 0; i < Singleton <NetManager> .instance.m_nodes.m_size; ++i)
     {
         nodeTrafficLightFlag[i] = null;
         if (!all && TrafficPriority.IsPriorityNode(i))
         {
             continue;
         }
         Singleton <NetManager> .instance.UpdateNodeFlags(i);
     }
 }
Example #15
0
        public void ChangeMode()
        {
            var hasLeftSegment    = TrafficPriority.HasLeftSegment(segmentId, nodeId) && TrafficPriority.HasLeftLane(nodeId, segmentId);
            var hasForwardSegment = TrafficPriority.HasForwardSegment(segmentId, nodeId) && TrafficPriority.HasForwardLane(nodeId, segmentId);
            var hasRightSegment   = TrafficPriority.HasRightSegment(segmentId, nodeId) && TrafficPriority.HasRightLane(nodeId, segmentId);

            if (CurrentMode == Mode.Simple)
            {
                if (!hasLeftSegment)
                {
                    CurrentMode = Mode.SingleRight;
                }
                else
                {
                    CurrentMode = Mode.SingleLeft;
                }
            }
            else if (CurrentMode == Mode.SingleLeft)
            {
                if (!hasForwardSegment || !hasRightSegment)
                {
                    CurrentMode = Mode.Simple;
                }
                else
                {
                    CurrentMode = Mode.SingleRight;
                }
            }
            else if (CurrentMode == Mode.SingleRight)
            {
                if (!hasLeftSegment)
                {
                    CurrentMode = Mode.Simple;
                }
                else
                {
                    CurrentMode = Mode.All;
                }
            }
            else
            {
                CurrentMode = Mode.Simple;
            }

            if (CurrentMode == Mode.Simple)
            {
                LightLeft       = LightMain;
                LightRight      = LightMain;
                LightPedestrian = _checkPedestrianLight();
            }
        }
        private void SetupSegmentEnd(ushort segmentId)
        {
            if (segmentId <= 0)
            {
                return;
            }
            //SegmentGeometry.Get(segmentId).Recalculate(true, true);
            if (!TrafficPriority.IsPrioritySegment(NodeId, segmentId))
            {
                TrafficPriority.AddPrioritySegment(NodeId, segmentId, SegmentEnd.PriorityType.None);
            }

            /*if (!CustomTrafficLights.IsSegmentLight(nodeId, segmentId))
             *      CustomTrafficLights.AddSegmentLights(nodeId, segmentId);*/
        }
        public bool CustomCheckTrafficLights(ushort node, ushort segment)
        {
            var nodeSimulation = TrafficPriority.GetNodeSimulation(node);

            var instance          = Singleton <NetManager> .instance;
            var currentFrameIndex = Singleton <SimulationManager> .instance.m_currentFrameIndex;

            var num  = (uint)((node << 8) / 32768);
            var num2 = currentFrameIndex - num & 255u;

            RoadBaseAI.TrafficLightState pedestrianLightState;
            ManualSegmentLight           light = TrafficLightsManual.GetSegmentLight(node, segment);

            if (light == null || nodeSimulation == null || (nodeSimulation.FlagTimedTrafficLights && !nodeSimulation.TimedTrafficLightsActive))
            {
                RoadBaseAI.TrafficLightState vehicleLightState;
                bool vehicles;
                bool pedestrians;

                RoadBaseAI.GetTrafficLightState(node, ref instance.m_segments.m_buffer[segment], currentFrameIndex - num, out vehicleLightState, out pedestrianLightState, out vehicles, out pedestrians);
                if ((pedestrianLightState == RoadBaseAI.TrafficLightState.GreenToRed || pedestrianLightState == RoadBaseAI.TrafficLightState.Red) && !pedestrians && num2 >= 196u)
                {
                    RoadBaseAI.SetTrafficLightState(node, ref instance.m_segments.m_buffer[segment], currentFrameIndex - num, vehicleLightState, pedestrianLightState, vehicles, true);
                    return(true);
                }
            }
            else
            {
                pedestrianLightState = light.GetLightPedestrian();
            }

            switch (pedestrianLightState)
            {
            case RoadBaseAI.TrafficLightState.RedToGreen:
                if (num2 < 60u)
                {
                    return(false);
                }
                break;

            case RoadBaseAI.TrafficLightState.Red:
            case RoadBaseAI.TrafficLightState.GreenToRed:
                return(false);
            }
            return(true);
        }
        internal static List <object[]> GetSortedVehicleLanes(ushort segmentId, NetInfo info, ushort?nodeId)           // TODO refactor together with getSegmentNumVehicleLanes, especially the vehicle type and lane type checks
        {
            var laneList = new List <object[]>();

            NetInfo.Direction?dir  = null;
            NetInfo.Direction?dir2 = null;
            NetInfo.Direction?dir3 = null;
            if (nodeId != null)
            {
                dir  = nodeId == Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startNode ? NetInfo.Direction.Backward : NetInfo.Direction.Forward;
                dir2 = ((Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) ? dir : NetInfo.InvertDirection((NetInfo.Direction)dir);
                dir3 = TrafficPriority.IsLeftHandDrive() ? NetInfo.InvertDirection((NetInfo.Direction)dir2) : dir2;
            }

            uint curLaneId = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_lanes;
            uint laneIndex = 0;

            while (laneIndex < info.m_lanes.Length && curLaneId != 0u)
            {
                if ((info.m_lanes[laneIndex].m_laneType & (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle)) != NetInfo.LaneType.None &&
                    (info.m_lanes[laneIndex].m_vehicleType & (VehicleInfo.VehicleType.Car | VehicleInfo.VehicleType.Train)) != VehicleInfo.VehicleType.None &&
                    (dir2 == null || info.m_lanes[laneIndex].m_finalDirection == dir2))
                {
                    laneList.Add(new object[] { curLaneId, info.m_lanes[laneIndex].m_position, laneIndex });
                }

                curLaneId = Singleton <NetManager> .instance.m_lanes.m_buffer[curLaneId].m_nextLane;
                laneIndex++;
            }

            // sort lanes from left to right
            laneList.Sort(delegate(object[] x, object[] y) {
                if ((float)x[1] == (float)y[1])
                {
                    return(0);
                }

                if ((dir2 == NetInfo.Direction.Forward) ^ (float)x[1] < (float)y[1])
                {
                    return(1);
                }
                return(-1);
            });
            return(laneList);
        }
Example #19
0
        public void CustomSimulationStep(ushort nodeId, ref NetNode data)
        {
            if (TrafficLightTool.getToolMode() != ToolMode.AddPrioritySigns)
            {
                TrafficPriority.housekeeping();
            }

            var nodeSim = TrafficPriority.GetNodeSimulation(nodeId);

            if (nodeSim != null && nodeSim.FlagTimedTrafficLights && nodeSim.TimedTrafficLightsActive)
            {
                nodeSim.SimulationStep();
            }
            else if (nodeSim == null || (nodeSim.FlagTimedTrafficLights && !nodeSim.TimedTrafficLightsActive))
            {
                OriginalSimulationStep(nodeId, ref data);
            }
        }
        internal static int GetSegmentNumVehicleLanes(ushort segmentId, ushort?nodeId, out int numDirections)
        {
            var info      = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].Info;
            var num2      = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_lanes;
            var laneIndex = 0;

            NetInfo.Direction?dir  = null;
            NetInfo.Direction?dir2 = null;
            NetInfo.Direction?dir3 = null;

            numDirections = 0;
            HashSet <NetInfo.Direction> directions = new HashSet <NetInfo.Direction>();

            if (nodeId != null)
            {
                dir  = (Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startNode == nodeId) ? NetInfo.Direction.Backward : NetInfo.Direction.Forward;
                dir2 = ((Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) ? dir : NetInfo.InvertDirection((NetInfo.Direction)dir);
                dir3 = TrafficPriority.IsLeftHandDrive() ? NetInfo.InvertDirection((NetInfo.Direction)dir2) : dir2;
            }

            var numLanes = 0;

            while (laneIndex < info.m_lanes.Length && num2 != 0u)
            {
                if (((info.m_lanes[laneIndex].m_laneType & (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle)) != NetInfo.LaneType.None &&
                     (info.m_lanes[laneIndex].m_vehicleType & (VehicleInfo.VehicleType.Car | VehicleInfo.VehicleType.Train)) != VehicleInfo.VehicleType.None) &&
                    (dir3 == null || info.m_lanes[laneIndex].m_direction == dir3))
                {
                    if (!directions.Contains(info.m_lanes[laneIndex].m_direction))
                    {
                        directions.Add(info.m_lanes[laneIndex].m_direction);
                        ++numDirections;
                    }
                    numLanes++;
                }

                num2 = Singleton <NetManager> .instance.m_lanes.m_buffer[(int)((UIntPtr)num2)].m_nextLane;
                laneIndex++;
            }

            return(numLanes);
        }
        /// <summary>
        /// Stops & destroys the traffic light simulation(s) at this node (group)
        /// </summary>
        public void Destroy()
        {
            var node      = getNode();
            var timedNode = TrafficLightsTimed.GetTimedLight(nodeId);

            if (timedNode != null)
            {
                foreach (var timedNodeId in timedNode.NodeGroup)
                {
                    var nodeSim = TrafficPriority.GetNodeSimulation(timedNodeId);                     // `this` is one of `nodeSim`
                    TrafficLightsTimed.RemoveTimedLight(timedNodeId);
                    if (nodeSim == null)
                    {
                        continue;
                    }
                    nodeSim.TimedTrafficLightsActive = false;
                    nodeSim.TimedTrafficLights       = false;
                }
            }
        }
        /// <summary>
        /// Determines the set of segments for which timed steps are defined but no real road segment exist
        /// </summary>
        /// <returns></returns>
        internal HashSet <ushort> getInvalidSegmentIds()
        {
            HashSet <ushort> invalidSegmentIds = new HashSet <ushort>();

            if (Steps.Count <= 0)
            {
                return(invalidSegmentIds);
            }

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

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

            return(invalidSegmentIds);
        }
Example #23
0
        public override void RenderOverlay(RenderManager.CameraInfo cameraInfo)
        {
            if (MainTool.GetToolController().IsInsideUI || !Cursor.visible)
            {
                return;
            }

            // no highlight for existing priority node in sign mode
            if (TrafficPriority.IsPriorityNode(HoveredNodeId))
            {
                return;
            }

            if (HoveredNodeId == 0)
            {
                return;
            }

            if (!Flags.mayHaveTrafficLight(HoveredNodeId))
            {
                return;
            }

            var segment = Singleton <NetManager> .instance.m_segments.m_buffer[Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_segment0];

            Bezier3 bezier;

            bezier.a = Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_position;
            bezier.d = Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_position;

            var color = MainTool.GetToolColor(Input.GetMouseButton(0), false);

            NetSegment.CalculateMiddlePoints(bezier.a, segment.m_startDirection, bezier.d,
                                             segment.m_endDirection,
                                             false, false, out bezier.b, out bezier.c);

            MainTool.DrawOverlayBezier(cameraInfo, bezier, color);
        }
        private static int GetNumberOfMainRoads(ushort nodeId, ref NetNode node)
        {
            var numMainRoads = 0;

            for (var s = 0; s < 8; s++)
            {
                var segmentId2 = node.GetSegment(s);

                if (segmentId2 == 0 ||
                    !TrafficPriority.IsPrioritySegment(nodeId, segmentId2))
                {
                    continue;
                }
                var prioritySegment2 = TrafficPriority.GetPrioritySegment(nodeId,
                                                                          segmentId2);

                if (prioritySegment2.Type == SegmentEnd.PriorityType.Main)
                {
                    numMainRoads++;
                }
            }
            return(numMainRoads);
        }
Example #25
0
        public override void OnPrimaryClickOverlay()
        {
            if (HoveredNodeId == 0)
            {
                return;
            }

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

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

            TrafficPriority.RemovePrioritySegments(HoveredNodeId);
            Flags.setNodeTrafficLight(HoveredNodeId, (Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_flags & NetNode.Flags.TrafficLights) == NetNode.Flags.None);
        }
Example #26
0
        public TimedTrafficLights(ushort nodeId, IEnumerable <ushort> nodeGroup)
        {
            this.NodeId  = nodeId;
            NodeGroup    = new List <ushort>(nodeGroup);
            masterNodeId = NodeGroup[0];

            // setup priority segments & live traffic lights
            foreach (ushort slaveNodeId in nodeGroup)
            {
                for (int s = 0; s < 8; ++s)
                {
                    ushort segmentId = Singleton <NetManager> .instance.m_nodes.m_buffer[slaveNodeId].GetSegment(s);
                    if (segmentId <= 0)
                    {
                        continue;
                    }
                    CustomRoadAI.GetSegmentGeometry(segmentId).Recalculate(true, true);
                    TrafficPriority.AddPrioritySegment(slaveNodeId, segmentId, SegmentEnd.PriorityType.None);
                    CustomTrafficLights.AddLiveSegmentLights(slaveNodeId, segmentId);
                }
            }

            started = false;
        }
 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);
         }
     }
 }
        /// <summary>
        /// Displays segment ids over segments
        /// </summary>
        private void _guiSegments()
        {
            GUIStyle             _counterStyle = new GUIStyle();
            Array16 <NetSegment> segments      = Singleton <NetManager> .instance.m_segments;

            for (int i = 1; i < segments.m_size; ++i)
            {
                if (segments.m_buffer[i].m_flags == NetSegment.Flags.None)                 // segment is unused
                {
                    continue;
                }
#if !DEBUG
                if ((segments.m_buffer[i].m_flags & NetSegment.Flags.Untouchable) != NetSegment.Flags.None)
                {
                    continue;
                }
#endif
                var segmentInfo = segments.m_buffer[i].Info;

                Vector3 centerPos = segments.m_buffer[i].m_bounds.center;
                var     screenPos = Camera.main.WorldToScreenPoint(centerPos);
                screenPos.y = Screen.height - screenPos.y;

                if (screenPos.z < 0)
                {
                    continue;
                }

                var camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position;
                var diff   = centerPos - camPos;
                if (diff.magnitude > DebugCloseLod)
                {
                    continue;                     // do not draw if too distant
                }
                if (Options.nodesOverlay)
                {
                    var zoom = 1.0f / diff.magnitude * 150f;

                    _counterStyle.fontSize         = (int)(12f * zoom);
                    _counterStyle.normal.textColor = new Color(1f, 0f, 0f);

                    String labelStr = "Segment " + i;
#if DEBUGx
                    labelStr += ", flags: " + segments.m_buffer[i].m_flags.ToString() + ", condition: " + segments.m_buffer[i].m_condition;
#endif
#if DEBUG
                    SegmentEnd startEnd = TrafficPriority.GetPrioritySegment(segments.m_buffer[i].m_startNode, (ushort)i);
                    SegmentEnd endEnd   = TrafficPriority.GetPrioritySegment(segments.m_buffer[i].m_endNode, (ushort)i);
                    labelStr += "\nstart? " + (startEnd != null) + " veh.: " + startEnd?.GetRegisteredVehicleCount() + ", end? " + (endEnd != null) + " veh.: " + endEnd?.GetRegisteredVehicleCount();
#endif
                    labelStr += "\nTraffic: " + segments.m_buffer[i].m_trafficDensity + " %";
#if MARKCONGESTEDSEGMENTS
                    if (CustomRoadAI.initDone && CustomRoadAI.segmentCongestion[i])
                    {
                        labelStr += " congested!";
                    }
#endif

                    float meanLaneSpeed = 0f;

                    int  lIndex     = 0;
                    uint laneId     = segments.m_buffer[i].m_lanes;
                    int  validLanes = 0;
                    while (lIndex < segmentInfo.m_lanes.Length && laneId != 0u)
                    {
                        NetInfo.Lane lane = segmentInfo.m_lanes[lIndex];
                        if (lane.CheckType(NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, VehicleInfo.VehicleType.Car))
                        {
                            if (CustomRoadAI.laneMeanSpeeds[i] != null && lIndex < CustomRoadAI.laneMeanSpeeds[i].Length)
                            {
                                if (CustomRoadAI.laneMeanSpeeds[i][lIndex] >= 0)
                                {
                                    meanLaneSpeed += (float)CustomRoadAI.laneMeanSpeeds[i][lIndex];
                                    ++validLanes;
                                }
                            }
                        }
                        lIndex++;
                        laneId = Singleton <NetManager> .instance.m_lanes.m_buffer[laneId].m_nextLane;
                    }

                    if (validLanes > 0)
                    {
                        meanLaneSpeed /= Convert.ToSingle(validLanes);
                    }

                    /*if (CustomRoadAI.InStartupPhase)
                     *      labelStr += " (in start-up phase)";
                     * else*/
                    labelStr += " (avg. speed: " + String.Format("{0:0.##}", meanLaneSpeed) + " %)";

#if DEBUG
                    labelStr += "\nstart: " + segments.m_buffer[i].m_startNode + ", end: " + segments.m_buffer[i].m_endNode;
#endif

                    Vector2 dim       = _counterStyle.CalcSize(new GUIContent(labelStr));
                    Rect    labelRect = new Rect(screenPos.x - dim.x / 2f, screenPos.y, dim.x, dim.y);

                    GUI.Label(labelRect, labelStr, _counterStyle);

                    if (Options.showLanes)
                    {
                        _guiLanes((ushort)i, ref segments.m_buffer[i], ref segmentInfo);
                    }
                }
            }
        }
        /// <summary>
        /// Calculates the current metrics for flowing and waiting vehicles
        /// </summary>
        /// <param name="wait"></param>
        /// <param name="flow"></param>
        /// <returns>true if the values could be calculated, false otherwise</returns>
        public bool calcWaitFlow(out float wait, out float flow)
        {
#if TRACE
            Singleton <CodeProfiler> .instance.Start("TimedTrafficLightsStep.calcWaitFlow");
#endif

#if DEBUGMETRIC
            bool debug = timedNode.NodeId == 3201;
#else
            bool debug = false;
#endif

#if DEBUGMETRIC
            if (debug)
            {
                Log.Warning($"TimedTrafficLightsStep.calcWaitFlow: ***START*** @ node {timedNode.NodeId}");
            }
#endif

            uint numFlows    = 0;
            uint numWaits    = 0;
            uint curMeanFlow = 0;
            uint curMeanWait = 0;

            // we are the master node. calculate traffic data
            foreach (ushort timedNodeId in timedNode.NodeGroup)
            {
                TrafficLightSimulation sim = TrafficLightSimulation.GetNodeSimulation(timedNodeId);
                if (sim == null || !sim.IsTimedLight())
                {
                    continue;
                }
                TimedTrafficLights slaveTimedNode = sim.TimedLight;
                if (slaveTimedNode.NumSteps() <= timedNode.CurrentStep)
                {
                    for (int i = 0; i < slaveTimedNode.NumSteps(); ++i)
                    {
                        slaveTimedNode.GetStep(i).invalid = true;
                    }
                    continue;
                }
                TimedTrafficLightsStep slaveStep = slaveTimedNode.Steps[timedNode.CurrentStep];

                //List<int> segmentIdsToDelete = new List<int>();

                // minimum time reached. check traffic!
                foreach (KeyValuePair <ushort, CustomSegmentLights> e in slaveStep.segmentLights)
                {
                    var fromSegmentId = e.Key;
                    var segLights     = e.Value;

                    // one of the traffic lights at this segment is green: count minimum traffic flowing through
                    SegmentEnd fromSeg = TrafficPriority.GetPrioritySegment(timedNodeId, fromSegmentId);
                    if (fromSeg == null)
                    {
#if DEBUGMETRIC
                        if (debug)
                        {
                            Log.Warning($"TimedTrafficLightsStep.calcWaitFlow: No priority segment @ seg. {fromSegmentId} found!");
                        }
#endif
                        //Log.Warning("stepDone(): prioSeg is null");
                        //segmentIdsToDelete.Add(fromSegmentId);
                        continue;                         // skip invalid segment
                    }

                    //bool startPhase = getCurrentFrame() <= startFrame + minTime + 2; // during start phase all vehicles on "green" segments are counted as flowing
                    ExtVehicleType validVehicleTypes = VehicleRestrictionsManager.GetAllowedVehicleTypes(fromSegmentId, timedNode.NodeId);

                    foreach (KeyValuePair <byte, ExtVehicleType> e2 in segLights.VehicleTypeByLaneIndex)
                    {
                        byte           laneIndex   = e2.Key;
                        ExtVehicleType vehicleType = e2.Value;
                        if (vehicleType != ExtVehicleType.None && (validVehicleTypes & vehicleType) == ExtVehicleType.None)
                        {
                            continue;
                        }
                        CustomSegmentLight segLight = segLights.GetCustomLight(laneIndex);
                        if (segLight == null)
                        {
                            Log.Warning($"Timed traffic light step: Failed to get custom light for vehicleType {vehicleType} @ seg. {fromSegmentId}, node {timedNode.NodeId}!");
                            continue;
                        }

#if DEBUGMETRIC
                        if (debug)
                        {
                            Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Checking lane {laneIndex} @ seg. {fromSegmentId}. Vehicle types: {vehicleType}");
                        }
#endif

                        Dictionary <ushort, uint> carsFlowingToSegmentMetric = null;
                        Dictionary <ushort, uint> allCarsToSegmentMetric     = null;
                        try {
                            carsFlowingToSegmentMetric = fromSeg.GetVehicleMetricGoingToSegment(false, laneIndex, debug);
                        } catch (Exception ex) {
                            Log.Warning("calcWaitFlow (1): " + ex.ToString());
                        }

                        try {
                            allCarsToSegmentMetric = fromSeg.GetVehicleMetricGoingToSegment(true, laneIndex, debug);
                        } catch (Exception ex) {
                            Log.Warning("calcWaitFlow (2): " + ex.ToString());
                        }

                        if (carsFlowingToSegmentMetric == null)
                        {
                            continue;
                        }

                        // build directions from toSegment to fromSegment
                        Dictionary <ushort, Direction> directions = new Dictionary <ushort, Direction>();
                        foreach (KeyValuePair <ushort, uint> f in allCarsToSegmentMetric)
                        {
                            var             toSegmentId = f.Key;
                            SegmentGeometry geometry    = SegmentGeometry.Get(fromSegmentId);
                            Direction       dir         = geometry.GetDirection(toSegmentId, timedNodeId == geometry.StartNodeId());
                            directions[toSegmentId] = dir;
#if DEBUGMETRIC
                            if (debug)
                            {
                                Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Calculated direction for seg. {fromSegmentId} -> seg. {toSegmentId}: {dir}");
                            }
#endif
                        }

                        // calculate waiting/flowing traffic
                        foreach (KeyValuePair <ushort, uint> f in allCarsToSegmentMetric)
                        {
                            ushort toSegmentId               = f.Key;
                            uint   totalNormCarLength        = f.Value;
                            uint   totalFlowingNormCarLength = carsFlowingToSegmentMetric[f.Key];

#if DEBUGMETRIC
                            if (debug)
                            {
                                Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Total norm. car length of vehicles on lane {laneIndex} going to seg. {toSegmentId}: {totalNormCarLength}");
                            }
#endif

                            bool addToFlow = false;
                            switch (directions[toSegmentId])
                            {
                            case Direction.Turn:
                                addToFlow = TrafficPriority.IsLeftHandDrive() ? segLight.isRightGreen() : segLight.isLeftGreen();
                                break;

                            case Direction.Left:
                                addToFlow = segLight.isLeftGreen();
                                break;

                            case Direction.Right:
                                addToFlow = segLight.isRightGreen();
                                break;

                            case Direction.Forward:
                            default:
                                addToFlow = segLight.isForwardGreen();
                                break;
                            }

                            if (addToFlow)
                            {
                                ++numFlows;
                                curMeanFlow += totalFlowingNormCarLength;
                            }
                            else
                            {
                                ++numWaits;
                                curMeanWait += totalNormCarLength;
                            }

#if DEBUGMETRIC
                            if (debug)
                            {
                                Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Vehicles on lane {laneIndex} on seg. {fromSegmentId} going to seg. {toSegmentId} flowing? {addToFlow} curMeanFlow={curMeanFlow}, curMeanWait={curMeanWait}");
                            }
#endif
                        }
                    }
                }

                // delete invalid segments from step

                /*foreach (int segmentId in segmentIdsToDelete) {
                 *      slaveStep.segmentLightStates.Remove(segmentId);
                 * }*/

                if (slaveStep.segmentLights.Count <= 0)
                {
                    invalid = true;
                    flow    = 0f;
                    wait    = 0f;
#if TRACE
                    Singleton <CodeProfiler> .instance.Stop("TimedTrafficLightsStep.calcWaitFlow");
#endif
                    return(false);
                }
            }

#if DEBUGMETRIC
            if (debug)
            {
                Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: ### Calculation completed. numFlows={numFlows}, numWaits={numWaits}, curMeanFlow={curMeanFlow}, curMeanWait={curMeanWait}");
            }

            wait = curMeanWait;
            flow = curMeanFlow;
#else
            if (numFlows > 0)
            {
                curMeanFlow /= numFlows;
            }
            if (numWaits > 0)
            {
                curMeanWait /= numWaits;
            }

            float fCurMeanFlow = curMeanFlow;
            fCurMeanFlow /= waitFlowBalance;             // a value smaller than 1 rewards steady traffic currents

            wait = (float)curMeanWait;
            flow = fCurMeanFlow;
#endif
#if TRACE
            Singleton <CodeProfiler> .instance.Stop("TimedTrafficLightsStep.calcWaitFlow");
#endif
            return(true);
        }
        /// <summary>
        /// Checks for traffic lights and priority signs when changing segments (for road & rail vehicles).
        /// Sets the maximum allowed speed <paramref name="maxSpeed"/> if segment change is not allowed (otherwise <paramref name="maxSpeed"/> has to be set by the calling method).
        /// </summary>
        /// <param name="vehicleId">vehicle id</param>
        /// <param name="vehicleData">vehicle data</param>
        /// <param name="lastFrameData">last frame data of vehicle</param>
        /// <param name="isRecklessDriver">if true, this vehicle ignores red traffic lights and priority signs</param>
        /// <param name="prevPos">previous path position</param>
        /// <param name="prevTargetNodeId">previous target node</param>
        /// <param name="prevLaneID">previous lane</param>
        /// <param name="position">current path position</param>
        /// <param name="targetNodeId">transit node</param>
        /// <param name="laneID">current lane</param>
        /// <param name="nextPosition">next path position</param>
        /// <param name="nextTargetNodeId">next target node</param>
        /// <param name="maxSpeed">maximum allowed speed (only valid if method returns false)</param>
        /// <returns>true, if the vehicle may change segments, false otherwise.</returns>
        internal static bool MayChangeSegment(ushort vehicleId, ref Vehicle vehicleData, ref Vehicle.Frame lastFrameData, bool isRecklessDriver, ref PathUnit.Position prevPos, ushort prevTargetNodeId, uint prevLaneID, ref PathUnit.Position position, ushort targetNodeId, uint laneID, ref PathUnit.Position nextPosition, ushort nextTargetNodeId, out float maxSpeed, bool debug = false)
        {
            debug = false;
            if (prevTargetNodeId != targetNodeId)
            {
                // method should only be called if targetNodeId == prevTargetNode
                maxSpeed = 0f;
                return(true);
            }

            bool         forceUpdatePos = false;
            VehicleState vehicleState   = null;

            try {
                vehicleState = VehicleStateManager.GetVehicleState(vehicleId);

                if (vehicleState == null)
                {
                    VehicleStateManager.OnPathFindReady(vehicleId, ref vehicleData);
                    vehicleState = VehicleStateManager.GetVehicleState(vehicleId);

                    if (vehicleState == null)
                    {
#if DEBUG
                        Log._Debug($"Could not get vehicle state of {vehicleId}!");
#endif
                    }
                    else
                    {
                        forceUpdatePos = true;
                    }
                }
            } catch (Exception e) {
                Log.Error("VehicleAI MayChangeSegment vehicle state error: " + e.ToString());
            }

            if (forceUpdatePos || Options.simAccuracy >= 2)
            {
                try {
                    VehicleStateManager.UpdateVehiclePos(vehicleId, ref vehicleData, ref prevPos, ref position);
                } catch (Exception e) {
                    Log.Error("VehicleAI MayChangeSegment Error: " + e.ToString());
                }
            }

            var netManager = Singleton <NetManager> .instance;

            uint currentFrameIndex        = Singleton <SimulationManager> .instance.m_currentFrameIndex;
            uint prevTargetNodeLower8Bits = (uint)((prevTargetNodeId << 8) / 32768);
            uint random = currentFrameIndex - prevTargetNodeLower8Bits & 255u;

            bool isRailVehicle = (vehicleData.Info.m_vehicleType & (VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Metro)) != VehicleInfo.VehicleType.None;

            NetNode.Flags targetNodeFlags    = netManager.m_nodes.m_buffer[targetNodeId].m_flags;
            bool          hasTrafficLight    = (targetNodeFlags & NetNode.Flags.TrafficLights) != NetNode.Flags.None;
            bool          checkTrafficLights = false;
            if (!isRailVehicle)
            {
                // check if to check space

#if DEBUG
                if (debug)
                {
                    Log._Debug($"CustomVehicleAI.MayChangeSegment: Vehicle {vehicleId} is not a train.");
                }
#endif

                var  prevLaneFlags    = (NetLane.Flags)netManager.m_lanes.m_buffer[(int)((UIntPtr)prevLaneID)].m_flags;
                var  hasCrossing      = (targetNodeFlags & NetNode.Flags.LevelCrossing) != NetNode.Flags.None;
                var  isJoinedJunction = (prevLaneFlags & NetLane.Flags.JoinedJunction) != NetLane.Flags.None;
                bool checkSpace       = !Flags.getEnterWhenBlockedAllowed(prevPos.m_segment, netManager.m_segments.m_buffer[prevPos.m_segment].m_startNode == targetNodeId) && !isRecklessDriver;
                //TrafficLightSimulation nodeSim = TrafficLightSimulation.GetNodeSimulation(destinationNodeId);
                //if (timedNode != null && timedNode.vehiclesMayEnterBlockedJunctions) {
                //	checkSpace = false;
                //}

                if (checkSpace)
                {
                    // check if there is enough space
                    if ((targetNodeFlags & (NetNode.Flags.Junction | NetNode.Flags.OneWayOut | NetNode.Flags.OneWayIn)) == NetNode.Flags.Junction &&
                        netManager.m_nodes.m_buffer[targetNodeId].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)
                            {
                                NetNode.Flags nextTargetNodeFlags = netManager.m_nodes.m_buffer[nextTargetNodeId].m_flags;
                                if ((nextTargetNodeFlags & (NetNode.Flags.Junction | NetNode.Flags.OneWayOut | NetNode.Flags.OneWayIn)) != NetNode.Flags.Junction ||
                                    netManager.m_nodes.m_buffer[nextTargetNodeId].CountSegments() == 2)
                                {
                                    uint nextLaneId = PathManager.GetLaneID(nextPosition);
                                    if (nextLaneId != 0u)
                                    {
                                        sufficientSpace = netManager.m_lanes.m_buffer[(int)((UIntPtr)nextLaneId)].CheckSpace(len);
                                    }
                                }
                            }
                            if (!sufficientSpace)
                            {
                                maxSpeed = 0f;
                                try {
                                    if (vehicleState != null)
                                    {
#if DEBUG
                                        if (debug)
                                        {
                                            Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to BLOCKED");
                                        }
#endif

                                        vehicleState.JunctionTransitState = VehicleJunctionTransitState.Blocked;
                                    }
                                } catch (Exception e) {
                                    Log.Error("VehicleAI MayChangeSegment error while setting junction state to BLOCKED: " + e.ToString());
                                }
                                return(false);
                            }
                        }
                    }
                }

                checkTrafficLights = (!isJoinedJunction || hasCrossing);
            }
            else
            {
#if DEBUG
                if (debug)
                {
                    Log._Debug($"CustomVehicleAI.MayChangeSegment: Vehicle {vehicleId} is a train.");
                }
#endif

                checkTrafficLights = true;
            }

            try {
                if (vehicleState != null && vehicleState.JunctionTransitState == VehicleJunctionTransitState.Blocked)
                {
#if DEBUG
                    if (debug)
                    {
                        Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState from BLOCKED to ENTER");
                    }
#endif
                    vehicleState.JunctionTransitState = VehicleJunctionTransitState.Enter;
                }

                if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == 0)
                {
                    if (hasTrafficLight && checkTrafficLights)
                    {
#if DEBUG
                        if (debug)
                        {
                            Log._Debug($"CustomVehicleAI.MayChangeSegment: Node {targetNodeId} has a traffic light.");
                        }
#endif

                        var destinationInfo = netManager.m_nodes.m_buffer[targetNodeId].Info;

                        if (vehicleState != null && vehicleState.JunctionTransitState == VehicleJunctionTransitState.None)
                        {
#if DEBUG
                            if (debug)
                            {
                                Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to ENTER (1)");
                            }
#endif
                            vehicleState.JunctionTransitState = VehicleJunctionTransitState.Enter;
                        }

                        RoadBaseAI.TrafficLightState vehicleLightState;
                        RoadBaseAI.TrafficLightState pedestrianLightState;
                        bool vehicles;
                        bool pedestrians;
                        CustomRoadAI.GetTrafficLightState(vehicleId, ref vehicleData, targetNodeId, prevPos.m_segment, prevPos.m_lane, position.m_segment, ref netManager.m_segments.m_buffer[prevPos.m_segment], currentFrameIndex - prevTargetNodeLower8Bits, out vehicleLightState, out pedestrianLightState, out vehicles, out pedestrians);

                        if (vehicleData.Info.m_vehicleType == VehicleInfo.VehicleType.Car && isRecklessDriver)                           // no reckless driving at railroad crossings
                        {
                            vehicleLightState = RoadBaseAI.TrafficLightState.Green;
                        }

#if DEBUG
                        if (debug)
                        {
                            Log._Debug($"CustomVehicleAI.MayChangeSegment: Vehicle {vehicleId} has {vehicleLightState} at node {targetNodeId}");
                        }
#endif

                        if (!vehicles && random >= 196u)
                        {
                            vehicles = true;
                            RoadBaseAI.SetTrafficLightState(targetNodeId, ref netManager.m_segments.m_buffer[prevPos.m_segment], currentFrameIndex - prevTargetNodeLower8Bits, vehicleLightState, pedestrianLightState, vehicles, pedestrians);
                        }

                        var stopCar = false;
                        switch (vehicleLightState)
                        {
                        case RoadBaseAI.TrafficLightState.RedToGreen:
                            if (random < 60u)
                            {
                                stopCar = true;
                            }
                            else
                            {
#if DEBUG
                                if (debug)
                                {
                                    Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to LEAVE (RedToGreen)");
                                }
#endif
                                if (vehicleState != null)
                                {
                                    vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave;
                                }
                            }
                            break;

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

                        case RoadBaseAI.TrafficLightState.GreenToRed:
                            if (random >= 30u)
                            {
                                stopCar = true;
                            }
                            else if (vehicleState != null)
                            {
#if DEBUG
                                if (debug)
                                {
                                    Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to LEAVE (GreenToRed)");
                                }
#endif
                                vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave;
                            }
                            break;
                        }

                        /*if ((vehicleLightState == RoadBaseAI.TrafficLightState.Green || vehicleLightState == RoadBaseAI.TrafficLightState.RedToGreen) && !Flags.getEnterWhenBlockedAllowed(prevPos.m_segment, netManager.m_segments.m_buffer[prevPos.m_segment].m_startNode == targetNodeId)) {
                         *      var hasIncomingCars = TrafficPriority.HasIncomingVehiclesWithHigherPriority(vehicleId, targetNodeId);
                         *
                         *      if (hasIncomingCars) {
                         *              // green light but other cars are incoming and they have priority: stop
                         *              stopCar = true;
                         *      }
                         * }*/

                        if (stopCar)
                        {
                            if (vehicleState != null)
                            {
#if DEBUG
                                if (debug)
                                {
                                    Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to STOP");
                                }
#endif
                                vehicleState.JunctionTransitState = VehicleJunctionTransitState.Stop;
                            }
                            maxSpeed = 0f;
                            return(false);
                        }
                    }
                    else if (vehicleState != null)
                    {
#if DEBUG
                        //bool debug = destinationNodeId == 10864;
                        //bool debug = destinationNodeId == 13531;
                        //bool debug = false;// targetNodeId == 5027;
#endif
                        //bool debug = false;
#if DEBUG
                        if (debug)
                        {
                            Log._Debug($"Vehicle {vehicleId} is arriving @ seg. {prevPos.m_segment} ({position.m_segment}, {nextPosition.m_segment}), node {targetNodeId} which is not a traffic light.");
                        }
#endif

                        var prioritySegment = TrafficPriority.GetPrioritySegment(targetNodeId, prevPos.m_segment);
                        if (prioritySegment != null)
                        {
#if DEBUG
                            if (debug)
                            {
                                Log._Debug($"Vehicle {vehicleId} is arriving @ seg. {prevPos.m_segment} ({position.m_segment}, {nextPosition.m_segment}), node {targetNodeId} which is not a traffic light and is a priority segment.");
                            }
#endif
                            //if (prioritySegment.HasVehicle(vehicleId)) {
#if DEBUG
                            if (debug)
                            {
                                Log._Debug($"Vehicle {vehicleId}: segment target position found");
                            }
#endif
#if DEBUG
                            if (debug)
                            {
                                Log._Debug($"Vehicle {vehicleId}: global target position found. carState = {vehicleState.JunctionTransitState.ToString()}");
                            }
#endif
                            var   currentFrameIndex2 = Singleton <SimulationManager> .instance.m_currentFrameIndex;
                            var   frame = currentFrameIndex2 >> 4;
                            float speed = lastFrameData.m_velocity.magnitude;

                            if (vehicleState.JunctionTransitState == VehicleJunctionTransitState.None)
                            {
#if DEBUG
                                if (debug)
                                {
                                    Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to ENTER (prio)");
                                }
#endif
                                vehicleState.JunctionTransitState = VehicleJunctionTransitState.Enter;
                            }

                            if (vehicleState.JunctionTransitState != VehicleJunctionTransitState.Leave)
                            {
                                bool hasIncomingCars;
                                switch (prioritySegment.Type)
                                {
                                case SegmentEnd.PriorityType.Stop:
#if DEBUG
                                    if (debug)
                                    {
                                        Log._Debug($"Vehicle {vehicleId}: STOP sign. waittime={vehicleState.WaitTime}, vel={speed}");
                                    }
#endif

                                    if (Options.simAccuracy <= 2 || (Options.simAccuracy >= 3 && vehicleState.WaitTime < MaxPriorityWaitTime))
                                    {
#if DEBUG
                                        if (debug)
                                        {
                                            Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to STOP (wait)");
                                        }
#endif
                                        vehicleState.JunctionTransitState = VehicleJunctionTransitState.Stop;

                                        if (speed <= TrafficPriority.maxStopVelocity)
                                        {
                                            vehicleState.WaitTime++;

                                            float minStopWaitTime = UnityEngine.Random.Range(0f, 3f);
                                            if (vehicleState.WaitTime >= minStopWaitTime)
                                            {
                                                if (Options.simAccuracy >= 4)
                                                {
                                                    vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave;
                                                }
                                                else
                                                {
                                                    hasIncomingCars = TrafficPriority.HasIncomingVehiclesWithHigherPriority(vehicleId, ref vehicleData, ref prevPos, ref position);
#if DEBUG
                                                    if (debug)
                                                    {
                                                        Log._Debug($"hasIncomingCars: {hasIncomingCars}");
                                                    }
#endif

                                                    if (hasIncomingCars)
                                                    {
                                                        maxSpeed = 0f;
                                                        return(false);
                                                    }
#if DEBUG
                                                    if (debug)
                                                    {
                                                        Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to LEAVE (min wait timeout)");
                                                    }
#endif
                                                    vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave;
                                                }
                                            }
                                            else
                                            {
                                                maxSpeed = 0;
                                                return(false);
                                            }
                                        }
                                        else
                                        {
                                            vehicleState.WaitTime = 0;
                                            maxSpeed = 0f;
                                            return(false);
                                        }
                                    }
                                    else
                                    {
#if DEBUG
                                        if (debug)
                                        {
                                            Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to LEAVE (max wait timeout)");
                                        }
#endif
                                        vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave;
                                    }
                                    break;

                                case SegmentEnd.PriorityType.Yield:
#if DEBUG
                                    if (debug)
                                    {
                                        Log._Debug($"Vehicle {vehicleId}: YIELD sign. waittime={vehicleState.WaitTime}");
                                    }
#endif

                                    if (Options.simAccuracy <= 2 || (Options.simAccuracy >= 3 && vehicleState.WaitTime < MaxPriorityWaitTime))
                                    {
                                        vehicleState.WaitTime++;
#if DEBUG
                                        if (debug)
                                        {
                                            Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to STOP (wait)");
                                        }
#endif
                                        vehicleState.JunctionTransitState = VehicleJunctionTransitState.Stop;

                                        if (speed <= TrafficPriority.maxYieldVelocity || Options.simAccuracy <= 2)
                                        {
                                            if (Options.simAccuracy >= 4)
                                            {
                                                vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave;
                                            }
                                            else
                                            {
                                                hasIncomingCars = TrafficPriority.HasIncomingVehiclesWithHigherPriority(vehicleId, ref vehicleData, ref prevPos, ref position);
#if DEBUG
                                                if (debug)
                                                {
                                                    Log._Debug($"Vehicle {vehicleId}: hasIncomingCars: {hasIncomingCars}");
                                                }
#endif

                                                if (hasIncomingCars)
                                                {
                                                    maxSpeed = 0f;
                                                    return(false);
                                                }
                                                else
                                                {
#if DEBUG
                                                    if (debug)
                                                    {
                                                        Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to LEAVE (no incoming cars)");
                                                    }
#endif
                                                    vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave;
                                                }
                                            }
                                        }
                                        else
                                        {
#if DEBUG
                                            if (debug)
                                            {
                                                Log._Debug($"Vehicle {vehicleId}: Vehicle has not yet reached yield speed (reduce {speed} by {vehicleState.ReduceSpeedByValueToYield})");
                                            }
#endif

                                            // vehicle has not yet reached yield speed
                                            maxSpeed = TrafficPriority.maxYieldVelocity;
                                            return(false);
                                        }
                                    }
                                    else
                                    {
#if DEBUG
                                        if (debug)
                                        {
                                            Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to LEAVE (max wait timeout)");
                                        }
#endif
                                        vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave;
                                    }
                                    break;

                                case SegmentEnd.PriorityType.Main:
                                case SegmentEnd.PriorityType.None:
#if DEBUG
                                    if (debug)
                                    {
                                        Log._Debug($"Vehicle {vehicleId}: MAIN sign. waittime={vehicleState.WaitTime}");
                                    }
#endif
                                    maxSpeed = 0f;

                                    if (Options.simAccuracy == 4)
                                    {
                                        return(true);
                                    }

                                    if (Options.simAccuracy <= 2 || (Options.simAccuracy == 3 && vehicleState.WaitTime < MaxPriorityWaitTime))
                                    {
                                        vehicleState.WaitTime++;
#if DEBUG
                                        if (debug)
                                        {
                                            Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to STOP (wait)");
                                        }
#endif
                                        vehicleState.JunctionTransitState = VehicleJunctionTransitState.Stop;

                                        hasIncomingCars = TrafficPriority.HasIncomingVehiclesWithHigherPriority(vehicleId, ref vehicleData, ref prevPos, ref position);
#if DEBUG
                                        if (debug)
                                        {
                                            Log._Debug($"hasIncomingCars: {hasIncomingCars}");
                                        }
#endif

                                        if (hasIncomingCars)
                                        {
                                            return(false);
                                        }
#if DEBUG
                                        if (debug)
                                        {
                                            Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to LEAVE (no conflicting car)");
                                        }
#endif
                                        vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave;
                                    }
                                    return(true);
                                }
                            }
                            else if (speed <= TrafficPriority.maxStopVelocity)
                            {
                                // vehicle is not moving. reset allowance to leave junction
#if DEBUG
                                if (debug)
                                {
                                    Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState from LEAVE to BLOCKED (speed to low)");
                                }
#endif
                                vehicleState.JunctionTransitState = VehicleJunctionTransitState.Blocked;

                                maxSpeed = 0f;
                                return(false);
                            }
                        }
                    }
                }
            } catch (Exception e) {
                Log.Error($"Error occured in MayChangeSegment: {e.ToString()}");
            }
            maxSpeed = 0f;             // maxSpeed should be set by caller
            return(true);
        }