/// <summary> /// Stores that the given vehicle's path has been dynamically recalculated at the current frame. /// </summary> /// <param name="vehicleId"></param> #if PATHRECALC internal static void MarkPathRecalculation(ushort vehicleId, ushort segmentId) { VehicleState state = VehicleStateManager.GetVehicleState(vehicleId); if (state == null) { return; } state.LastPathRecalculation = GetVehiclePathRecalculationFrame(); state.LastPathRecalculationSegmentId = segmentId; state.PathRecalculationRequested = true; }
/// <summary> /// Displays vehicle ids over vehicles /// </summary> private void _guiVehicles() { GUIStyle _counterStyle = new GUIStyle(); Array16 <Vehicle> vehicles = Singleton <VehicleManager> .instance.m_vehicles; LaneConnectionManager connManager = Singleton <LaneConnectionManager> .instance; SimulationManager simManager = Singleton <SimulationManager> .instance; NetManager netManager = Singleton <NetManager> .instance; for (int i = 1; i < vehicles.m_size; ++i) { Vehicle vehicle = vehicles.m_buffer[i]; if (vehicle.m_flags == 0) // node is unused { continue; } Vector3 vehPos = vehicle.GetLastFramePosition(); var screenPos = Camera.main.WorldToScreenPoint(vehPos); screenPos.y = Screen.height - screenPos.y; if (screenPos.z < 0) { continue; } var camPos = simManager.m_simulationView.m_position; var diff = vehPos - 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)); VehicleState vState = VehicleStateManager.GetVehicleState((ushort)i); PathUnit.Position?curPos = vState?.GetCurrentPathPosition(ref vehicle); PathUnit.Position?nextPos = vState?.GetNextPathPosition(ref vehicle); bool? startNode = vState?.CurrentSegmentEnd?.StartNode; ushort?segmentId = vState?.CurrentSegmentEnd?.SegmentId; ushort?transitNodeId = vState?.CurrentSegmentEnd?.NodeId; /*float distanceToTransitNode = Single.NaN; * float timeToTransitNode = Single.NaN;*/ float vehSpeed = vehicle.GetLastFrameVelocity().magnitude; Vector3?targetPos = null; if (transitNodeId != null) { targetPos = netManager.m_nodes.m_buffer[(ushort)transitNodeId].m_position; } /*if (transitNodeId != null && segmentId != null && startNode != null && curPos != null) { * bool outgoing = false; * connManager.GetLaneEndPoint((ushort)segmentId, (bool)startNode, ((PathUnit.Position)curPos).m_lane, null, null, out outgoing, out targetPos); * }*/ /*if (targetPos != null) { * distanceToTransitNode = ((Vector3)targetPos - vehPos).magnitude; * if (vehSpeed > 0) * timeToTransitNode = distanceToTransitNode / vehSpeed; * else * timeToTransitNode = Single.PositiveInfinity; * }*/ String labelStr = "V #" + i + " @ " + vState?.CurrentSegmentEnd?.SegmentId; //String labelStr = "Veh. " + i + " @ " + String.Format("{0:0.##}", vehSpeed) + "/" + (vState != null ? vState.CurrentMaxSpeed.ToString() : "-") + " (" + (vState != null ? vState.VehicleType.ToString() : "-") + ", valid? " + (vState != null ? vState.Valid.ToString() : "-") + ")" + ", len: " + (vState != null ? vState.TotalLength.ToString() : "-") + ", state: " + (vState != null ? vState.JunctionTransitState.ToString() : "-"); #if PATHRECALC labelStr += ", recalc: " + (vState != null ? vState.LastPathRecalculation.ToString() : "-"); #endif //labelStr += "\npos: " + curPos?.m_segment + "(" + curPos?.m_lane + ")->" + nextPos?.m_segment + "(" + nextPos?.m_lane + ")" /* + ", dist: " + distanceToTransitNode + ", time: " + timeToTransitNode*/ + ", last update: " + vState?.LastPositionUpdate; #if USEPATHWAITCOUNTER labelStr += ", wait: " + vState?.PathWaitCounter; #endif 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; } }
public static bool ShouldRecalculatePath(ushort vehicleId, ref Vehicle vehicleData, int maxBlockCounter, out ushort segmentId) { segmentId = 0; if (!Options.IsDynamicPathRecalculationActive()) { return(false); } if (Options.simAccuracy > 1) { return(false); } if (!CustomPathManager.InitDone #if EXTRAPF || CustomPathManager.ExtraQueuedPathFinds > Options.someValue8 #elif QUEUEDSTATS || CustomPathManager.TotalQueuedPathFinds > Options.someValue8 #endif ) { return(false); } if (vehicleData.m_leadingVehicle != 0) { return(false); } if (vehicleData.m_path == 0) { return(false); } /*if (vehicleData.GetLastFrameVelocity().magnitude > Options.someValue9) * return false;*/ /*if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == 0) * return false;*/ VehicleState state = VehicleStateManager.GetVehicleState(vehicleId); if (state == null || state.LastPathRecalculation >= GetVehiclePathRecalculationFrame()) { return(false); } if (vehicleData.GetLastFrameVelocity().magnitude > Options.someValue9 * state.CurrentMaxSpeed) { return(false); } NetManager netManager = Singleton <NetManager> .instance; bool recalc = false; ushort outSegmentId = 0; state.ProcessCurrentAndNextPathPosition(ref vehicleData, delegate(ref PathUnit.Position curPos, ref PathUnit.Position nextPos) { if (curPos.m_segment == 0 || nextPos.m_segment == 0) { return; } if (state.LastPathRecalculationSegmentId == curPos.m_segment) { return; } if (curPos.m_lane >= netManager.m_segments.m_buffer[curPos.m_segment].Info.m_lanes.Length) { return; } if (nextPos.m_lane >= netManager.m_segments.m_buffer[nextPos.m_segment].Info.m_lanes.Length) { return; } if (CustomRoadAI.laneMeanSpeeds[nextPos.m_segment] == null || nextPos.m_lane >= CustomRoadAI.laneMeanSpeeds[nextPos.m_segment].Length) { return; } if (CustomRoadAI.laneMeanSpeeds[nextPos.m_segment][nextPos.m_lane] >= 60) { return; } /*if (CustomRoadAI.laneMeanDensities[nextPos.m_segment] == null || nextPos.m_lane >= CustomRoadAI.laneMeanDensities[nextPos.m_segment].Length) * return; * byte nextDensity = CustomRoadAI.laneMeanDensities[nextPos.m_segment][nextPos.m_lane]; * * if (nextDensity < 0.5) // TODO incorporate number of lanes (density is measured relatively) * return;*/ recalc = true; outSegmentId = curPos.m_segment; }); segmentId = outSegmentId; return(recalc); }
/// <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); }