public bool IsCargoTruckAllowed(ExtVehicleType?allowedTypes) { return(IsAllowed(allowedTypes, ExtVehicleType.CargoTruck)); }
public bool IsRoadVehicleAllowed(ExtVehicleType?allowedTypes) { return(IsAllowed(allowedTypes, ExtVehicleType.RoadVehicle)); }
public bool IsBicycleAllowed(ExtVehicleType?allowedTypes) { return(IsAllowed(allowedTypes, ExtVehicleType.Bicycle)); }
public bool IsTaxiAllowed(ExtVehicleType?allowedTypes) { return(IsAllowed(allowedTypes, ExtVehicleType.Taxi)); }
public bool IsCableCarAllowed(ExtVehicleType?allowedTypes) { return(IsAllowed(allowedTypes, ExtVehicleType.CableCar)); }
// TODO improve & remove public void Housekeeping(bool mayDelete, bool calculateAutoPedLight) { #if DEBUGHK bool debug = GlobalConfig.Instance.Debug.Switches[7] && GlobalConfig.Instance.Debug.NodeId == NodeId; #endif // we intentionally never delete vehicle types (because we may want to retain traffic light states if a segment is upgraded or replaced) ICustomSegmentLight mainLight = MainSegmentLight; ushort nodeId = NodeId; HashSet <ExtVehicleType> setupLights = new HashSet <ExtVehicleType>(); IDictionary <byte, ExtVehicleType> allAllowedTypes = Constants.ManagerFactory.VehicleRestrictionsManager.GetAllowedVehicleTypesAsDict(SegmentId, nodeId, VehicleRestrictionsMode.Restricted); // TODO improve ExtVehicleType allAllowedMask = Constants.ManagerFactory.VehicleRestrictionsManager.GetAllowedVehicleTypes(SegmentId, nodeId, VehicleRestrictionsMode.Restricted); SeparateVehicleTypes = ExtVehicleType.None; #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping started @ seg. {SegmentId}, node {nodeId}, allAllowedTypes={allAllowedTypes.DictionaryToString()}, allAllowedMask={allAllowedMask}"); } #endif //bool addPedestrianLight = false; uint separateLanes = 0; int defaultLanes = 0; NetInfo segmentInfo = null; Constants.ServiceFactory.NetService.ProcessSegment(SegmentId, delegate(ushort segId, ref NetSegment segment) { VehicleTypeByLaneIndex = new ExtVehicleType?[segment.Info.m_lanes.Length]; segmentInfo = segment.Info; return(true); }); HashSet <byte> laneIndicesWithoutSeparateLights = new HashSet <byte>(allAllowedTypes.Keys); // TODO improve // check if separate traffic lights are required bool separateLightsRequired = false; foreach (KeyValuePair <byte, ExtVehicleType> e in allAllowedTypes) { if (e.Value != allAllowedMask) { separateLightsRequired = true; break; } } // set up vehicle-separated traffic lights if (separateLightsRequired) { foreach (KeyValuePair <byte, ExtVehicleType> e in allAllowedTypes) { byte laneIndex = e.Key; NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex]; ExtVehicleType allowedTypes = e.Value; ExtVehicleType defaultMask = Constants.ManagerFactory.VehicleRestrictionsManager.GetDefaultAllowedVehicleTypes(SegmentId, segmentInfo, laneIndex, laneInfo, VehicleRestrictionsMode.Unrestricted); #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}: Processing lane {laneIndex} with allowedTypes={allowedTypes}, defaultMask={defaultMask}"); } #endif if (laneInfo.m_vehicleType == VehicleInfo.VehicleType.Car && allowedTypes == defaultMask) { #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}, lane {laneIndex}: Allowed types equal default mask. Ignoring lane."); } #endif // no vehicle restrictions applied, generic lights are handled further below ++defaultLanes; continue; } ExtVehicleType mask = allowedTypes & ~ExtVehicleType.Emergency; #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}, lane {laneIndex}: Trying to add {mask} light"); } #endif ICustomSegmentLight segmentLight; if (!CustomLights.TryGetValue(mask, out segmentLight)) { // add a new light segmentLight = new CustomSegmentLight(this, RoadBaseAI.TrafficLightState.Red); if (mainLight != null) { segmentLight.CurrentMode = mainLight.CurrentMode; segmentLight.SetStates(mainLight.LightMain, mainLight.LightLeft, mainLight.LightRight, false); } #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}, lane {laneIndex}: Light for mask {mask} does not exist. Created new light: {segmentLight} (mainLight: {mainLight})"); } #endif CustomLights.Add(mask, segmentLight); VehicleTypes.AddFirst(mask); } mainVehicleType = mask; VehicleTypeByLaneIndex[laneIndex] = mask; laneIndicesWithoutSeparateLights.Remove(laneIndex); ++separateLanes; //addPedestrianLight = true; setupLights.Add(mask); SeparateVehicleTypes |= mask; #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}: Finished processing lane {laneIndex}: mainVehicleType={mainVehicleType}, VehicleTypeByLaneIndex={VehicleTypeByLaneIndex.ArrayToString()}, laneIndicesWithoutSeparateLights={laneIndicesWithoutSeparateLights.CollectionToString()}, numLights={separateLanes}, SeparateVehicleTypes={SeparateVehicleTypes}"); } #endif } } if (separateLanes == 0 || defaultLanes > 0) { #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}: Adding default main vehicle light: {DEFAULT_MAIN_VEHICLETYPE}"); } #endif // generic traffic lights ICustomSegmentLight defaultSegmentLight; if (!CustomLights.TryGetValue(DEFAULT_MAIN_VEHICLETYPE, out defaultSegmentLight)) { defaultSegmentLight = new CustomSegmentLight(this, RoadBaseAI.TrafficLightState.Red); if (mainLight != null) { defaultSegmentLight.CurrentMode = mainLight.CurrentMode; defaultSegmentLight.SetStates(mainLight.LightMain, mainLight.LightLeft, mainLight.LightRight, false); } CustomLights.Add(DEFAULT_MAIN_VEHICLETYPE, defaultSegmentLight); VehicleTypes.AddFirst(DEFAULT_MAIN_VEHICLETYPE); } mainVehicleType = DEFAULT_MAIN_VEHICLETYPE; setupLights.Add(DEFAULT_MAIN_VEHICLETYPE); foreach (byte laneIndex in laneIndicesWithoutSeparateLights) { VehicleTypeByLaneIndex[laneIndex] = ExtVehicleType.None; } #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}: Added default main vehicle light: {defaultSegmentLight}"); } #endif //addPedestrianLight = true; } else { //addPedestrianLight = allAllowedMask == ExtVehicleType.None || (allAllowedMask & ~ExtVehicleType.RailVehicle) != ExtVehicleType.None; } #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}: Created all necessary lights. VehicleTypeByLaneIndex={VehicleTypeByLaneIndex.ArrayToString()}, CustomLights={CustomLights.DictionaryToString()}"); } #endif if (mayDelete) { // delete traffic lights for non-existing vehicle-separated configurations HashSet <ExtVehicleType> vehicleTypesToDelete = new HashSet <ExtVehicleType>(); foreach (KeyValuePair <ExtVehicleType, ICustomSegmentLight> e in CustomLights) { /*if (e.Key == DEFAULT_MAIN_VEHICLETYPE) { * continue; * }*/ if (!setupLights.Contains(e.Key)) { vehicleTypesToDelete.Add(e.Key); } } #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}: Going to delete unnecessary lights now: vehicleTypesToDelete={vehicleTypesToDelete.CollectionToString()}"); } #endif foreach (ExtVehicleType vehicleType in vehicleTypesToDelete) { CustomLights.Remove(vehicleType); VehicleTypes.Remove(vehicleType); } } if (CustomLights.ContainsKey(DEFAULT_MAIN_VEHICLETYPE) && VehicleTypes.First.Value != DEFAULT_MAIN_VEHICLETYPE) { VehicleTypes.Remove(DEFAULT_MAIN_VEHICLETYPE); VehicleTypes.AddFirst(DEFAULT_MAIN_VEHICLETYPE); } //if (addPedestrianLight) { #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}: adding pedestrian light"); } #endif if (InternalPedestrianLightState == null) { InternalPedestrianLightState = RoadBaseAI.TrafficLightState.Red; } /*} else { * InternalPedestrianLightState = null; * }*/ OnChange(calculateAutoPedLight); #if DEBUGHK if (debug) { Log._Debug($"CustomSegmentLights.Housekeeping({mayDelete}, {calculateAutoPedLight}): housekeeping @ seg. {SegmentId}, node {nodeId}: Housekeeping complete. VehicleTypeByLaneIndex={VehicleTypeByLaneIndex.ArrayToString()} CustomLights={CustomLights.DictionaryToString()}"); } #endif }
public bool IsPassengerTrainAllowed(ExtVehicleType?allowedTypes) { return(IsAllowed(allowedTypes, ExtVehicleType.PassengerTrain)); }
/// <summary> /// coppies vehicle restrictions of the current segment /// and applies them to all segments until the next junction. /// </summary> /// <param name="sortedLaneIndex">if provided only current lane is considered</param> /// <param name="vehicleTypes"> /// if provided only bits for which vehicleTypes is set are considered. /// </param> private void ApplyRestrictionsToAllSegments( int?sortedLaneIndex = null, ExtVehicleType?vehicleTypes = null) { NetManager netManager = Singleton <NetManager> .instance; NetInfo selectedSegmentInfo = netManager.m_segments.m_buffer[SelectedSegmentId].Info; bool LaneVisitorFun(SegmentLaneVisitData data) { if (data.SegVisitData.Initial) { return(true); } if (sortedLaneIndex != null && data.SortedLaneIndex != sortedLaneIndex) { return(true); } ushort segmentId = data.SegVisitData.CurSeg.segmentId; NetInfo segmentInfo = netManager.m_segments.m_buffer[segmentId].Info; byte selectedLaneIndex = data.InitLanePos.laneIndex; NetInfo.Lane selectedLaneInfo = selectedSegmentInfo.m_lanes[selectedLaneIndex]; uint laneId = data.CurLanePos.laneId; byte laneIndex = data.CurLanePos.laneIndex; NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex]; // apply restrictions of selected segment & lane ExtVehicleType mask = VehicleRestrictionsManager.Instance.GetAllowedVehicleTypes( SelectedSegmentId, selectedSegmentInfo, selectedLaneIndex, selectedLaneInfo, VehicleRestrictionsMode.Configured);; if (vehicleTypes != null) { ExtVehicleType currentMask = VehicleRestrictionsManager.Instance.GetAllowedVehicleTypes( segmentId, segmentInfo, laneIndex, laneInfo, VehicleRestrictionsMode.Configured); // only apply changes where types is 1. that means: // for bits where types is 0, use currentMask, // for bits where types is 1, use initial mask. ExtVehicleType types2 = (ExtVehicleType)vehicleTypes; //cast mask = (types2 & mask) | (~types2 & currentMask); } VehicleRestrictionsManager.Instance.SetAllowedVehicleTypes( segmentId, segmentInfo, laneIndex, laneInfo, laneId, mask); RefreshCurrentRestrictedSegmentIds(segmentId); return(true); } SegmentLaneTraverser.Traverse( SelectedSegmentId, SegmentTraverser.TraverseDirection.AnyDirection, SegmentTraverser.TraverseSide.AnySide, SegmentLaneTraverser.LaneStopCriterion.LaneCount, SegmentTraverser.SegmentStopCriterion.Junction, VehicleRestrictionsManager.LANE_TYPES, VehicleRestrictionsManager.VEHICLE_TYPES, LaneVisitorFun); }
public bool CustomStartPathFind(ushort vehicleId, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays) { /// NON-STOCK CODE START /// ExtVehicleType?vehicleType = VehicleStateManager.DetermineVehicleType(vehicleId, ref vehicleData); if (vehicleType == ExtVehicleType.CargoTrain) { vehicleType = ExtVehicleType.CargoVehicle; } #if DEBUG /*bool reversed = (vehicleData.m_flags & Vehicle.Flags.Reversed) != 0; * ushort frontVehicleId; * if (reversed) { * frontVehicleId = vehicleData.GetLastVehicle(vehicleId); * } else { * frontVehicleId = vehicleId; * } * Log._Debug($"CustomTrainAI.CustomStartPathFind. vehicleID={vehicleId}. reversed={reversed} frontVehicleId={frontVehicleId} type={this.GetType().ToString()} vehicleType={vehicleType} target={vehicleData.m_targetBuilding}");*/ #endif /// NON-STOCK CODE END /// VehicleInfo info = this.m_info; if ((vehicleData.m_flags & Vehicle.Flags.Spawned) == 0 && Vector3.Distance(startPos, endPos) < 100f) { startPos = endPos; } bool allowUnderground; bool allowUnderground2; if (info.m_vehicleType == VehicleInfo.VehicleType.Metro) { allowUnderground = true; allowUnderground2 = true; } else { allowUnderground = ((vehicleData.m_flags & (Vehicle.Flags.Underground | Vehicle.Flags.Transition)) != 0); allowUnderground2 = false; } PathUnit.Position startPosA; PathUnit.Position startPosB; float num; float num2; PathUnit.Position endPosA; PathUnit.Position endPosB; float num3; float num4; if (CustomPathManager.FindPathPosition(startPos, ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, info.m_vehicleType, allowUnderground, false, 32f, out startPosA, out startPosB, out num, out num2) && CustomPathManager.FindPathPosition(endPos, ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, info.m_vehicleType, allowUnderground2, false, 32f, out endPosA, out endPosB, out num3, out num4)) { if (!startBothWays || num2 > num * 1.2f) { startPosB = default(PathUnit.Position); } if (!endBothWays || num4 > num3 * 1.2f) { endPosB = default(PathUnit.Position); } uint path; bool res = false; if (vehicleType == null) { res = Singleton <PathManager> .instance.CreatePath(out path, ref Singleton <SimulationManager> .instance.m_randomizer, Singleton <SimulationManager> .instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, NetInfo.LaneType.Vehicle, info.m_vehicleType, 20000f, false, false, true, false); } else { res = Singleton <CustomPathManager> .instance.CreatePath((ExtVehicleType)vehicleType, out path, ref Singleton <SimulationManager> .instance.m_randomizer, Singleton <SimulationManager> .instance.m_currentBuildIndex, ref startPosA, ref startPosB, ref endPosA, ref endPosB, NetInfo.LaneType.Vehicle, info.m_vehicleType, 20000f, false, false, true, false); } if (res) { if (vehicleData.m_path != 0u) { Singleton <PathManager> .instance.ReleasePath(vehicleData.m_path); } vehicleData.m_path = path; vehicleData.m_flags |= Vehicle.Flags.WaitingPath; return(true); } } return(false); }
public void Record() { allowedVehicleTypes_ = VehicleRestrictionsManager.Instance.GetAllowedVehicleTypesRaw(SegmentId, LaneIndex); }
public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays, bool undergroundTarget) { ExtVehicleType?vehicleType = VehicleStateManager.DetermineVehicleType(vehicleID, ref vehicleData); #if PATHRECALC VehicleState state = VehicleStateManager._GetVehicleState(vehicleID); bool recalcRequested = state.PathRecalculationRequested; state.PathRecalculationRequested = false; #endif /*if (vehicleType == null) { * Log._Debug($"CustomCarAI.CustomStartPathFind: Could not determine ExtVehicleType from class type. typeof this={this.GetType().ToString()}"); * } else { * Log._Debug($"CustomCarAI.CustomStartPathFind: vehicleType={vehicleType}. typeof this={this.GetType().ToString()}"); * }*/ VehicleInfo info = this.m_info; bool allowUnderground = (vehicleData.m_flags & (Vehicle.Flags.Underground | Vehicle.Flags.Transition)) != 0; PathUnit.Position startPosA; PathUnit.Position startPosB; float num; float num2; PathUnit.Position endPosA; PathUnit.Position endPosB; float num3; float num4; if (CustomPathManager.FindPathPosition(startPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, allowUnderground, false, 32f, out startPosA, out startPosB, out num, out num2) && CustomPathManager.FindPathPosition(endPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, undergroundTarget, false, 32f, out endPosA, out endPosB, out num3, out num4)) { if (!startBothWays || num < 10f) { startPosB = default(PathUnit.Position); } if (!endBothWays || num3 < 10f) { endPosB = default(PathUnit.Position); } uint path; bool res = false; if (vehicleType == null) { res = Singleton <CustomPathManager> .instance.CreatePath(out path, ref Singleton <SimulationManager> .instance.m_randomizer, Singleton <SimulationManager> .instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, NetInfo.LaneType.Vehicle, info.m_vehicleType, 20000f, this.IsHeavyVehicle(), this.IgnoreBlocked(vehicleID, ref vehicleData), false, false); } else { res = Singleton <CustomPathManager> .instance.CreatePath( #if PATHRECALC recalcRequested, #endif (ExtVehicleType)vehicleType, out path, ref Singleton <SimulationManager> .instance.m_randomizer, Singleton <SimulationManager> .instance.m_currentBuildIndex, ref startPosA, ref startPosB, ref endPosA, ref endPosB, NetInfo.LaneType.Vehicle, info.m_vehicleType, 20000f, this.IsHeavyVehicle(), this.IgnoreBlocked(vehicleID, ref vehicleData), false, false); } if (res) { if (vehicleData.m_path != 0u) { Singleton <PathManager> .instance.ReleasePath(vehicleData.m_path); } vehicleData.m_path = path; vehicleData.m_flags |= Vehicle.Flags.WaitingPath; return(true); } } return(false); }
internal static float CalcMaxSpeed(ushort vehicleId, ref Vehicle vehicleData, PathUnit.Position position, Vector3 pos, float maxSpeed, bool isRecklessDriver) { var netManager = Singleton <NetManager> .instance; NetInfo segmentInfo = netManager.m_segments.m_buffer[(int)position.m_segment].Info; bool highwayRules = (segmentInfo.m_netAI is RoadBaseAI && ((RoadBaseAI)segmentInfo.m_netAI).m_highwayRules); if (!highwayRules) { if (netManager.m_treatWetAsSnow) { DistrictManager districtManager = Singleton <DistrictManager> .instance; byte district = districtManager.GetDistrict(pos); DistrictPolicies.CityPlanning cityPlanningPolicies = districtManager.m_districts.m_buffer[(int)district].m_cityPlanningPolicies; if ((cityPlanningPolicies & DistrictPolicies.CityPlanning.StuddedTires) != DistrictPolicies.CityPlanning.None) { if (Options.strongerRoadConditionEffects) { if (maxSpeed > ICY_ROADS_STUDDED_MIN_SPEED) { maxSpeed = ICY_ROADS_STUDDED_MIN_SPEED + (float)(255 - netManager.m_segments.m_buffer[(int)position.m_segment].m_wetness) * 0.0039215686f * (maxSpeed - ICY_ROADS_STUDDED_MIN_SPEED); } } else { maxSpeed *= 1f - (float)netManager.m_segments.m_buffer[(int)position.m_segment].m_wetness * 0.0005882353f; // vanilla: -15% .. � } districtManager.m_districts.m_buffer[(int)district].m_cityPlanningPoliciesEffect |= DistrictPolicies.CityPlanning.StuddedTires; } else { if (Options.strongerRoadConditionEffects) { if (maxSpeed > ICY_ROADS_MIN_SPEED) { maxSpeed = ICY_ROADS_MIN_SPEED + (float)(255 - netManager.m_segments.m_buffer[(int)position.m_segment].m_wetness) * 0.0039215686f * (maxSpeed - ICY_ROADS_MIN_SPEED); } } else { maxSpeed *= 1f - (float)netManager.m_segments.m_buffer[(int)position.m_segment].m_wetness * 0.00117647066f; // vanilla: -30% .. � } } } else { if (Options.strongerRoadConditionEffects) { float minSpeed = Math.Min(maxSpeed * WET_ROADS_FACTOR, WET_ROADS_MAX_SPEED); if (maxSpeed > minSpeed) { maxSpeed = minSpeed + (float)(255 - netManager.m_segments.m_buffer[(int)position.m_segment].m_wetness) * 0.0039215686f * (maxSpeed - minSpeed); } } else { maxSpeed *= 1f - (float)netManager.m_segments.m_buffer[(int)position.m_segment].m_wetness * 0.0005882353f; // vanilla: -15% .. � } } if (Options.strongerRoadConditionEffects) { float minSpeed = Math.Min(maxSpeed * BROKEN_ROADS_FACTOR, BROKEN_ROADS_MAX_SPEED); if (maxSpeed > minSpeed) { maxSpeed = minSpeed + (float)netManager.m_segments.m_buffer[(int)position.m_segment].m_condition * 0.0039215686f * (maxSpeed - minSpeed); } } else { maxSpeed *= 1f + (float)netManager.m_segments.m_buffer[(int)position.m_segment].m_condition * 0.0005882353f; // vanilla: � .. +15 % } } ExtVehicleType?vehicleType = CustomVehicleAI.DetermineVehicleTypeFromVehicle(vehicleId, ref vehicleData); float vehicleRand = Math.Min(1f, (float)(vehicleId % 101) * 0.01f); // we choose 101 because it's a prime number if (isRecklessDriver) { maxSpeed *= 1.5f + vehicleRand * 1.5f; // woohooo, 1.5 .. 3 } else if ((vehicleType & ExtVehicleType.PassengerCar) != ExtVehicleType.None) { maxSpeed *= 0.8f + vehicleRand * 0.3f; // a little variance, 0.8 .. 1.1 } else if ((vehicleType & ExtVehicleType.Taxi) != ExtVehicleType.None) { maxSpeed *= 0.9f + vehicleRand * 0.4f; // a little variance, 0.9 .. 1.3 } maxSpeed = Math.Max(MIN_SPEED, maxSpeed); // at least 10 km/h return(maxSpeed); }
/// <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) == Vehicle.Flags.None) { 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 && realTimePositions[0].m_segment != 0) { // add traffic to lane uint laneId = PathManager.GetLaneID(realTimePositions[0]); //Log._Debug($"HandleVehicle: adding traffic to segment {realTimePositions[0].m_segment}, lane {realTimePositions[0].m_lane}"); CustomRoadAI.AddTraffic(laneId, Singleton <NetManager> .instance.m_segments.m_buffer[realTimePositions[0].m_segment].Info.m_lanes[realTimePositions[0].m_lane], (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) != Vehicle.Flags.None; 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) != Vehicle.Flags.None; 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 }
/// <summary> /// Determines the allowed vehicle types for the given segment and lane. /// </summary> /// <param name="segmentId"></param> /// <param name="laneIndex"></param> /// <param name="segmetnInfo"></param> /// <param name="laneInfo"></param> /// <returns></returns> internal static ExtVehicleType GetAllowedVehicleTypes(ushort segmentId, NetInfo segmentInfo, uint laneIndex, NetInfo.Lane laneInfo) { if (Flags.IsInitDone()) { ExtVehicleType?[] fastArray = Flags.laneAllowedVehicleTypesArray[segmentId]; if (fastArray != null && fastArray.Length > laneIndex && fastArray[laneIndex] != null) { return((ExtVehicleType)fastArray[laneIndex]); } } // manage cached default vehicle types if (defaultVehicleTypeCache == null) { defaultVehicleTypeCache = new ExtVehicleType?[NetManager.MAX_SEGMENT_COUNT][]; } ExtVehicleType?[] cachedDefaultTypes = defaultVehicleTypeCache[segmentId]; if (cachedDefaultTypes == null || cachedDefaultTypes.Length != segmentInfo.m_lanes.Length) { defaultVehicleTypeCache[segmentId] = cachedDefaultTypes = new ExtVehicleType?[segmentInfo.m_lanes.Length]; } ExtVehicleType?defaultVehicleType = cachedDefaultTypes[laneIndex]; if (defaultVehicleType == null) { ExtVehicleType ret = ExtVehicleType.None; if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Bicycle) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.Bicycle; } if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Tram) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.Tram; } if ((laneInfo.m_laneType & NetInfo.LaneType.TransportVehicle) != NetInfo.LaneType.None) { ret |= ExtVehicleType.RoadPublicTransport | ExtVehicleType.Emergency; } else if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Car) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.RoadVehicle; } if ((laneInfo.m_vehicleType & (VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Metro)) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.RailVehicle; } if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Ship) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.Ship; } if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Plane) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.Plane; } cachedDefaultTypes[laneIndex] = ret; return(ret); } else { return((ExtVehicleType)defaultVehicleType); } }
public static void setLaneAllowedVehicleTypes(ushort segmentId, uint laneIndex, uint laneId, ExtVehicleType vehicleTypes) { if (segmentId <= 0 || laneIndex < 0 || laneId <= 0) return; if ((Singleton<NetManager>.instance.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Created) == NetSegment.Flags.None) { return; } if (((NetLane.Flags)Singleton<NetManager>.instance.m_lanes.m_buffer[laneId].m_flags & NetLane.Flags.Created) == NetLane.Flags.None) return; NetInfo segmentInfo = Singleton<NetManager>.instance.m_segments.m_buffer[segmentId].Info; if (laneIndex >= segmentInfo.m_lanes.Length) { return; } try { Monitor.Enter(laneAllowedVehicleTypesLock); Log._Debug($"Flags.setLaneAllowedVehicleTypes: setting allowed vehicles of lane index {laneIndex} @ seg. {segmentId} to {vehicleTypes.ToString()}"); laneAllowedVehicleTypes[laneId] = vehicleTypes; // save allowed vehicle types into the fast-access array. // (1) ensure that the array is defined and large enough if (laneAllowedVehicleTypesArray[segmentId] == null) { laneAllowedVehicleTypesArray[segmentId] = new ExtVehicleType?[segmentInfo.m_lanes.Length]; } else if (laneAllowedVehicleTypesArray[segmentId].Length < segmentInfo.m_lanes.Length) { var oldArray = laneAllowedVehicleTypesArray[segmentId]; laneAllowedVehicleTypesArray[segmentId] = new ExtVehicleType?[segmentInfo.m_lanes.Length]; Array.Copy(oldArray, laneAllowedVehicleTypesArray[segmentId], oldArray.Length); } // (2) insert the custom speed limit laneAllowedVehicleTypesArray[segmentId][laneIndex] = vehicleTypes; } finally { Monitor.Exit(laneAllowedVehicleTypesLock); } }
/// <summary> /// Determines the default set of allowed vehicle types for a given segment and lane. /// </summary> /// <param name="segmentId"></param> /// <param name="segmentInfo"></param> /// <param name="laneIndex"></param> /// <param name="laneInfo"></param> /// <returns></returns> public static ExtVehicleType GetDefaultAllowedVehicleTypes(ushort segmentId, NetInfo segmentInfo, uint laneIndex, NetInfo.Lane laneInfo) { #if TRACE Singleton <CodeProfiler> .instance.Start("VehicleRestrictionsManager.GetDefaultAllowedVehicleTypes"); #endif // manage cached default vehicle types if (defaultVehicleTypeCache == null) { defaultVehicleTypeCache = new ExtVehicleType?[NetManager.MAX_SEGMENT_COUNT][]; } ExtVehicleType?[] cachedDefaultTypes = defaultVehicleTypeCache[segmentId]; if (cachedDefaultTypes == null || cachedDefaultTypes.Length != segmentInfo.m_lanes.Length) { defaultVehicleTypeCache[segmentId] = cachedDefaultTypes = new ExtVehicleType?[segmentInfo.m_lanes.Length]; } ExtVehicleType?defaultVehicleType = cachedDefaultTypes[laneIndex]; if (defaultVehicleType == null) { ExtVehicleType ret = ExtVehicleType.None; if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Bicycle) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.Bicycle; } if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Tram) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.Tram; } if ((laneInfo.m_laneType & NetInfo.LaneType.TransportVehicle) != NetInfo.LaneType.None) { ret |= ExtVehicleType.RoadPublicTransport | ExtVehicleType.Service | ExtVehicleType.Emergency; } else if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Car) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.RoadVehicle; } if ((laneInfo.m_vehicleType & (VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Metro)) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.RailVehicle; } if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Ship) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.Ship; } if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Plane) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.Plane; } cachedDefaultTypes[laneIndex] = ret; #if TRACE Singleton <CodeProfiler> .instance.Stop("VehicleRestrictionsManager.GetDefaultAllowedVehicleTypes"); #endif return(ret); } else { #if TRACE Singleton <CodeProfiler> .instance.Stop("VehicleRestrictionsManager.GetDefaultAllowedVehicleTypes"); #endif return((ExtVehicleType)defaultVehicleType); } }
private static void GetCustomTrafficLightState(ushort vehicleId, ref Vehicle vehicleData, ushort nodeId, ushort fromSegmentId, ushort toSegmentId, out RoadBaseAI.TrafficLightState vehicleLightState, out RoadBaseAI.TrafficLightState pedestrianLightState, TrafficLightSimulation nodeSim = null) { if (nodeSim == null) { nodeSim = TrafficLightSimulation.GetNodeSimulation(nodeId); if (nodeSim == null) { Log.Error($"GetCustomTrafficLightState: node traffic light simulation not found at node {nodeId}! Vehicle {vehicleId} comes from segment {fromSegmentId} and goes to node {nodeId}"); throw new ApplicationException($"GetCustomTrafficLightState: node traffic light simulation not found at node {nodeId}! Vehicle {vehicleId} comes from segment {fromSegmentId} and goes to node {nodeId}"); } } // get vehicle position /*VehiclePosition vehiclePos = TrafficPriority.GetVehiclePosition(vehicleId); * if (!vehiclePos.Valid || vehiclePos.FromSegment != fromSegmentId || vehiclePos.ToNode != nodeId) { * Log._Debug($"GetTrafficLightState: Recalculating position for vehicle {vehicleId}! FromSegment={vehiclePos.FromSegment} Valid={vehiclePos.Valid}"); * try { * HandleVehicle(vehicleId, ref Singleton<VehicleManager>.instance.m_vehicles.m_buffer[vehicleId], false, false); * } catch (Exception e) { * Log.Error("VehicleAI GetTrafficLightState Error: " + e.ToString()); * } * } * * if (!vehiclePos.Valid || vehiclePos.FromSegment != fromSegmentId || vehiclePos.ToNode != nodeId) { * Log.Warning($"GetTrafficLightState: Vehicle {vehicleId} is not moving at segment {fromSegmentId} to node {nodeId}! FromSegment={vehiclePos.FromSegment} ToNode={vehiclePos.ToNode} Valid={vehiclePos.Valid}"); * vehicleLightState = RoadBaseAI.TrafficLightState.Red; * pedestrianLightState = RoadBaseAI.TrafficLightState.Red; * return; * }*/ // get vehicle type ExtVehicleType?vehicleType = CustomVehicleAI.DetermineVehicleTypeFromVehicle(vehicleId, ref vehicleData); if (vehicleData.Info.m_vehicleType == VehicleInfo.VehicleType.Tram && vehicleType != ExtVehicleType.Tram) { Log.Warning($"vehicleType={vehicleType} ({(int)vehicleType}) for Tram"); } //Log._Debug($"GetCustomTrafficLightState: Vehicle {vehicleId} is a {vehicleType}"); if (vehicleType == null) { Log.Warning($"GetTrafficLightState: Could not determine vehicle type of vehicle {vehicleId}!"); vehicleLightState = RoadBaseAI.TrafficLightState.Red; pedestrianLightState = RoadBaseAI.TrafficLightState.Red; return; } // get responsible traffic light CustomSegmentLights lights = CustomTrafficLights.GetSegmentLights(nodeId, fromSegmentId); CustomSegmentLight light = lights == null ? null : lights.GetCustomLight((ExtVehicleType)vehicleType); if (lights == null || light == null) { Log.Warning($"GetTrafficLightState: No custom light for vehicleType {vehicleType} @ node {nodeId}, segment {fromSegmentId} found. lights null? {lights == null} light null? {light == null}"); vehicleLightState = RoadBaseAI.TrafficLightState.Red; pedestrianLightState = RoadBaseAI.TrafficLightState.Red; return; } SegmentGeometry geometry = CustomRoadAI.GetSegmentGeometry(fromSegmentId); // get traffic light state from responsible traffic light if (geometry.IsLeftSegment(toSegmentId, nodeId)) { vehicleLightState = light.GetLightLeft(); } else if (geometry.IsRightSegment(toSegmentId, nodeId)) { vehicleLightState = light.GetLightRight(); } else { vehicleLightState = light.GetLightMain(); } // get traffic lights state for pedestrians pedestrianLightState = (lights.PedestrianLightState != null) ? (RoadBaseAI.TrafficLightState)lights.PedestrianLightState : RoadBaseAI.TrafficLightState.Red; }
public bool IsBlimpAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.Blimp); }
public bool IsEmergencyAllowed(ExtVehicleType?allowedTypes) { return(IsAllowed(allowedTypes, ExtVehicleType.Emergency)); }
public bool IsCargoTrainAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.CargoTrain); }
public bool IsServiceAllowed(ExtVehicleType?allowedTypes) { return(IsAllowed(allowedTypes, ExtVehicleType.Service)); }
public bool IsPassengerCarAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.PassengerCar); }
public bool IsTramAllowed(ExtVehicleType?allowedTypes) { return(IsAllowed(allowedTypes, ExtVehicleType.Tram)); }
public bool IsRailVehicleAllowed(ExtVehicleType? allowedTypes) { return IsAllowed(allowedTypes, ExtVehicleType.RailVehicle); }
public bool IsFerryAllowed(ExtVehicleType?allowedTypes) { return(IsAllowed(allowedTypes, ExtVehicleType.Ferry)); }
internal ExtVehicleType OnStartPathFind(ushort vehicleId, ref Vehicle vehicleData, ExtVehicleType?vehicleType) { if ((vehicleData.Info.m_vehicleType & VEHICLE_TYPES) == VehicleInfo.VehicleType.None || (vehicleData.m_flags & (Vehicle.Flags.Created | Vehicle.Flags.Deleted)) != Vehicle.Flags.Created) { #if DEBUG if (GlobalConfig.Instance.Debug.Switches[9]) { Log._Debug($"VehicleStateManager.OnStartPathFind({vehicleId}, {vehicleType}): unhandled vehicle! type: {vehicleData.Info.m_vehicleType}"); } #endif return(ExtVehicleType.None); } /*ushort connectedVehicleId = vehicleId; * while (connectedVehicleId != 0) { #if DEBUG * if (GlobalConfig.Instance.Debug.Switches[9]) * Log._Debug($"VehicleStateManager.OnStartPathFind({vehicleId}, {vehicleType}): overriding vehicle type for connected vehicle {connectedVehicleId} of vehicle {vehicleId} (leading)"); #endif * VehicleStates[connectedVehicleId].vehicleType = type; * * connectedVehicleId = Singleton<VehicleManager>.instance.m_vehicles.m_buffer[connectedVehicleId].m_leadingVehicle; * }*/ ExtVehicleType ret = VehicleStates[vehicleId].OnStartPathFind(ref vehicleData, vehicleType); ushort connectedVehicleId = vehicleId; while (true) { connectedVehicleId = Singleton <VehicleManager> .instance.m_vehicles.m_buffer[connectedVehicleId].m_trailingVehicle; if (connectedVehicleId == 0) { break; } #if DEBUG if (GlobalConfig.Instance.Debug.Switches[9]) { Log._Debug($"VehicleStateManager.OnStartPathFind({vehicleId}, {vehicleType}): overriding vehicle type for connected vehicle {connectedVehicleId} of vehicle {vehicleId} (trailing)"); } #endif VehicleStates[connectedVehicleId].OnStartPathFind(ref Singleton <VehicleManager> .instance.m_vehicles.m_buffer[connectedVehicleId], vehicleType); } return(ret); }
public bool IsAllowed(ExtVehicleType?allowedTypes, ExtVehicleType vehicleType) { return(allowedTypes == null || ((ExtVehicleType)allowedTypes & vehicleType) != ExtVehicleType.None); }
// TODO improve & remove public void Housekeeping(bool mayDelete, bool calculateAutoPedLight) { // we intentionally never delete vehicle types (because we may want to retain traffic light states if a segment is upgraded or replaced) ICustomSegmentLight mainLight = MainSegmentLight; ushort nodeId = NodeId; HashSet <ExtVehicleType> setupLights = new HashSet <ExtVehicleType>(); // TODO improve IDictionary <byte, ExtVehicleType> allAllowedTypes = Constants.ManagerFactory.VehicleRestrictionsManager.GetAllowedVehicleTypesAsDict(SegmentId, nodeId, VehicleRestrictionsMode.Restricted); // TODO improve ExtVehicleType allAllowedMask = Constants.ManagerFactory.VehicleRestrictionsManager.GetAllowedVehicleTypes(SegmentId, nodeId, VehicleRestrictionsMode.Restricted); SeparateVehicleTypes = ExtVehicleType.None; #if DEBUGHK Log._Debug($"CustomSegmentLights: housekeeping @ seg. {SegmentId}, node {nodeId}, allAllowedTypes={string.Join(", ", allAllowedTypes.Select(x => x.ToString()).ToArray())}, allAllowedMask={allAllowedMask}"); #endif bool addPedestrianLight = false; uint numLights = 0; Constants.ServiceFactory.NetService.ProcessSegment(SegmentId, delegate(ushort segId, ref NetSegment segment) { VehicleTypeByLaneIndex = new ExtVehicleType?[segment.Info.m_lanes.Length]; return(true); }); HashSet <byte> laneIndicesWithoutSeparateLights = new HashSet <byte>(allAllowedTypes.Keys); // TODO improve foreach (KeyValuePair <byte, ExtVehicleType> e in allAllowedTypes) { byte laneIndex = e.Key; ExtVehicleType allowedTypes = e.Value; foreach (ExtVehicleType mask in SINGLE_LANE_VEHICLETYPES) { if (setupLights.Contains(mask)) { ++numLights; break; } if ((allowedTypes & mask) != ExtVehicleType.None && (allowedTypes & ~(mask | ExtVehicleType.Emergency)) == ExtVehicleType.None) { #if DEBUGHK Log._Debug($"CustomSegmentLights: housekeeping @ seg. {SegmentId}, node {nodeId}: adding {mask} light"); #endif ICustomSegmentLight segmentLight; if (!CustomLights.TryGetValue(mask, out segmentLight)) { segmentLight = new CustomSegmentLight(this, RoadBaseAI.TrafficLightState.Red); if (mainLight != null) { segmentLight.CurrentMode = mainLight.CurrentMode; segmentLight.SetStates(mainLight.LightMain, mainLight.LightLeft, mainLight.LightRight, false); } CustomLights.Add(mask, segmentLight); VehicleTypes.AddFirst(mask); } mainVehicleType = mask; VehicleTypeByLaneIndex[laneIndex] = mask; laneIndicesWithoutSeparateLights.Remove(laneIndex); ++numLights; addPedestrianLight = true; setupLights.Add(mask); SeparateVehicleTypes |= mask; break; } } } if (allAllowedTypes.Count > numLights) { #if DEBUGHK Log._Debug($"CustomSegmentLights: housekeeping @ seg. {SegmentId}, node {nodeId}: adding default main vehicle light: {DEFAULT_MAIN_VEHICLETYPE}"); #endif // traffic lights for cars ICustomSegmentLight defaultSegmentLight; if (!CustomLights.TryGetValue(DEFAULT_MAIN_VEHICLETYPE, out defaultSegmentLight)) { defaultSegmentLight = new CustomSegmentLight(this, RoadBaseAI.TrafficLightState.Red); if (mainLight != null) { defaultSegmentLight.CurrentMode = mainLight.CurrentMode; defaultSegmentLight.SetStates(mainLight.LightMain, mainLight.LightLeft, mainLight.LightRight, false); } CustomLights.Add(DEFAULT_MAIN_VEHICLETYPE, defaultSegmentLight); VehicleTypes.AddFirst(DEFAULT_MAIN_VEHICLETYPE); } mainVehicleType = DEFAULT_MAIN_VEHICLETYPE; foreach (byte laneIndex in laneIndicesWithoutSeparateLights) { VehicleTypeByLaneIndex[laneIndex] = ExtVehicleType.None; } addPedestrianLight = true; } else { addPedestrianLight = allAllowedMask == ExtVehicleType.None || (allAllowedMask & ~ExtVehicleType.RailVehicle) != ExtVehicleType.None; } if (mayDelete) { // delete traffic lights for non-existing configurations HashSet <ExtVehicleType> vehicleTypesToDelete = new HashSet <ExtVehicleType>(); foreach (KeyValuePair <ExtVehicleType, ICustomSegmentLight> e in CustomLights) { if (e.Key == DEFAULT_MAIN_VEHICLETYPE) { continue; } if (!setupLights.Contains(e.Key)) { vehicleTypesToDelete.Add(e.Key); } } foreach (ExtVehicleType vehicleType in vehicleTypesToDelete) { #if DEBUGHK Log._Debug($"Deleting traffic light for {vehicleType} at segment {SegmentId}, node {nodeId}"); #endif CustomLights.Remove(vehicleType); VehicleTypes.Remove(vehicleType); } } if (CustomLights.ContainsKey(DEFAULT_MAIN_VEHICLETYPE) && VehicleTypes.First.Value != DEFAULT_MAIN_VEHICLETYPE) { VehicleTypes.Remove(DEFAULT_MAIN_VEHICLETYPE); VehicleTypes.AddFirst(DEFAULT_MAIN_VEHICLETYPE); } if (addPedestrianLight) { #if DEBUGHK Log._Debug($"CustomSegmentLights: housekeeping @ seg. {SegmentId}, node {nodeId}: adding pedestrian light"); #endif if (InternalPedestrianLightState == null) { InternalPedestrianLightState = RoadBaseAI.TrafficLightState.Red; } } else { InternalPedestrianLightState = null; } OnChange(calculateAutoPedLight); #if DEBUGHK Log._Debug($"CustomSegmentLights: housekeeping @ seg. {SegmentId}, node {nodeId}: Housekeeping complete. VehicleTypeByLaneIndex={string.Join("; ", VehicleTypeByLaneIndex.Select(x => x == null ? "null" : x.ToString()).ToArray())} CustomLights={string.Join("; ", CustomLights.Select(x => x.Key.ToString()).ToArray())}"); #endif }
public bool IsBusAllowed(ExtVehicleType?allowedTypes) { return(IsAllowed(allowedTypes, ExtVehicleType.Bus)); }
internal static IDictionary <uint, ExtVehicleType> GetAllLaneAllowedVehicleTypes() { IDictionary <uint, ExtVehicleType> ret = new Dictionary <uint, ExtVehicleType>(); for (uint segmentId = 0; segmentId < NetManager.MAX_SEGMENT_COUNT; ++segmentId) { // Begin local function bool ForEachLane(ushort segId, ref NetSegment segment) { if ((segment.m_flags & (NetSegment.Flags.Created | NetSegment.Flags.Deleted)) != NetSegment.Flags.Created) { return(true); } ExtVehicleType?[] allowedTypes = laneAllowedVehicleTypesArray[segId]; if (allowedTypes == null) { return(true); } Constants.ServiceFactory.NetService.IterateSegmentLanes( segId, ref segment, (uint laneId, ref NetLane lane, NetInfo.Lane laneInfo, ushort sId, ref NetSegment seg, byte laneIndex) => { if (laneInfo.m_vehicleType == VehicleInfo.VehicleType.None) { return(true); } if (laneIndex >= allowedTypes.Length) { return(true); } ExtVehicleType?allowedType = allowedTypes[laneIndex]; if (allowedType == null) { return(true); } ret.Add(laneId, (ExtVehicleType)allowedType); return(true); }); return(true); } // ↑↑↑ // end local function Constants.ServiceFactory.NetService.ProcessSegment( (ushort)segmentId, ForEachLane); } return(ret); }
// PathFind protected void PathFindImplementation(uint unit, ref PathUnit data) { //pfCurrentState = 0; NetManager instance = Singleton<NetManager>.instance; this._laneTypes = (NetInfo.LaneType)this.PathUnits.m_buffer[(int)((UIntPtr)unit)].m_laneTypes; this._vehicleTypes = (VehicleInfo.VehicleType)this.PathUnits.m_buffer[(int)((UIntPtr)unit)].m_vehicleTypes; this._maxLength = this.PathUnits.m_buffer[(int)((UIntPtr)unit)].m_length; this._pathFindIndex = (this._pathFindIndex + 1u & 32767u); this._pathRandomizer = new Randomizer(unit); this._isHeavyVehicle = ((this.PathUnits.m_buffer[(int)((UIntPtr)unit)].m_simulationFlags & 16) != 0); this._ignoreBlocked = ((this.PathUnits.m_buffer[(int)((UIntPtr)unit)].m_simulationFlags & 32) != 0); this._stablePath = ((this.PathUnits.m_buffer[(int)((UIntPtr)unit)].m_simulationFlags & 64) != 0); this._transportVehicle = ((byte)(this._laneTypes & NetInfo.LaneType.TransportVehicle) != 0); this._extVehicleType = pathUnitExtVehicleType[unit]; if ((byte)(this._laneTypes & NetInfo.LaneType.Vehicle) != 0) { this._laneTypes |= NetInfo.LaneType.TransportVehicle; } int num = (int)(this.PathUnits.m_buffer[(int)((UIntPtr)unit)].m_positionCount & 15); int num2 = this.PathUnits.m_buffer[(int)((UIntPtr)unit)].m_positionCount >> 4; BufferItem bufferItemStartA; if (data.m_position00.m_segment != 0 && num >= 1) { this._startLaneA = PathManager.GetLaneID(data.m_position00); this._startOffsetA = data.m_position00.m_offset; bufferItemStartA.m_laneID = this._startLaneA; bufferItemStartA.m_position = data.m_position00; this.GetLaneDirection(data.m_position00, out bufferItemStartA.m_direction, out bufferItemStartA.m_lanesUsed); bufferItemStartA.m_comparisonValue = 0f; } else { this._startLaneA = 0u; this._startOffsetA = 0; bufferItemStartA = default(BufferItem); } BufferItem bufferItemStartB; if (data.m_position02.m_segment != 0 && num >= 3) { this._startLaneB = PathManager.GetLaneID(data.m_position02); this._startOffsetB = data.m_position02.m_offset; bufferItemStartB.m_laneID = this._startLaneB; bufferItemStartB.m_position = data.m_position02; this.GetLaneDirection(data.m_position02, out bufferItemStartB.m_direction, out bufferItemStartB.m_lanesUsed); bufferItemStartB.m_comparisonValue = 0f; } else { this._startLaneB = 0u; this._startOffsetB = 0; bufferItemStartB = default(BufferItem); } BufferItem bufferItemEndA; if (data.m_position01.m_segment != 0 && num >= 2) { this._endLaneA = PathManager.GetLaneID(data.m_position01); bufferItemEndA.m_laneID = this._endLaneA; bufferItemEndA.m_position = data.m_position01; this.GetLaneDirection(data.m_position01, out bufferItemEndA.m_direction, out bufferItemEndA.m_lanesUsed); bufferItemEndA.m_methodDistance = 0f; bufferItemEndA.m_comparisonValue = 0f; } else { this._endLaneA = 0u; bufferItemEndA = default(BufferItem); } BufferItem bufferItemEndB; if (data.m_position03.m_segment != 0 && num >= 4) { this._endLaneB = PathManager.GetLaneID(data.m_position03); bufferItemEndB.m_laneID = this._endLaneB; bufferItemEndB.m_position = data.m_position03; this.GetLaneDirection(data.m_position03, out bufferItemEndB.m_direction, out bufferItemEndB.m_lanesUsed); bufferItemEndB.m_methodDistance = 0f; bufferItemEndB.m_comparisonValue = 0f; } else { this._endLaneB = 0u; bufferItemEndB = default(BufferItem); } if (data.m_position11.m_segment != 0 && num2 >= 1) { this._vehicleLane = PathManager.GetLaneID(data.m_position11); this._vehicleOffset = data.m_position11.m_offset; } else { this._vehicleLane = 0u; this._vehicleOffset = 0; } BufferItem finalBufferItem = default(BufferItem); byte startOffset = 0; this._bufferMinPos = 0; this._bufferMaxPos = -1; if (this._pathFindIndex == 0u) { uint num3 = 4294901760u; for (int i = 0; i < 262144; i++) { this._laneLocation[i] = num3; } } for (int j = 0; j < 1024; j++) { this._bufferMin[j] = 0; this._bufferMax[j] = -1; } if (bufferItemEndA.m_position.m_segment != 0) { this._bufferMax[0]++; this._buffer[++this._bufferMaxPos] = bufferItemEndA; } if (bufferItemEndB.m_position.m_segment != 0) { this._bufferMax[0]++; this._buffer[++this._bufferMaxPos] = bufferItemEndB; } bool canFindPath = false; #if DEBUGPF uint wIter = 0; #endif //Log.Message($"THREAD #{Thread.CurrentThread.ManagedThreadId} PF {this._pathFindIndex}: STARTING MAIN LOOP! bufferMinPos: {this._bufferMinPos}, bufferMaxPos: {this._bufferMaxPos}, startA: {bufferItemStartA.m_position.m_segment}, startB: {bufferItemStartB.m_position.m_segment}, endA: {bufferItemEndA.m_position.m_segment}, endB: {bufferItemEndB.m_position.m_segment}"); while (this._bufferMinPos <= this._bufferMaxPos) { //pfCurrentState = 1; #if DEBUGPF /*if (m_queuedPathFindCount > 100 && Options.disableSomething1) Log._Debug($"THREAD #{Thread.CurrentThread.ManagedThreadId} PF {this._pathFindIndex}: MAIN LOOP RUNNING! bufferMinPos: {this._bufferMinPos}, bufferMaxPos: {this._bufferMaxPos}, startA: {bufferItemStartA.m_position.m_segment}, startB: {bufferItemStartB.m_position.m_segment}, endA: {bufferItemEndA.m_position.m_segment}, endB: {bufferItemEndB.m_position.m_segment}");*/ #endif int num4 = this._bufferMin[this._bufferMinPos]; int num5 = this._bufferMax[this._bufferMinPos]; if (num4 > num5) { this._bufferMinPos++; } else { this._bufferMin[this._bufferMinPos] = num4 + 1; BufferItem candidateItem = this._buffer[(this._bufferMinPos << 6) + num4]; if (candidateItem.m_position.m_segment == bufferItemStartA.m_position.m_segment && candidateItem.m_position.m_lane == bufferItemStartA.m_position.m_lane) { // we reached startA if ((byte)(candidateItem.m_direction & NetInfo.Direction.Forward) != 0 && candidateItem.m_position.m_offset >= this._startOffsetA) { finalBufferItem = candidateItem; startOffset = this._startOffsetA; canFindPath = true; break; } if ((byte)(candidateItem.m_direction & NetInfo.Direction.Backward) != 0 && candidateItem.m_position.m_offset <= this._startOffsetA) { finalBufferItem = candidateItem; startOffset = this._startOffsetA; canFindPath = true; break; } } if (candidateItem.m_position.m_segment == bufferItemStartB.m_position.m_segment && candidateItem.m_position.m_lane == bufferItemStartB.m_position.m_lane) { // we reached startB if ((byte)(candidateItem.m_direction & NetInfo.Direction.Forward) != 0 && candidateItem.m_position.m_offset >= this._startOffsetB) { finalBufferItem = candidateItem; startOffset = this._startOffsetB; canFindPath = true; break; } if ((byte)(candidateItem.m_direction & NetInfo.Direction.Backward) != 0 && candidateItem.m_position.m_offset <= this._startOffsetB) { finalBufferItem = candidateItem; startOffset = this._startOffsetB; canFindPath = true; break; } } // explore the path if ((byte)(candidateItem.m_direction & NetInfo.Direction.Forward) != 0) { ushort startNode = instance.m_segments.m_buffer[(int)candidateItem.m_position.m_segment].m_startNode; this.ProcessItemMain(unit, candidateItem, startNode, ref instance.m_nodes.m_buffer[(int)startNode], 0, false); } if ((byte)(candidateItem.m_direction & NetInfo.Direction.Backward) != 0) { ushort endNode = instance.m_segments.m_buffer[(int)candidateItem.m_position.m_segment].m_endNode; this.ProcessItemMain(unit, candidateItem, endNode, ref instance.m_nodes.m_buffer[(int)endNode], 255, false); } // handle special nodes (e.g. bus stops) int num6 = 0; ushort specialNodeId = instance.m_lanes.m_buffer[(int)((UIntPtr)candidateItem.m_laneID)].m_nodes; if (specialNodeId != 0) { ushort startNode2 = instance.m_segments.m_buffer[(int)candidateItem.m_position.m_segment].m_startNode; ushort endNode2 = instance.m_segments.m_buffer[(int)candidateItem.m_position.m_segment].m_endNode; bool flag2 = ((instance.m_nodes.m_buffer[(int)startNode2].m_flags | instance.m_nodes.m_buffer[(int)endNode2].m_flags) & NetNode.Flags.Disabled) != NetNode.Flags.None; while (specialNodeId != 0) { NetInfo.Direction direction = NetInfo.Direction.None; byte laneOffset = instance.m_nodes.m_buffer[(int)specialNodeId].m_laneOffset; if (laneOffset <= candidateItem.m_position.m_offset) { direction |= NetInfo.Direction.Forward; } if (laneOffset >= candidateItem.m_position.m_offset) { direction |= NetInfo.Direction.Backward; } if ((byte)(candidateItem.m_direction & direction) != 0 && (!flag2 || (instance.m_nodes.m_buffer[(int)specialNodeId].m_flags & NetNode.Flags.Disabled) != NetNode.Flags.None)) { this.ProcessItemMain(unit, candidateItem, specialNodeId, ref instance.m_nodes.m_buffer[(int)specialNodeId], laneOffset, true); } specialNodeId = instance.m_nodes.m_buffer[(int)specialNodeId].m_nextLaneNode; if (++num6 == 32768) { Log.Warning("Special loop: Too many iterations"); break; } } } } #if DEBUGPF ++wIter; if (wIter > 1000000) { Log.Error("Too many iterations in PathFindImpl."); break; } #endif } //pfCurrentState = 2; /*if (m_queuedPathFindCount > 100 && Options.disableSomething0) Log.Message($"THREAD #{Thread.CurrentThread.ManagedThreadId} PF {this._pathFindIndex}: MAIN LOOP FINISHED! bufferMinPos: {this._bufferMinPos}, bufferMaxPos: {this._bufferMaxPos}, startA: {bufferItemStartA.m_position.m_segment}, startB: {bufferItemStartB.m_position.m_segment}, endA: {bufferItemEndA.m_position.m_segment}, endB: {bufferItemEndB.m_position.m_segment}");*/ if (!canFindPath) { // we could not find a path //pfCurrentState = 3; PathUnits.m_buffer[(int)unit].m_pathFindFlags = (byte)(PathUnits.m_buffer[(int)((UIntPtr)unit)].m_pathFindFlags | 8); #if DEBUG ++_failedPathFinds; //Log._Debug($"THREAD #{Thread.CurrentThread.ManagedThreadId} PF {this._pathFindIndex}: Cannot find path (pfCurrentState={pfCurrentState}) for unit {unit}"); #endif pathUnitExtVehicleType[unit] = null; /*PathUnit[] expr_909_cp_0 = this._pathUnits.m_buffer; UIntPtr expr_909_cp_1 = (UIntPtr)unit; expr_909_cp_0[(int)expr_909_cp_1].m_pathFindFlags = (byte)(expr_909_cp_0[(int)expr_909_cp_1].m_pathFindFlags | 8);*/ return; } // we could calculate a valid path //pfCurrentState = 4; float totalPathLength = finalBufferItem.m_comparisonValue * this._maxLength; this.PathUnits.m_buffer[(int)((UIntPtr)unit)].m_length = totalPathLength; uint currentPathUnitId = unit; int currentItemPositionCount = 0; int sumOfPositionCounts = 0; PathUnit.Position currentPosition = finalBufferItem.m_position; if ((currentPosition.m_segment != bufferItemEndA.m_position.m_segment || currentPosition.m_lane != bufferItemEndA.m_position.m_lane || currentPosition.m_offset != bufferItemEndA.m_position.m_offset) && (currentPosition.m_segment != bufferItemEndB.m_position.m_segment || currentPosition.m_lane != bufferItemEndB.m_position.m_lane || currentPosition.m_offset != bufferItemEndB.m_position.m_offset)) { // the found starting position differs from the desired end position if (startOffset != currentPosition.m_offset) { // the offsets differ: copy the found starting position and modify the offset to fit the desired offset PathUnit.Position position2 = currentPosition; position2.m_offset = startOffset; this.PathUnits.m_buffer[(int)((UIntPtr)currentPathUnitId)].SetPosition(currentItemPositionCount++, position2); // now we have: [desired starting position] } // add the found starting position to the path unit this.PathUnits.m_buffer[(int)((UIntPtr)currentPathUnitId)].SetPosition(currentItemPositionCount++, currentPosition); currentPosition = this._laneTarget[(int)((UIntPtr)finalBufferItem.m_laneID)]; // go to the next path position // now we have either [desired starting position, found starting position] or [found starting position], depending on if the found starting position matched the desired } //pfCurrentState = 5; // beginning with the starting position, going to the target position: assemble the path units for (int k = 0; k < 262144; k++) { //pfCurrentState = 6; this.PathUnits.m_buffer[(int)((UIntPtr)currentPathUnitId)].SetPosition(currentItemPositionCount++, currentPosition); // add the next path position to the current unit if ((currentPosition.m_segment == bufferItemEndA.m_position.m_segment && currentPosition.m_lane == bufferItemEndA.m_position.m_lane && currentPosition.m_offset == bufferItemEndA.m_position.m_offset) || (currentPosition.m_segment == bufferItemEndB.m_position.m_segment && currentPosition.m_lane == bufferItemEndB.m_position.m_lane && currentPosition.m_offset == bufferItemEndB.m_position.m_offset)) { // we have reached the end position this.PathUnits.m_buffer[(int)((UIntPtr)currentPathUnitId)].m_positionCount = (byte)currentItemPositionCount; sumOfPositionCounts += currentItemPositionCount; // add position count of last unit to sum if (sumOfPositionCounts != 0) { // for each path unit from start to target: calculate length (distance) to target currentPathUnitId = this.PathUnits.m_buffer[(int)((UIntPtr)unit)].m_nextPathUnit; // (we do not need to calculate the length for the starting unit since this is done before; it's the total path length) currentItemPositionCount = (int)this.PathUnits.m_buffer[(int)((UIntPtr)unit)].m_positionCount; int totalIter = 0; while (currentPathUnitId != 0u) { //pfCurrentState = 7; this.PathUnits.m_buffer[(int)((UIntPtr)currentPathUnitId)].m_length = totalPathLength * (float)(sumOfPositionCounts - currentItemPositionCount) / (float)sumOfPositionCounts; currentItemPositionCount += (int)this.PathUnits.m_buffer[(int)((UIntPtr)currentPathUnitId)].m_positionCount; currentPathUnitId = this.PathUnits.m_buffer[(int)((UIntPtr)currentPathUnitId)].m_nextPathUnit; if (++totalIter >= 262144) { #if DEBUG Log.Error("THREAD #{Thread.CurrentThread.ManagedThreadId} PF {this._pathFindIndex}: PathFindImplementation: Invalid list detected."); #endif CODebugBase<LogChannel>.Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } } #if DEBUG //Log._Debug($"THREAD #{Thread.CurrentThread.ManagedThreadId} PF {this._pathFindIndex}: Path found (pfCurrentState={pfCurrentState}) for unit {unit}"); #endif PathUnits.m_buffer[(int)unit].m_pathFindFlags = (byte)(PathUnits.m_buffer[(int)((UIntPtr)unit)].m_pathFindFlags | 4); // Path found #if DEBUG ++_succeededPathFinds; pathUnitExtVehicleType[unit] = null; #endif return; } // We have not reached the target position yet if (currentItemPositionCount == 12) { // the current path unit is full, we need a new one //pfCurrentState = 8; uint createdPathUnitId; try { Monitor.Enter(this._bufferLock); //pfCurrentState = 10; if (!this.PathUnits.CreateItem(out createdPathUnitId, ref this._pathRandomizer)) { // we failed to create a new path unit, thus the path-finding also failed PathUnits.m_buffer[(int)((UIntPtr)unit)].m_pathFindFlags = (byte)(PathUnits.m_buffer[(int)unit].m_pathFindFlags | 8); #if DEBUG ++_failedPathFinds; //Log._Debug($"THREAD #{Thread.CurrentThread.ManagedThreadId} PF {this._pathFindIndex}: Cannot find path (pfCurrentState={pfCurrentState}) for unit {unit}"); #endif pathUnitExtVehicleType[unit] = null; return; } this.PathUnits.m_buffer[(int)((UIntPtr)createdPathUnitId)] = this.PathUnits.m_buffer[(int)currentPathUnitId]; this.PathUnits.m_buffer[(int)((UIntPtr)createdPathUnitId)].m_referenceCount = 1; this.PathUnits.m_buffer[(int)((UIntPtr)createdPathUnitId)].m_pathFindFlags = 4; this.PathUnits.m_buffer[(int)((UIntPtr)currentPathUnitId)].m_nextPathUnit = createdPathUnitId; this.PathUnits.m_buffer[(int)((UIntPtr)currentPathUnitId)].m_positionCount = (byte)currentItemPositionCount; sumOfPositionCounts += currentItemPositionCount; Singleton<PathManager>.instance.m_pathUnitCount = (int)(this.PathUnits.ItemCount() - 1u); } catch (Exception e) { Log.Error("CustomPathFind.PathFindImplementation Error: " + e.ToString()); break; } finally { Monitor.Exit(this._bufferLock); } currentPathUnitId = createdPathUnitId; currentItemPositionCount = 0; } uint laneID = PathManager.GetLaneID(currentPosition); // NON-STOCK CODE START CustomRoadAI.AddTraffic(laneID, (ushort)(this._isHeavyVehicle || _extVehicleType == ExtVehicleType.Bus ? 50 : 25), (ushort)GetLaneSpeedLimit(currentPosition.m_segment, currentPosition.m_lane, laneID, Singleton<NetManager>.instance.m_segments.m_buffer[currentPosition.m_segment].Info.m_lanes[currentPosition.m_lane]), false); //SpeedLimitManager.GetLockFreeGameSpeedLimit(currentPosition.m_segment, currentPosition.m_lane, laneID, ref Singleton<NetManager>.instance.m_segments.m_buffer[currentPosition.m_segment].Info.m_lanes[currentPosition.m_lane]) // NON-STOCK CODE END currentPosition = this._laneTarget[(int)((UIntPtr)laneID)]; } PathUnits.m_buffer[(int)((UIntPtr)unit)].m_pathFindFlags = (byte)(PathUnits.m_buffer[(int)unit].m_pathFindFlags | 8); #if DEBUG ++_failedPathFinds; #endif pathUnitExtVehicleType[unit] = null; #if DEBUG //Log._Debug($"THREAD #{Thread.CurrentThread.ManagedThreadId} PF {this._pathFindIndex}: Cannot find path (pfCurrentState={pfCurrentState}) for unit {unit}"); #endif }
/// <summary> /// Calculates for each segment the number of cars going to this segment. /// We use integer arithmetic for better performance. /// </summary> public Dictionary <ushort, uint> GetVehicleMetricGoingToSegment(float?minSpeed, ExtVehicleType?vehicleTypes = null, ExtVehicleType separateVehicleTypes = ExtVehicleType.None, bool debug = false) { Dictionary <ushort, uint> numCarsGoingToSegmentId = new Dictionary <ushort, uint>(); VehicleManager vehicleManager = Singleton <VehicleManager> .instance; NetManager netManager = Singleton <NetManager> .instance; for (var s = 0; s < 8; s++) { var segmentId = netManager.m_nodes.m_buffer[NodeId].GetSegment(s); if (segmentId == 0 || segmentId == SegmentId) { continue; } if (CustomRoadAI.GetSegmentGeometry(segmentId).IsIncomingOneWay(NodeId)) { continue; } numCarsGoingToSegmentId[segmentId] = 0; } List <ushort> vehicleIdsToReHandle = new List <ushort>(); foreach (KeyValuePair <ushort, VehiclePosition> e in Vehicles) { var vehicleId = e.Key; var carPos = e.Value; if (vehicleId <= 0 || carPos.ToSegment <= 0) { continue; } if ((vehicleManager.m_vehicles.m_buffer[vehicleId].m_flags & Vehicle.Flags.Created) == Vehicle.Flags.None) { vehicleIdsToReHandle.Add(vehicleId); continue; } if (minSpeed != null && vehicleManager.m_vehicles.m_buffer[vehicleId].GetLastFrameVelocity().magnitude < minSpeed) { continue; } VehiclePosition globalPos = TrafficPriority.GetVehiclePosition(vehicleId); if (globalPos == null || !globalPos.Valid || globalPos.LastFrame >> 7 < Singleton <SimulationManager> .instance.m_currentFrameIndex >> 7) // ~64 sec. { vehicleIdsToReHandle.Add(vehicleId); continue; } if (vehicleTypes != null) { if (vehicleTypes == ExtVehicleType.None) { if ((globalPos.VehicleType & separateVehicleTypes) != ExtVehicleType.None) { // we want all vehicles that do not have separate traffic lights continue; } } else { if ((globalPos.VehicleType & vehicleTypes) == ExtVehicleType.None) { continue; } } } //debug = vehicleManager.m_vehicles.m_buffer[vehicleId].Info.m_vehicleType == VehicleInfo.VehicleType.Tram; #if DEBUG /*if (debug) { * Log._Debug($"getNumCarsGoingToSegment: Handling vehicle {vehicleId} going from {carPos.FromSegment}/{SegmentId} to {carPos.ToSegment}. carState={globalPos.CarState}. lastUpdate={globalPos.LastCarStateUpdate}"); * }*/ #endif uint avgSegmentLength = (uint)Singleton <NetManager> .instance.m_segments.m_buffer[SegmentId].m_averageLength; uint normLength = (uint)(vehicleManager.m_vehicles.m_buffer[vehicleId].CalculateTotalLength(vehicleId) * 100u) / avgSegmentLength; #if DEBUG /*if (debug) { * Log._Debug($"getNumCarsGoingToSegment: NormLength of vehicle {vehicleId} going to {carPos.ToSegment}: {avgSegmentLength} -> {normLength}"); * }*/ #endif if (numCarsGoingToSegmentId.ContainsKey(carPos.ToSegment)) { /*if (carPos.OnEmergency) * numCarsGoingToSegmentId[carPos.ToSegment] += 10000f; * else*/ numCarsGoingToSegmentId[carPos.ToSegment] += normLength; } // "else" must not happen (incoming one-way) } foreach (ushort vehicleId in vehicleIdsToReHandle) { CustomVehicleAI.HandleVehicle(vehicleId, ref Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleId], false, false); } return(numCarsGoingToSegmentId); }