/// <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; } }
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;*/ }
/// <summary> /// Handles vehicle path information in order to manage special nodes (nodes with priority signs or traffic lights). /// Data like "vehicle X is on segment S0 and is going to segment S1" is collected. /// </summary> /// <param name="vehicleId"></param> /// <param name="vehicleData"></param> internal static void HandleVehicle(ushort vehicleId, ref Vehicle vehicleData, bool addTraffic, bool realTraffic, byte maxUpcomingPathPositions, bool debug = false) { if (maxUpcomingPathPositions <= 0) { maxUpcomingPathPositions = 1; // we need at least one upcoming path position } var netManager = Singleton <NetManager> .instance; var lastFrameData = vehicleData.GetLastFrameData(); var lastFrameVehiclePos = lastFrameData.m_position; #if DEBUGV var camPos = Camera.main.transform.position; //debug = (lastFrameVehiclePos - camPos).sqrMagnitude < CloseLod; debug = false; List <String> logBuffer = new List <String>(); bool logme = false; #endif if ((vehicleData.m_flags & Vehicle.Flags.Created) == 0) { TrafficPriority.RemoveVehicleFromSegments(vehicleId); return; } if (vehicleData.Info.m_vehicleType != VehicleInfo.VehicleType.Car && vehicleData.Info.m_vehicleType != VehicleInfo.VehicleType.Train && vehicleData.Info.m_vehicleType != VehicleInfo.VehicleType.Tram) { //Log._Debug($"HandleVehicle does not handle vehicles of type {vehicleData.Info.m_vehicleType}"); return; } #if DEBUGV logBuffer.Add("Calculating prio info for vehicleId " + vehicleId); #endif ExtVehicleType?vehicleType = CustomVehicleAI.DetermineVehicleTypeFromVehicle(vehicleId, ref vehicleData); if (vehicleType == null) { Log.Warning($"Could not determine vehicle type of vehicle {vehicleId}!"); } if (vehicleType == null || vehicleType == ExtVehicleType.None) { return; } // add vehicle to our vehicle list VehiclePosition vehiclePos = TrafficPriority.GetVehiclePosition(vehicleId); // we extract the segment information directly from the vehicle var currentPathUnitId = vehicleData.m_path; List <ushort> realTimeDestinationNodes = new List <ushort>(); // current and upcoming node ids List <PathUnit.Position> realTimePositions = new List <PathUnit.Position>(); // current and upcoming vehicle positions #if DEBUGV logBuffer.Add("* vehicleId " + vehicleId + ". currentPathId: " + currentPathUnitId + " pathPositionIndex: " + vehicleData.m_pathPositionIndex); #endif if (currentPathUnitId > 0) { // vehicle has a path... if ((Singleton <PathManager> .instance.m_pathUnits.m_buffer[currentPathUnitId].m_pathFindFlags & PathUnit.FLAG_READY) != 0) { // The path(unit) is established and is ready for use: get the vehicle's current position in terms of segment and lane realTimePositions.Add(Singleton <PathManager> .instance.m_pathUnits.m_buffer[currentPathUnitId].GetPosition(vehicleData.m_pathPositionIndex >> 1)); if (realTimePositions[0].m_offset == 0) { realTimeDestinationNodes.Add(netManager.m_segments.m_buffer[realTimePositions[0].m_segment].m_startNode); } else { realTimeDestinationNodes.Add(netManager.m_segments.m_buffer[realTimePositions[0].m_segment].m_endNode); } if (maxUpcomingPathPositions > 0) { // evaluate upcoming path units byte i = 0; uint pathUnitId = currentPathUnitId; int pathPos = (byte)((vehicleData.m_pathPositionIndex >> 1) + 1); while (true) { if (pathPos > 11) { // go to next path unit pathPos = 0; pathUnitId = Singleton <PathManager> .instance.m_pathUnits.m_buffer[pathUnitId].m_nextPathUnit; #if DEBUGV logBuffer.Add("* vehicleId " + vehicleId + ". Going to next path unit (1). pathUnitId=" + pathUnitId); #endif if (pathUnitId <= 0) { break; } } PathUnit.Position nextRealTimePosition = default(PathUnit.Position); if (!Singleton <PathManager> .instance.m_pathUnits.m_buffer[pathUnitId].GetPosition(pathPos, out nextRealTimePosition)) // if this returns false, there is no next path unit { #if DEBUGV logBuffer.Add("* vehicleId " + vehicleId + ". No next path unit! pathPos=" + pathPos + ", pathUnitId=" + pathUnitId); #endif break; } ushort destNodeId = 0; if (nextRealTimePosition.m_segment > 0) { if (nextRealTimePosition.m_offset == 0) { destNodeId = netManager.m_segments.m_buffer[nextRealTimePosition.m_segment].m_startNode; } else { destNodeId = netManager.m_segments.m_buffer[nextRealTimePosition.m_segment].m_endNode; } } #if DEBUGV logBuffer.Add("* vehicleId " + vehicleId + ". Next path unit! node " + destNodeId + ", seg. " + nextRealTimePosition.m_segment + ", pathUnitId=" + pathUnitId + ", pathPos: " + pathPos); #endif realTimePositions.Add(nextRealTimePosition); realTimeDestinationNodes.Add(destNodeId); if (i >= maxUpcomingPathPositions - 1) { break; // we calculate up to 2 upcoming path units at the moment } ++pathPos; ++i; } } // please don't ask why we use "m_pathPositionIndex >> 1" (which equals to "m_pathPositionIndex / 2") here (Though it would // be interesting to know why they used such an ugly indexing scheme!!). I assume the oddness of m_pathPositionIndex relates // to the car's position on the segment. If it is even the car might be in the segment's first half and if it is odd, it might // be in the segment's second half. #if DEBUGV logBuffer.Add("* vehicleId " + vehicleId + ". *INFO* rtPos.seg=" + realTimePositions[0].m_segment + " nrtPos.seg=" + (realTimePositions.Count > 1 ? "" + realTimePositions[1].m_segment : "n/a")); #endif } } // we have seen the car! vehiclePos.LastFrame = Singleton <SimulationManager> .instance.m_currentFrameIndex; #if DEBUGV logBuffer.Add("* vehicleId " + vehicleId + ". ToNode: " + vehiclePos.ToNode + ". FromSegment: " + vehiclePos.FromSegment /* + ". FromLaneId: " + TrafficPriority.Vehicles[vehicleId].FromLaneId*/); #endif if (addTraffic && vehicleData.m_leadingVehicle == 0 && realTimePositions.Count > 0) { // add traffic to lane uint laneId = PathManager.GetLaneID(realTimePositions[0]); CustomRoadAI.AddTraffic(laneId, (ushort)Mathf.RoundToInt(vehicleData.CalculateTotalLength(vehicleId)), (ushort)Mathf.RoundToInt(lastFrameData.m_velocity.magnitude), realTraffic); } #if DEBUGV logBuffer.Add("* vehicleId " + vehicleId + ". Real time positions: " + realTimePositions.Count + ", Destination nodes: " + realTimeDestinationNodes.Count); #endif if (realTimePositions.Count >= 1) { // we found a valid path unit var sourceLaneIndex = realTimePositions[0].m_lane; if ( !vehiclePos.Valid || vehiclePos.ToNode != realTimeDestinationNodes[0] || vehiclePos.FromSegment != realTimePositions[0].m_segment || vehiclePos.FromLaneIndex != sourceLaneIndex) { // vehicle information is not up-to-date. remove the car from old priority segments (if existing)... TrafficPriority.RemoveVehicleFromSegments(vehicleId); if (realTimePositions.Count >= 2) { // save vehicle information for priority rule handling vehiclePos.Valid = true; vehiclePos.CarState = VehicleJunctionTransitState.None; vehiclePos.WaitTime = 0; vehiclePos.Stopped = false; vehiclePos.ToNode = realTimeDestinationNodes[0]; vehiclePos.FromSegment = realTimePositions[0].m_segment; vehiclePos.FromLaneIndex = realTimePositions[0].m_lane; vehiclePos.ToSegment = realTimePositions[1].m_segment; vehiclePos.ToLaneIndex = realTimePositions[1].m_lane; vehiclePos.ReduceSpeedByValueToYield = UnityEngine.Random.Range(16f, 28f); vehiclePos.OnEmergency = (vehicleData.m_flags & Vehicle.Flags.Emergency2) != 0; vehiclePos.VehicleType = (ExtVehicleType)vehicleType; #if DEBUGV logBuffer.Add($"* vehicleId {vehicleId}. Setting current position to: from {vehiclePos.FromSegment} (lane {vehiclePos.FromLaneIndex}), going over {vehiclePos.ToNode}, to {vehiclePos.ToSegment} (lane {vehiclePos.ToLaneIndex})"); #endif //if (!Options.disableSomething) { // add the vehicle to upcoming priority segments that have timed traffic lights for (int i = 0; i < realTimePositions.Count - 1; ++i) { var prioritySegment = TrafficPriority.GetPrioritySegment(realTimeDestinationNodes[i], realTimePositions[i].m_segment); if (prioritySegment == null) { continue; } // add upcoming segments only if there is a timed traffic light TrafficLightSimulation nodeSim = TrafficLightSimulation.GetNodeSimulation(realTimeDestinationNodes[i]); if (i > 0 && (nodeSim == null || !nodeSim.IsTimedLight() || !nodeSim.IsTimedLightActive())) { continue; } VehiclePosition upcomingVehiclePos = new VehiclePosition(); upcomingVehiclePos.Valid = true; upcomingVehiclePos.CarState = VehicleJunctionTransitState.None; upcomingVehiclePos.LastFrame = vehiclePos.LastFrame; upcomingVehiclePos.ToNode = realTimeDestinationNodes[i]; upcomingVehiclePos.FromSegment = realTimePositions[i].m_segment; upcomingVehiclePos.FromLaneIndex = realTimePositions[i].m_lane; upcomingVehiclePos.ToSegment = realTimePositions[i + 1].m_segment; upcomingVehiclePos.ToLaneIndex = realTimePositions[i + 1].m_lane; upcomingVehiclePos.ReduceSpeedByValueToYield = UnityEngine.Random.Range(16f, 28f); upcomingVehiclePos.OnEmergency = (vehicleData.m_flags & Vehicle.Flags.Emergency2) != 0; upcomingVehiclePos.VehicleType = (ExtVehicleType)vehicleType; #if DEBUGV logBuffer.Add($"* vehicleId {vehicleId}. Adding future position: from {upcomingVehiclePos.FromSegment} (lane {upcomingVehiclePos.FromLaneIndex}), going over {upcomingVehiclePos.ToNode}, to {upcomingVehiclePos.ToSegment} (lane {upcomingVehiclePos.ToLaneIndex})"); #endif prioritySegment.AddVehicle(vehicleId, upcomingVehiclePos); } } //} } else { #if DEBUGV logBuffer.Add($"* vehicleId {vehicleId}. Nothing has changed. from {vehiclePos.FromSegment} (lane {vehiclePos.FromLaneIndex}), going over {vehiclePos.ToNode}, to {vehiclePos.ToSegment} (lane {vehiclePos.ToLaneIndex})"); logme = false; #endif } } else { #if DEBUGV logBuffer.Add($"* vehicleId {vehicleId}. Insufficient path unit positions."); #endif TrafficPriority.RemoveVehicleFromSegments(vehicleId); } #if DEBUGV if (logme) { Log._Debug("vehicleId: " + vehicleId + " ============================================"); foreach (String logBuf in logBuffer) { Log._Debug(logBuf); } Log._Debug("vehicleId: " + vehicleId + " ============================================"); } #endif }
public void CustomCalculateSegmentPosition(ushort vehicleId, ref Vehicle vehicleData, PathUnit.Position nextPosition, PathUnit.Position position, uint laneID, byte offset, PathUnit.Position prevPos, uint prevLaneID, byte prevOffset, int index, out Vector3 pos, out Vector3 dir, out float maxSpeed) { var netManager = Singleton <NetManager> .instance; //var vehicleManager = Singleton<VehicleManager>.instance; netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].CalculatePositionAndDirection(offset * 0.003921569f, out pos, out dir); bool isRecklessDriver = IsRecklessDriver(vehicleId, ref vehicleData); var lastFrameData = vehicleData.GetLastFrameData(); var lastFrameVehiclePos = lastFrameData.m_position; var camPos = Camera.main.transform.position; bool simulatePrioritySigns = (lastFrameVehiclePos - camPos).sqrMagnitude < FarLod && !isRecklessDriver; if (Options.simAccuracy <= 0) { if (vehicleData.Info.m_vehicleType == VehicleInfo.VehicleType.Car) { VehiclePosition vehiclePos = TrafficPriority.GetVehiclePosition(vehicleId); if (vehiclePos.Valid && simulatePrioritySigns) // TODO check if this should be !vehiclePos.Valid { try { CustomVehicleAI.HandleVehicle(vehicleId, ref Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleId], false, false); } catch (Exception e) { Log.Error("CarAI TmCalculateSegmentPosition Error: " + e.ToString()); } } } else { //Log._Debug($"TmCalculateSegmentPosition does not handle vehicles of type {vehicleData.Info.m_vehicleType}"); } } // I think this is supposed to be the lane position? // [VN, 12/23/2015] It's the 3D car position on the Bezier curve of the lane. // This crazy 0.003921569f equals to 1f/255 and prevOffset is the byte value (0..255) of the car position. var vehiclePosOnBezier = netManager.m_lanes.m_buffer[(int)((UIntPtr)prevLaneID)].CalculatePosition(prevOffset * 0.003921569f); //ushort currentSegmentId = netManager.m_lanes.m_buffer[(int)((UIntPtr)prevLaneID)].m_segment; ushort destinationNodeId; ushort sourceNodeId; if (offset < position.m_offset) { destinationNodeId = netManager.m_segments.m_buffer[position.m_segment].m_startNode; sourceNodeId = netManager.m_segments.m_buffer[position.m_segment].m_endNode; } else { destinationNodeId = netManager.m_segments.m_buffer[position.m_segment].m_endNode; sourceNodeId = netManager.m_segments.m_buffer[position.m_segment].m_startNode; } var previousDestinationNode = prevOffset == 0 ? netManager.m_segments.m_buffer[prevPos.m_segment].m_startNode : netManager.m_segments.m_buffer[prevPos.m_segment].m_endNode; // this seems to be like the required braking force in order to stop the vehicle within its half length. var crazyValue = 0.5f * lastFrameData.m_velocity.sqrMagnitude / m_info.m_braking + m_info.m_generatedInfo.m_size.z * 0.5f; // Essentially, this is true if the car has enough time and space to brake (e.g. for a red traffic light) if (destinationNodeId == previousDestinationNode) { if (Vector3.Distance(lastFrameVehiclePos, vehiclePosOnBezier) >= crazyValue - 1f) { var currentFrameIndex = Singleton <SimulationManager> .instance.m_currentFrameIndex; var num5 = (uint)((previousDestinationNode << 8) / 32768); var num6 = currentFrameIndex - num5 & 255u; var nodeFlags = netManager.m_nodes.m_buffer[destinationNodeId].m_flags; var prevLaneFlags = (NetLane.Flags)netManager.m_lanes.m_buffer[(int)((UIntPtr)prevLaneID)].m_flags; var hasTrafficLight = (nodeFlags & NetNode.Flags.TrafficLights) != NetNode.Flags.None; var hasCrossing = (nodeFlags & NetNode.Flags.LevelCrossing) != NetNode.Flags.None; var isJoinedJunction = (prevLaneFlags & NetLane.Flags.JoinedJunction) != NetLane.Flags.None; bool checkSpace = !Flags.getEnterWhenBlockedAllowed(prevPos.m_segment, netManager.m_segments.m_buffer[prevPos.m_segment].m_startNode == destinationNodeId) && !isRecklessDriver; //TrafficLightSimulation nodeSim = TrafficLightSimulation.GetNodeSimulation(destinationNodeId); /*if (timedNode != null && timedNode.vehiclesMayEnterBlockedJunctions) { * checkSpace = false; * }*/ if (checkSpace) { // check if there is enough space if ((nodeFlags & (NetNode.Flags.Junction | NetNode.Flags.OneWayOut | NetNode.Flags.OneWayIn)) == NetNode.Flags.Junction && netManager.m_nodes.m_buffer[destinationNodeId].CountSegments() != 2) { var len = vehicleData.CalculateTotalLength(vehicleId) + 2f; if (!netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].CheckSpace(len)) { var sufficientSpace = false; if (nextPosition.m_segment != 0 && netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_length < 30f) { var flags3 = netManager.m_nodes.m_buffer[sourceNodeId].m_flags; if ((flags3 & (NetNode.Flags.Junction | NetNode.Flags.OneWayOut | NetNode.Flags.OneWayIn)) != NetNode.Flags.Junction || netManager.m_nodes.m_buffer[sourceNodeId].CountSegments() == 2) { var laneId2 = PathManager.GetLaneID(nextPosition); if (laneId2 != 0u) { sufficientSpace = netManager.m_lanes.m_buffer[(int)((UIntPtr)laneId2)].CheckSpace(len); } } } if (!sufficientSpace) { maxSpeed = 0f; return; } } } } try { VehiclePosition globalTargetPos = TrafficPriority.GetVehiclePosition(vehicleId); if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == 0) { if (vehicleData.Info.m_vehicleType == VehicleInfo.VehicleType.Car) { if (hasTrafficLight && (!isJoinedJunction || hasCrossing)) { var destinationInfo = netManager.m_nodes.m_buffer[destinationNodeId].Info; if (globalTargetPos.CarState == VehicleJunctionTransitState.None) { globalTargetPos.CarState = VehicleJunctionTransitState.Enter; } RoadBaseAI.TrafficLightState vehicleLightState; RoadBaseAI.TrafficLightState pedestrianLightState; bool vehicles; bool pedestrians; CustomRoadAI.GetTrafficLightState(vehicleId, ref vehicleData, destinationNodeId, prevPos.m_segment, position.m_segment, ref netManager.m_segments.m_buffer[prevPos.m_segment], currentFrameIndex - num5, out vehicleLightState, out pedestrianLightState, out vehicles, out pedestrians); if (isRecklessDriver && (destinationInfo.GetConnectionClass().m_service & ItemClass.Service.PublicTransport) == ItemClass.Service.None) // no reckless driving at railroad crossings { vehicleLightState = RoadBaseAI.TrafficLightState.Green; } if (!vehicles && num6 >= 196u) { vehicles = true; RoadBaseAI.SetTrafficLightState(destinationNodeId, ref netManager.m_segments.m_buffer[prevPos.m_segment], currentFrameIndex - num5, vehicleLightState, pedestrianLightState, vehicles, pedestrians); } var stopCar = false; switch (vehicleLightState) { case RoadBaseAI.TrafficLightState.RedToGreen: if (num6 < 60u) { stopCar = true; } else { globalTargetPos.CarState = VehicleJunctionTransitState.Leave; } break; case RoadBaseAI.TrafficLightState.Red: stopCar = true; break; case RoadBaseAI.TrafficLightState.GreenToRed: if (num6 >= 30u) { stopCar = true; } else { globalTargetPos.CarState = 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 == destinationNodeId)) { var hasIncomingCars = TrafficPriority.HasIncomingVehiclesWithHigherPriority(vehicleId, destinationNodeId); if (hasIncomingCars) { // green light but other cars are incoming and they have priority: stop stopCar = true; } } if (stopCar) { globalTargetPos.CarState = VehicleJunctionTransitState.Stop; maxSpeed = 0f; return; } } else if (simulatePrioritySigns) { #if DEBUG //bool debug = destinationNodeId == 10864; //bool debug = destinationNodeId == 13531; bool debug = false; #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 {destinationNodeId} which is not a traffic light."); } #endif var prioritySegment = TrafficPriority.GetPrioritySegment(destinationNodeId, 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 {destinationNodeId} 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 (globalTargetPos.Valid) { #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: global target position found. carState = {globalTargetPos.CarState.ToString()}"); } #endif var currentFrameIndex2 = Singleton <SimulationManager> .instance.m_currentFrameIndex; var frame = currentFrameIndex2 >> 4; if (globalTargetPos.CarState == VehicleJunctionTransitState.None) { globalTargetPos.CarState = VehicleJunctionTransitState.Enter; } if (globalTargetPos.CarState != VehicleJunctionTransitState.Leave) { bool hasIncomingCars; switch (prioritySegment.Type) { case SegmentEnd.PriorityType.Stop: #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: STOP sign. waittime={globalTargetPos.WaitTime}, vel={lastFrameData.m_velocity.magnitude}"); } #endif if (globalTargetPos.WaitTime < MaxPriorityWaitTime) { globalTargetPos.CarState = VehicleJunctionTransitState.Stop; if (lastFrameData.m_velocity.magnitude < 0.5f || globalTargetPos.Stopped) { globalTargetPos.Stopped = true; globalTargetPos.WaitTime++; float minStopWaitTime = Random.Range(0f, 3f); if (globalTargetPos.WaitTime >= minStopWaitTime) { hasIncomingCars = TrafficPriority.HasIncomingVehiclesWithHigherPriority(vehicleId, destinationNodeId); #if DEBUG if (debug) { Log._Debug($"hasIncomingCars: {hasIncomingCars}"); } #endif if (hasIncomingCars) { maxSpeed = 0f; return; } globalTargetPos.CarState = VehicleJunctionTransitState.Leave; } else { maxSpeed = 0; return; } } else { maxSpeed = 0f; return; } } else { globalTargetPos.CarState = VehicleJunctionTransitState.Leave; } break; case SegmentEnd.PriorityType.Yield: #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: YIELD sign. waittime={globalTargetPos.WaitTime}"); } #endif if (globalTargetPos.WaitTime < MaxPriorityWaitTime) { globalTargetPos.WaitTime++; globalTargetPos.CarState = VehicleJunctionTransitState.Stop; hasIncomingCars = TrafficPriority.HasIncomingVehiclesWithHigherPriority(vehicleId, destinationNodeId); #if DEBUG if (debug) { Log._Debug($"hasIncomingCars: {hasIncomingCars}"); } #endif if (hasIncomingCars) { if (lastFrameData.m_velocity.magnitude > 0) { maxSpeed = Math.Max(0f, lastFrameData.m_velocity.magnitude - globalTargetPos.ReduceSpeedByValueToYield); } else { maxSpeed = 0; } #if DEBUG /*if (TrafficPriority.Vehicles[vehicleId].ToNode == 8621) * Log.Message($"Vehicle {vehicleId} is yielding at node {destinationNodeId}. Speed: {maxSpeed}, Waiting time: {TrafficPriority.Vehicles[vehicleId].WaitTime}");*/ #endif return; } else { #if DEBUG /*if (TrafficPriority.Vehicles[vehicleId].ToNode == 8621) * Log.Message($"Vehicle {vehicleId} is NOT yielding at node {destinationNodeId}.");*/ #endif if (lastFrameData.m_velocity.magnitude > 0) { maxSpeed = Math.Max(1f, lastFrameData.m_velocity.magnitude - globalTargetPos.ReduceSpeedByValueToYield * 0.5f); } } globalTargetPos.CarState = VehicleJunctionTransitState.Leave; } else { globalTargetPos.CarState = VehicleJunctionTransitState.Leave; } break; case SegmentEnd.PriorityType.Main: #if DEBUG if (debug) { Log._Debug($"Vehicle {vehicleId}: MAIN sign. waittime={globalTargetPos.WaitTime}"); } #endif if (globalTargetPos.WaitTime < MaxPriorityWaitTime) { globalTargetPos.WaitTime++; globalTargetPos.CarState = VehicleJunctionTransitState.Stop; maxSpeed = 0f; hasIncomingCars = TrafficPriority.HasIncomingVehiclesWithHigherPriority(vehicleId, destinationNodeId); #if DEBUG if (debug) { Log._Debug($"hasIncomingCars: {hasIncomingCars}"); } #endif if (hasIncomingCars) { globalTargetPos.Stopped = true; return; } globalTargetPos.CarState = VehicleJunctionTransitState.Leave; globalTargetPos.Stopped = false; } var info3 = netManager.m_segments.m_buffer[position.m_segment].Info; if (info3.m_lanes != null && info3.m_lanes.Length > position.m_lane) { //maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, info3.m_lanes[position.m_lane].m_speedLimit, netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_curve) * 0.8f; maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, SpeedLimitManager.GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneID, info3.m_lanes[position.m_lane]), netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_curve); } else { maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f); } return; } } else { globalTargetPos.CarState = VehicleJunctionTransitState.Leave; } } else { #if DEBUG if (debug) { Log._Debug($"globalTargetPos is null! {vehicleId} @ seg. {prevPos.m_segment} @ node {destinationNodeId}"); } #endif } } else { #if DEBUG if (debug) { Log._Debug($"targetPos is null! {vehicleId} @ seg. {prevPos.m_segment} @ node {destinationNodeId}"); } #endif } } } } } } catch (Exception e) { Log.Error($"Error occured in TmCalculateSegmentPosition: {e.ToString()}"); } } } var info2 = netManager.m_segments.m_buffer[position.m_segment].Info; if (info2.m_lanes != null && info2.m_lanes.Length > position.m_lane) { var laneSpeedLimit = SpeedLimitManager.GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneID, info2.m_lanes[position.m_lane]); // info2.m_lanes[position.m_lane].m_speedLimit; #if DEBUG /*if (position.m_segment == 275) { * Log._Debug($"Applying lane speed limit of {laneSpeedLimit} to lane {laneID} @ seg. {position.m_segment}"); * }*/ #endif /*if (TrafficRoadRestrictions.IsSegment(position.m_segment)) { * var restrictionSegment = TrafficRoadRestrictions.GetSegment(position.m_segment); * * if (restrictionSegment.SpeedLimits[position.m_lane] > 0.1f) { * laneSpeedLimit = restrictionSegment.SpeedLimits[position.m_lane]; * } * }*/ maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, laneSpeedLimit, netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_curve); } else { maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f); } maxSpeed = CalcMaxSpeed(vehicleId, ref vehicleData, position, pos, maxSpeed, isRecklessDriver); }
/// <summary> /// Stores that the given vehicle's path has been dynamically recalculated at the current frame. /// </summary> /// <param name="vehicleId"></param> internal static void MarkPathRecalculation(ushort vehicleId) { TrafficPriority.GetVehiclePosition(vehicleId).LastPathRecalculation = GetVehiclePathRecalculationFrame(); }