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); }
/// <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> /// 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); }
/// <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); }
public void TmCalculateSegmentPosition(ushort vehicleId, ref Vehicle vehicleData, PathUnit.Position nextPosition, PathUnit.Position position, uint laneID, byte offset, PathUnit.Position prevPos, uint prevLaneID, byte prevOffset, out Vector3 pos, out Vector3 dir, out float maxSpeed) { var netManager = Singleton <NetManager> .instance; //var vehicleManager = Singleton<VehicleManager>.instance; netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].CalculatePositionAndDirection(offset * 0.003921569f, out pos, out dir); var lastFrameData = vehicleData.GetLastFrameData(); var lastFrameVehiclePos = lastFrameData.m_position; if (vehicleData.Info.m_vehicleType == VehicleInfo.VehicleType.Car) { // add vehicle to our vehicle list if (!TrafficPriority.VehicleList.ContainsKey(vehicleId)) { TrafficPriority.VehicleList.Add(vehicleId, new PriorityCar()); } } HandleVehicle(vehicleId, ref vehicleData); // I think this is supposed to be the lane position? // [VN, 12/23/2015] It's the 3D car position on the Bezier curve of the lane. // This crazy 0.003921569f equals to 1f/255 and prevOffset is the byte value (0..255) of the car position. var vehiclePosOnBezier = netManager.m_lanes.m_buffer[(int)((UIntPtr)prevLaneID)].CalculatePosition(prevOffset * 0.003921569f); //ushort currentSegmentId = netManager.m_lanes.m_buffer[(int)((UIntPtr)prevLaneID)].m_segment; ushort destinationNodeId; ushort sourceNodeId; if (offset < position.m_offset) { destinationNodeId = netManager.m_segments.m_buffer[position.m_segment].m_startNode; sourceNodeId = netManager.m_segments.m_buffer[position.m_segment].m_endNode; } else { destinationNodeId = netManager.m_segments.m_buffer[position.m_segment].m_endNode; sourceNodeId = netManager.m_segments.m_buffer[position.m_segment].m_startNode; } var interestingNodeId = prevOffset == 0 ? netManager.m_segments.m_buffer[prevPos.m_segment].m_startNode : netManager.m_segments.m_buffer[prevPos.m_segment].m_endNode; // this seems to be like the required braking force in order to stop the vehicle within its half length. var crazyValue = 0.5f * lastFrameData.m_velocity.sqrMagnitude / m_info.m_braking + m_info.m_generatedInfo.m_size.z * 0.5f; // Essentially, this is true if the car has enough time and space to brake (e.g. for a red traffic light) if (destinationNodeId == interestingNodeId) { if (Vector3.Distance(lastFrameVehiclePos, vehiclePosOnBezier) >= crazyValue - 1f) { var currentFrameIndex = Singleton <SimulationManager> .instance.m_currentFrameIndex; var num5 = (uint)((interestingNodeId << 8) / 32768); var num6 = currentFrameIndex - num5 & 255u; var nodeFlags = netManager.m_nodes.m_buffer[destinationNodeId].m_flags; var prevLaneFlags = (NetLane.Flags)netManager.m_lanes.m_buffer[(int)((UIntPtr)prevLaneID)].m_flags; var hasTrafficLight = (nodeFlags & NetNode.Flags.TrafficLights) != NetNode.Flags.None; var hasCrossing = (nodeFlags & NetNode.Flags.LevelCrossing) != NetNode.Flags.None; var isJoinedJunction = (prevLaneFlags & NetLane.Flags.JoinedJunction) != NetLane.Flags.None; if ((nodeFlags & (NetNode.Flags.Junction | NetNode.Flags.OneWayOut | NetNode.Flags.OneWayIn)) == NetNode.Flags.Junction && netManager.m_nodes.m_buffer[destinationNodeId].CountSegments() != 2) { var len = vehicleData.CalculateTotalLength(vehicleId) + 2f; if (!netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].CheckSpace(len)) { var sufficientSpace = false; if (nextPosition.m_segment != 0 && netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_length < 30f) { var flags3 = netManager.m_nodes.m_buffer[sourceNodeId].m_flags; if ((flags3 & (NetNode.Flags.Junction | NetNode.Flags.OneWayOut | NetNode.Flags.OneWayIn)) != NetNode.Flags.Junction || netManager.m_nodes.m_buffer[sourceNodeId].CountSegments() == 2) { var laneId2 = PathManager.GetLaneID(nextPosition); if (laneId2 != 0u) { sufficientSpace = netManager.m_lanes.m_buffer[(int)((UIntPtr)laneId2)].CheckSpace(len); } } } if (!sufficientSpace) { maxSpeed = 0f; return; } } } if (vehicleData.Info.m_vehicleType == VehicleInfo.VehicleType.Car) { if (hasTrafficLight && (!isJoinedJunction || hasCrossing)) { var nodeSimulation = TrafficPriority.GetNodeSimulation(interestingNodeId); var destinationInfo = netManager.m_nodes.m_buffer[destinationNodeId].Info; RoadBaseAI.TrafficLightState vehicleLightState; ManualSegmentLight light = TrafficLightsManual.GetSegmentLight(interestingNodeId, prevPos.m_segment); // TODO rework if (light == null || nodeSimulation == null || (nodeSimulation.FlagTimedTrafficLights && !nodeSimulation.TimedTrafficLightsActive)) { RoadBaseAI.TrafficLightState pedestrianLightState; bool flag5; bool pedestrians; RoadBaseAI.GetTrafficLightState(interestingNodeId, ref netManager.m_segments.m_buffer[prevPos.m_segment], currentFrameIndex - num5, out vehicleLightState, out pedestrianLightState, out flag5, out pedestrians); if (!flag5 && num6 >= 196u) { flag5 = true; RoadBaseAI.SetTrafficLightState(interestingNodeId, ref netManager.m_segments.m_buffer[prevPos.m_segment], currentFrameIndex - num5, vehicleLightState, pedestrianLightState, flag5, pedestrians); } if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.None || destinationInfo.m_class.m_service != ItemClass.Service.Road) { switch (vehicleLightState) { case RoadBaseAI.TrafficLightState.RedToGreen: if (num6 < 60u) { maxSpeed = 0f; return; } break; case RoadBaseAI.TrafficLightState.Red: maxSpeed = 0f; return; case RoadBaseAI.TrafficLightState.GreenToRed: if (num6 >= 30u) { maxSpeed = 0f; return; } break; } } } else { // traffic light simulation is active var stopCar = false; // determine responsible traffic light (left, right or main) if (TrafficPriority.IsLeftSegment(prevPos.m_segment, position.m_segment, destinationNodeId)) { vehicleLightState = light.GetLightLeft(); } else if (TrafficPriority.IsRightSegment(prevPos.m_segment, position.m_segment, destinationNodeId)) { vehicleLightState = light.GetLightRight(); } else { vehicleLightState = light.GetLightMain(); } if (vehicleLightState == RoadBaseAI.TrafficLightState.Green) { var hasIncomingCars = TrafficPriority.HasIncomingVehicles(vehicleId, destinationNodeId); if (hasIncomingCars) { // green light but other cars are incoming: slow approach maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f) * 0.01f; //stopCar = true; } } if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.None || destinationInfo.m_class.m_service != ItemClass.Service.Road) { switch (vehicleLightState) { case RoadBaseAI.TrafficLightState.RedToGreen: if (num6 < 60u) { stopCar = true; } break; case RoadBaseAI.TrafficLightState.Red: stopCar = true; break; case RoadBaseAI.TrafficLightState.GreenToRed: if (num6 >= 30u) { stopCar = true; } break; } } if (stopCar) { maxSpeed = 0f; return; } } } else { if (TrafficPriority.VehicleList.ContainsKey(vehicleId) && TrafficPriority.IsPrioritySegment(destinationNodeId, prevPos.m_segment)) { var currentFrameIndex2 = Singleton <SimulationManager> .instance.m_currentFrameIndex; var frame = currentFrameIndex2 >> 4; var prioritySegment = TrafficPriority.GetPrioritySegment(destinationNodeId, prevPos.m_segment); if (TrafficPriority.VehicleList[vehicleId].CarState == CarState.None) { TrafficPriority.VehicleList[vehicleId].CarState = CarState.Enter; } if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.None && TrafficPriority.VehicleList[vehicleId].CarState != CarState.Leave) { bool hasIncomingCars; switch (prioritySegment.Type) { case PrioritySegment.PriorityType.Stop: if (TrafficPriority.VehicleList[vehicleId].WaitTime < 75) { TrafficPriority.VehicleList[vehicleId].CarState = CarState.Stop; if (lastFrameData.m_velocity.sqrMagnitude < 0.1f || TrafficPriority.VehicleList[vehicleId].Stopped) { TrafficPriority.VehicleList[vehicleId].Stopped = true; TrafficPriority.VehicleList[vehicleId].WaitTime++; if (TrafficPriority.VehicleList[vehicleId].WaitTime > 2) { hasIncomingCars = TrafficPriority.HasIncomingVehicles(vehicleId, destinationNodeId); if (hasIncomingCars) { maxSpeed = 0f; return; } TrafficPriority.VehicleList[vehicleId].CarState = CarState.Leave; } else { maxSpeed = 0f; return; } } else { maxSpeed = 0f; return; } } else { TrafficPriority.VehicleList[vehicleId].CarState = CarState.Leave; } break; case PrioritySegment.PriorityType.Yield: if (TrafficPriority.VehicleList[vehicleId].WaitTime < 75) { TrafficPriority.VehicleList[vehicleId].WaitTime++; TrafficPriority.VehicleList[vehicleId].CarState = CarState.Stop; maxSpeed = 0f; if (lastFrameData.m_velocity.sqrMagnitude < TrafficPriority.VehicleList[vehicleId].ReduceSpeedByValueToYield) { hasIncomingCars = TrafficPriority.HasIncomingVehicles(vehicleId, destinationNodeId); if (hasIncomingCars) { return; } } else { maxSpeed = lastFrameData.m_velocity.sqrMagnitude - TrafficPriority.VehicleList[vehicleId] .ReduceSpeedByValueToYield; return; } } else { TrafficPriority.VehicleList[vehicleId].CarState = CarState.Leave; } break; case PrioritySegment.PriorityType.Main: TrafficPriority.VehicleList[vehicleId].WaitTime++; TrafficPriority.VehicleList[vehicleId].CarState = CarState.Stop; maxSpeed = 0f; hasIncomingCars = TrafficPriority.HasIncomingVehicles(vehicleId, destinationNodeId); if (hasIncomingCars) { TrafficPriority.VehicleList[vehicleId].Stopped = true; return; } TrafficPriority.VehicleList[vehicleId].Stopped = false; var info3 = netManager.m_segments.m_buffer[position.m_segment].Info; if (info3.m_lanes != null && info3.m_lanes.Length > position.m_lane) { maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, info3.m_lanes[position.m_lane].m_speedLimit, netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_curve) * 0.8f; } else { maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f) * 0.8f; } return; } } else { TrafficPriority.VehicleList[vehicleId].CarState = CarState.Transit; } } } } } } var info2 = netManager.m_segments.m_buffer[position.m_segment].Info; if (info2.m_lanes != null && info2.m_lanes.Length > position.m_lane) { var laneSpeedLimit = info2.m_lanes[position.m_lane].m_speedLimit; if (TrafficRoadRestrictions.IsSegment(position.m_segment)) { var restrictionSegment = TrafficRoadRestrictions.GetSegment(position.m_segment); if (restrictionSegment.SpeedLimits[position.m_lane] > 0.1f) { laneSpeedLimit = restrictionSegment.SpeedLimits[position.m_lane]; } } maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, laneSpeedLimit, netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_curve); } else { maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f); } }
private static void LoadDataState() { Log.Info("Loading State from Config"); if (_configuration == null) { Log.Warning("Configuration NULL, Couldn't load save data. Possibly a new game?"); return; } // load priority segments if (_configuration.PrioritySegments != null) { Log.Info($"Loading {_configuration.PrioritySegments.Count()} priority segments"); foreach (var segment in _configuration.PrioritySegments) { try { if (segment.Length < 3) { continue; } #if DEBUG bool debug = segment[0] == 13630; #endif if ((SegmentEnd.PriorityType)segment[2] == SegmentEnd.PriorityType.None) { #if DEBUG if (debug) { Log._Debug($"Loading priority segment: Not adding 'None' priority segment: {segment[1]} @ node {segment[0]}"); } #endif continue; } if ((Singleton <NetManager> .instance.m_nodes.m_buffer[segment[0]].m_flags & NetNode.Flags.Created) == NetNode.Flags.None) { #if DEBUG if (debug) { Log._Debug($"Loading priority segment: node {segment[0]} is invalid"); } #endif continue; } if ((Singleton <NetManager> .instance.m_segments.m_buffer[segment[1]].m_flags & NetSegment.Flags.Created) == NetSegment.Flags.None) { #if DEBUG if (debug) { Log._Debug($"Loading priority segment: segment {segment[1]} @ node {segment[0]} is invalid"); } #endif continue; } if (TrafficPriority.IsPrioritySegment((ushort)segment[0], (ushort)segment[1])) { #if DEBUG if (debug) { Log._Debug($"Loading priority segment: segment {segment[1]} @ node {segment[0]} is already a priority segment"); } #endif TrafficPriority.GetPrioritySegment((ushort)segment[0], (ushort)segment[1]).Type = (SegmentEnd.PriorityType)segment[2]; continue; } #if DEBUG Log._Debug($"Adding Priority Segment of type: {segment[2].ToString()} to segment {segment[1]} @ node {segment[0]}"); #endif TrafficPriority.AddPrioritySegment((ushort)segment[0], (ushort)segment[1], (SegmentEnd.PriorityType)segment[2]); } catch (Exception e) { // ignore, as it's probably corrupt save data. it'll be culled on next save Log.Warning("Error loading data from Priority segments: " + e.ToString()); } } } else { Log.Warning("Priority segments data structure undefined!"); } // load vehicle restrictions (warning: has to be done before loading timed lights!) if (_configuration.LaneAllowedVehicleTypes != null) { Log.Info($"Loading lane vehicle restriction data. {_configuration.LaneAllowedVehicleTypes.Count} elements"); foreach (Configuration.LaneVehicleTypes laneVehicleTypes in _configuration.LaneAllowedVehicleTypes) { try { ExtVehicleType baseMask = VehicleRestrictionsManager.GetBaseMask(laneVehicleTypes.laneId); ExtVehicleType maskedType = laneVehicleTypes.vehicleTypes & baseMask; Log._Debug($"Loading lane vehicle restriction: lane {laneVehicleTypes.laneId} = {laneVehicleTypes.vehicleTypes}, masked = {maskedType}"); if (maskedType != baseMask) { Flags.setLaneAllowedVehicleTypes(laneVehicleTypes.laneId, maskedType); } else { Log._Debug($"Masked type does not differ from base type. Ignoring."); } } catch (Exception e) { // ignore, as it's probably corrupt save data. it'll be culled on next save Log.Warning("Error loading data from vehicle restrictions: " + e.ToString()); } } } else { Log.Warning("Vehicle restrctions structure undefined!"); } var timedStepCount = 0; var timedStepSegmentCount = 0; NetManager netManager = Singleton <NetManager> .instance; if (_configuration.TimedLights != null) { Log.Info($"Loading {_configuration.TimedLights.Count()} timed traffic lights (new method)"); foreach (Configuration.TimedTrafficLights cnfTimedLights in _configuration.TimedLights) { try { if ((Singleton <NetManager> .instance.m_nodes.m_buffer[cnfTimedLights.nodeId].m_flags & NetNode.Flags.Created) == NetNode.Flags.None) { continue; } Flags.setNodeTrafficLight(cnfTimedLights.nodeId, true); Log._Debug($"Adding Timed Node at node {cnfTimedLights.nodeId}"); TrafficLightSimulation sim = TrafficLightSimulation.AddNodeToSimulation(cnfTimedLights.nodeId); sim.SetupTimedTrafficLight(cnfTimedLights.nodeGroup); var timedNode = sim.TimedLight; int j = 0; foreach (Configuration.TimedTrafficLightsStep cnfTimedStep in cnfTimedLights.timedSteps) { Log._Debug($"Loading timed step {j} at node {cnfTimedLights.nodeId}"); TimedTrafficLightsStep step = timedNode.AddStep(cnfTimedStep.minTime, cnfTimedStep.maxTime, cnfTimedStep.waitFlowBalance); foreach (KeyValuePair <ushort, Configuration.CustomSegmentLights> e in cnfTimedStep.segmentLights) { Log._Debug($"Loading timed step {j}, segment {e.Key} at node {cnfTimedLights.nodeId}"); CustomSegmentLights lights = null; if (!step.segmentLights.TryGetValue(e.Key, out lights)) { Log._Debug($"No segment lights found at timed step {j} for segment {e.Key}, node {cnfTimedLights.nodeId}"); continue; } Configuration.CustomSegmentLights cnfLights = e.Value; Log._Debug($"Loading pedestrian light @ seg. {e.Key}, step {j}: {cnfLights.pedestrianLightState} {cnfLights.manualPedestrianMode}"); lights.ManualPedestrianMode = cnfLights.manualPedestrianMode; lights.PedestrianLightState = cnfLights.pedestrianLightState; foreach (KeyValuePair <ExtVehicleType, Configuration.CustomSegmentLight> e2 in cnfLights.customLights) { Log._Debug($"Loading timed step {j}, segment {e.Key}, vehicleType {e2.Key} at node {cnfTimedLights.nodeId}"); CustomSegmentLight light = null; if (!lights.CustomLights.TryGetValue(e2.Key, out light)) { Log._Debug($"No segment light found for timed step {j}, segment {e.Key}, vehicleType {e2.Key} at node {cnfTimedLights.nodeId}"); continue; } Configuration.CustomSegmentLight cnfLight = e2.Value; light.CurrentMode = (CustomSegmentLight.Mode)cnfLight.currentMode; light.LightLeft = cnfLight.leftLight; light.LightMain = cnfLight.mainLight; light.LightRight = cnfLight.rightLight; } } ++j; } if (cnfTimedLights.started) { timedNode.Start(); } } catch (Exception e) { // ignore, as it's probably corrupt save data. it'll be culled on next save Log.Warning("Error loading data from TimedNode (new method): " + e.ToString()); } } } else if (_configuration.TimedNodes != null && _configuration.TimedNodeGroups != null) { Log.Info($"Loading {_configuration.TimedNodes.Count()} timed traffic lights (old method)"); for (var i = 0; i < _configuration.TimedNodes.Count; i++) { try { var nodeid = (ushort)_configuration.TimedNodes[i][0]; if ((Singleton <NetManager> .instance.m_nodes.m_buffer[nodeid].m_flags & NetNode.Flags.Created) == NetNode.Flags.None) { continue; } Flags.setNodeTrafficLight(nodeid, true); Log._Debug($"Adding Timed Node {i} at node {nodeid}"); var nodeGroup = new List <ushort>(); for (var j = 0; j < _configuration.TimedNodeGroups[i].Length; j++) { nodeGroup.Add(_configuration.TimedNodeGroups[i][j]); } TrafficLightSimulation sim = TrafficLightSimulation.AddNodeToSimulation(nodeid); sim.SetupTimedTrafficLight(nodeGroup); var timedNode = sim.TimedLight; timedNode.CurrentStep = _configuration.TimedNodes[i][1]; for (var j = 0; j < _configuration.TimedNodes[i][2]; j++) { var cfgstep = _configuration.TimedNodeSteps[timedStepCount]; // old (pre 1.3.0): // cfgstep[0]: time of step // cfgstep[1]: number of segments // new (post 1.3.0): // cfgstep[0]: min. time of step // cfgstep[1]: max. time of step // cfgstep[2]: number of segments int minTime = 1; int maxTime = 1; //int numSegments = 0; float waitFlowBalance = 1f; if (cfgstep.Length == 2) { minTime = cfgstep[0]; maxTime = cfgstep[0]; //numSegments = cfgstep[1]; } else if (cfgstep.Length >= 3) { minTime = cfgstep[0]; maxTime = cfgstep[1]; //numSegments = cfgstep[2]; if (cfgstep.Length == 4) { waitFlowBalance = Convert.ToSingle(cfgstep[3]) / 10f; } if (cfgstep.Length == 5) { waitFlowBalance = Convert.ToSingle(cfgstep[4]) / 1000f; } } Log._Debug($"Adding timed step to node {nodeid}: min/max: {minTime}/{maxTime}, waitFlowBalance: {waitFlowBalance}"); timedNode.AddStep(minTime, maxTime, waitFlowBalance); var step = timedNode.Steps[j]; for (var s = 0; s < 8; s++) { var segmentId = netManager.m_nodes.m_buffer[nodeid].GetSegment(s); if (segmentId <= 0) { continue; } bool tooFewSegments = (timedStepSegmentCount >= _configuration.TimedNodeStepSegments.Count); var leftLightState = tooFewSegments ? RoadBaseAI.TrafficLightState.Red : (RoadBaseAI.TrafficLightState)_configuration.TimedNodeStepSegments[timedStepSegmentCount][0]; var mainLightState = tooFewSegments ? RoadBaseAI.TrafficLightState.Red : (RoadBaseAI.TrafficLightState)_configuration.TimedNodeStepSegments[timedStepSegmentCount][1]; var rightLightState = tooFewSegments ? RoadBaseAI.TrafficLightState.Red : (RoadBaseAI.TrafficLightState)_configuration.TimedNodeStepSegments[timedStepSegmentCount][2]; var pedLightState = tooFewSegments ? RoadBaseAI.TrafficLightState.Red : (RoadBaseAI.TrafficLightState)_configuration.TimedNodeStepSegments[timedStepSegmentCount][3]; CustomSegmentLight.Mode?mode = null; if (_configuration.TimedNodeStepSegments[timedStepSegmentCount].Length >= 5) { mode = (CustomSegmentLight.Mode)_configuration.TimedNodeStepSegments[timedStepSegmentCount][4]; } foreach (KeyValuePair <ExtVehicleType, CustomSegmentLight> e in step.segmentLights[segmentId].CustomLights) { //ManualSegmentLight segmentLight = new ManualSegmentLight(step.NodeId, step.segmentIds[k], mainLightState, leftLightState, rightLightState, pedLightState); e.Value.LightLeft = leftLightState; e.Value.LightMain = mainLightState; e.Value.LightRight = rightLightState; if (mode != null) { e.Value.CurrentMode = (CustomSegmentLight.Mode)mode; } } if (step.segmentLights[segmentId].PedestrianLightState != null) { step.segmentLights[segmentId].PedestrianLightState = pedLightState; } timedStepSegmentCount++; } timedStepCount++; } if (Convert.ToBoolean(_configuration.TimedNodes[i][3])) { timedNode.Start(); } } catch (Exception e) { // ignore, as it's probably corrupt save data. it'll be culled on next save Log.Warning("Error loading data from the TimedNodes: " + e.ToString()); } } } else { Log.Warning("Timed traffic lights data structure undefined!"); } var trafficLightDefs = _configuration.NodeTrafficLights.Split(','); Log.Info($"Loading junction traffic light data"); if (trafficLightDefs.Length <= 1) { // old method Log.Info($"Using old method to load traffic light data"); var saveDataIndex = 0; for (var i = 0; i < Singleton <NetManager> .instance.m_nodes.m_buffer.Length; i++) { //Log.Message($"Adding NodeTrafficLights iteration: {i1}"); try { if ((Singleton <NetManager> .instance.m_nodes.m_buffer[i].Info.m_class.m_service != ItemClass.Service.Road && Singleton <NetManager> .instance.m_nodes.m_buffer[i].Info.m_class.m_service != ItemClass.Service.PublicTransport) || (Singleton <NetManager> .instance.m_nodes.m_buffer[i].m_flags & NetNode.Flags.Created) == NetNode.Flags.None) { continue; } // prevent overflow if (_configuration.NodeTrafficLights.Length > saveDataIndex) { var trafficLight = _configuration.NodeTrafficLights[saveDataIndex]; #if DEBUG Log._Debug("Setting traffic light flag for node " + i + ": " + (trafficLight == '1')); #endif Flags.setNodeTrafficLight((ushort)i, trafficLight == '1'); } ++saveDataIndex; } catch (Exception e) { // ignore as it's probably bad save data. Log.Warning("Error setting the NodeTrafficLights (old): " + e.Message); } } } else { // new method foreach (var split in trafficLightDefs.Select(def => def.Split(':')).Where(split => split.Length > 1)) { try { Log.Info($"Traffic light split data: {split[0]} , {split[1]}"); var nodeId = Convert.ToUInt16(split[0]); uint flag = Convert.ToUInt16(split[1]); Flags.setNodeTrafficLight(nodeId, flag > 0); } catch (Exception e) { // ignore as it's probably bad save data. Log.Warning("Error setting the NodeTrafficLights (new): " + e.Message); } } } if (_configuration.LaneFlags != null) { Log.Info($"Loading lane arrow data"); #if DEBUG Log._Debug($"LaneFlags: {_configuration.LaneFlags}"); #endif var lanes = _configuration.LaneFlags.Split(','); if (lanes.Length > 1) { foreach (var split in lanes.Select(lane => lane.Split(':')).Where(split => split.Length > 1)) { try { Log.Info($"Split Data: {split[0]} , {split[1]}"); var laneId = Convert.ToUInt32(split[0]); uint flags = Convert.ToUInt32(split[1]); //make sure we don't cause any overflows because of bad save data. if (Singleton <NetManager> .instance.m_lanes.m_buffer.Length <= laneId) { continue; } if (flags > ushort.MaxValue) { continue; } if ((Singleton <NetManager> .instance.m_lanes.m_buffer[laneId].m_flags & (ushort)NetLane.Flags.Created) == 0 || Singleton <NetManager> .instance.m_lanes.m_buffer[laneId].m_segment == 0) { continue; } //Singleton<NetManager>.instance.m_lanes.m_buffer[laneId].m_flags = fixLaneFlags(Singleton<NetManager>.instance.m_lanes.m_buffer[laneId].m_flags); uint laneArrowFlags = flags & Flags.lfr; uint origFlags = (Singleton <NetManager> .instance.m_lanes.m_buffer[laneId].m_flags & Flags.lfr); #if DEBUG Log._Debug("Setting flags for lane " + laneId + " to " + flags + " (" + ((Flags.LaneArrows)(laneArrowFlags)).ToString() + ")"); if ((origFlags | laneArrowFlags) == origFlags) // only load if setting differs from default { Log._Debug("Flags for lane " + laneId + " are original (" + ((NetLane.Flags)(origFlags)).ToString() + ")"); } #endif Flags.setLaneArrowFlags(laneId, (Flags.LaneArrows)(laneArrowFlags)); } catch (Exception e) { Log.Error($"Error loading Lane Split data. Length: {split.Length} value: {split}\nError: {e.Message}"); } } } } else { Log.Warning("Lane arrow data structure undefined!"); } // load lane connections if (_configuration.LaneConnections != null) { Log.Info($"Loading {_configuration.LaneConnections.Count()} lane connections"); foreach (Configuration.LaneConnection conn in _configuration.LaneConnections) { try { Log._Debug($"Loading lane connection: lane {conn.lowerLaneId} -> {conn.higherLaneId}"); Singleton <LaneConnectionManager> .instance.AddLaneConnection(conn.lowerLaneId, conn.higherLaneId, conn.lowerStartNode); } catch (Exception e) { // ignore, as it's probably corrupt save data. it'll be culled on next save Log.Warning("Error loading data from lane connection: " + e.ToString()); } } } else { Log.Warning("Lane connection data structure undefined!"); } // load speed limits if (_configuration.LaneSpeedLimits != null) { Log.Info($"Loading lane speed limit data. {_configuration.LaneSpeedLimits.Count} elements"); foreach (Configuration.LaneSpeedLimit laneSpeedLimit in _configuration.LaneSpeedLimits) { try { Log._Debug($"Loading lane speed limit: lane {laneSpeedLimit.laneId} = {laneSpeedLimit.speedLimit}"); Flags.setLaneSpeedLimit(laneSpeedLimit.laneId, laneSpeedLimit.speedLimit); } catch (Exception e) { // ignore, as it's probably corrupt save data. it'll be culled on next save Log.Warning("Error loading speed limits: " + e.ToString()); } } } else { Log.Warning("Lane speed limit structure undefined!"); } // Load segment-at-node flags if (_configuration.SegmentNodeConfs != null) { Log.Info($"Loading segment-at-node data. {_configuration.SegmentNodeConfs.Count} elements"); foreach (Configuration.SegmentNodeConf segNodeConf in _configuration.SegmentNodeConfs) { try { if ((Singleton <NetManager> .instance.m_segments.m_buffer[segNodeConf.segmentId].m_flags & NetSegment.Flags.Created) == NetSegment.Flags.None) { continue; } Flags.setSegmentNodeFlags(segNodeConf.segmentId, true, segNodeConf.startNodeFlags); Flags.setSegmentNodeFlags(segNodeConf.segmentId, false, segNodeConf.endNodeFlags); } catch (Exception e) { // ignore, as it's probably corrupt save data. it'll be culled on next save Log.Warning("Error loading segment-at-node config: " + e.ToString()); } } } else { Log.Warning("Segment-at-node structure undefined!"); } }
private bool HandleVehicle(ushort vehicleId, ref Vehicle vehicleData, bool handleWatched) { bool handledVehicle = false; if (handleWatched) { var vehManager = Singleton <VehicleManager> .instance; // handle watched vehicles HashSet <ushort> toDelete = new HashSet <ushort>(); foreach (ushort otherVehicleId in watchedVehicleIds) { Vehicle otherVehicle = vehManager.m_vehicles.m_buffer[otherVehicleId]; if (otherVehicle.m_flags != Vehicle.Flags.None) { if (HandleVehicle(otherVehicleId, ref otherVehicle, false)) { toDelete.Add(otherVehicleId); } } else { toDelete.Add(otherVehicleId); } } foreach (ushort vehicleIdToDelete in toDelete) { watchedVehicleIds.Remove(vehicleIdToDelete); } } var netManager = Singleton <NetManager> .instance; var lastFrameData = vehicleData.GetLastFrameData(); #if DEBUG List <String> logBuffer = new List <String>(); bool logme = false; #endif if (vehicleData.Info.m_vehicleType != VehicleInfo.VehicleType.Car) { return(false); } #if DEBUG if (vehicleId % 5 == 0) { logBuffer.Add("Calculating prio info for vehicleId " + vehicleId); } #endif // we extract the segment information directly from the vehicle var currentPathId = vehicleData.m_path; //ushort realTimeSourceNode = 0; // the car is currently moving from this node... ushort realTimeDestinationNode = 0; // ... to this node ... //ushort realTimeVeryNextDestinationNode = 0; // ... and then to this node ... PathUnit.Position? realTimePosition = null; // car position at current frame PathUnit.Position veryNextRealTimePosition = default(PathUnit.Position); List <PathUnit.Position> nextRealTimePositions = new List <PathUnit.Position>(); // car position after passing the next nodes List <ushort> nextRealTimeDestinationNodes = new List <ushort>(); // upcoming node ids #if DEBUG if (vehicleId % 5 == 0) { logBuffer.Add("* vehicleId " + vehicleId + ". currentPathId: " + currentPathId); } #endif if (currentPathId > 0) { // vehicle has a path... var vehiclePathUnit = Singleton <PathManager> .instance.m_pathUnits.m_buffer[currentPathId]; if ((vehiclePathUnit.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 realTimePosition = vehiclePathUnit.GetPosition(vehicleData.m_pathPositionIndex >> 1); var currentSegment = netManager.m_segments.m_buffer[realTimePosition.Value.m_segment]; if (realTimePosition.Value.m_offset == 0) { realTimeDestinationNode = currentSegment.m_startNode; //realTimeSourceNode = currentSegment.m_endNode; } else { realTimeDestinationNode = currentSegment.m_endNode; //realTimeSourceNode = currentSegment.m_startNode; } // evaluate upcoming path units bool first = true; for (byte pathPos = (byte)((vehicleData.m_pathPositionIndex >> 1) + 1); pathPos < vehiclePathUnit.m_positionCount; ++pathPos) { PathUnit.Position nextRealTimePosition = default(PathUnit.Position); if (!vehiclePathUnit.GetPosition(pathPos, out nextRealTimePosition)) // if this returns false, there is no next path unit { break; } ushort destNodeId = 0; if (nextRealTimePosition.m_segment > 0) { var nextSegment = netManager.m_segments.m_buffer[nextRealTimePosition.m_segment]; if (nextRealTimePosition.m_offset == 0) { destNodeId = nextSegment.m_startNode; } else { destNodeId = nextSegment.m_endNode; } } // this is the very next path node, save it separately if (first) { veryNextRealTimePosition = nextRealTimePosition; //realTimeVeryNextDestinationNode = destNodeId; first = false; if (!handleWatched) { break; // we only need the first path unit } } nextRealTimePositions.Add(nextRealTimePosition); nextRealTimeDestinationNodes.Add(destNodeId); } // 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 m_pathPositionIndex relates to the car's position // on the segment. If it is even the car might be in the segement's first half and if it is odd, it might be in the segment's // second half. #if DEBUG if (vehicleId % 5 == 0) { logBuffer.Add("* vehicleId " + vehicleId + ". *INFO* rtPos.seg=" + realTimePosition.Value.m_segment + " nrtPos.seg=" + veryNextRealTimePosition.m_segment); } #endif } } // we have seen the car! TrafficPriority.VehicleList[vehicleId].LastFrame = Singleton <SimulationManager> .instance.m_currentFrameIndex >> 4; TrafficPriority.VehicleList[vehicleId].LastSpeed = lastFrameData.m_velocity.sqrMagnitude; #if DEBUG if (vehicleId % 5 == 0) { logBuffer.Add("* vehicleId " + vehicleId + ". ToNode: " + TrafficPriority.VehicleList[vehicleId].ToNode + ". FromSegment: " + TrafficPriority.VehicleList[vehicleId].FromSegment + ". FromLaneId: " + TrafficPriority.VehicleList[vehicleId].FromLaneId); } #endif if (realTimePosition != null) { // we found a valid path unit var sourceLaneId = PathManager.GetLaneID(realTimePosition.Value); if (TrafficPriority.VehicleList[vehicleId].ToNode != realTimeDestinationNode || TrafficPriority.VehicleList[vehicleId].FromSegment != realTimePosition.Value.m_segment || TrafficPriority.VehicleList[vehicleId].FromLaneId != sourceLaneId) { // vehicle information is not up-to-date. remove the car from the old priority segment (if existing)... var oldNode = TrafficPriority.VehicleList[vehicleId].ToNode; var oldSegment = TrafficPriority.VehicleList[vehicleId].FromSegment; var oldPrioritySegment = TrafficPriority.GetPrioritySegment(oldNode, oldSegment); if (oldPrioritySegment != null) { TrafficPriority.VehicleList[vehicleId].WaitTime = 0; TrafficPriority.VehicleList[vehicleId].Stopped = false; if (oldPrioritySegment.RemoveCar(vehicleId)) { #if DEBUG if (vehicleId % 5 == 0) { logBuffer.Add("### REMOVING vehicle " + vehicleId); } #endif } else { #if DEBUG if (vehicleId % 5 == 0) { logBuffer.Add("* vehicleId " + vehicleId + " was NOT REMOVED!"); } #endif } } else { #if DEBUG if (vehicleId % 5 == 0) { logBuffer.Add("* vehicleId " + vehicleId + ". oldPrioSeg is null"); } #endif } #if DEBUG if (vehicleId % 5 == 0) { logBuffer.Add("* vehicleId " + vehicleId + ". *VEHINFO* ToNode=" + realTimeDestinationNode + " FromSegment=" + realTimePosition.Value.m_segment + " FromLaneId=" + PathManager.GetLaneID(realTimePosition.Value) + " ToSegment=" + veryNextRealTimePosition.m_segment + " ToLaneId=" + (veryNextRealTimePosition.m_segment > 0 ? "" + PathManager.GetLaneID(veryNextRealTimePosition) : "n/a")); } #endif if (handleWatched) { watchedVehicleIds.Remove(vehicleId); } handledVehicle = true; // ... and add it to the new priority segment var prioritySegment = TrafficPriority.GetPrioritySegment(realTimeDestinationNode, realTimePosition.Value.m_segment); if (prioritySegment != null) { #if DEBUG logme = true; #endif if (handleWatched) { watchedVehicleIds.Add(vehicleId); } TrafficPriority.VehicleList[vehicleId].ToNode = realTimeDestinationNode; TrafficPriority.VehicleList[vehicleId].FromSegment = realTimePosition.Value.m_segment; TrafficPriority.VehicleList[vehicleId].FromLaneId = PathManager.GetLaneID(realTimePosition.Value); TrafficPriority.VehicleList[vehicleId].ToSegment = veryNextRealTimePosition.m_segment; if (veryNextRealTimePosition.m_segment > 0) { TrafficPriority.VehicleList[vehicleId].ToLaneId = PathManager.GetLaneID(veryNextRealTimePosition); } else { TrafficPriority.VehicleList[vehicleId].ToLaneId = 0; } TrafficPriority.VehicleList[vehicleId].FromLaneFlags = netManager.m_lanes.m_buffer[TrafficPriority.VehicleList[vehicleId].FromLaneId].m_flags; TrafficPriority.VehicleList[vehicleId].ReduceSpeedByValueToYield = Random.Range(13f, 18f); if (prioritySegment.AddCar(vehicleId)) { #if DEBUG if (vehicleId % 5 == 0) { logBuffer.Add("* vehicleId " + vehicleId + " was added!"); } #endif /*if (vehicleId % 16 == 0) { * Log.Message("query: vehicleId: " + vehicleId + ", prevLaneID: " + prevLaneID + ", laneID: " + laneID + ", prevOffset: " + prevOffset + ", offset: " + offset); * Log.Warning("*** ADDING vehicle " + vehicleId + " at (prev/cur/next) lane: (" + TrafficPriority.VehicleList[vehicleId].FromLaneId + "/" + TrafficPriority.VehicleList[vehicleId].ToLaneId + "/" + (nextPosition.m_segment > 0 ? "" + PathManager.GetLaneID(nextPosition) : "n/a") + "), (prev/cur/next) offset: (" + prevPos.m_offset + "/" + position.m_offset + "/" + nextPosition.m_offset + "), (prev/cur/next) segment: (" + prevPos.m_segment + "/" + position.m_segment + "/" + nextPosition.m_segment + ") at (src/dest/intrst) node (" + sourceNodeId + "/" + destinationNodeId + "/" + interestingNodeId + "), pathId: " + vehicleData.m_path + ", pathPosIndex: " + vehicleData.m_pathPositionIndex); * }*/ } else { #if DEBUG if (vehicleId % 5 == 0) { logBuffer.Add("* vehicleId " + vehicleId + " was NOT added!"); } #endif } } else { #if DEBUG if (vehicleId % 5 == 0) { logBuffer.Add("* vehicleId " + vehicleId + ". prioSeg is null"); } #endif } // add to watchlist if any upcoming node is a priority node if (handleWatched) { for (int i = 0; i < nextRealTimePositions.Count; ++i) { if (nextRealTimePositions[i].m_segment > 0) { var nextPrioritySegment = TrafficPriority.GetPrioritySegment(nextRealTimeDestinationNodes[i], nextRealTimePositions[i].m_segment); if (nextPrioritySegment != null) { watchedVehicleIds.Add(vehicleId); } } } } } else { var prioritySegment = TrafficPriority.GetPrioritySegment(realTimeDestinationNode, realTimePosition.Value.m_segment); if (prioritySegment != null) { // vehicle is still on priority segment if (handleWatched) { watchedVehicleIds.Add(vehicleId); } } } } else { if (TrafficPriority.VehicleList.ContainsKey(vehicleId)) { var oldNode = TrafficPriority.VehicleList[vehicleId].ToNode; var oldSegment = TrafficPriority.VehicleList[vehicleId].FromSegment; var oldPrioritySegment = TrafficPriority.GetPrioritySegment(oldNode, oldSegment); if (oldPrioritySegment != null) { oldPrioritySegment.RemoveCar(vehicleId); } } if (handleWatched) { watchedVehicleIds.Remove(vehicleId); } handledVehicle = true; } #if DEBUG if (false && vehicleId == (ushort)12000 /*logme || vehicleId % 100 == 0*/) { if (logme) { Log.Error("vehicleId: " + vehicleId + " ============================================"); } else { Log.Warning("vehicleId: " + vehicleId + " ============================================"); } foreach (String logBuf in logBuffer) { Log.Message(logBuf); } } #endif return(handledVehicle); }
/// <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); }
public void ShowGUI(bool viewOnly) { try { if (viewOnly && !Options.prioritySignsOverlay) { return; } bool clicked = !viewOnly?MainTool.CheckClicked() : false; var hoveredSegment = false; //Log.Message("_guiPrioritySigns called. num of prio segments: " + TrafficPriority.PrioritySegments.Count); HashSet <ushort> nodeIdsWithSigns = new HashSet <ushort>(); for (ushort segmentId = 0; segmentId < NetManager.MAX_SEGMENT_COUNT; ++segmentId) { var trafficSegment = TrafficPriority.TrafficSegments[segmentId]; if (trafficSegment == null) { continue; } SegmentGeometry geometry = SegmentGeometry.Get(segmentId); List <SegmentEnd> prioritySegments = new List <SegmentEnd>(); if (TrafficLightSimulation.GetNodeSimulation(trafficSegment.Node1) == null) { SegmentEnd tmpSeg1 = TrafficPriority.GetPrioritySegment(trafficSegment.Node1, segmentId); bool startNode = geometry.StartNodeId() == trafficSegment.Node1; if (tmpSeg1 != null && !geometry.IsOutgoingOneWay(startNode)) { prioritySegments.Add(tmpSeg1); nodeIdsWithSigns.Add(trafficSegment.Node1); } } if (TrafficLightSimulation.GetNodeSimulation(trafficSegment.Node2) == null) { SegmentEnd tmpSeg2 = TrafficPriority.GetPrioritySegment(trafficSegment.Node2, segmentId); bool startNode = geometry.StartNodeId() == trafficSegment.Node2; if (tmpSeg2 != null && !geometry.IsOutgoingOneWay(startNode)) { prioritySegments.Add(tmpSeg2); nodeIdsWithSigns.Add(trafficSegment.Node2); } } //Log.Message("init ok"); foreach (var prioritySegment in prioritySegments) { var nodeId = prioritySegment.NodeId; //Log.Message("_guiPrioritySigns: nodeId=" + nodeId); var nodePositionVector3 = Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId].m_position; var camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position; var diff = nodePositionVector3 - camPos; if (diff.magnitude > TrafficManagerTool.PriorityCloseLod) { continue; // do not draw if too distant } if (Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startNode == (ushort)nodeId) { nodePositionVector3.x += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startDirection.x * 10f; nodePositionVector3.y += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startDirection.y * 10f; nodePositionVector3.z += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startDirection.z * 10f; } else { nodePositionVector3.x += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_endDirection.x * 10f; nodePositionVector3.y += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_endDirection.y * 10f; nodePositionVector3.z += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_endDirection.z * 10f; } var nodeScreenPosition = Camera.main.WorldToScreenPoint(nodePositionVector3); nodeScreenPosition.y = Screen.height - nodeScreenPosition.y; if (nodeScreenPosition.z < 0) { continue; } var zoom = 1.0f / diff.magnitude * 100f * MainTool.GetBaseZoom(); var size = 110f * zoom; var guiColor = GUI.color; var nodeBoundingBox = new Rect(nodeScreenPosition.x - size / 2, nodeScreenPosition.y - size / 2, size, size); hoveredSegment = !viewOnly && TrafficManagerTool.IsMouseOver(nodeBoundingBox); if (hoveredSegment) { // mouse hovering over sign guiColor.a = 0.8f; } else { guiColor.a = 0.5f; size = 90f * zoom; } var nodeDrawingBox = new Rect(nodeScreenPosition.x - size / 2, nodeScreenPosition.y - size / 2, size, size); GUI.color = guiColor; bool setUndefinedSignsToMainRoad = false; switch (prioritySegment.Type) { case SegmentEnd.PriorityType.Main: GUI.DrawTexture(nodeDrawingBox, TrafficLightToolTextureResources.SignPriorityTexture2D); if (clicked && hoveredSegment) { //Log._Debug("Click on node " + nodeId + ", segment " + segmentId + " to change prio type (1)"); //Log.Message("PrioritySegment.Type = Yield"); prioritySegment.Type = SegmentEnd.PriorityType.Yield; setUndefinedSignsToMainRoad = true; clicked = false; } break; case SegmentEnd.PriorityType.Yield: GUI.DrawTexture(nodeDrawingBox, TrafficLightToolTextureResources.SignYieldTexture2D); if (clicked && hoveredSegment) { //Log._Debug("Click on node " + nodeId + ", segment " + segmentId + " to change prio type (2)"); prioritySegment.Type = SegmentEnd.PriorityType.Stop; setUndefinedSignsToMainRoad = true; clicked = false; } break; case SegmentEnd.PriorityType.Stop: GUI.DrawTexture(nodeDrawingBox, TrafficLightToolTextureResources.SignStopTexture2D); if (clicked && hoveredSegment) { //Log._Debug("Click on node " + nodeId + ", segment " + segmentId + " to change prio type (3)"); prioritySegment.Type = SegmentEnd.PriorityType.Main; clicked = false; } break; case SegmentEnd.PriorityType.None: if (viewOnly) { break; } GUI.DrawTexture(nodeDrawingBox, TrafficLightToolTextureResources.SignNoneTexture2D); if (clicked && hoveredSegment) { //Log._Debug("Click on node " + nodeId + ", segment " + segmentId + " to change prio type (4)"); //Log.Message("PrioritySegment.Type = None"); prioritySegment.Type = GetNumberOfMainRoads(nodeId, ref Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId]) >= 2 ? SegmentEnd.PriorityType.Yield : SegmentEnd.PriorityType.Main; if (prioritySegment.Type == SegmentEnd.PriorityType.Yield) { setUndefinedSignsToMainRoad = true; } clicked = false; } break; } if (setUndefinedSignsToMainRoad) { foreach (var otherPrioritySegment in TrafficPriority.GetPrioritySegments(nodeId)) { if (otherPrioritySegment.SegmentId == prioritySegment.SegmentId) { continue; } if (otherPrioritySegment.Type == SegmentEnd.PriorityType.None) { otherPrioritySegment.Type = SegmentEnd.PriorityType.Main; } } } } } if (viewOnly) { return; } ushort hoveredExistingNodeId = 0; foreach (ushort nodeId in nodeIdsWithSigns) { var nodePositionVector3 = Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId].m_position; var camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position; var diff = nodePositionVector3 - camPos; if (diff.magnitude > TrafficManagerTool.PriorityCloseLod) { continue; } // draw deletion button var nodeScreenPosition = Camera.main.WorldToScreenPoint(nodePositionVector3); nodeScreenPosition.y = Screen.height - nodeScreenPosition.y; if (nodeScreenPosition.z < 0) { continue; } var zoom = 1.0f / diff.magnitude * 100f; var size = 100f * zoom; var nodeBoundingBox = new Rect(nodeScreenPosition.x - size / 2, nodeScreenPosition.y - size / 2, size, size); var guiColor = GUI.color; var nodeCenterHovered = TrafficManagerTool.IsMouseOver(nodeBoundingBox); if (nodeCenterHovered) { hoveredExistingNodeId = nodeId; guiColor.a = 0.8f; } else { guiColor.a = 0.5f; } GUI.color = guiColor; GUI.DrawTexture(nodeBoundingBox, TrafficLightToolTextureResources.SignRemoveTexture2D); } // add a new or delete a priority segment node if (HoveredNodeId != 0 || hoveredExistingNodeId != 0) { bool delete = false; if (hoveredExistingNodeId > 0) { delete = true; } // determine if we may add new priority signs to this node bool ok = false; TrafficLightSimulation nodeSim = TrafficLightSimulation.GetNodeSimulation(HoveredNodeId); if ((Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_flags & NetNode.Flags.TrafficLights) == NetNode.Flags.None) { // no traffic light set ok = true; } else if (nodeSim == null || !nodeSim.IsTimedLight()) { ok = true; } if (!Flags.mayHaveTrafficLight(HoveredNodeId)) { ok = false; } if (clicked) { //Log._Debug("_guiPrioritySigns: hovered+clicked @ nodeId=" + HoveredNodeId + "/" + hoveredExistingNodeId); if (delete) { TrafficPriority.RemovePrioritySegments(hoveredExistingNodeId); } else if (ok) { if (!TrafficPriority.IsPriorityNode(HoveredNodeId)) { //Log._Debug("_guiPrioritySigns: adding prio segments @ nodeId=" + HoveredNodeId); TrafficLightSimulation.RemoveNodeFromSimulation(HoveredNodeId, false, true); Flags.setNodeTrafficLight(HoveredNodeId, false); // TODO refactor! TrafficPriority.AddPriorityNode(HoveredNodeId); } } else if (nodeSim != null && nodeSim.IsTimedLight()) { MainTool.ShowTooltip(Translation.GetString("NODE_IS_TIMED_LIGHT"), Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_position); } } } } catch (Exception e) { Log.Error(e.ToString()); } }
/// <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 DEBUG bool debug = timedNode.NodeId == 17857; #else bool debug = false; #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 groupNodeIds) { 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) { //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 (ExtVehicleType vehicleType in segLights.VehicleTypes) { if (vehicleType != ExtVehicleType.None && (validVehicleTypes & vehicleType) == ExtVehicleType.None) { continue; } CustomSegmentLight segLight = segLights.GetCustomLight(vehicleType); if (segLight == null) { Log.Warning($"Timed traffic light step: Failed to get custom light for vehicleType {vehicleType} @ seg. {fromSegmentId}, node {timedNode.NodeId}!"); continue; } Dictionary <ushort, uint>[] carsToSegmentMetrics = new Dictionary <ushort, uint> [startPhase ? 1: 2]; try { carsToSegmentMetrics[0] = fromSeg.GetVehicleMetricGoingToSegment(null, vehicleType, segLights.SeparateVehicleTypes, debug); } catch (Exception ex) { Log.Warning("calcWaitFlow: " + ex.ToString()); } if (!startPhase) { try { carsToSegmentMetrics[1] = fromSeg.GetVehicleMetricGoingToSegment(0.1f, vehicleType, segLights.SeparateVehicleTypes, debug); } catch (Exception ex) { Log.Warning("calcWaitFlow: " + ex.ToString()); } } if (carsToSegmentMetrics[0] == null) { continue; } // build directions from toSegment to fromSegment Dictionary <ushort, Direction> directions = new Dictionary <ushort, Direction>(); foreach (KeyValuePair <ushort, uint> f in carsToSegmentMetrics[0]) { var toSegmentId = f.Key; SegmentGeometry geometry = CustomRoadAI.GetSegmentGeometry(fromSegmentId); Direction dir = geometry.GetDirection(toSegmentId, timedNodeId); directions[toSegmentId] = dir; } // calculate waiting/flowing traffic for (int i = 0; i < carsToSegmentMetrics.Length; ++i) { if (carsToSegmentMetrics[i] == null) { continue; } foreach (KeyValuePair <ushort, uint> f in carsToSegmentMetrics[i]) { ushort toSegmentId = f.Key; uint totalNormCarLength = f.Value; bool addToFlow = false; switch (directions[toSegmentId]) { case Direction.Left: if (segLight.isLeftGreen()) { addToFlow = true; } break; case Direction.Right: if (segLight.isRightGreen()) { addToFlow = true; } break; case Direction.Forward: default: if (segLight.isForwardGreen()) { addToFlow = true; } break; } if (addToFlow) { if (i > 0 || startPhase) { ++numFlows; curMeanFlow += totalNormCarLength; } } else if (i == 0) { ++numWaits; curMeanWait += totalNormCarLength; } } } } } // 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; return(false); } } if (numFlows > 0) { curMeanFlow /= numFlows; } if (numWaits > 0) { curMeanWait /= numWaits; } float fCurMeanFlow = curMeanFlow; fCurMeanFlow /= 100f * waitFlowBalance; // a value smaller than 1 rewards steady traffic currents wait = (float)curMeanWait / 100f; flow = fCurMeanFlow; return(true); }