public bool CreatePath(ExtVehicleType vehicleType, out uint unit, ref Randomizer randomizer, uint buildIndex, PathUnit.Position startPosA, PathUnit.Position startPosB, PathUnit.Position endPosA, PathUnit.Position endPosB, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, float maxLength, bool isHeavyVehicle, bool ignoreBlocked, bool stablePath, bool skipQueue) { return(this.CreatePath(vehicleType, out unit, ref randomizer, buildIndex, startPosA, startPosB, endPosA, endPosB, default(PathUnit.Position), laneTypes, vehicleTypes, maxLength, isHeavyVehicle, ignoreBlocked, stablePath, skipQueue)); }
public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays, bool undergroundTarget) { #if DEBUG //Log._Debug($"CustomCargoTruckAI.CustomStartPathFind called for vehicle {vehicleID}"); #endif if ((vehicleData.m_flags & (Vehicle.Flags.TransferToSource | Vehicle.Flags.GoingBack)) != 0) { return(base.StartPathFind(vehicleID, ref vehicleData, startPos, endPos, startBothWays, endBothWays, undergroundTarget)); } bool allowUnderground = (vehicleData.m_flags & (Vehicle.Flags.Underground | Vehicle.Flags.Transition)) != 0; PathUnit.Position startPosA; PathUnit.Position startPosB; float num; float num2; bool startPosFound = CustomPathManager.FindPathPosition(startPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, VehicleInfo.VehicleType.Car, allowUnderground, false, 32f, out startPosA, out startPosB, out num, out num2); PathUnit.Position position; PathUnit.Position position2; float num3; float num4; if (CustomPathManager.FindPathPosition(startPos, ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Ship, allowUnderground, false, 32f, out position, out position2, out num3, out num4)) { if (!startPosFound || num3 < num) { startPosA = position; startPosB = position2; num = num3; num2 = num4; } startPosFound = true; } PathUnit.Position endPosA; PathUnit.Position endPosB; float num5; float num6; bool endPosFound = CustomPathManager.FindPathPosition(endPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, VehicleInfo.VehicleType.Car, undergroundTarget, false, 32f, out endPosA, out endPosB, out num5, out num6); PathUnit.Position position3; PathUnit.Position position4; float num7; float num8; if (CustomPathManager.FindPathPosition(endPos, ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Ship, undergroundTarget, false, 32f, out position3, out position4, out num7, out num8)) { if (!endPosFound || num7 < num5) { endPosA = position3; endPosB = position4; num5 = num7; num6 = num8; } endPosFound = true; } if (startPosFound && endPosFound) { CustomPathManager instance = Singleton <CustomPathManager> .instance; if (!startBothWays || num < 10f) { startPosB = default(PathUnit.Position); } if (!endBothWays || num5 < 10f) { endPosB = default(PathUnit.Position); } NetInfo.LaneType laneTypes = NetInfo.LaneType.Vehicle | NetInfo.LaneType.CargoVehicle; VehicleInfo.VehicleType vehicleTypes = VehicleInfo.VehicleType.Car | VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Ship; uint path; if (instance.CreatePath(ExtVehicleType.CargoVehicle, vehicleID, out path, ref Singleton <SimulationManager> .instance.m_randomizer, Singleton <SimulationManager> .instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, laneTypes, vehicleTypes, 20000f, this.IsHeavyVehicle(), this.IgnoreBlocked(vehicleID, ref vehicleData), false, false)) { #if USEPATHWAITCOUNTER VehicleState state = VehicleStateManager.Instance()._GetVehicleState(vehicleID); state.PathWaitCounter = 0; #endif if (vehicleData.m_path != 0u) { instance.ReleasePath(vehicleData.m_path); } vehicleData.m_path = path; vehicleData.m_flags |= Vehicle.Flags.WaitingPath; return(true); } } return(false); }
public bool StartPathFind2(ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays) { if ((vehicleData.m_flags & (Vehicle.Flags.TransferToSource | Vehicle.Flags.GoingBack)) != Vehicle.Flags.None) { return(base.StartPathFind(vehicleID, ref vehicleData, startPos, endPos, startBothWays, endBothWays)); } PathUnit.Position startPosA; PathUnit.Position startPosB; float num; float num2; bool flag = PathManager.FindPathPosition(startPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Car, 32f, out startPosA, out startPosB, out num, out num2); PathUnit.Position position; PathUnit.Position position2; float num3; float num4; if (PathManager.FindPathPosition(startPos, ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Ship, 32f, out position, out position2, out num3, out num4)) { if (!flag || num3 < num) { startPosA = position; startPosB = position2; num = num3; num2 = num4; } flag = true; } PathUnit.Position endPosA; PathUnit.Position endPosB; float num5; float num6; bool flag2 = PathManager.FindPathPosition(endPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Car, 32f, out endPosA, out endPosB, out num5, out num6); PathUnit.Position position3; PathUnit.Position position4; float num7; float num8; if (PathManager.FindPathPosition(endPos, ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Ship, 32f, out position3, out position4, out num7, out num8)) { if (!flag2 || num7 < num5) { endPosA = position3; endPosB = position4; num5 = num7; num6 = num8; } flag2 = true; } if (flag && flag2) { CustomPathManager instance = Singleton <CustomPathManager> .instance; if (!startBothWays || num < 10f) { startPosB = default(PathUnit.Position); } if (!endBothWays || num5 < 10f) { endPosB = default(PathUnit.Position); } NetInfo.LaneType laneTypes = NetInfo.LaneType.Vehicle | NetInfo.LaneType.Cargo; VehicleInfo.VehicleType vehicleTypes = VehicleInfo.VehicleType.Car | VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Ship; uint path; if (instance.CreatePath(out path, ref Singleton <SimulationManager> .instance.m_randomizer, Singleton <SimulationManager> .instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, laneTypes, vehicleTypes, 20000f, this.IsHeavyVehicle(), this.IgnoreBlocked(vehicleID, ref vehicleData), false, false, ItemClass.Service.Industrial)) { if (vehicleData.m_path != 0u) { instance.ReleasePath(vehicleData.m_path); } vehicleData.m_path = path; vehicleData.m_flags |= Vehicle.Flags.WaitingPath; return(true); } } return(false); }
public override bool AllowVehicleType(VehicleInfo.VehicleType type, OutsideConnectionAI ai) => type == VehicleInfo.VehicleType.Train || type == VehicleInfo.VehicleType.Car || type == VehicleInfo.VehicleType.Ship || type == VehicleInfo.VehicleType.Plane;
public override bool AllowVehicleType(VehicleInfo.VehicleType type, DisasterResponseBuildingAI ai) => type == VehicleInfo.VehicleType.Car || type == VehicleInfo.VehicleType.Helicopter;
public override bool AllowVehicleType(VehicleInfo.VehicleType type, LandfillSiteAI ai) => type == VehicleInfo.VehicleType.Car;
public override string GetVehicleMaxCountField(VehicleInfo.VehicleType veh) => "m_maxVehicleCount";
public override bool AllowVehicleType(VehicleInfo.VehicleType type, CemeteryAI ai) => type == VehicleInfo.VehicleType.Car;
public override string GetVehicleMaxCountField(VehicleInfo.VehicleType veh) => "m_helicopterCount";
public bool FindPathPositionWithSpiralLoop(Vector3 position, Vector3?secondaryPosition, ItemClass.Service service, NetInfo.LaneType laneType, VehicleInfo.VehicleType vehicleType, NetInfo.LaneType otherLaneType, VehicleInfo.VehicleType otherVehicleType, VehicleInfo.VehicleType stopType, bool allowUnderground, bool requireConnect, float maxDistance, out PathUnit.Position pathPosA, out PathUnit.Position pathPosB, out float distanceSqrA, out float distanceSqrB) { int iMin = Mathf.Max( (int)(((position.z - NetManager.NODEGRID_CELL_SIZE) / NetManager.NODEGRID_CELL_SIZE) + (NetManager.NODEGRID_RESOLUTION / 2f)), 0); int iMax = Mathf.Min( (int)(((position.z + NetManager.NODEGRID_CELL_SIZE) / NetManager.NODEGRID_CELL_SIZE) + (NetManager.NODEGRID_RESOLUTION / 2f)), NetManager.NODEGRID_RESOLUTION - 1); int jMin = Mathf.Max( (int)(((position.x - NetManager.NODEGRID_CELL_SIZE) / NetManager.NODEGRID_CELL_SIZE) + (NetManager.NODEGRID_RESOLUTION / 2f)), 0); int jMax = Mathf.Min( (int)(((position.x + NetManager.NODEGRID_CELL_SIZE) / NetManager.NODEGRID_CELL_SIZE) + (NetManager.NODEGRID_RESOLUTION / 2f)), NetManager.NODEGRID_RESOLUTION - 1); int width = iMax - iMin + 1; int height = jMax - jMin + 1; int centerI = (int)(position.z / NetManager.NODEGRID_CELL_SIZE + NetManager.NODEGRID_RESOLUTION / 2f); int centerJ = (int)(position.x / NetManager.NODEGRID_CELL_SIZE + NetManager.NODEGRID_RESOLUTION / 2f); int radius = Math.Max(1, (int)(maxDistance / (BuildingManager.BUILDINGGRID_CELL_SIZE / 2f)) + 1); NetManager netManager = Singleton <NetManager> .instance; /*pathPosA.m_segment = 0; * pathPosA.m_lane = 0; * pathPosA.m_offset = 0;*/ distanceSqrA = 1E+10f; /*pathPosB.m_segment = 0; * pathPosB.m_lane = 0; * pathPosB.m_offset = 0;*/ distanceSqrB = 1E+10f; float minDist = float.MaxValue; PathUnit.Position myPathPosA = default; float myDistanceSqrA = float.MaxValue; PathUnit.Position myPathPosB = default; float myDistanceSqrB = float.MaxValue; int lastSpiralDist = 0; bool found = false; bool FindHelper(int i, int j) { if (i < 0 || i >= NetManager.NODEGRID_RESOLUTION || j < 0 || j >= NetManager.NODEGRID_RESOLUTION) { return(true); } int spiralDist = Math.Max(Math.Abs(i - centerI), Math.Abs(j - centerJ)); // maximum norm if (found && spiralDist > lastSpiralDist) { // last iteration return(false); } ushort segmentId = netManager.m_segmentGrid[i * NetManager.NODEGRID_RESOLUTION + j]; int iterations = 0; ExtSegmentManager extSegmentManager = ExtSegmentManager.Instance; while (segmentId != 0) { ref NetSegment netSegment = ref segmentId.ToSegment(); NetInfo segmentInfo = netSegment.Info; if (segmentInfo != null && segmentInfo.m_class.m_service == service && (netSegment.m_flags & (NetSegment.Flags.Collapsed | NetSegment.Flags.Flooded)) == NetSegment.Flags.None && (allowUnderground || !segmentInfo.m_netAI.IsUnderground())) { bool otherPassed = true; if (otherLaneType != NetInfo.LaneType.None || otherVehicleType != VehicleInfo.VehicleType.None) { // check if any lane is present that matches the given conditions otherPassed = false; foreach (LaneIdAndIndex laneIdAndIndex in extSegmentManager.GetSegmentLaneIdsAndLaneIndexes(segmentId)) { NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIdAndIndex.laneIndex]; if ((otherLaneType == NetInfo.LaneType.None || (laneInfo.m_laneType & otherLaneType) != NetInfo.LaneType.None) && (otherVehicleType == VehicleInfo.VehicleType.None || (laneInfo.m_vehicleType & otherVehicleType) != VehicleInfo.VehicleType.None)) { otherPassed = true; break; } } } if (otherPassed) { if (netSegment.GetClosestLanePosition( position, laneType, vehicleType, stopType, requireConnect, out Vector3 posA, out int laneIndexA, out float laneOffsetA, out Vector3 posB, out int laneIndexB, out float laneOffsetB)) { float dist = Vector3.SqrMagnitude(position - posA); if (secondaryPosition != null) { dist += Vector3.SqrMagnitude((Vector3)secondaryPosition - posA); } if (dist < minDist) { found = true; minDist = dist; myPathPosA.m_segment = segmentId; myPathPosA.m_lane = (byte)laneIndexA; myPathPosA.m_offset = (byte)Mathf.Clamp( Mathf.RoundToInt(laneOffsetA * 255f), 0, 255); myDistanceSqrA = dist; dist = Vector3.SqrMagnitude(position - posB); if (secondaryPosition != null) { dist += Vector3.SqrMagnitude( (Vector3)secondaryPosition - posB); } if (laneIndexB < 0) { myPathPosB.m_segment = 0; myPathPosB.m_lane = 0; myPathPosB.m_offset = 0; myDistanceSqrB = float.MaxValue; } else { myPathPosB.m_segment = segmentId; myPathPosB.m_lane = (byte)laneIndexB; myPathPosB.m_offset = (byte)Mathf.Clamp( Mathf.RoundToInt(laneOffsetB * 255f), 0, 255); myDistanceSqrB = dist; } } } // if GetClosestLanePosition } // if othersPassed } // if segmentId = netSegment.m_nextGridSegment; if (++iterations >= NetManager.MAX_SEGMENT_COUNT) { CODebugBase <LogChannel> .Error( LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } lastSpiralDist = spiralDist; return(true); }
/// <summary> /// Finds a suitable path position for a walking citizen with the given world position. /// If secondary lane constraints are given also checks whether there exists another lane that matches those constraints. /// </summary> /// <param name="pos">world position</param> /// <param name="laneTypes">allowed lane types</param> /// <param name="vehicleTypes">allowed vehicle types</param> /// <param name="otherLaneTypes">allowed lane types for secondary lane</param> /// <param name="otherVehicleTypes">other vehicle types for secondary lane</param> /// <param name="allowTransport">public transport allowed?</param> /// <param name="allowUnderground">underground position allowed?</param> /// <param name="position">resulting path position</param> /// <returns><code>true</code> if a position could be found, <code>false</code> otherwise</returns> public bool FindCitizenPathPosition(Vector3 pos, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, NetInfo.LaneType otherLaneTypes, VehicleInfo.VehicleType otherVehicleTypes, bool allowTransport, bool allowUnderground, out PathUnit.Position position) { position = default(PathUnit.Position); float minDist = 1E+10f; if (FindPathPositionWithSpiralLoop( position: pos, service: ItemClass.Service.Road, laneType: laneTypes, vehicleType: vehicleTypes, otherLaneType: otherLaneTypes, otherVehicleType: otherVehicleTypes, allowUnderground: allowUnderground, requireConnect: false, maxDistance: Options.parkingAI ? GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance : 32f, pathPosA: out PathUnit.Position posA, pathPosB: out _, distanceSqrA: out float distA, distanceSqrB: out _) && distA < minDist) { minDist = distA; position = posA; } if (FindPathPositionWithSpiralLoop( pos, ItemClass.Service.Beautification, laneTypes, vehicleTypes, otherLaneTypes, otherVehicleTypes, allowUnderground, false, Options.parkingAI ? GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance : 32f, out posA, out _, out distA, out _) && distA < minDist) { minDist = distA; position = posA; } if (allowTransport && FindPathPositionWithSpiralLoop( pos, ItemClass.Service.PublicTransport, laneTypes, vehicleTypes, otherLaneTypes, otherVehicleTypes, allowUnderground, false, Options.parkingAI ? GlobalConfig .Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance : 32f, out posA, out _, out distA, out _) && distA < minDist) { position = posA; } return(position.m_segment != 0); }
public bool CustomFindPathPosition(ushort instanceID, ref CitizenInstance citizenData, Vector3 pos, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, bool allowUnderground, out PathUnit.Position position) { position = default(PathUnit.Position); float minDist = 1E+10f; PathUnit.Position posA; PathUnit.Position posB; float distA; float distB; if (PathManager.FindPathPosition(pos, ItemClass.Service.Road, laneTypes, vehicleTypes, allowUnderground, false, Options.prohibitPocketCars ? GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance : 32f, out posA, out posB, out distA, out distB) && distA < minDist) { minDist = distA; position = posA; } if (PathManager.FindPathPosition(pos, ItemClass.Service.Beautification, laneTypes, vehicleTypes, allowUnderground, false, Options.prohibitPocketCars ? GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance : 32f, out posA, out posB, out distA, out distB) && distA < minDist) { minDist = distA; position = posA; } if ((citizenData.m_flags & CitizenInstance.Flags.CannotUseTransport) == CitizenInstance.Flags.None && PathManager.FindPathPosition(pos, ItemClass.Service.PublicTransport, laneTypes, vehicleTypes, allowUnderground, false, Options.prohibitPocketCars ? GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance : 32f, out posA, out posB, out distA, out distB) && distA < minDist) { minDist = distA; position = posA; } return(position.m_segment != 0); }
public bool ExtStartPathFind(ushort instanceID, ref CitizenInstance instanceData, ref ExtCitizenInstance extInstance, ref ExtCitizen extCitizen, Vector3 startPos, Vector3 endPos, VehicleInfo vehicleInfo, bool enableTransport, bool ignoreCost) { #if DEBUG bool citDebug = GlobalConfig.Instance.Debug.CitizenId == 0 || GlobalConfig.Instance.Debug.CitizenId == instanceData.m_citizen; bool debug = GlobalConfig.Instance.Debug.Switches[2] && citDebug; bool fineDebug = GlobalConfig.Instance.Debug.Switches[4] && citDebug; if (debug) { Log.Warning($"CustomCitizenAI.ExtStartPathFind({instanceID}): called for citizen {instanceData.m_citizen}, startPos={startPos}, endPos={endPos}, sourceBuilding={instanceData.m_sourceBuilding}, targetBuilding={instanceData.m_targetBuilding}, pathMode={extInstance.pathMode}"); } #endif // NON-STOCK CODE START CitizenManager citizenManager = Singleton <CitizenManager> .instance; ushort parkedVehicleId = citizenManager.m_citizens.m_buffer[instanceData.m_citizen].m_parkedVehicle; ushort homeId = citizenManager.m_citizens.m_buffer[instanceData.m_citizen].m_homeBuilding; CarUsagePolicy carUsageMode = CarUsagePolicy.Allowed; // disallow car usage if citizen is on a walking tour if ((instanceData.m_flags & CitizenInstance.Flags.OnTour) != CitizenInstance.Flags.None) { carUsageMode = CarUsagePolicy.Forbidden; vehicleInfo = null; // TODO check if citizens may use bikes on walking tours } #if BENCHMARK using (var bm = new Benchmark(null, "ParkingAI.Preparation")) { #endif if (Options.prohibitPocketCars) { switch (extInstance.pathMode) { case ExtPathMode.RequiresWalkingPathToParkedCar: case ExtPathMode.CalculatingWalkingPathToParkedCar: case ExtPathMode.WalkingToParkedCar: case ExtPathMode.ApproachingParkedCar: if (parkedVehicleId == 0 || carUsageMode == CarUsagePolicy.Forbidden) { // parked vehicle not present or citizen is on a walking tour #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode} but no parked vehicle present OR citizen is on a walking tour (carUsageMode={carUsageMode}). Change to 'None'."); } #endif extInstance.Reset(); } else { #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode}. Change to 'CalculatingWalkingPathToParkedCar'."); } #endif extInstance.pathMode = ExtPathMode.CalculatingWalkingPathToParkedCar; } break; case ExtPathMode.RequiresWalkingPathToTarget: case ExtPathMode.CalculatingWalkingPathToTarget: case ExtPathMode.WalkingToTarget: #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode}. Change to 'CalculatingWalkingPathToTarget'."); } #endif extInstance.pathMode = ExtPathMode.CalculatingWalkingPathToTarget; break; case ExtPathMode.RequiresCarPath: case ExtPathMode.DrivingToTarget: case ExtPathMode.DrivingToKnownParkPos: case ExtPathMode.DrivingToAltParkPos: case ExtPathMode.CalculatingCarPathToAltParkPos: case ExtPathMode.CalculatingCarPathToKnownParkPos: case ExtPathMode.CalculatingCarPathToTarget: if (parkedVehicleId == 0 || carUsageMode == CarUsagePolicy.Forbidden) { // parked vehicle not present or citizen is on a walking tour #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode} but no parked vehicle present OR citizen is on a walking tour (carUsageMode={carUsageMode}). Change to 'None'."); } #endif extInstance.Reset(); } else { #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode}. Change to 'RequiresCarPath'."); } #endif extInstance.pathMode = ExtPathMode.RequiresCarPath; } break; default: #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen has CurrentPathMode={extInstance.pathMode}. Change to 'None'."); } #endif extInstance.Reset(); break; } /* * the following holds: * - pathMode is now either CalculatingWalkingPathToParkedCar, CalculatingWalkingPathToTarget, RequiresCarPath or None. * - if pathMode is CalculatingWalkingPathToParkedCar or RequiresCarPath: parked car is present and citizen is not on a walking tour */ /* * reuse parked vehicle info */ if (parkedVehicleId != 0) { vehicleInfo = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].Info; } /* * check if the citizen must use their car on their current path */ if (parkedVehicleId != 0 && // parked car present carUsageMode != CarUsagePolicy.Forbidden && // cititzen is not on a walking tour extInstance.pathMode == ExtPathMode.None && // initiating a new path homeId != 0 && // home building present instanceData.m_targetBuilding == homeId // current target is home ) { /* * citizen travels back home * -> check if their car should be returned */ if ((extCitizen.lastTransportMode & ExtCitizen.ExtTransportMode.Car) != ExtCitizen.ExtTransportMode.None) { /* * citizen travelled by car * -> return car back home */ extInstance.pathMode = ExtCitizenInstance.ExtPathMode.CalculatingWalkingPathToParkedCar; #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen used their car before and is not at home. Forcing to walk to parked car."); } #endif } else { /* * citizen travelled by other means of transport * -> check distance between home and parked car. if too far away: force to take the car back home */ float distHomeToParked = (Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position - Singleton <BuildingManager> .instance.m_buildings.m_buffer[homeId].m_position).magnitude; if (distHomeToParked > GlobalConfig.Instance.ParkingAI.MaxParkedCarDistanceToHome) { /* * force to take car back home */ extInstance.pathMode = ExtCitizenInstance.ExtPathMode.CalculatingWalkingPathToParkedCar; #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen wants to go home and parked car is too far away ({distHomeToParked}). Forcing walking to parked car."); } #endif } } } /* * modify path-finding constraints (vehicleInfo, endPos) if citizen is forced to walk */ if (extInstance.pathMode == ExtPathMode.CalculatingWalkingPathToParkedCar || extInstance.pathMode == ExtPathMode.CalculatingWalkingPathToTarget) { /* * vehicle must not be used since we need a walking path to either * 1. a parked car or * 2. the target building */ vehicleInfo = null; carUsageMode = CarUsagePolicy.Forbidden; if (extInstance.pathMode == ExtCitizenInstance.ExtPathMode.CalculatingWalkingPathToParkedCar) { /* * walk to parked car * -> end position is parked car */ endPos = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position; #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen shall go to parked vehicle @ {endPos}"); } #endif } } else if (extInstance.pathMode == ExtPathMode.RequiresCarPath) { /* * citizen stands in front of their parked vehicle * -> find a car-only path now */ carUsageMode = CarUsagePolicy.Forced; startPos = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position; // force to start from the parked car #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen is forced to drive their car"); } #endif } } #if BENCHMARK } #endif #if DEBUG if (fineDebug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen is allowed to drive their car? {carUsageMode}"); } #endif // NON-STOCK CODE END /* * semi-stock code: determine path-finding parameters (laneTypes, vehicleTypes, extVehicleType, etc.) */ NetInfo.LaneType laneTypes = NetInfo.LaneType.Pedestrian; VehicleInfo.VehicleType vehicleTypes = VehicleInfo.VehicleType.None; bool randomParking = false; bool combustionEngine = false; ExtVehicleType extVehicleType = ExtVehicleType.None; if (vehicleInfo != null) { if (vehicleInfo.m_class.m_subService == ItemClass.SubService.PublicTransportTaxi) { if ((instanceData.m_flags & CitizenInstance.Flags.CannotUseTaxi) == CitizenInstance.Flags.None && Singleton <DistrictManager> .instance.m_districts.m_buffer[0].m_productionData.m_finalTaxiCapacity != 0u) { SimulationManager instance = Singleton <SimulationManager> .instance; if (instance.m_isNightTime || instance.m_randomizer.Int32(2u) == 0) { laneTypes |= (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle); vehicleTypes |= vehicleInfo.m_vehicleType; extVehicleType = ExtVehicleType.Taxi; // NON-STOCK CODE // NON-STOCK CODE START if (Options.prohibitPocketCars) { extInstance.pathMode = ExtPathMode.TaxiToTarget; } // NON-STOCK CODE END } } } else // NON-STOCK CODE START if (vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Car) { if (carUsageMode != CarUsagePolicy.Forbidden) { extVehicleType = ExtVehicleType.PassengerCar; laneTypes |= NetInfo.LaneType.Vehicle; vehicleTypes |= vehicleInfo.m_vehicleType; combustionEngine = vehicleInfo.m_class.m_subService == ItemClass.SubService.ResidentialLow; } } else if (vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Bicycle) { extVehicleType = ExtVehicleType.Bicycle; laneTypes |= NetInfo.LaneType.Vehicle; vehicleTypes |= vehicleInfo.m_vehicleType; } // NON-STOCK CODE END } // NON-STOCK CODE START ExtPathType extPathType = ExtPathType.None; PathUnit.Position endPosA = default(PathUnit.Position); bool calculateEndPos = true; bool allowRandomParking = true; #if BENCHMARK using (var bm = new Benchmark(null, "ParkingAI.Main")) { #endif if (Options.prohibitPocketCars) { // Parking AI if (extInstance.pathMode == ExtCitizenInstance.ExtPathMode.RequiresCarPath) { #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Setting startPos={startPos} for citizen instance {instanceID}. CurrentDepartureMode={extInstance.pathMode}"); } #endif if (instanceData.m_targetBuilding == 0 || (Singleton <BuildingManager> .instance.m_buildings.m_buffer[instanceData.m_targetBuilding].m_flags & Building.Flags.IncomingOutgoing) == Building.Flags.None) { /* * the citizen is starting their journey and the target is not an outside connection * -> find a suitable parking space near the target */ #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Finding parking space at target for citizen instance {instanceID}. CurrentDepartureMode={extInstance.pathMode} parkedVehicleId={parkedVehicleId}"); } #endif // find a parking space in the vicinity of the target bool calcEndPos; Vector3 parkPos; if (AdvancedParkingManager.Instance.FindParkingSpaceForCitizen(endPos, vehicleInfo, ref extInstance, homeId, instanceData.m_targetBuilding == homeId, 0, false, out parkPos, ref endPosA, out calcEndPos) && extInstance.CalculateReturnPath(parkPos, endPos)) { // success extInstance.pathMode = ExtCitizenInstance.ExtPathMode.CalculatingCarPathToKnownParkPos; calculateEndPos = calcEndPos; // if true, the end path position still needs to be calculated allowRandomParking = false; // find a direct path to the calculated parking position #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Finding known parking space for citizen instance {instanceID}, parked vehicle {parkedVehicleId} succeeded and return path {extInstance.returnPathId} ({extInstance.returnPathState}) is calculating. PathMode={extInstance.pathMode}"); } #endif /*if (! extInstance.CalculateReturnPath(parkPos, endPos)) { * // TODO retry? * if (debug) * Log._Debug($"CustomCitizenAI.CustomStartPathFind: [PFFAIL] Could not calculate return path for citizen instance {instanceID}, parked vehicle {parkedVehicleId}. Calling OnPathFindFailed."); * CustomHumanAI.OnPathFindFailure(extInstance); * return false; * }*/ } } if (extInstance.pathMode == ExtPathMode.RequiresCarPath) { /* * no known parking space found (pathMode has not been updated in the block above) * -> calculate direct path to target */ #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} is still at CurrentPathMode={extInstance.pathMode} (no parking space found?). Setting it to CalculatingCarPath. parkedVehicleId={parkedVehicleId}"); } #endif extInstance.pathMode = ExtCitizenInstance.ExtPathMode.CalculatingCarPathToTarget; } } /* * determine path type from path mode */ extPathType = extInstance.GetPathType(); /* * the following holds: * - pathMode is now either CalculatingWalkingPathToParkedCar, CalculatingWalkingPathToTarget, CalculatingCarPathToTarget, CalculatingCarPathToKnownParkPos or None. */ } #if BENCHMARK } #endif /* * enable random parking if exact parking space was not calculated yet */ if (extVehicleType == ExtVehicleType.PassengerCar || extVehicleType == ExtVehicleType.Bicycle) { if (allowRandomParking && instanceData.m_targetBuilding != 0 && ( Singleton <BuildingManager> .instance.m_buildings.m_buffer[instanceData.m_targetBuilding].Info.m_class.m_service > ItemClass.Service.Office || (instanceData.m_flags & CitizenInstance.Flags.TargetIsNode) != 0 )) { randomParking = true; } } // NON-STOCK CODE END /* * determine the path position of the parked vehicle */ PathUnit.Position parkedVehiclePathPos = default(PathUnit.Position); if (parkedVehicleId != 0 && extVehicleType == ExtVehicleType.PassengerCar) { Vector3 position = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position; CustomPathManager.FindPathPositionWithSpiralLoop(position, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, VehicleInfo.VehicleType.Car, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, false, false, GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance, out parkedVehiclePathPos); } bool allowUnderground = (instanceData.m_flags & (CitizenInstance.Flags.Underground | CitizenInstance.Flags.Transition)) != CitizenInstance.Flags.None; #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Requesting path-finding for citizen instance {instanceID}, citizen {instanceData.m_citizen}, extVehicleType={extVehicleType}, extPathType={extPathType}, startPos={startPos}, endPos={endPos}, sourceBuilding={instanceData.m_sourceBuilding}, targetBuilding={instanceData.m_targetBuilding} pathMode={extInstance.pathMode}"); } #endif /* * determine start & end path positions */ bool foundEndPos = !calculateEndPos || FindPathPosition(instanceID, ref instanceData, endPos, Options.prohibitPocketCars && (instanceData.m_targetBuilding == 0 || (Singleton <BuildingManager> .instance.m_buildings.m_buffer[instanceData.m_targetBuilding].m_flags & Building.Flags.IncomingOutgoing) == Building.Flags.None) ? NetInfo.LaneType.Pedestrian : laneTypes, vehicleTypes, false, out endPosA); // NON-STOCK CODE: with Parking AI enabled, the end position must be a pedestrian position bool foundStartPos = false; PathUnit.Position startPosA; if (Options.prohibitPocketCars && (extInstance.pathMode == ExtPathMode.CalculatingCarPathToTarget || extInstance.pathMode == ExtPathMode.CalculatingCarPathToKnownParkPos)) { /* * citizen will enter their car now * -> find a road start position */ foundStartPos = CustomPathManager.FindPathPosition(startPos, ItemClass.Service.Road, laneTypes & ~NetInfo.LaneType.Pedestrian, vehicleTypes, allowUnderground, false, GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance, out startPosA); } else { foundStartPos = FindPathPosition(instanceID, ref instanceData, startPos, laneTypes, vehicleTypes, allowUnderground, out startPosA); } /* * start path-finding */ if (foundStartPos && // TODO probably fails if vehicle is parked too far away from road foundEndPos // NON-STOCK CODE ) { if (enableTransport) { /* * public transport usage is allowed for this path */ if ((instanceData.m_flags & CitizenInstance.Flags.CannotUseTransport) == CitizenInstance.Flags.None) { if (carUsageMode != CarUsagePolicy.Forced) // NON-STOCK CODE /* * citizen may use public transport */ { laneTypes |= NetInfo.LaneType.PublicTransport; uint citizenId = instanceData.m_citizen; if (citizenId != 0u && (citizenManager.m_citizens.m_buffer[citizenId].m_flags & Citizen.Flags.Evacuating) != Citizen.Flags.None) { laneTypes |= NetInfo.LaneType.EvacuationTransport; } } } else if (Options.prohibitPocketCars) // TODO check for incoming connection /* * citizen tried to use public transport but waiting time was too long * -> add public transport demand for source building */ { if (instanceData.m_sourceBuilding != 0) { #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} cannot uses public transport from building {instanceData.m_sourceBuilding} to {instanceData.m_targetBuilding}. Incrementing public transport demand."); } #endif ExtBuildingManager.Instance.ExtBuildings[instanceData.m_sourceBuilding].AddPublicTransportDemand((uint)GlobalConfig.Instance.ParkingAI.PublicTransportDemandWaitingIncrement, true); } } } PathUnit.Position dummyPathPos = default(PathUnit.Position); uint path; // NON-STOCK CODE START PathCreationArgs args; args.extPathType = extPathType; args.extVehicleType = extVehicleType; args.vehicleId = 0; args.buildIndex = Singleton <SimulationManager> .instance.m_currentBuildIndex; args.startPosA = startPosA; args.startPosB = dummyPathPos; args.endPosA = endPosA; args.endPosB = dummyPathPos; args.vehiclePosition = parkedVehiclePathPos; args.laneTypes = laneTypes; args.vehicleTypes = vehicleTypes; args.maxLength = 20000f; args.isHeavyVehicle = false; args.hasCombustionEngine = combustionEngine; args.ignoreBlocked = false; args.ignoreFlooded = false; args.ignoreCosts = ignoreCost; args.randomParking = randomParking; args.stablePath = false; args.skipQueue = false; if ((instanceData.m_flags & CitizenInstance.Flags.OnTour) != 0) { args.stablePath = true; args.maxLength = 160000f; //args.laneTypes &= ~(NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle); } else { args.stablePath = false; args.maxLength = 20000f; } bool res = CustomPathManager._instance.CreatePath(out path, ref Singleton <SimulationManager> .instance.m_randomizer, args); // NON-STOCK CODE END if (res) { #if DEBUG if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Path-finding starts for citizen instance {instanceID}, path={path}, extVehicleType={extVehicleType}, startPosA.segment={startPosA.m_segment}, startPosA.lane={startPosA.m_lane}, laneType={laneTypes}, vehicleType={vehicleTypes}, endPosA.segment={endPosA.m_segment}, endPosA.lane={endPosA.m_lane}, vehiclePos.m_segment={parkedVehiclePathPos.m_segment}, vehiclePos.m_lane={parkedVehiclePathPos.m_lane}, vehiclePos.m_offset={parkedVehiclePathPos.m_offset}"); } #endif if (instanceData.m_path != 0u) { Singleton <PathManager> .instance.ReleasePath(instanceData.m_path); } instanceData.m_path = path; instanceData.m_flags |= CitizenInstance.Flags.WaitingPath; return(true); } } #if DEBUG if (Options.prohibitPocketCars) { if (debug) { Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): CustomCitizenAI.CustomStartPathFind: [PFFAIL] failed for citizen instance {instanceID} (CurrentPathMode={extInstance.pathMode}). startPosA.segment={startPosA.m_segment}, startPosA.lane={startPosA.m_lane}, startPosA.offset={startPosA.m_offset}, endPosA.segment={endPosA.m_segment}, endPosA.lane={endPosA.m_lane}, endPosA.offset={endPosA.m_offset}, foundStartPos={foundStartPos}, foundEndPos={foundEndPos}"); } } #endif return(false); }
public bool CustomStartPathFind(ushort vehicleId, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays, bool undergroundTarget) { ExtVehicleType vehicleType = ExtVehicleManager.Instance.OnStartPathFind(vehicleId, ref vehicleData, null); if (vehicleType == ExtVehicleType.None) { Log._DebugOnlyWarning( $"CustomCargoTruck.CustomStartPathFind: Vehicle {vehicleId} " + $"does not have a valid vehicle type!"); } if ((vehicleData.m_flags & (Vehicle.Flags.TransferToSource | Vehicle.Flags.GoingBack)) != 0) { return(base.StartPathFind( vehicleId, ref vehicleData, startPos, endPos, startBothWays, endBothWays, undergroundTarget)); } bool allowUnderground = (vehicleData.m_flags & (Vehicle.Flags.Underground | Vehicle.Flags.Transition)) != 0; bool startPosFound = PathManager.FindPathPosition( startPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, VehicleInfo.VehicleType.Car, allowUnderground, false, 32f, out PathUnit.Position startPosA, out PathUnit.Position startPosB, out float startDistSqrA, out _); if (PathManager.FindPathPosition( startPos, ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Ship | VehicleInfo.VehicleType.Plane, allowUnderground, false, 32f, out PathUnit.Position startAltPosA, out PathUnit.Position startAltPosB, out float startAltDistSqrA, out _)) { if (!startPosFound || (startAltDistSqrA < startDistSqrA && (Mathf.Abs(endPos.x) > 8000f || Mathf.Abs(endPos.z) > 8000f))) { startPosA = startAltPosA; startPosB = startAltPosB; startDistSqrA = startAltDistSqrA; } startPosFound = true; } bool endPosFound = PathManager.FindPathPosition( endPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, VehicleInfo.VehicleType.Car, undergroundTarget, false, 32f, out PathUnit.Position endPosA, out PathUnit.Position endPosB, out float endDistSqrA, out _); if (PathManager.FindPathPosition( endPos, ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Ship | VehicleInfo.VehicleType.Plane, undergroundTarget, false, 32f, out PathUnit.Position endAltPosA, out PathUnit.Position endAltPosB, out float endAltDistSqrA, out _)) { if (!endPosFound || (endAltDistSqrA < endDistSqrA && (Mathf.Abs(endPos.x) > 8000f || Mathf.Abs(endPos.z) > 8000f))) { endPosA = endAltPosA; endPosB = endAltPosB; endDistSqrA = endAltDistSqrA; } endPosFound = true; } if (!startPosFound || !endPosFound) { return(false); } CustomPathManager pathMan = CustomPathManager._instance; if (!startBothWays || startDistSqrA < 10f) { startPosB = default; } if (!endBothWays || endDistSqrA < 10f) { endPosB = default; } const NetInfo.LaneType LANE_TYPES = NetInfo.LaneType.Vehicle | NetInfo.LaneType.CargoVehicle; const VehicleInfo.VehicleType VEHICLE_TYPES = VehicleInfo.VehicleType.Car | VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Ship | VehicleInfo.VehicleType.Plane; // NON-STOCK CODE START PathCreationArgs args; args.extPathType = ExtPathType.None; args.extVehicleType = ExtVehicleType.CargoVehicle; args.vehicleId = vehicleId; args.spawned = (vehicleData.m_flags & Vehicle.Flags.Spawned) != 0; args.buildIndex = Singleton <SimulationManager> .instance.m_currentBuildIndex; args.startPosA = startPosA; args.startPosB = startPosB; args.endPosA = endPosA; args.endPosB = endPosB; args.vehiclePosition = default; args.laneTypes = LANE_TYPES; args.vehicleTypes = VEHICLE_TYPES; args.maxLength = 20000f; args.isHeavyVehicle = IsHeavyVehicle(); args.hasCombustionEngine = CombustionEngine(); args.ignoreBlocked = IgnoreBlocked(vehicleId, ref vehicleData); args.ignoreFlooded = false; args.ignoreCosts = false; args.randomParking = false; args.stablePath = false; args.skipQueue = (vehicleData.m_flags & Vehicle.Flags.Spawned) != 0; if (!pathMan.CustomCreatePath( out uint path, ref Singleton <SimulationManager> .instance.m_randomizer, args)) { return(false); } // NON-STOCK CODE END if (vehicleData.m_path != 0u) { pathMan.ReleasePath(vehicleData.m_path); } vehicleData.m_path = path; vehicleData.m_flags |= Vehicle.Flags.WaitingPath; return(true); }
// be aware: // (1) path-finding works from target to start. the "next" segment is always the previous and the "previous" segment is always the next segment on the path! // (2) when I use the term "lane index from right" this holds for right-hand traffic systems. On maps where you activate left-hand traffic, the "lane index from right" values represent lane indices starting from the left side. // 1 private void ProcessItemMain(uint unitId, BufferItem item, ushort nextNodeId, ref NetNode nextNode, byte connectOffset, bool isMiddle) { //mCurrentState = 0; #if DEBUGPF //bool debug = Options.disableSomething1 && item.m_position.m_segment == 1459 && nextNodeId == 19630; //bool debug = Options.disableSomething1 && (item.m_position.m_segment == 3833 || item.m_position.m_segment == 9649); bool debug = Options.disableSomething1; #endif #if DEBUGPF /*if (m_queuedPathFindCount > 100 && Options.disableSomething1) Log._Debug($"THREAD #{Thread.CurrentThread.ManagedThreadId} PF {this._pathFindIndex}: processItemMain RUNNING! item: {item.m_position.m_segment}, {item.m_position.m_lane} nextNodeId: {nextNodeId}");*/ #endif //Log.Message($"THREAD #{Thread.CurrentThread.ManagedThreadId} Path finder: " + this._pathFindIndex + " vehicle types: " + this._vehicleTypes); #if DEBUGPF //bool debug = isTransportVehicle && isMiddle && item.m_position.m_segment == 13550; List<String> logBuf = null; if (debug) logBuf = new List<String>(); //bool debug = nextNodeId == 12732; #else bool debug = false; #endif //mCurrentState = 1; NetManager instance = Singleton<NetManager>.instance; bool isPedestrianLane = false; bool isBicycleLane = false; bool isCenterPlatform = false; int similarLaneIndexFromLeft = 0; // similar index, starting with 0 at leftmost lane NetInfo prevSegmentInfo = instance.m_segments.m_buffer[(int)item.m_position.m_segment].Info; int prevSimiliarLaneCount = 0; if ((int)item.m_position.m_lane < prevSegmentInfo.m_lanes.Length) { NetInfo.Lane prevLane = prevSegmentInfo.m_lanes[(int)item.m_position.m_lane]; isPedestrianLane = (prevLane.m_laneType == NetInfo.LaneType.Pedestrian); isBicycleLane = (prevLane.m_laneType == NetInfo.LaneType.Vehicle && prevLane.m_vehicleType == VehicleInfo.VehicleType.Bicycle); isCenterPlatform = prevLane.m_centerPlatform; prevSimiliarLaneCount = prevLane.m_similarLaneCount; if ((byte)(prevLane.m_finalDirection & NetInfo.Direction.Forward) != 0) { similarLaneIndexFromLeft = prevLane.m_similarLaneIndex; } else { similarLaneIndexFromLeft = prevLane.m_similarLaneCount - prevLane.m_similarLaneIndex - 1; } //debug = Options.disableSomething1 && (prevLane.m_vehicleType & VehicleInfo.VehicleType.Ship) != VehicleInfo.VehicleType.None; } int firstSimilarLaneIndexFromLeft = similarLaneIndexFromLeft; //mCurrentState = 2; ushort prevSegmentId = item.m_position.m_segment; if (isMiddle) { //mCurrentState = 3; for (int i = 0; i < 8; i++) { ushort nextSegmentId = nextNode.GetSegment(i); if (nextSegmentId <= 0) continue; this.ProcessItemCosts(false, debug, item, nextNodeId, nextSegmentId, ref instance.m_segments.m_buffer[(int)nextSegmentId], ref similarLaneIndexFromLeft, connectOffset, !isPedestrianLane, isPedestrianLane); } //mCurrentState = 4; } else if (isPedestrianLane) { //mCurrentState = 5; int prevLaneIndex = (int)item.m_position.m_lane; if (nextNode.Info.m_class.m_service != ItemClass.Service.Beautification) { bool flag4 = (nextNode.m_flags & (NetNode.Flags.End | NetNode.Flags.Bend | NetNode.Flags.Junction)) != NetNode.Flags.None; bool flag5 = isCenterPlatform && (nextNode.m_flags & (NetNode.Flags.End | NetNode.Flags.Junction)) == NetNode.Flags.None; ushort num2 = prevSegmentId; ushort num3 = prevSegmentId; int laneIndex; int laneIndex2; uint leftLaneId; uint rightLaneId; instance.m_segments.m_buffer[(int)prevSegmentId].GetLeftAndRightLanes(nextNodeId, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, prevLaneIndex, flag5, out laneIndex, out laneIndex2, out leftLaneId, out rightLaneId); if (leftLaneId == 0u || rightLaneId == 0u) { ushort leftSegment; ushort rightSegment; instance.m_segments.m_buffer[(int)prevSegmentId].GetLeftAndRightSegments(nextNodeId, out leftSegment, out rightSegment); int num6 = 0; //mCurrentState = 6; while (leftSegment != 0 && leftSegment != prevSegmentId && leftLaneId == 0u) { int num7; int num8; uint num9; uint num10; instance.m_segments.m_buffer[(int)leftSegment].GetLeftAndRightLanes(nextNodeId, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, -1, flag5, out num7, out num8, out num9, out num10); if (num10 != 0u) { num2 = leftSegment; laneIndex = num8; leftLaneId = num10; } else { leftSegment = instance.m_segments.m_buffer[(int)leftSegment].GetLeftSegment(nextNodeId); } if (++num6 == 8) { break; } } //mCurrentState = 7; num6 = 0; while (rightSegment != 0 && rightSegment != prevSegmentId && rightLaneId == 0u) { int num11; int num12; uint num13; uint num14; instance.m_segments.m_buffer[(int)rightSegment].GetLeftAndRightLanes(nextNodeId, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, -1, flag5, out num11, out num12, out num13, out num14); if (num13 != 0u) { num3 = rightSegment; laneIndex2 = num11; rightLaneId = num13; } else { rightSegment = instance.m_segments.m_buffer[(int)rightSegment].GetRightSegment(nextNodeId); } if (++num6 == 8) { break; } } //mCurrentState = 8; } if (leftLaneId != 0u && (num2 != prevSegmentId || flag4 || flag5)) { this.ProcessItemPedBicycle(item, nextNodeId, num2, ref instance.m_segments.m_buffer[(int)num2], connectOffset, laneIndex, leftLaneId); // ped } if (rightLaneId != 0u && rightLaneId != leftLaneId && (num3 != prevSegmentId || flag4 || flag5)) { this.ProcessItemPedBicycle(item, nextNodeId, num3, ref instance.m_segments.m_buffer[(int)num3], connectOffset, laneIndex2, rightLaneId); // ped } int laneIndex3; uint lane3; if ((this._vehicleTypes & VehicleInfo.VehicleType.Bicycle) != VehicleInfo.VehicleType.None && instance.m_segments.m_buffer[(int)prevSegmentId].GetClosestLane((int)item.m_position.m_lane, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Bicycle, out laneIndex3, out lane3)) { this.ProcessItemPedBicycle(item, nextNodeId, prevSegmentId, ref instance.m_segments.m_buffer[(int)prevSegmentId], connectOffset, laneIndex3, lane3); // bicycle } } else { //mCurrentState = 9; for (int j = 0; j < 8; j++) { ushort segment3 = nextNode.GetSegment(j); if (segment3 != 0 && segment3 != prevSegmentId) { this.ProcessItemCosts(false, debug, item, nextNodeId, segment3, ref instance.m_segments.m_buffer[(int)segment3], ref similarLaneIndexFromLeft, connectOffset, false, true); } } //mCurrentState = 10; } //mCurrentState = 11; NetInfo.LaneType laneType = this._laneTypes & ~NetInfo.LaneType.Pedestrian; VehicleInfo.VehicleType vehicleType = this._vehicleTypes & ~VehicleInfo.VehicleType.Bicycle; if ((byte)(item.m_lanesUsed & (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle)) != 0) { laneType &= ~(NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle); } int num15; uint lane4; if (laneType != NetInfo.LaneType.None && vehicleType != VehicleInfo.VehicleType.None && instance.m_segments.m_buffer[(int)prevSegmentId].GetClosestLane(prevLaneIndex, laneType, vehicleType, out num15, out lane4)) { NetInfo.Lane lane5 = prevSegmentInfo.m_lanes[num15]; byte connectOffset2; if ((instance.m_segments.m_buffer[(int)prevSegmentId].m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None == ((byte)(lane5.m_finalDirection & NetInfo.Direction.Backward) != 0)) { connectOffset2 = 1; } else { connectOffset2 = 254; } //mCurrentState = 12; this.ProcessItemPedBicycle(item, nextNodeId, prevSegmentId, ref instance.m_segments.m_buffer[(int)prevSegmentId], connectOffset2, num15, lane4); // ped //mCurrentState = 13; } } else { //mCurrentState = 14; bool mayTurnAround = (nextNode.m_flags & (NetNode.Flags.End | NetNode.Flags.OneWayOut)) != NetNode.Flags.None; bool pedestrianAllowed = (byte)(this._laneTypes & NetInfo.LaneType.Pedestrian) != 0; bool enablePedestrian = false; byte connectOffset3 = 0; if (pedestrianAllowed) { if (isBicycleLane) { connectOffset3 = connectOffset; enablePedestrian = (nextNode.Info.m_class.m_service == ItemClass.Service.Beautification); } else if (this._vehicleLane != 0u) { if (this._vehicleLane != item.m_laneID) { pedestrianAllowed = false; } else { connectOffset3 = this._vehicleOffset; } } else if (this._stablePath) { connectOffset3 = 128; } else { connectOffset3 = (byte)this._pathRandomizer.UInt32(1u, 254u); } } //mCurrentState = 15; // NON-STOCK CODE START // #if DEBUGPF if (debug) logBuf.Add($"Exploring path! Segment {item.m_position.m_segment} @ node {nextNodeId}: Preparation started"); #endif CustomPathManager pathManager = Singleton<CustomPathManager>.instance; bool nextIsJunction = (nextNode.m_flags & NetNode.Flags.Junction) != NetNode.Flags.None; bool nextIsRealJunction = nextNode.CountSegments() > 2; bool nextIsTransition = (nextNode.m_flags & NetNode.Flags.Transition) != NetNode.Flags.None; bool prevIsHighway = false; if (prevSegmentInfo.m_netAI is RoadBaseAI) prevIsHighway = ((RoadBaseAI)prevSegmentInfo.m_netAI).m_highwayRules; //mCurrentState = 16; NetInfo.Direction normDirection = TrafficPriority.IsLeftHandDrive() ? NetInfo.Direction.Forward : NetInfo.Direction.Backward; // direction to normalize indices to int prevRightSimilarLaneIndex; int prevLeftSimilarLaneIndex; NetInfo.Lane lane = prevSegmentInfo.m_lanes[(int)item.m_position.m_lane]; if ((byte)(lane.m_direction & normDirection) != 0) { prevRightSimilarLaneIndex = lane.m_similarLaneIndex; prevLeftSimilarLaneIndex = lane.m_similarLaneCount - lane.m_similarLaneIndex - 1; } else { prevRightSimilarLaneIndex = lane.m_similarLaneCount - lane.m_similarLaneIndex - 1; prevLeftSimilarLaneIndex = lane.m_similarLaneIndex; } bool foundForced = false; int totalIncomingLanes = 0; int totalOutgoingLanes = 0; bool isStrictLaneArrowPolicyEnabled = IsLaneArrowChangerEnabled() && _extVehicleType != ExtVehicleType.Emergency && (nextIsJunction || nextIsTransition) && !(Options.allRelaxed || (Options.relaxedBusses && _transportVehicle)) && (this._vehicleTypes & VehicleInfo.VehicleType.Car) != VehicleInfo.VehicleType.None; //mCurrentState = 17; // geometries are validated here #if DEBUGPF /*if (m_queuedPathFindCount > 100 && Options.disableSomething1) Log._Debug($"THREAD #{Thread.CurrentThread.ManagedThreadId} PF {this._pathFindIndex}: Getting segment geometry of {prevSegmentId} @ {nextNodeId} START");*/ #endif SegmentGeometry geometry = IsMasterPathFind ? CustomRoadAI.GetSegmentGeometry(prevSegmentId, nextNodeId) : CustomRoadAI.GetSegmentGeometry(prevSegmentId); #if DEBUGPF /*if (m_queuedPathFindCount > 100 && Options.disableSomething1) Log._Debug($"THREAD #{Thread.CurrentThread.ManagedThreadId} PF {this._pathFindIndex}: Getting segment geometry of {prevSegmentId} @ {nextNodeId} END");*/ #endif //mCurrentState = 18; bool prevIsOutgoingOneWay = geometry.IsOutgoingOneWay(nextNodeId); //mCurrentState = 19; #if DEBUGPF /*if (m_queuedPathFindCount > 100 && Options.disableSomething1) Log._Debug($"THREAD #{Thread.CurrentThread.ManagedThreadId} PF {this._pathFindIndex}: Verifying segment geometry of {prevSegmentId} @ {nextNodeId} START");*/ #endif bool nextAreOnlyOneWayHighways = true; for (int k = 0; k < 8; k++) { ushort nextSegId = instance.m_nodes.m_buffer[nextNodeId].GetSegment(k); if (nextSegId == 0 || nextSegId == prevSegmentId) { continue; } if (IsMasterPathFind) { geometry.VerifyConnectedSegment(nextSegId); } if (instance.m_segments.m_buffer[nextSegId].Info.m_netAI is RoadBaseAI) { if (!CustomRoadAI.GetSegmentGeometry(nextSegId).IsOneWay() || !((RoadBaseAI)instance.m_segments.m_buffer[nextSegId].Info.m_netAI).m_highwayRules) { nextAreOnlyOneWayHighways = false; break; } } else { nextAreOnlyOneWayHighways = false; break; } } //mCurrentState = 20; #if DEBUGPF /*if (m_queuedPathFindCount > 100 && Options.disableSomething1) Log._Debug($"THREAD #{Thread.CurrentThread.ManagedThreadId} PF {this._pathFindIndex}: Verifying segment geometry of {prevSegmentId} @ {nextNodeId} END");*/ #endif ushort[] incomingStraightSegmentsArray = null; ushort[] incomingRightSegmentsArray = null; ushort[] incomingLeftSegmentsArray = null; bool startNode = instance.m_segments.m_buffer[(int)prevSegmentId].m_startNode == nextNodeId; if (isStrictLaneArrowPolicyEnabled) { if (startNode) { incomingStraightSegmentsArray = geometry.StartNodeIncomingStraightSegmentsArray; incomingLeftSegmentsArray = geometry.StartNodeIncomingLeftSegmentsArray; incomingRightSegmentsArray = geometry.StartNodeIncomingRightSegmentsArray; } else { incomingStraightSegmentsArray = geometry.EndNodeIncomingStraightSegmentsArray; incomingLeftSegmentsArray = geometry.EndNodeIncomingLeftSegmentsArray; incomingRightSegmentsArray = geometry.EndNodeIncomingRightSegmentsArray; } } //mCurrentState = 21 bool explorePrevSegment = Flags.getUTurnAllowed(prevSegmentId, startNode) && !Options.isStockLaneChangerUsed() && nextIsJunction && !prevIsHighway && !prevIsOutgoingOneWay && (_extVehicleType != null && (_extVehicleType & ExtVehicleType.RoadVehicle) != ExtVehicleType.None); ushort nextSegmentId = explorePrevSegment ? prevSegmentId : instance.m_segments.m_buffer[prevSegmentId].GetRightSegment(nextNodeId); #if DEBUGPF if (debug) logBuf.Add($"Exploring path! Segment {item.m_position.m_segment} @ node {nextNodeId}: Preparation ended"); #endif #if DEBUGPF if (debug) logBuf.Add($"pathfind @ node {nextNodeId}: Path from {nextSegmentId} to {prevSegmentId}."); #endif #if DEBUGPF if (debug) logBuf.Add($"Exploring path from {nextSegmentId} to {item.m_position.m_segment}, lane id {item.m_position.m_lane}, {prevRightSimilarLaneIndex} from right: Custom part started"); #endif // NON-STOCK CODE END // //mCurrentState = 22; for (int k = 0; k < 8; k++) { #if DEBUGPF if (debug) logBuf.Add($"Exploring path from {nextSegmentId} to {item.m_position.m_segment}, lane id {item.m_position.m_lane}, {prevRightSimilarLaneIndex} from right: Segment Iteration {k}. nextSegmentId={nextSegmentId}"); #endif // NON-STOCK CODE START // int outgoingVehicleLanes = 0; int incomingVehicleLanes = 0; bool couldFindCustomPath = false; if (nextSegmentId == 0) { break; } if (!explorePrevSegment && nextSegmentId == prevSegmentId) { break; } //mCurrentState = 23; bool nextIsHighway = false; if (instance.m_segments.m_buffer[nextSegmentId].Info.m_netAI is RoadBaseAI) nextIsHighway = ((RoadBaseAI)instance.m_segments.m_buffer[nextSegmentId].Info.m_netAI).m_highwayRules; bool applyHighwayRules = Options.highwayRules && nextAreOnlyOneWayHighways && prevIsOutgoingOneWay && prevIsHighway && nextIsRealJunction; bool applyHighwayRulesAtSegment = applyHighwayRules; bool isUntouchable = (instance.m_segments.m_buffer[nextSegmentId].m_flags & NetSegment.Flags.Untouchable) != NetSegment.Flags.None; if (!isStrictLaneArrowPolicyEnabled || isUntouchable) { #if DEBUGPF if (debug) logBuf.Add($"Exploring path from {nextSegmentId} to {item.m_position.m_segment}, lane id {item.m_position.m_lane}, {prevRightSimilarLaneIndex} from right: strict lane arrow policy disabled. ({nextIsJunction} || {nextIsTransition}) && !({Options.allRelaxed} || ({Options.relaxedBusses} && {_transportVehicle})) && {(this._vehicleTypes & VehicleInfo.VehicleType.Car) != VehicleInfo.VehicleType.None}"); #endif // NON-STOCK CODE END // //mCurrentState = 24; if (ProcessItemCosts(true, debug, item, nextNodeId, nextSegmentId, ref instance.m_segments.m_buffer[nextSegmentId], ref similarLaneIndexFromLeft, connectOffset, true, enablePedestrian)) { mayTurnAround = true; } //mCurrentState = 25; // NON-STOCK CODE START // couldFindCustomPath = true; // not of interest } else if (!enablePedestrian) { //mCurrentState = 26; if ((_vehicleTypes & ~VehicleInfo.VehicleType.Car) != VehicleInfo.VehicleType.None) { // handle non-car paths #if DEBUGPF if (debug) logBuf.Add($"Exploring path from {nextSegmentId} to {item.m_position.m_segment}, lane id {item.m_position.m_lane}, {prevRightSimilarLaneIndex} from right: Handling everything that is not a car: {this._vehicleTypes}"); #endif _vehicleTypes &= ~VehicleInfo.VehicleType.Car; if (ProcessItemCosts(false, debug, item, nextNodeId, nextSegmentId, ref instance.m_segments.m_buffer[nextSegmentId], ref similarLaneIndexFromLeft, connectOffset, true, enablePedestrian)) { mayTurnAround = true; } _vehicleTypes |= VehicleInfo.VehicleType.Car; } #if DEBUGPF if (debug) logBuf.Add($"Exploring path from {nextSegmentId} to {item.m_position.m_segment}, lane id {item.m_position.m_lane}, {prevRightSimilarLaneIndex} from right: !enablePedestrian"); #endif //try { var nextSegmentInfo = instance.m_segments.m_buffer[nextSegmentId].Info; bool isIncomingRight = false; bool isIncomingStraight = false; bool isIncomingLeft = false; bool isIncomingTurn = false; if (nextSegmentId != prevSegmentId) { for (int j = 0; j < 7; ++j) { if (incomingRightSegmentsArray[j] == nextSegmentId) isIncomingRight = true; if (incomingLeftSegmentsArray[j] == nextSegmentId) isIncomingLeft = true; if (incomingStraightSegmentsArray[j] == nextSegmentId) isIncomingStraight = true; } } else { isIncomingTurn = true; } // we need outgoing lanes too! if (!isIncomingTurn && !isIncomingLeft && !isIncomingRight && !isIncomingStraight) { #if DEBUGPF if (debug) logBuf.Add($"(PFWARN) Segment {nextSegmentId} is neither incoming left, right or straight segment @ {nextNodeId}, going to segment {prevSegmentId}"); #endif // recalculate geometry if segment is unknown geometry.VerifyConnectedSegment(nextSegmentId); if (!applyHighwayRulesAtSegment) { couldFindCustomPath = true; // not of interest goto nextIter; } else { // we do not stop here because we need the number of outgoing lanes in highway mode } } //mCurrentState = 27; VehicleInfo.VehicleType vehicleType2 = this._vehicleTypes; NetInfo.LaneType drivingEnabledLaneTypes = this._laneTypes; drivingEnabledLaneTypes &= ~NetInfo.LaneType.Pedestrian; drivingEnabledLaneTypes &= ~NetInfo.LaneType.Parking; //if (debug) { //Log.Message($"Path finding ({this._pathFindIndex}): Segment {nextSegmentId}"); //} NetInfo.Direction nextDir = instance.m_segments.m_buffer[nextSegmentId].m_startNode != nextNodeId ? NetInfo.Direction.Forward : NetInfo.Direction.Backward; NetInfo.Direction nextDir2 = ((instance.m_segments.m_buffer[nextSegmentId].m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) ? nextDir : NetInfo.InvertDirection(nextDir); // valid next lanes: int[] laneIndexes = new int[16]; // index of NetNode.Info.m_lanes uint[] laneIds = new uint[16]; // index of NetManager.m_lanes.m_buffer uint[] indexByRightSimilarLaneIndex = new uint[16]; uint[] indexByLeftSimilarLaneIndex = new uint[16]; uint curLaneI = 0; uint curLaneId = instance.m_segments.m_buffer[nextSegmentId].m_lanes; int laneIndex = 0; #if DEBUG uint wIter = 0; #endif //mCurrentState = 28; while (laneIndex < nextSegmentInfo.m_lanes.Length && curLaneId != 0u) { //mCurrentState = 29; #if DEBUGPF if (debug) logBuf.Add($"Exploring path from {nextSegmentId} to {item.m_position.m_segment}, lane id {item.m_position.m_lane}, {prevRightSimilarLaneIndex} from right: Lane Iteration {laneIndex}. nextSegmentId={nextSegmentId}, curLaneId={curLaneId}"); #endif #if DEBUG ++wIter; if (wIter >= 20) { Log.Error("Too many iterations in ProcessItemMain!"); break; } #endif // determine valid lanes based on lane arrows NetInfo.Lane nextLane = nextSegmentInfo.m_lanes[laneIndex]; bool incomingLane = (byte)(nextLane.m_finalDirection & nextDir2) != 0; bool compatibleLane = nextLane.CheckType(drivingEnabledLaneTypes, _vehicleTypes); if (incomingLane && compatibleLane) { ++incomingVehicleLanes; #if DEBUGPF if (debug) logBuf.Add($"Segment {nextSegmentId}, lane {curLaneId}, {laneIndex} is compatible (prevSegment: {prevSegmentId}). laneTypes: {_laneTypes.ToString()}, vehicleTypes: {_vehicleTypes.ToString()}, incomingLanes={incomingVehicleLanes}, isIncomingRight? {isIncomingRight}, isIncomingLeft? {isIncomingLeft}, isIncomingStraight? {isIncomingStraight}"); #endif // calculate current similar lane index starting from right line int nextRightSimilarLaneIndex; int nextLeftSimilarLaneIndex; if ((byte)(nextLane.m_direction & normDirection) != 0) { nextRightSimilarLaneIndex = nextLane.m_similarLaneIndex; nextLeftSimilarLaneIndex = nextLane.m_similarLaneCount - nextLane.m_similarLaneIndex - 1; } else { nextRightSimilarLaneIndex = nextLane.m_similarLaneCount - nextLane.m_similarLaneIndex - 1; nextLeftSimilarLaneIndex = nextLane.m_similarLaneIndex; } bool hasLeftArrow = ((NetLane.Flags)instance.m_lanes.m_buffer[curLaneId].m_flags & NetLane.Flags.Left) == NetLane.Flags.Left; bool hasRightArrow = ((NetLane.Flags)instance.m_lanes.m_buffer[curLaneId].m_flags & NetLane.Flags.Right) == NetLane.Flags.Right; bool hasForwardArrow = ((NetLane.Flags)instance.m_lanes.m_buffer[curLaneId].m_flags & NetLane.Flags.Forward) != NetLane.Flags.None || ((NetLane.Flags)instance.m_lanes.m_buffer[curLaneId].m_flags & NetLane.Flags.LeftForwardRight) == NetLane.Flags.None; #if DEBUGPF if (debug) { if (hasLeftArrow) { logBuf.Add($"Segment {nextSegmentId}, lane {curLaneId}, {laneIndex} has LEFT arrow. isIncomingRight? {isIncomingRight}, isIncomingLeft? {isIncomingLeft}, isIncomingStraight? {isIncomingStraight}"); } if (hasRightArrow) { logBuf.Add($"Segment {nextSegmentId}, lane {curLaneId}, {laneIndex} has RIGHT arrow. isIncomingRight? {isIncomingRight}, isIncomingLeft? {isIncomingLeft}, isIncomingStraight? {isIncomingStraight}"); } if (hasForwardArrow) { logBuf.Add($"Segment {nextSegmentId}, lane {curLaneId}, {laneIndex} has FORWARD arrow. isIncomingRight? {isIncomingRight}, isIncomingLeft? {isIncomingLeft}, isIncomingStraight? {isIncomingStraight}"); } } #endif bool isValidIncomingRight = isIncomingRight && hasLeftArrow; bool isValidIncomingLeft = isIncomingLeft && hasRightArrow; bool isValidIncomingStraight = isIncomingStraight && hasForwardArrow; bool isValidIncomingTurn = isIncomingTurn && ((TrafficPriority.IsLeftHandDrive() && hasRightArrow) || (!TrafficPriority.IsLeftHandDrive() && hasLeftArrow)); #if DEBUGPF if (debug) logBuf.Add($"Segment {nextSegmentId}, lane {curLaneId}, {laneIndex}. isValidIncomingRight? {isValidIncomingRight}, isValidIncomingLeft? {isValidIncomingLeft}, isValidIncomingStraight? {isValidIncomingStraight} isValidIncomingTurn? {isValidIncomingTurn}"); #endif // add valid next lanes if (applyHighwayRulesAtSegment || isValidIncomingRight || isValidIncomingLeft || isValidIncomingStraight || isValidIncomingTurn) { laneIndexes[curLaneI] = laneIndex; laneIds[curLaneI] = curLaneId; indexByRightSimilarLaneIndex[nextRightSimilarLaneIndex] = curLaneI + 1; indexByLeftSimilarLaneIndex[nextLeftSimilarLaneIndex] = curLaneI + 1; #if DEBUGPF if (debug) logBuf.Add($"Adding lane #{curLaneI} (id {curLaneId}, idx {laneIndex}), right sim. idx: {nextRightSimilarLaneIndex}, left sim. idx.: {nextLeftSimilarLaneIndex}"); #endif curLaneI++; } } if (!incomingLane && compatibleLane) { // outgoing lane ++outgoingVehicleLanes; } curLaneId = instance.m_lanes.m_buffer[(int)((UIntPtr)curLaneId)].m_nextLane; laneIndex++; } // foreach lane //mCurrentState = 30; if (curLaneI > 0) { //mCurrentState = 31; // we found compatible lanes var nextLaneIndex = 0; var nextLaneId = 0u; int nextLaneI = -1; int nextCompatibleLaneCount = Convert.ToInt32(curLaneI); #if DEBUGPF if (debug) { logBuf.Add($"Compatible lanes found."); logBuf.Add($"next segment: {nextSegmentId}, number of next lanes: {nextCompatibleLaneCount}, prev. segment: {prevSegmentId}, prev. lane ID: {item.m_laneID}, prev. lane idx: {item.m_position.m_lane}, prev. right sim. idx: {prevRightSimilarLaneIndex}, prev. left sim. idx: {prevLeftSimilarLaneIndex}, laneTypes: {_laneTypes.ToString()}, vehicleTypes: {_vehicleTypes.ToString()}, incomingLanes={incomingVehicleLanes}, isIncomingRight? {isIncomingRight}, isIncomingLeft? {isIncomingLeft}, isIncomingStraight? {isIncomingStraight}"); } #endif // mix of incoming/outgoing lanes on the right sight of prev segment is not allowed in highway mode if (totalIncomingLanes > 0 && totalOutgoingLanes > 0) { #if DEBUGPF if (debug) logBuf.Add($"{totalIncomingLanes} incoming lanes and {totalOutgoingLanes} outgoing lanes found. Disabling highway rules."); #endif applyHighwayRulesAtSegment = false; } if (applyHighwayRulesAtSegment) { //mCurrentState = 32; int numRightLanes = Math.Max(totalIncomingLanes, totalOutgoingLanes); #if DEBUGPF if (debug) logBuf.Add($"Applying highway rules. {numRightLanes} right lanes found ({totalIncomingLanes} incoming, {totalOutgoingLanes} outgoing)."); #endif int nextLeftSimilarIndex; if (totalOutgoingLanes > 0) { nextLeftSimilarIndex = prevLeftSimilarLaneIndex + numRightLanes; // lane splitting #if DEBUGPF if (debug) logBuf.Add($"Performing lane split. nextLeftSimilarIndex={nextLeftSimilarIndex} = prevLeftSimilarIndex({prevLeftSimilarLaneIndex}) + numRightLanes({numRightLanes})"); #endif } else { nextLeftSimilarIndex = prevLeftSimilarLaneIndex - numRightLanes; // lane merging #if DEBUGPF if (debug) logBuf.Add($"Performing lane merge. nextLeftSimilarIndex={nextLeftSimilarIndex} = prevLeftSimilarIndex({prevLeftSimilarLaneIndex}) - numRightLanes({numRightLanes})"); #endif } if (nextLeftSimilarIndex >= 0 && nextLeftSimilarIndex < nextCompatibleLaneCount) { // enough lanes available nextLaneI = Convert.ToInt32(indexByLeftSimilarLaneIndex[nextLeftSimilarIndex]) - 1; #if DEBUGPF if (debug) logBuf.Add($"Next lane within bounds. nextLaneI={nextLaneI}"); #endif } else { if (nextLeftSimilarIndex < 0) { // too few lanes at prevSegment or nextSegment: sort right if (totalIncomingLanes >= prevSimiliarLaneCount) nextLaneI = Convert.ToInt32(indexByRightSimilarLaneIndex[prevRightSimilarLaneIndex]) - 1; } else { if (totalOutgoingLanes >= nextCompatibleLaneCount) nextLaneI = Convert.ToInt32(indexByRightSimilarLaneIndex[0]) - 1; } #if DEBUGPF if (debug) logBuf.Add($"Next lane out of bounds. nextLaneI={nextLaneI}, isIncomingLeft={isIncomingLeft}, prevRightSimilarIndex={prevRightSimilarLaneIndex}, prevLeftSimilarIndex={prevLeftSimilarLaneIndex}"); #endif } if (nextLaneI < 0 || nextLaneI >= nextCompatibleLaneCount) { #if DEBUGPF if (debug) Log.Error($"(PFERR) Exploring path from {nextSegmentId} ({nextDir}) to {item.m_position.m_segment}, lane id {item.m_position.m_lane}, {prevRightSimilarLaneIndex} from right, {prevLeftSimilarLaneIndex} from left: Highway lane selector cannot find suitable lane! isIncomingLeft={isIncomingLeft} isIncomingRight={isIncomingRight} totalIncomingLanes={totalIncomingLanes}"); #endif couldFindCustomPath = true; // not of interest for us //mCurrentState = 33; goto nextIter; // no path to this lane } } else if (nextCompatibleLaneCount == 1) { //mCurrentState = 34; nextLaneI = 0; #if DEBUGPF if (debug) logBuf.Add($"Single target lane found. nextLaneI={nextLaneI}"); #endif } else { //mCurrentState = 35; // lane matching int prevSimilarLaneCount = lane.m_similarLaneCount; #if DEBUGPF if (debug) logBuf.Add($"Multiple target lanes found. prevSimilarLaneCount={prevSimilarLaneCount}"); #endif int minNextRightSimilarIndex = -1; int maxNextRightSimilarIndex = -1; if (nextIsRealJunction) { // at junctions: try to match distinct lanes (1-to-1, n-to-1) minNextRightSimilarIndex = prevRightSimilarLaneIndex; maxNextRightSimilarIndex = prevRightSimilarLaneIndex; // vehicles may change lanes at straight segments?w if (isIncomingStraight && Flags.getStraightLaneChangingAllowed(nextSegmentId, Singleton<NetManager>.instance.m_segments.m_buffer[nextSegmentId].m_startNode == nextNodeId)) { minNextRightSimilarIndex = Math.Max(0, minNextRightSimilarIndex - 1); maxNextRightSimilarIndex = Math.Min(nextCompatibleLaneCount - 1, maxNextRightSimilarIndex + 1); #if DEBUGPF if (debug) logBuf.Add($"Next is incoming straight. Allowing lane changes! minNextRightSimilarIndex={minNextRightSimilarIndex}, maxNextRightSimilarIndex={maxNextRightSimilarIndex}"); #endif } #if DEBUGPF if (debug) logBuf.Add($"Next is junction. minNextRightSimilarIndex={minNextRightSimilarIndex}, maxNextRightSimilarIndex={maxNextRightSimilarIndex}"); #endif } else { // lane merging/splitting //mCurrentState = 36; HandleLaneMergesAndSplits(prevRightSimilarLaneIndex, nextCompatibleLaneCount, prevSimilarLaneCount, out minNextRightSimilarIndex, out maxNextRightSimilarIndex); //mCurrentState = 37; #if DEBUGPF if (debug) logBuf.Add($"Next is not a junction. nextRightSimilarLaneIndex=HandleLaneMergesAndSplits({prevRightSimilarLaneIndex}, {nextCompatibleLaneCount}, {prevSimilarLaneCount})= min. {minNextRightSimilarIndex} max. {maxNextRightSimilarIndex}"); #endif } // find best matching lane(s) for (int nextRightSimilarIndex = minNextRightSimilarIndex; nextRightSimilarIndex <= maxNextRightSimilarIndex; ++nextRightSimilarIndex) { #if DEBUGPF if (debug) logBuf.Add($"current right similar index = {nextRightSimilarIndex}, min. {minNextRightSimilarIndex} max. {maxNextRightSimilarIndex}"); #endif //mCurrentState = 38; nextLaneI = FindNthCompatibleLane(ref indexByRightSimilarLaneIndex, nextRightSimilarIndex); //mCurrentState = 39; #if DEBUGPF if (debug) logBuf.Add($"(*) nextLaneI = {nextLaneI}"); #endif if (nextLaneI < 0) { continue; } // go to matched lane nextLaneIndex = laneIndexes[nextLaneI]; nextLaneId = laneIds[nextLaneI]; #if DEBUGPF if (debug) logBuf.Add($"Exploring path from {nextSegmentId} ({nextDir}) to {item.m_position.m_segment}, lane idx {item.m_position.m_lane}, {prevRightSimilarLaneIndex} from right. There are {curLaneI} candidate lanes. We choose lane {nextLaneI} (index {nextLaneIndex}, {nextRightSimilarIndex} compatible from right). lhd: {TrafficPriority.IsLeftHandDrive()}, ped: {pedestrianAllowed}, magical flag4: {mayTurnAround}"); #endif //mCurrentState = 40; if (ProcessItemCosts(true, debug, item, nextNodeId, nextSegmentId, ref instance.m_segments.m_buffer[nextSegmentId], ref similarLaneIndexFromLeft, connectOffset, true, enablePedestrian, nextLaneIndex, nextLaneId, out foundForced)) { mayTurnAround = true; } //mCurrentState = 41; couldFindCustomPath = true; } goto nextIter; } //mCurrentState = 42; if (nextLaneI < 0) { #if DEBUGPF if (debug) Log.Error($"(PFERR) Exploring path from {nextSegmentId} ({nextDir}) to {item.m_position.m_segment}, lane id {item.m_position.m_lane}, {prevRightSimilarLaneIndex} from right: nextLaneI < 0!"); #endif //mCurrentState = 43; goto nextIter; } //mCurrentState = 44; // go to matched lane nextLaneIndex = laneIndexes[nextLaneI]; nextLaneId = laneIds[nextLaneI]; #if DEBUGPF if (debug) logBuf.Add($"Exploring path from {nextSegmentId} ({nextDir}) to {item.m_position.m_segment}, lane id {item.m_position.m_lane}, {prevRightSimilarLaneIndex} from right: nextLaneIndex={nextLaneIndex} nextLaneId={nextLaneId}"); #endif //mCurrentState = 45; if (IsMasterPathFind && applyHighwayRulesAtSegment) { // udpate highway mode arrows #if DEBUGPF /*if (Options.disableSomething1) Log._Debug($"THREAD #{Thread.CurrentThread.ManagedThreadId} PF {this._pathFindIndex}: Setting highway arrows @ lane {nextLaneId}: START");*/ #endif Flags.LaneArrows? prevHighwayArrows = Flags.getHighwayLaneArrowFlags(nextLaneId); Flags.LaneArrows newHighwayArrows = Flags.LaneArrows.None; if (prevHighwayArrows != null) newHighwayArrows = (Flags.LaneArrows)prevHighwayArrows; if (isIncomingRight) newHighwayArrows |= Flags.LaneArrows.Left; else if (isIncomingLeft) newHighwayArrows |= Flags.LaneArrows.Right; else if (isIncomingStraight) newHighwayArrows |= Flags.LaneArrows.Forward; if (newHighwayArrows != prevHighwayArrows && newHighwayArrows != Flags.LaneArrows.None) Flags.setHighwayLaneArrowFlags(nextLaneId, newHighwayArrows); #if DEBUGPF /*if (Options.disableSomething1) Log._Debug($"THREAD #{Thread.CurrentThread.ManagedThreadId} PF {this._pathFindIndex}: Setting highway arrows @ lane {nextLaneId} to {newHighwayArrows.ToString()}: END");*/ #endif } //mCurrentState = 46; if (ProcessItemCosts(true, debug, item, nextNodeId, nextSegmentId, ref instance.m_segments.m_buffer[nextSegmentId], ref similarLaneIndexFromLeft, connectOffset, true, enablePedestrian, nextLaneIndex, nextLaneId, out foundForced)) { mayTurnAround = true; } //mCurrentState = 47; if (foundForced) { #if DEBUGPF if (debug) logBuf.Add($"Exploring path from {nextSegmentId} ({nextDir}) to {item.m_position.m_segment}, lane id {item.m_position.m_lane}, {prevRightSimilarLaneIndex} from right: FORCED LANE FOUND!"); #endif couldFindCustomPath = true; } } else { // no compatible lanes found //mCurrentState = 48; #if DEBUGPF if (debug) Log.Error($"(PFERR) Exploring path from {nextSegmentId} ({nextDir}) to {item.m_position.m_segment}, lane id {item.m_position.m_lane}, {prevRightSimilarLaneIndex} from right: No lane arrows defined"); #endif couldFindCustomPath = true; // the player did not set lane arrows. this is ok... /*if (ProcessItem(debug, item, nextNodeId, nextSegmentId, ref instance.m_segments.m_buffer[nextSegmentId], ref similarLaneIndexFromLeft, connectOffset, true, enablePedestrian)) { blocked = true; }*/ } /*} catch (Exception e) { Log.Error($"(PFERR) Error occurred in custom path-finding (main): {e.ToString()}"); couldFindCustomPath = true; // not of interest for us // stock code fallback if (this.ProcessItemSub(debug, item, nextNodeId, nextSegmentId, ref instance.m_segments.m_buffer[(int)nextSegmentId], ref similarLaneIndexFromLeft, connectOffset, true, enablePedestrian)) { blocked = true; } }*/ // NON-STOCK CODE END } else { //mCurrentState = 49; // pedestrians // stock code: if (this.ProcessItemCosts(false, debug, item, nextNodeId, nextSegmentId, ref instance.m_segments.m_buffer[(int)nextSegmentId], ref similarLaneIndexFromLeft, connectOffset, true, enablePedestrian)) { mayTurnAround = true; } couldFindCustomPath = true; // not of interest for us //mCurrentState = 50; } nextIter: //mCurrentState = 51; if (!couldFindCustomPath) { #if DEBUGPF if (debug) logBuf.Add($"(PFERR) Could not find custom path from segment {nextSegmentId} to segment {prevSegmentId}, lane {item.m_position.m_lane}, off {item.m_position.m_offset} at node {nextNodeId}!"); #endif // stock code: /*if (this.ProcessItem(debug, item, nextNodeId, nextSegmentId, ref instance.m_segments.m_buffer[(int)nextSegmentId], ref similarLaneIndexFromLeft, connectOffset, true, enablePedestrian)) { blocked = true; }*/ } if (nextSegmentId == prevSegmentId) similarLaneIndexFromLeft = firstSimilarLaneIndexFromLeft; // u-turning does not "consume" a lane nextSegmentId = instance.m_segments.m_buffer[(int)nextSegmentId].GetRightSegment(nextNodeId); if (nextSegmentId != prevSegmentId) { totalIncomingLanes += incomingVehicleLanes; totalOutgoingLanes += outgoingVehicleLanes; } if (explorePrevSegment && nextSegmentId == prevSegmentId) break; //mCurrentState = 52; } // foreach segment //mCurrentState = 53; #if DEBUGPF if (debug) logBuf.Add($"Exploring path from {nextSegmentId} to {item.m_position.m_segment}, lane id {item.m_position.m_lane}, {prevRightSimilarLaneIndex} from right: Custom part finished"); #endif if (mayTurnAround && (this._vehicleTypes & VehicleInfo.VehicleType.Tram) == VehicleInfo.VehicleType.None) { // turn-around for vehicles (if street is blocked) #if DEBUGPF if (debug) logBuf.Add($"Exploring path from {nextSegmentId} to {item.m_position.m_segment}, lane id {item.m_position.m_lane}, {prevRightSimilarLaneIndex} from right: Road may be blocked"); #endif // vehicles may turn around if the street is blocked nextSegmentId = item.m_position.m_segment; //mCurrentState = 54; this.ProcessItemCosts(false, debug, item, nextNodeId, nextSegmentId, ref instance.m_segments.m_buffer[(int)nextSegmentId], ref similarLaneIndexFromLeft, connectOffset, true, false); //mCurrentState = 55; } //mCurrentState = 56; // NON-STOCK CODE START /*if (foundForced) return;*/ // NON-STOCK CODE END if (pedestrianAllowed) { // turn-around for pedestrians #if DEBUGPF if (debug) logBuf.Add($"Exploring path from {nextSegmentId} to {item.m_position.m_segment}, lane id {item.m_position.m_lane}, {prevRightSimilarLaneIndex} from right: Ped allowed"); #endif nextSegmentId = item.m_position.m_segment; int laneIndex4; uint lane6; if (instance.m_segments.m_buffer[(int)nextSegmentId].GetClosestLane((int)item.m_position.m_lane, NetInfo.LaneType.Pedestrian, this._vehicleTypes, out laneIndex4, out lane6)) { //mCurrentState = 57; this.ProcessItemPedBicycle(item, nextNodeId, nextSegmentId, ref instance.m_segments.m_buffer[(int)nextSegmentId], connectOffset3, laneIndex4, lane6); // ped //mCurrentState = 58; } } } if (nextNode.m_lane != 0u) { bool targetDisabled = (nextNode.m_flags & NetNode.Flags.Disabled) != NetNode.Flags.None; ushort segment4 = instance.m_lanes.m_buffer[(int)((UIntPtr)nextNode.m_lane)].m_segment; if (segment4 != 0 && segment4 != item.m_position.m_segment) { #if DEBUGPF if (debug) logBuf.Add($"Exploring path from {segment4} to {item.m_position.m_segment}, lane id {item.m_position.m_lane}: handling special lanes"); #endif //mCurrentState = 59; this.ProcessItem2(item, nextNodeId, targetDisabled, segment4, ref instance.m_segments.m_buffer[(int)segment4], nextNode.m_lane, nextNode.m_laneOffset, connectOffset); //mCurrentState = 60; } } //mCurrentState = 61; #if DEBUGPF if (debug) { foreach (String toLog in logBuf) { Log._Debug($"Pathfinder ({this._pathFindIndex}) for unit {unitId}: " + toLog); } } #endif //mCurrentState = 62; }
public override bool AllowVehicleType(VehicleInfo.VehicleType type, HelicopterDepotAI ai) => type == VehicleInfo.VehicleType.Helicopter;
internal static bool CheckFlags(this VehicleInfo.VehicleType value, VehicleInfo.VehicleType required, VehicleInfo.VehicleType forbidden = 0) => (value & (required | forbidden)) == required;
public override bool AllowVehicleType(VehicleInfo.VehicleType type, HospitalAI ai) => type == VehicleInfo.VehicleType.Car;
public override string GetVehicleMaxCountField(VehicleInfo.VehicleType veh) => "m_garbageTruckCount";
public override string GetVehicleMaxCountField(VehicleInfo.VehicleType veh) => "m_maintenanceTruckCount";
public override string GetVehicleMaxCountField(VehicleInfo.VehicleType veh) => DepotAIOverrides.instance.GetVehicleMaxCountField(veh);
public override bool AllowVehicleType(VehicleInfo.VehicleType type, MaintenanceDepotAI ai) => type == VehicleInfo.VehicleType.Car;
public override string GetVehicleMaxCountField(VehicleInfo.VehicleType veh) => null;
public override string GetVehicleMaxCountField(VehicleInfo.VehicleType veh) => "m_policeCarCount";
public new bool NeedChangeVehicleType(ushort vehicleID, ref Vehicle vehicleData, PathUnit.Position pathPos, uint laneID, VehicleInfo.VehicleType laneVehicleType, ref Vector4 target) { return(base.NeedChangeVehicleType(vehicleID, ref vehicleData, pathPos, laneID, laneVehicleType, ref target)); }
public override bool AllowVehicleType(VehicleInfo.VehicleType type, PoliceStationAI ai) => type == VehicleInfo.VehicleType.Car;
/*public static readonly int[] FREE_TRANSPORT_USAGE_PROBABILITY = { 80, 50, 5 }; * public static readonly int[] TRANSPORT_USAGE_PROBABILITY = { 40, 25, 10 };*/ // CitizenAI public bool CustomStartPathFind(ushort instanceID, ref CitizenInstance citizenData, Vector3 startPos, Vector3 endPos, VehicleInfo vehicleInfo) { NetInfo.LaneType laneType = NetInfo.LaneType.Pedestrian; VehicleInfo.VehicleType vehicleType = VehicleInfo.VehicleType.None; bool randomParking = false; if (vehicleInfo != null) { if (vehicleInfo.m_class.m_subService == ItemClass.SubService.PublicTransportTaxi) { if ((citizenData.m_flags & CitizenInstance.Flags.CannotUseTaxi) == CitizenInstance.Flags.None && Singleton <DistrictManager> .instance.m_districts.m_buffer[0].m_productionData.m_finalTaxiCapacity != 0u) { SimulationManager instance = Singleton <SimulationManager> .instance; if (instance.m_isNightTime || instance.m_randomizer.Int32(2u) == 0) { laneType |= (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle); vehicleType |= vehicleInfo.m_vehicleType; } } } else { laneType |= NetInfo.LaneType.Vehicle; vehicleType |= vehicleInfo.m_vehicleType; if (citizenData.m_targetBuilding != 0 && Singleton <BuildingManager> .instance.m_buildings.m_buffer[(int)citizenData.m_targetBuilding].Info.m_class.m_service > ItemClass.Service.Office) { randomParking = true; } } } PathUnit.Position vehiclePosition = default(PathUnit.Position); ushort parkedVehicle = Singleton <CitizenManager> .instance.m_citizens.m_buffer[(int)((UIntPtr)citizenData.m_citizen)].m_parkedVehicle; if (parkedVehicle != 0) { Vector3 position = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[(int)parkedVehicle].m_position; PathManager.FindPathPosition(position, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, VehicleInfo.VehicleType.Car, false, false, 32f, out vehiclePosition); } bool allowUnderground = (citizenData.m_flags & (CitizenInstance.Flags.Underground | CitizenInstance.Flags.Transition)) != CitizenInstance.Flags.None; PathUnit.Position startPosA; PathUnit.Position endPosA; if (this.FindPathPosition(instanceID, ref citizenData, startPos, laneType, vehicleType, allowUnderground, out startPosA) && this.FindPathPosition(instanceID, ref citizenData, endPos, laneType, vehicleType, false, out endPosA)) { // NON-STOCK CODE START // /*Citizen.Wealth wealthLevel = Singleton<CitizenManager>.instance.m_citizens.m_buffer[citizenData.m_citizen].WealthLevel; * * byte districtId = Singleton<DistrictManager>.instance.GetDistrict(startPos); * DistrictPolicies.Services servicePolicies = Singleton<DistrictManager>.instance.m_districts.m_buffer[(int)districtId].m_servicePolicies; * int transportUsageProb = (servicePolicies & DistrictPolicies.Services.FreeTransport) != DistrictPolicies.Services.None ? FREE_TRANSPORT_USAGE_PROBABILITY[(int)wealthLevel] : TRANSPORT_USAGE_PROBABILITY[(int)wealthLevel];*/ //bool mayUseTransport = false; if ((citizenData.m_flags & CitizenInstance.Flags.CannotUseTransport) == CitizenInstance.Flags.None) // STOCK CODE //if (vehicleInfo == null || (instanceID % 100)+1 <= transportUsageProb) { { laneType |= NetInfo.LaneType.PublicTransport; // STOCK CODE //mayUseTransport = true; //Log._Debug($"CustomCitizenAI: citizen {instanceID} can use public transport"); //} } // NON-STOCK CODE END // PathUnit.Position position2 = default(PathUnit.Position); uint path; // NON-STOCK CODE START // ExtVehicleType extVehicleType = ExtVehicleType.PassengerCar; if (vehicleInfo != null && vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Bicycle) { extVehicleType = ExtVehicleType.Bicycle; } //Log._Debug($"CustomCitizenAI: citizen instance {instanceID}, id {citizenData.m_citizen}. {vehicleType} {extVehicleType} mayUseTransport={mayUseTransport} wealthLevel={wealthLevel}"); bool res = Singleton <CustomPathManager> .instance.CreatePath(false, (ExtVehicleType)extVehicleType, out path, ref Singleton <SimulationManager> .instance.m_randomizer, Singleton <SimulationManager> .instance.m_currentBuildIndex, ref startPosA, ref position2, ref endPosA, ref position2, ref vehiclePosition, laneType, vehicleType, 20000f, false, false, false, false, randomParking); // NON-STOCK CODE END // if (res) { if (citizenData.m_path != 0u) { Singleton <PathManager> .instance.ReleasePath(citizenData.m_path); } citizenData.m_path = path; citizenData.m_flags |= CitizenInstance.Flags.WaitingPath; return(true); } } return(false); }
public override bool AllowVehicleType(VehicleInfo.VehicleType type, SnowDumpAI ai) => type == VehicleInfo.VehicleType.Car;
public bool CreatePath(ExtVehicleType vehicleType, out uint unit, ref Randomizer randomizer, uint buildIndex, PathUnit.Position startPosA, PathUnit.Position startPosB, PathUnit.Position endPosA, PathUnit.Position endPosB, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, float maxLength) { return(this.CreatePath(vehicleType, out unit, ref randomizer, buildIndex, startPosA, startPosB, endPosA, endPosB, default(PathUnit.Position), laneTypes, vehicleTypes, maxLength, false, false, false, false)); }
public override string GetVehicleMaxCountField(VehicleInfo.VehicleType veh) => "m_pumpingVehicles";
// 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 }
public override bool AllowVehicleType(VehicleInfo.VehicleType type, WaterFacilityAI ai) => type == VehicleInfo.VehicleType.Car;
protected virtual void PathFindImplementation(uint unit, ref PathUnit data) { NetManager instance = Singleton<NetManager>.instance; this.m_laneTypes = (NetInfo.LaneType)this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_laneTypes; this.m_vehicleTypes = (VehicleInfo.VehicleType)this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_vehicleTypes; this.m_maxLength = this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_length; this.m_pathFindIndex = (this.m_pathFindIndex + 1u & 32767u); this.m_pathRandomizer = new Randomizer(unit); this.m_isHeavyVehicle = ((this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_simulationFlags & 16) != 0); this.m_ignoreBlocked = ((this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_simulationFlags & 32) != 0); this.m_stablePath = ((this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_simulationFlags & 64) != 0); this.m_transportVehicle = ((byte)(this.m_laneTypes & NetInfo.LaneType.TransportVehicle) != 0); if ((byte)(this.m_laneTypes & NetInfo.LaneType.Vehicle) != 0) { this.m_laneTypes |= NetInfo.LaneType.TransportVehicle; } int num = (int)(this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_positionCount & 15); int num2 = this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_positionCount >> 4; BufferItem bufferItem; if (data.m_position00.m_segment != 0 && num >= 1) { this.m_startLaneA = PathManager.GetLaneID(data.m_position00); this.m_startOffsetA = data.m_position00.m_offset; bufferItem.m_laneID = this.m_startLaneA; bufferItem.m_position = data.m_position00; this.GetLaneDirection(data.m_position00, out bufferItem.m_direction, out bufferItem.m_lanesUsed); bufferItem.m_comparisonValue = 0f; } else { this.m_startLaneA = 0u; this.m_startOffsetA = 0; bufferItem = default(BufferItem); } BufferItem bufferItem2; if (data.m_position02.m_segment != 0 && num >= 3) { this.m_startLaneB = PathManager.GetLaneID(data.m_position02); this.m_startOffsetB = data.m_position02.m_offset; bufferItem2.m_laneID = this.m_startLaneB; bufferItem2.m_position = data.m_position02; this.GetLaneDirection(data.m_position02, out bufferItem2.m_direction, out bufferItem2.m_lanesUsed); bufferItem2.m_comparisonValue = 0f; } else { this.m_startLaneB = 0u; this.m_startOffsetB = 0; bufferItem2 = default(BufferItem); } BufferItem bufferItem3; if (data.m_position01.m_segment != 0 && num >= 2) { this.m_endLaneA = PathManager.GetLaneID(data.m_position01); bufferItem3.m_laneID = this.m_endLaneA; bufferItem3.m_position = data.m_position01; this.GetLaneDirection(data.m_position01, out bufferItem3.m_direction, out bufferItem3.m_lanesUsed); bufferItem3.m_methodDistance = 0f; bufferItem3.m_comparisonValue = 0f; } else { this.m_endLaneA = 0u; bufferItem3 = default(BufferItem); } BufferItem bufferItem4; if (data.m_position03.m_segment != 0 && num >= 4) { this.m_endLaneB = PathManager.GetLaneID(data.m_position03); bufferItem4.m_laneID = this.m_endLaneB; bufferItem4.m_position = data.m_position03; this.GetLaneDirection(data.m_position03, out bufferItem4.m_direction, out bufferItem4.m_lanesUsed); bufferItem4.m_methodDistance = 0f; bufferItem4.m_comparisonValue = 0f; } else { this.m_endLaneB = 0u; bufferItem4 = default(BufferItem); } if (data.m_position11.m_segment != 0 && num2 >= 1) { this.m_vehicleLane = PathManager.GetLaneID(data.m_position11); this.m_vehicleOffset = data.m_position11.m_offset; } else { this.m_vehicleLane = 0u; this.m_vehicleOffset = 0; } BufferItem bufferItem5 = default(BufferItem); byte b = 0; this.m_bufferMinPos = 0; this.m_bufferMaxPos = -1; if (this.m_pathFindIndex == 0u) { uint num3 = 4294901760u; for (int i = 0; i < 262144; i++) { this.m_laneLocation[i] = num3; } } for (int j = 0; j < 1024; j++) { this.m_bufferMin[j] = 0; this.m_bufferMax[j] = -1; } if (bufferItem3.m_position.m_segment != 0) { this.m_bufferMax[0]++; this.m_buffer[++this.m_bufferMaxPos] = bufferItem3; } if (bufferItem4.m_position.m_segment != 0) { this.m_bufferMax[0]++; this.m_buffer[++this.m_bufferMaxPos] = bufferItem4; } bool flag = false; while (this.m_bufferMinPos <= this.m_bufferMaxPos) { int num4 = this.m_bufferMin[this.m_bufferMinPos]; int num5 = this.m_bufferMax[this.m_bufferMinPos]; if (num4 > num5) { this.m_bufferMinPos++; } else { this.m_bufferMin[this.m_bufferMinPos] = num4 + 1; BufferItem bufferItem6 = this.m_buffer[(this.m_bufferMinPos << 6) + num4]; if (bufferItem6.m_position.m_segment == bufferItem.m_position.m_segment && bufferItem6.m_position.m_lane == bufferItem.m_position.m_lane) { if ((byte)(bufferItem6.m_direction & NetInfo.Direction.Forward) != 0 && bufferItem6.m_position.m_offset >= this.m_startOffsetA) { bufferItem5 = bufferItem6; b = this.m_startOffsetA; flag = true; break; } if ((byte)(bufferItem6.m_direction & NetInfo.Direction.Backward) != 0 && bufferItem6.m_position.m_offset <= this.m_startOffsetA) { bufferItem5 = bufferItem6; b = this.m_startOffsetA; flag = true; break; } } if (bufferItem6.m_position.m_segment == bufferItem2.m_position.m_segment && bufferItem6.m_position.m_lane == bufferItem2.m_position.m_lane) { if ((byte)(bufferItem6.m_direction & NetInfo.Direction.Forward) != 0 && bufferItem6.m_position.m_offset >= this.m_startOffsetB) { bufferItem5 = bufferItem6; b = this.m_startOffsetB; flag = true; break; } if ((byte)(bufferItem6.m_direction & NetInfo.Direction.Backward) != 0 && bufferItem6.m_position.m_offset <= this.m_startOffsetB) { bufferItem5 = bufferItem6; b = this.m_startOffsetB; flag = true; break; } } if ((byte)(bufferItem6.m_direction & NetInfo.Direction.Forward) != 0) { ushort startNode = instance.m_segments.m_buffer[(int)bufferItem6.m_position.m_segment].m_startNode; this.ProcessItem(bufferItem6, startNode, ref instance.m_nodes.m_buffer[(int)startNode], 0, false); } if ((byte)(bufferItem6.m_direction & NetInfo.Direction.Backward) != 0) { ushort endNode = instance.m_segments.m_buffer[(int)bufferItem6.m_position.m_segment].m_endNode; this.ProcessItem(bufferItem6, endNode, ref instance.m_nodes.m_buffer[(int)endNode], 255, false); } int num6 = 0; ushort num7 = instance.m_lanes.m_buffer[(int)((UIntPtr)bufferItem6.m_laneID)].m_nodes; if (num7 != 0) { ushort startNode2 = instance.m_segments.m_buffer[(int)bufferItem6.m_position.m_segment].m_startNode; ushort endNode2 = instance.m_segments.m_buffer[(int)bufferItem6.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 (num7 != 0) { NetInfo.Direction direction = NetInfo.Direction.None; byte laneOffset = instance.m_nodes.m_buffer[(int)num7].m_laneOffset; if (laneOffset <= bufferItem6.m_position.m_offset) { direction |= NetInfo.Direction.Forward; } if (laneOffset >= bufferItem6.m_position.m_offset) { direction |= NetInfo.Direction.Backward; } if ((byte)(bufferItem6.m_direction & direction) != 0 && (!flag2 || (instance.m_nodes.m_buffer[(int)num7].m_flags & NetNode.Flags.Disabled) != NetNode.Flags.None)) { this.ProcessItem(bufferItem6, num7, ref instance.m_nodes.m_buffer[(int)num7], laneOffset, true); } num7 = instance.m_nodes.m_buffer[(int)num7].m_nextLaneNode; if (++num6 == 32768) { break; } } } } } if (!flag) { PathUnit[] expr_909_cp_0 = this.m_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; } float num8 = bufferItem5.m_comparisonValue * this.m_maxLength; this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_length = num8; uint num9 = unit; int num10 = 0; int num11 = 0; PathUnit.Position position = bufferItem5.m_position; if ((position.m_segment != bufferItem3.m_position.m_segment || position.m_lane != bufferItem3.m_position.m_lane || position.m_offset != bufferItem3.m_position.m_offset) && (position.m_segment != bufferItem4.m_position.m_segment || position.m_lane != bufferItem4.m_position.m_lane || position.m_offset != bufferItem4.m_position.m_offset)) { if (b != position.m_offset) { PathUnit.Position position2 = position; position2.m_offset = b; this.m_pathUnits.m_buffer[(int)((UIntPtr)num9)].SetPosition(num10++, position2); } this.m_pathUnits.m_buffer[(int)((UIntPtr)num9)].SetPosition(num10++, position); position = this.m_laneTarget[(int)((UIntPtr)bufferItem5.m_laneID)]; } for (int k = 0; k < 262144; k++) { this.m_pathUnits.m_buffer[(int)((UIntPtr)num9)].SetPosition(num10++, position); if ((position.m_segment == bufferItem3.m_position.m_segment && position.m_lane == bufferItem3.m_position.m_lane && position.m_offset == bufferItem3.m_position.m_offset) || (position.m_segment == bufferItem4.m_position.m_segment && position.m_lane == bufferItem4.m_position.m_lane && position.m_offset == bufferItem4.m_position.m_offset)) { this.m_pathUnits.m_buffer[(int)((UIntPtr)num9)].m_positionCount = (byte)num10; num11 += num10; if (num11 != 0) { num9 = this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_nextPathUnit; num10 = (int)this.m_pathUnits.m_buffer[(int)((UIntPtr)unit)].m_positionCount; int num12 = 0; while (num9 != 0u) { this.m_pathUnits.m_buffer[(int)((UIntPtr)num9)].m_length = num8 * (float)(num11 - num10) / (float)num11; num10 += (int)this.m_pathUnits.m_buffer[(int)((UIntPtr)num9)].m_positionCount; num9 = this.m_pathUnits.m_buffer[(int)((UIntPtr)num9)].m_nextPathUnit; if (++num12 >= 262144) { CODebugBase<LogChannel>.Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } } PathUnit[] expr_C16_cp_0 = this.m_pathUnits.m_buffer; UIntPtr expr_C16_cp_1 = (UIntPtr)unit; expr_C16_cp_0[(int)expr_C16_cp_1].m_pathFindFlags = (byte)(expr_C16_cp_0[(int)expr_C16_cp_1].m_pathFindFlags | 4); return; } if (num10 == 12) { while (!Monitor.TryEnter(this.m_bufferLock, SimulationManager.SYNCHRONIZE_TIMEOUT)) { } uint num13; try { if (!this.m_pathUnits.CreateItem(out num13, ref this.m_pathRandomizer)) { PathUnit[] expr_D15_cp_0 = this.m_pathUnits.m_buffer; UIntPtr expr_D15_cp_1 = (UIntPtr)unit; expr_D15_cp_0[(int)expr_D15_cp_1].m_pathFindFlags = (byte)(expr_D15_cp_0[(int)expr_D15_cp_1].m_pathFindFlags | 8); return; } this.m_pathUnits.m_buffer[(int)((UIntPtr)num13)] = this.m_pathUnits.m_buffer[(int)((UIntPtr)num9)]; this.m_pathUnits.m_buffer[(int)((UIntPtr)num13)].m_referenceCount = 1; this.m_pathUnits.m_buffer[(int)((UIntPtr)num13)].m_pathFindFlags = 4; this.m_pathUnits.m_buffer[(int)((UIntPtr)num9)].m_nextPathUnit = num13; this.m_pathUnits.m_buffer[(int)((UIntPtr)num9)].m_positionCount = (byte)num10; num11 += num10; Singleton<PathManager>.instance.m_pathUnitCount = (int)(this.m_pathUnits.ItemCount() - 1u); } finally { Monitor.Exit(this.m_bufferLock); } num9 = num13; num10 = 0; } uint laneID = PathManager.GetLaneID(position); position = this.m_laneTarget[(int)((UIntPtr)laneID)]; } PathUnit[] expr_D99_cp_0 = this.m_pathUnits.m_buffer; UIntPtr expr_D99_cp_1 = (UIntPtr)unit; expr_D99_cp_0[(int)expr_D99_cp_1].m_pathFindFlags = (byte)(expr_D99_cp_0[(int)expr_D99_cp_1].m_pathFindFlags | 8); }
private void PathFindImplementation(uint unit, ref PathUnit data) { var instance = Singleton<NetManager>.instance; _laneTypes = (NetInfo.LaneType)PathUnits.m_buffer[(int)((UIntPtr)unit)].m_laneTypes; _vehicleTypes = (VehicleInfo.VehicleType)PathUnits.m_buffer[(int)((UIntPtr)unit)].m_vehicleTypes; _maxLength = PathUnits.m_buffer[(int)((UIntPtr)unit)].m_length; _pathFindIndex = (_pathFindIndex + 1u & 32767u); _pathRandomizer = new Randomizer(unit); _isHeavyVehicle = ((PathUnits.m_buffer[(int)((UIntPtr)unit)].m_simulationFlags & 16) != 0); _ignoreBlocked = ((PathUnits.m_buffer[(int)((UIntPtr)unit)].m_simulationFlags & 32) != 0); _stablePath = ((PathUnits.m_buffer[(int)((UIntPtr)unit)].m_simulationFlags & 64) != 0); //this._vehicleType = // TrafficRoadRestrictions.vehicleType(this._pathUnits._buffer[(int) ((UIntPtr) unit)].m_simulationFlags); var num = PathUnits.m_buffer[(int)((UIntPtr)unit)].m_positionCount & 15; var num2 = PathUnits.m_buffer[(int)((UIntPtr)unit)].m_positionCount >> 4; BufferItem startPosA; if (data.m_position00.m_segment != 0 && num >= 1) { _startLaneA = PathManager.GetLaneID(data.m_position00); _startOffsetA = data.m_position00.m_offset; startPosA.LaneId = _startLaneA; startPosA.Position = data.m_position00; GetLaneDirection(data.m_position00, out startPosA.Direction, out startPosA.LanesUsed); startPosA.ComparisonValue = 0f; } else { _startLaneA = 0u; _startOffsetA = 0; startPosA = default(BufferItem); } BufferItem startPosB; if (data.m_position02.m_segment != 0 && num >= 3) { _startLaneB = PathManager.GetLaneID(data.m_position02); _startOffsetB = data.m_position02.m_offset; startPosB.LaneId = _startLaneB; startPosB.Position = data.m_position02; GetLaneDirection(data.m_position02, out startPosB.Direction, out startPosB.LanesUsed); startPosB.ComparisonValue = 0f; } else { _startLaneB = 0u; _startOffsetB = 0; startPosB = default(BufferItem); } BufferItem endPosA; if (data.m_position01.m_segment != 0 && num >= 2) { _endLaneA = PathManager.GetLaneID(data.m_position01); endPosA.LaneId = _endLaneA; endPosA.Position = data.m_position01; GetLaneDirection(data.m_position01, out endPosA.Direction, out endPosA.LanesUsed); endPosA.MethodDistance = 0f; endPosA.ComparisonValue = 0f; } else { _endLaneA = 0u; endPosA = default(BufferItem); } BufferItem endPosB; if (data.m_position03.m_segment != 0 && num >= 4) { _endLaneB = PathManager.GetLaneID(data.m_position03); endPosB.LaneId = _endLaneB; endPosB.Position = data.m_position03; GetLaneDirection(data.m_position03, out endPosB.Direction, out endPosB.LanesUsed); endPosB.MethodDistance = 0f; endPosB.ComparisonValue = 0f; } else { _endLaneB = 0u; endPosB = default(BufferItem); } if (data.m_position11.m_segment != 0 && num2 >= 1) { _vehicleLane = PathManager.GetLaneID(data.m_position11); _vehicleOffset = data.m_position11.m_offset; } else { _vehicleLane = 0u; _vehicleOffset = 0; } BufferItem goalItem = default(BufferItem); byte b = 0; _bufferMinPos = 0; _bufferMaxPos = -1; if (_pathFindIndex == 0u) { uint num3 = 4294901760u; for (int i = 0; i < 262144; i++) { _laneLocation[i] = num3; } } for (int j = 0; j < 1024; j++) { _bufferMin[j] = 0; _bufferMax[j] = -1; } if (endPosA.Position.m_segment != 0) { _bufferMax[0]++; _buffer[++_bufferMaxPos] = endPosA; } if (endPosB.Position.m_segment != 0) { _bufferMax[0]++; _buffer[++_bufferMaxPos] = endPosB; } bool flag = false; while (_bufferMinPos <= _bufferMaxPos) { int num4 = _bufferMin[_bufferMinPos]; int num5 = _bufferMax[_bufferMinPos]; if (num4 > num5) { _bufferMinPos++; } else { _bufferMin[_bufferMinPos] = num4 + 1; BufferItem currentItem = _buffer[(_bufferMinPos << 6) + num4]; if (currentItem.Position.m_segment == startPosA.Position.m_segment && currentItem.Position.m_lane == startPosA.Position.m_lane) { if ((byte)(currentItem.Direction & NetInfo.Direction.Forward) != 0 && currentItem.Position.m_offset >= _startOffsetA) { goalItem = currentItem; b = _startOffsetA; flag = true; break; } if ((byte)(currentItem.Direction & NetInfo.Direction.Backward) != 0 && currentItem.Position.m_offset <= _startOffsetA) { goalItem = currentItem; b = _startOffsetA; flag = true; break; } } if (currentItem.Position.m_segment == startPosB.Position.m_segment && currentItem.Position.m_lane == startPosB.Position.m_lane) { if ((byte)(currentItem.Direction & NetInfo.Direction.Forward) != 0 && currentItem.Position.m_offset >= _startOffsetB) { goalItem = currentItem; b = _startOffsetB; flag = true; break; } if ((byte)(currentItem.Direction & NetInfo.Direction.Backward) != 0 && currentItem.Position.m_offset <= _startOffsetB) { goalItem = currentItem; b = _startOffsetB; flag = true; break; } } if ((byte)(currentItem.Direction & NetInfo.Direction.Forward) != 0) { ushort startNode = instance.m_segments.m_buffer[currentItem.Position.m_segment].m_startNode; ProcessItem1(currentItem, startNode, ref instance.m_nodes.m_buffer[startNode], 0, false, ref data); } if ((byte)(currentItem.Direction & NetInfo.Direction.Backward) != 0) { ushort endNode = instance.m_segments.m_buffer[currentItem.Position.m_segment].m_endNode; ProcessItem1(currentItem, endNode, ref instance.m_nodes.m_buffer[endNode], 255, false, ref data); } int num6 = 0; ushort num7 = instance.m_lanes.m_buffer[(int)((UIntPtr)currentItem.LaneId)].m_nodes; if (num7 != 0) { ushort startNode2 = instance.m_segments.m_buffer[currentItem.Position.m_segment].m_startNode; ushort endNode2 = instance.m_segments.m_buffer[currentItem.Position.m_segment].m_endNode; bool flag2 = ((instance.m_nodes.m_buffer[startNode2].m_flags | instance.m_nodes.m_buffer[endNode2].m_flags) & NetNode.Flags.Disabled) != NetNode.Flags.None; while (num7 != 0) { NetInfo.Direction direction = NetInfo.Direction.None; byte laneOffset = instance.m_nodes.m_buffer[num7].m_laneOffset; if (laneOffset <= currentItem.Position.m_offset) { direction |= NetInfo.Direction.Forward; } if (laneOffset >= currentItem.Position.m_offset) { direction |= NetInfo.Direction.Backward; } if ((byte)(currentItem.Direction & direction) != 0 && (!flag2 || (instance.m_nodes.m_buffer[num7].m_flags & NetNode.Flags.Disabled) != NetNode.Flags.None)) { ProcessItem1(currentItem, num7, ref instance.m_nodes.m_buffer[num7], laneOffset, true, ref data); } num7 = instance.m_nodes.m_buffer[num7].m_nextLaneNode; if (++num6 == 32768) { break; } } } } } if (!flag) { var expr_8D5Cp0 = PathUnits.m_buffer; var expr_8D5Cp1 = (UIntPtr)unit; expr_8D5Cp0[(int)expr_8D5Cp1].m_pathFindFlags = (byte)(expr_8D5Cp0[(int)expr_8D5Cp1].m_pathFindFlags | 8); return; } var num8 = goalItem.ComparisonValue * _maxLength; PathUnits.m_buffer[(int)((UIntPtr)unit)].m_length = num8; var num9 = unit; var num10 = 0; var num11 = 0; var position = goalItem.Position; if ((position.m_segment != endPosA.Position.m_segment || position.m_lane != endPosA.Position.m_lane || position.m_offset != endPosA.Position.m_offset) && (position.m_segment != endPosB.Position.m_segment || position.m_lane != endPosB.Position.m_lane || position.m_offset != endPosB.Position.m_offset)) { if (b != position.m_offset) { var position2 = position; position2.m_offset = b; PathUnits.m_buffer[(int)((UIntPtr)num9)].SetPosition(num10++, position2); } PathUnits.m_buffer[(int)((UIntPtr)num9)].SetPosition(num10++, position); position = _laneTarget[(int)((UIntPtr)goalItem.LaneId)]; } for (var k = 0; k < 262144; k++) { PathUnits.m_buffer[(int)((UIntPtr)num9)].SetPosition(num10++, position); if ((position.m_segment == endPosA.Position.m_segment && position.m_lane == endPosA.Position.m_lane && position.m_offset == endPosA.Position.m_offset) || (position.m_segment == endPosB.Position.m_segment && position.m_lane == endPosB.Position.m_lane && position.m_offset == endPosB.Position.m_offset)) { PathUnits.m_buffer[(int)((UIntPtr)num9)].m_positionCount = (byte)num10; num11 += num10; if (num11 != 0) { num9 = PathUnits.m_buffer[(int)((UIntPtr)unit)].m_nextPathUnit; num10 = PathUnits.m_buffer[(int)((UIntPtr)unit)].m_positionCount; var num12 = 0; while (num9 != 0u) { PathUnits.m_buffer[(int)((UIntPtr)num9)].m_length = num8 * (num11 - num10) / num11; num10 += PathUnits.m_buffer[(int)((UIntPtr)num9)].m_positionCount; num9 = PathUnits.m_buffer[(int)((UIntPtr)num9)].m_nextPathUnit; if (++num12 >= 262144) { CODebugBase<LogChannel>.Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } } var exprBe2Cp0 = PathUnits.m_buffer; var exprBe2Cp1 = (UIntPtr)unit; exprBe2Cp0[(int)exprBe2Cp1].m_pathFindFlags = (byte)(exprBe2Cp0[(int)exprBe2Cp1].m_pathFindFlags | 4); return; } if (num10 == 12) { while (!Monitor.TryEnter(_bufferLock, SimulationManager.SYNCHRONIZE_TIMEOUT)) { } uint num13; try { var localRandom = _pathRandomizer; if (!PathUnits.CreateItem(out num13, ref localRandom)) { var exprCe1Cp0 = PathUnits.m_buffer; var exprCe1Cp1 = (UIntPtr)unit; exprCe1Cp0[(int)exprCe1Cp1].m_pathFindFlags = (byte)(exprCe1Cp0[(int)exprCe1Cp1].m_pathFindFlags | 8); return; } _pathRandomizer = localRandom; PathUnits.m_buffer[(int)((UIntPtr)num13)] = PathUnits.m_buffer[(int)((UIntPtr)num9)]; PathUnits.m_buffer[(int)((UIntPtr)num13)].m_referenceCount = 1; PathUnits.m_buffer[(int)((UIntPtr)num13)].m_pathFindFlags = 4; PathUnits.m_buffer[(int)((UIntPtr)num9)].m_nextPathUnit = num13; PathUnits.m_buffer[(int)((UIntPtr)num9)].m_positionCount = (byte)num10; num11 += num10; Singleton<PathManager>.instance.m_pathUnitCount = (int)(PathUnits.ItemCount() - 1u); } finally { Monitor.Exit(_bufferLock); } num9 = num13; num10 = 0; } var laneId = PathManager.GetLaneID(position); position = _laneTarget[(int)((UIntPtr)laneId)]; } var exprD65Cp0 = PathUnits.m_buffer; var exprD65Cp1 = (UIntPtr)unit; exprD65Cp0[(int)exprD65Cp1].m_pathFindFlags = (byte)(exprD65Cp0[(int)exprD65Cp1].m_pathFindFlags | 8); }