internal VehiclePosition GetVehicle(ushort vehicleId) { VehiclePosition ret = null; Vehicles.TryGetValue(vehicleId, out ret); return(ret); }
public void AddVehicle(ushort vehicleId, VehiclePosition carPos) { if (carPos.ToNode != NodeId || carPos.FromSegment != SegmentId) { Log.Warning($"Refusing to add vehicle {vehicleId} to PrioritySegment {SegmentId} @ {NodeId} (given: {carPos.FromSegment} @ {carPos.ToNode})."); return; } Vehicles[vehicleId] = carPos; TrafficPriority.MarkVehicleInSegment(vehicleId, SegmentId); }
static TrafficPriority() { PrioritySegments = new TrafficSegment[Singleton<NetManager>.instance.m_segments.m_size]; Vehicles = new VehiclePosition[Singleton<VehicleManager>.instance.m_vehicles.m_size]; for (int i = 0; i < Singleton<VehicleManager>.instance.m_vehicles.m_size; ++i) { Vehicles[i] = new VehiclePosition(); } markedVehicles = new HashSet<ushort>[Singleton<VehicleManager>.instance.m_vehicles.m_size]; for (int i = 0; i < markedVehicles.Length; ++i) { markedVehicles[i] = new HashSet<ushort>(); } }
/// <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 }
internal static void AddVehicle(ushort vehicleId, VehiclePosition vehiclePos) { Vehicles[vehicleId] = vehiclePos; }
public void TmCalculateSegmentPosition(ushort vehicleId, ref Vehicle vehicleData, PathUnit.Position nextPosition, PathUnit.Position position, uint laneID, byte offset, PathUnit.Position prevPos, uint prevLaneID, byte prevOffset, out Vector3 pos, out Vector3 dir, out float maxSpeed) { var netManager = Singleton<NetManager>.instance; //var vehicleManager = Singleton<VehicleManager>.instance; netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].CalculatePositionAndDirection(offset * 0.003921569f, out pos, out dir); bool isRecklessDriver = (uint)vehicleId % (Options.getRecklessDriverModulo()) == 0; var lastFrameData = vehicleData.GetLastFrameData(); var lastFrameVehiclePos = lastFrameData.m_position; var camPos = Camera.main.transform.position; if (vehicleData.Info.m_vehicleType == VehicleInfo.VehicleType.Car) { // add vehicle to our vehicle list VehiclePosition vehiclePos = TrafficPriority.Vehicles[vehicleId]; if (vehiclePos == null) { vehiclePos = new VehiclePosition(); TrafficPriority.Vehicles[vehicleId] = vehiclePos; } if ( ( (lastFrameVehiclePos - camPos).sqrMagnitude < CloseLod && (TrafficPriority.Vehicles[vehicleId].LastFrame >> closeLodUpdateMod[Options.simAccuracy]) < (Singleton<SimulationManager>.instance.m_currentFrameIndex >> closeLodUpdateMod[Options.simAccuracy]) // very often ) || ( (lastFrameVehiclePos - camPos).sqrMagnitude < FarLod && (TrafficPriority.Vehicles[vehicleId].LastFrame >> farLodUpdateMod[Options.simAccuracy]) < (Singleton<SimulationManager>.instance.m_currentFrameIndex >> farLodUpdateMod[Options.simAccuracy]) // often ) || (TrafficPriority.Vehicles[vehicleId].LastFrame >> veryFarLodUpdateMod[Options.simAccuracy]) < (Singleton<SimulationManager>.instance.m_currentFrameIndex >> veryFarLodUpdateMod[Options.simAccuracy]) // less often ) { //Log.Message("handle vehicle after threshold"); try { HandleVehicle(vehicleId, ref vehicleData, false); } catch (Exception e) { Log.Error("CarAI TmCalculateSegmentPosition Error: " + e.ToString()); } } } else { Log.Message($"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 = !Options.mayEnterBlockedJunctions; if (checkSpace && (uint)vehicleId % (Options.getRecklessDriverModulo() / 2) == 0) { 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 { if (vehicleData.Info.m_vehicleType == VehicleInfo.VehicleType.Car) { if (hasTrafficLight && (!isJoinedJunction || hasCrossing)) { var nodeSimulation = TrafficLightSimulation.GetNodeSimulation(previousDestinationNode); var destinationInfo = netManager.m_nodes.m_buffer[destinationNodeId].Info; RoadBaseAI.TrafficLightState vehicleLightState; ManualSegmentLight light = TrafficLightsManual.GetSegmentLight(previousDestinationNode, prevPos.m_segment); // TODO rework if (light == null || nodeSimulation == null || (nodeSimulation.TimedTrafficLights && !nodeSimulation.TimedTrafficLightsActive)) { RoadBaseAI.TrafficLightState pedestrianLightState; bool flag5; bool pedestrians; RoadBaseAI.GetTrafficLightState(previousDestinationNode, ref netManager.m_segments.m_buffer[prevPos.m_segment], currentFrameIndex - num5, out vehicleLightState, out pedestrianLightState, out flag5, out pedestrians); if (!flag5 && num6 >= 196u) { flag5 = true; RoadBaseAI.SetTrafficLightState(previousDestinationNode, ref netManager.m_segments.m_buffer[prevPos.m_segment], currentFrameIndex - num5, vehicleLightState, pedestrianLightState, flag5, pedestrians); } if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.None || destinationInfo.m_class.m_service != ItemClass.Service.Road) { switch (vehicleLightState) { case RoadBaseAI.TrafficLightState.RedToGreen: if (num6 < 60u) { maxSpeed = 0f; return; } break; case RoadBaseAI.TrafficLightState.Red: maxSpeed = 0f; return; case RoadBaseAI.TrafficLightState.GreenToRed: if (num6 >= 30u) { maxSpeed = 0f; return; } break; } } } else { // traffic light simulation is active var stopCar = false; if (isRecklessDriver) vehicleLightState = RoadBaseAI.TrafficLightState.Green; else { // determine responsible traffic light (left, right or main) if (CustomRoadAI.segmentGeometries[prevPos.m_segment].IsLeftSegment(position.m_segment, destinationNodeId)) { vehicleLightState = light.GetLightLeft(); } else if (CustomRoadAI.segmentGeometries[prevPos.m_segment].IsRightSegment(position.m_segment, destinationNodeId)) { vehicleLightState = light.GetLightRight(); } else { vehicleLightState = light.GetLightMain(); } } if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.None || destinationInfo.m_class.m_service != ItemClass.Service.Road) { switch (vehicleLightState) { case RoadBaseAI.TrafficLightState.RedToGreen: if (num6 < 60u) { stopCar = true; } break; case RoadBaseAI.TrafficLightState.Red: stopCar = true; break; case RoadBaseAI.TrafficLightState.GreenToRed: if (num6 >= 30u) { stopCar = true; } break; } } if (stopCar) { maxSpeed = 0f; return; } } } else if ((lastFrameVehiclePos - camPos).sqrMagnitude < FarLod && !isRecklessDriver) { #if DEBUG //bool debug = destinationNodeId == 10864; bool debug = false; #endif //bool debug = false; #if DEBUG if (debug) Log.Message($"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.Message($"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 VehiclePosition segTargetPos = prioritySegment.GetVehicle(vehicleId); if (segTargetPos != null) { #if DEBUG if (debug) Log.Message($"Vehicle {vehicleId}: segment target position found"); #endif VehiclePosition globalTargetPos = TrafficPriority.Vehicles[vehicleId]; if (globalTargetPos != null) { #if DEBUG if (debug) Log.Message($"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 == CarState.None) { globalTargetPos.CarState = CarState.Enter; } if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.None && globalTargetPos.CarState != CarState.Leave) { bool hasIncomingCars; switch (prioritySegment.Type) { case PrioritySegment.PriorityType.Stop: #if DEBUG if (debug) Log.Message($"Vehicle {vehicleId}: STOP sign. waittime={globalTargetPos.WaitTime}, vel={lastFrameData.m_velocity.magnitude}"); #endif if (globalTargetPos.WaitTime < 30) { globalTargetPos.CarState = CarState.Stop; if (lastFrameData.m_velocity.magnitude < 0.5f || globalTargetPos.Stopped) { globalTargetPos.Stopped = true; globalTargetPos.WaitTime++; if (globalTargetPos.WaitTime > 1) { hasIncomingCars = TrafficPriority.HasIncomingVehicles(vehicleId, destinationNodeId); #if DEBUG if (debug) Log.Message($"hasIncomingCars: {hasIncomingCars}"); #endif if (hasIncomingCars) { maxSpeed = 0f; return; } globalTargetPos.CarState = CarState.Leave; } else { maxSpeed = 0f; return; } } else { maxSpeed = 0f; return; } } else { globalTargetPos.CarState = CarState.Leave; } break; case PrioritySegment.PriorityType.Yield: #if DEBUG if (debug) Log.Message($"Vehicle {vehicleId}: YIELD sign. waittime={globalTargetPos.WaitTime}"); #endif if (globalTargetPos.WaitTime < 30) { globalTargetPos.WaitTime++; globalTargetPos.CarState = CarState.Stop; hasIncomingCars = TrafficPriority.HasIncomingVehicles(vehicleId, destinationNodeId); #if DEBUG if (debug) Log.Message($"hasIncomingCars: {hasIncomingCars}"); #endif if (hasIncomingCars) { if (lastFrameData.m_velocity.magnitude > 0) { maxSpeed = Math.Max(0f, lastFrameData.m_velocity.magnitude - globalTargetPos.ReduceSpeedByValueToYield); } else { maxSpeed = 0f; } #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 } globalTargetPos.CarState = CarState.Leave; } else { globalTargetPos.CarState = CarState.Leave; } break; case PrioritySegment.PriorityType.Main: #if DEBUG if (debug) Log.Message($"Vehicle {vehicleId}: MAIN sign. waittime={globalTargetPos.WaitTime}"); #endif if (globalTargetPos.WaitTime < 30) { globalTargetPos.WaitTime++; globalTargetPos.CarState = CarState.Stop; maxSpeed = 0f; hasIncomingCars = TrafficPriority.HasIncomingVehicles(vehicleId, destinationNodeId); #if DEBUG if (debug) Log.Message($"hasIncomingCars: {hasIncomingCars}"); #endif if (hasIncomingCars) { globalTargetPos.Stopped = true; return; } globalTargetPos.CarState = CarState.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; } else { maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f) * 0.8f; } return; } } else { globalTargetPos.CarState = CarState.Leave; } } else { #if DEBUG if (debug) Log.Warning($"globalTargetPos is null! {vehicleId} @ seg. {prevPos.m_segment} @ node {destinationNodeId}"); #endif } } else { #if DEBUG if (debug) Log.Warning($"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 = info2.m_lanes[position.m_lane].m_speedLimit; if (TrafficRoadRestrictions.IsSegment(position.m_segment)) { var restrictionSegment = TrafficRoadRestrictions.GetSegment(position.m_segment); if (restrictionSegment.SpeedLimits[position.m_lane] > 0.1f) { laneSpeedLimit = restrictionSegment.SpeedLimits[position.m_lane]; } } maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, laneSpeedLimit, netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_curve); } else { maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f); } if (isRecklessDriver) maxSpeed *= Random.Range(1.2f, 2.5f); }
/// <summary> /// Calculates for each segment the number of cars going to this segment. /// We use integer arithmetic for better performance. /// </summary> public Dictionary <ushort, uint> GetVehicleMetricGoingToSegment(float?minSpeed, ExtVehicleType?vehicleTypes = null, ExtVehicleType separateVehicleTypes = ExtVehicleType.None, bool debug = false) { Dictionary <ushort, uint> numCarsGoingToSegmentId = new Dictionary <ushort, uint>(); VehicleManager vehicleManager = Singleton <VehicleManager> .instance; NetManager netManager = Singleton <NetManager> .instance; for (var s = 0; s < 8; s++) { var segmentId = netManager.m_nodes.m_buffer[NodeId].GetSegment(s); if (segmentId == 0 || segmentId == SegmentId) { continue; } if (CustomRoadAI.GetSegmentGeometry(segmentId).IsIncomingOneWay(NodeId)) { continue; } numCarsGoingToSegmentId[segmentId] = 0; } List <ushort> vehicleIdsToReHandle = new List <ushort>(); foreach (KeyValuePair <ushort, VehiclePosition> e in Vehicles) { var vehicleId = e.Key; var carPos = e.Value; if (vehicleId <= 0 || carPos.ToSegment <= 0) { continue; } if ((vehicleManager.m_vehicles.m_buffer[vehicleId].m_flags & Vehicle.Flags.Created) == Vehicle.Flags.None) { vehicleIdsToReHandle.Add(vehicleId); continue; } if (minSpeed != null && vehicleManager.m_vehicles.m_buffer[vehicleId].GetLastFrameVelocity().magnitude < minSpeed) { continue; } VehiclePosition globalPos = TrafficPriority.GetVehiclePosition(vehicleId); if (globalPos == null || !globalPos.Valid || globalPos.LastFrame >> 7 < Singleton <SimulationManager> .instance.m_currentFrameIndex >> 7) // ~64 sec. { vehicleIdsToReHandle.Add(vehicleId); continue; } if (vehicleTypes != null) { if (vehicleTypes == ExtVehicleType.None) { if ((globalPos.VehicleType & separateVehicleTypes) != ExtVehicleType.None) { // we want all vehicles that do not have separate traffic lights continue; } } else { if ((globalPos.VehicleType & vehicleTypes) == ExtVehicleType.None) { continue; } } } //debug = vehicleManager.m_vehicles.m_buffer[vehicleId].Info.m_vehicleType == VehicleInfo.VehicleType.Tram; #if DEBUG /*if (debug) { * Log._Debug($"getNumCarsGoingToSegment: Handling vehicle {vehicleId} going from {carPos.FromSegment}/{SegmentId} to {carPos.ToSegment}. carState={globalPos.CarState}. lastUpdate={globalPos.LastCarStateUpdate}"); * }*/ #endif uint avgSegmentLength = (uint)Singleton <NetManager> .instance.m_segments.m_buffer[SegmentId].m_averageLength; uint normLength = (uint)(vehicleManager.m_vehicles.m_buffer[vehicleId].CalculateTotalLength(vehicleId) * 100u) / avgSegmentLength; #if DEBUG /*if (debug) { * Log._Debug($"getNumCarsGoingToSegment: NormLength of vehicle {vehicleId} going to {carPos.ToSegment}: {avgSegmentLength} -> {normLength}"); * }*/ #endif if (numCarsGoingToSegmentId.ContainsKey(carPos.ToSegment)) { /*if (carPos.OnEmergency) * numCarsGoingToSegmentId[carPos.ToSegment] += 10000f; * else*/ numCarsGoingToSegmentId[carPos.ToSegment] += normLength; } // "else" must not happen (incoming one-way) } foreach (ushort vehicleId in vehicleIdsToReHandle) { CustomVehicleAI.HandleVehicle(vehicleId, ref Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleId], false, false); } return(numCarsGoingToSegmentId); }