/// <summary> /// Starts path-finding of the walking path from parking position <paramref name="parkPos"/> to target position <paramref name="targetPos"/>. /// </summary> /// <param name="parkPos">Parking position</param> /// <param name="targetPos">Target position</param> /// <returns></returns> internal bool CalculateReturnPath(Vector3 parkPos, Vector3 targetPos) { ReleaseReturnPath(); PathUnit.Position parkPathPos; PathUnit.Position targetPathPos; if (CustomPathManager.FindPathPositionWithSpiralLoop(parkPos, ItemClass.Service.Road, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, false, false, GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance, out parkPathPos) && CustomPathManager.FindPathPositionWithSpiralLoop(targetPos, ItemClass.Service.Road, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, false, false, GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance, out targetPathPos)) { PathUnit.Position dummyPathPos = default(PathUnit.Position); uint pathId; PathCreationArgs args; args.extPathType = ExtCitizenInstance.ExtPathType.WalkingOnly; args.extVehicleType = ExtVehicleType.None; args.vehicleId = 0; args.buildIndex = Singleton <SimulationManager> .instance.m_currentBuildIndex; args.startPosA = parkPathPos; args.startPosB = dummyPathPos; args.endPosA = targetPathPos; args.endPosB = dummyPathPos; args.vehiclePosition = dummyPathPos; args.laneTypes = NetInfo.LaneType.Pedestrian; args.vehicleTypes = VehicleInfo.VehicleType.None; args.maxLength = 20000f; args.isHeavyVehicle = false; args.hasCombustionEngine = false; args.ignoreBlocked = false; args.ignoreFlooded = false; args.randomParking = false; args.stablePath = false; args.skipQueue = false; if (CustomPathManager._instance.CreatePath(out pathId, ref Singleton <SimulationManager> .instance.m_randomizer, args)) { #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"ExtCitizenInstance.CalculateReturnPath: Path-finding starts for return path of citizen instance {instanceId}, path={pathId}, parkPathPos.segment={parkPathPos.m_segment}, parkPathPos.lane={parkPathPos.m_lane}, targetPathPos.segment={targetPathPos.m_segment}, targetPathPos.lane={targetPathPos.m_lane}"); } #endif returnPathId = pathId; returnPathState = ExtPathState.Calculating; return(true); } } #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"ExtCitizenInstance.CalculateReturnPath: Could not find path position(s) for either the parking position or target position of citizen instance {instanceId}."); } #endif return(false); }
/// <summary> /// Starts path-finding of the walking path from parking position <paramref name="parkPos"/> to target position <paramref name="targetPos"/>. /// </summary> /// <param name="parkPos">Parking position</param> /// <param name="targetPos">Target position</param> /// <returns></returns> internal bool CalculateReturnPath(Vector3 parkPos, Vector3 targetPos) { ReleaseReturnPath(); PathUnit.Position parkPathPos; PathUnit.Position targetPathPos; if (CustomPathManager.FindPathPositionWithSpiralLoop(parkPos, ItemClass.Service.Road, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, false, false, GlobalConfig.Instance.MaxBuildingToPedestrianLaneDistance, out parkPathPos) && CustomPathManager.FindPathPositionWithSpiralLoop(targetPos, ItemClass.Service.Road, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, false, false, GlobalConfig.Instance.MaxBuildingToPedestrianLaneDistance, out targetPathPos)) { PathUnit.Position dummyPathPos = default(PathUnit.Position); uint pathId; if (CustomPathManager._instance.CreatePath(false, ExtVehicleType.None, 0, ExtCitizenInstance.ExtPathType.WalkingOnly, out pathId, ref Singleton <SimulationManager> .instance.m_randomizer, Singleton <SimulationManager> .instance.m_currentBuildIndex, parkPathPos, dummyPathPos, targetPathPos, dummyPathPos, dummyPathPos, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, 20000f, false, false, false, false, false, false)) { #if DEBUG if (GlobalConfig.Instance.DebugSwitches[2]) { Log._Debug($"ExtCitizenInstance.CalculateReturnPath: Path-finding starts for return path of citizen instance {InstanceId}, path={pathId}, parkPathPos.segment={parkPathPos.m_segment}, parkPathPos.lane={parkPathPos.m_lane}, targetPathPos.segment={targetPathPos.m_segment}, targetPathPos.lane={targetPathPos.m_lane}"); } #endif ReturnPathId = pathId; ReturnPathState = ExtPathState.Calculating; return(true); } } #if DEBUG if (GlobalConfig.Instance.DebugSwitches[2]) { Log._Debug($"ExtCitizenInstance.CalculateReturnPath: Could not find path position(s) for either the parking position or target position of citizen instance {InstanceId}."); } #endif return(false); }
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); }
/// <summary> /// Finds a free parking space in the vicinity of the given target position <paramref name="endPos"/> for the given citizen instance <paramref name="extDriverInstance"/>. /// </summary> /// <param name="endPos">target position</param> /// <param name="vehicleInfo">vehicle type that is being used</param> /// <param name="extDriverInstance">cititzen instance that is driving the car</param> /// <param name="homeId">Home building of the citizen (may be 0 for tourists/homeless cims)</param> /// <param name="vehicleId">Vehicle that is being used (used for logging)</param> /// <param name="allowTourists">If true, method fails if given citizen is a tourist (TODO remove this parameter)</param> /// <param name="parkPos">parking position (output)</param> /// <param name="endPathPos">sidewalk path position near parking space (output). only valid if <paramref name="calculateEndPos"/> yields false.</param> /// <param name="calculateEndPos">if false, a parking space path position could be calculated (TODO negate & rename parameter)</param> /// <returns>true if a parking space could be found, false otherwise</returns> public static bool FindParkingSpaceForExtInstance(Vector3 endPos, VehicleInfo vehicleInfo, ExtCitizenInstance extDriverInstance, ushort homeId, ushort vehicleId, bool allowTourists, out Vector3 parkPos, ref PathUnit.Position endPathPos, out bool calculateEndPos) { calculateEndPos = true; parkPos = default(Vector3); if (!allowTourists) { // TODO remove this from this method uint citizenId = extDriverInstance.GetCitizenId(); if (citizenId == 0 || (Singleton <CitizenManager> .instance.m_citizens.m_buffer[citizenId].m_flags & Citizen.Flags.Tourist) != Citizen.Flags.None) { return(false); } } #if DEBUG if (GlobalConfig.Instance.DebugSwitches[4]) { Log._Debug($"Citizen instance {extDriverInstance.InstanceId} (CurrentPathMode={extDriverInstance.PathMode}) can still use their passenger car and is either not a tourist or wants to find an alternative parking spot. Finding a parking space before starting path-finding."); } #endif ExtParkingSpaceLocation knownParkingSpaceLocation; ushort knownParkingSpaceLocationId; Quaternion parkRot; float parkOffset; // find a free parking space bool success = CustomPassengerCarAI.FindParkingSpaceInVicinity(endPos, vehicleInfo, homeId, vehicleId, out knownParkingSpaceLocation, out knownParkingSpaceLocationId, out parkPos, out parkRot, out parkOffset); extDriverInstance.ParkingSpaceLocation = knownParkingSpaceLocation; extDriverInstance.ParkingSpaceLocationId = knownParkingSpaceLocationId; if (success) { #if DEBUG if (GlobalConfig.Instance.DebugSwitches[4]) { Log._Debug($"Found a parking spot for citizen instance {extDriverInstance.InstanceId} (CurrentPathMode={extDriverInstance.PathMode}) before starting car path: {knownParkingSpaceLocation} @ {knownParkingSpaceLocationId}"); } #endif if (knownParkingSpaceLocation == ExtParkingSpaceLocation.RoadSide) { // found segment with parking space Vector3 pedPos; uint laneId; int laneIndex; float laneOffset; #if DEBUG if (GlobalConfig.Instance.DebugSwitches[2]) { Log._Debug($"Found segment {knownParkingSpaceLocationId} for road-side parking position for citizen instance {extDriverInstance.InstanceId}!"); } #endif // determine nearest sidewalk position for parking position at segment if (Singleton <NetManager> .instance.m_segments.m_buffer[knownParkingSpaceLocationId].GetClosestLanePosition(parkPos, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, out pedPos, out laneId, out laneIndex, out laneOffset)) { endPathPos.m_segment = knownParkingSpaceLocationId; endPathPos.m_lane = (byte)laneIndex; endPathPos.m_offset = (byte)(parkOffset * 255f); calculateEndPos = false; //extDriverInstance.CurrentPathMode = successMode;// ExtCitizenInstance.PathMode.CalculatingKnownCarPath; #if DEBUG if (GlobalConfig.Instance.DebugSwitches[2]) { Log._Debug($"Found an parking spot sidewalk position for citizen instance {extDriverInstance.InstanceId} @ segment {knownParkingSpaceLocationId}, laneId {laneId}, laneIndex {laneIndex}, offset={endPathPos.m_offset}! CurrentPathMode={extDriverInstance.PathMode}"); } #endif return(true); } else { #if DEBUG if (GlobalConfig.Instance.DebugSwitches[2]) { Log._Debug($"Could not find an alternative parking spot sidewalk position for citizen instance {extDriverInstance.InstanceId}! CurrentPathMode={extDriverInstance.PathMode}"); } #endif return(false); } } else if (knownParkingSpaceLocation == ExtParkingSpaceLocation.Building) { // found a building with parking space if (CustomPathManager.FindPathPositionWithSpiralLoop(parkPos, endPos, ItemClass.Service.Road, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, false, false, GlobalConfig.Instance.MaxBuildingToPedestrianLaneDistance, out endPathPos)) { calculateEndPos = false; } //endPos = parkPos; //extDriverInstance.CurrentPathMode = successMode;// ExtCitizenInstance.PathMode.CalculatingKnownCarPath; #if DEBUG if (GlobalConfig.Instance.DebugSwitches[2]) { Log._Debug($"Navigating citizen instance {extDriverInstance.InstanceId} to parking building {knownParkingSpaceLocationId}! segment={endPathPos.m_segment}, laneIndex={endPathPos.m_lane}, offset={endPathPos.m_offset}. CurrentPathMode={extDriverInstance.PathMode} calculateEndPos={calculateEndPos}"); } #endif return(true); } } return(false); }