public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays, bool undergroundTarget) { #if PATHRECALC VehicleState state = VehicleStateManager._GetVehicleState(vehicleID); bool recalcRequested = state.PathRecalculationRequested; state.PathRecalculationRequested = false; #endif VehicleInfo info = this.m_info; ushort driverInstance = CustomPassengerCarAI.GetDriverInstance(vehicleID, ref vehicleData); if (driverInstance == 0) { return(false); } CitizenManager instance = Singleton <CitizenManager> .instance; CitizenInfo info2 = instance.m_instances.m_buffer[(int)driverInstance].Info; NetInfo.LaneType laneTypes = NetInfo.LaneType.Vehicle | NetInfo.LaneType.Pedestrian; VehicleInfo.VehicleType vehicleType = this.m_info.m_vehicleType; bool allowUnderground = (vehicleData.m_flags & Vehicle.Flags.Underground) != 0; bool randomParking = false; ushort targetBuilding = instance.m_instances.m_buffer[(int)driverInstance].m_targetBuilding; if (targetBuilding != 0 && Singleton <BuildingManager> .instance.m_buildings.m_buffer[(int)targetBuilding].Info.m_class.m_service > ItemClass.Service.Office) { randomParking = true; } PathUnit.Position startPosA; PathUnit.Position startPosB; float num; float num2; PathUnit.Position endPosA; if (CustomPathManager.FindPathPosition(startPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, allowUnderground, false, 32f, out startPosA, out startPosB, out num, out num2) && info2.m_citizenAI.FindPathPosition(driverInstance, ref instance.m_instances.m_buffer[(int)driverInstance], endPos, laneTypes, vehicleType, undergroundTarget, out endPosA)) { if (!startBothWays || num < 10f) { startPosB = default(PathUnit.Position); } PathUnit.Position endPosB = default(PathUnit.Position); SimulationManager instance2 = Singleton <SimulationManager> .instance; uint path; PathUnit.Position def = default(PathUnit.Position); if (Singleton <CustomPathManager> .instance.CreatePath( #if PATHRECALC recalcRequested #else false #endif , ExtVehicleType.PassengerCar, out path, ref instance2.m_randomizer, instance2.m_currentBuildIndex, ref startPosA, ref startPosB, ref endPosA, ref endPosB, ref def, laneTypes, vehicleType, 20000f, false, false, false, false, randomParking)) { if (vehicleData.m_path != 0u) { Singleton <PathManager> .instance.ReleasePath(vehicleData.m_path); } vehicleData.m_path = path; vehicleData.m_flags |= Vehicle.Flags.WaitingPath; return(true); } } return(false); }
public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays, bool undergroundTarget) { ushort driverInstanceId = CustomPassengerCarAI.GetDriverInstanceId(vehicleID, ref vehicleData); if (driverInstanceId == 0) { return(false); } return(ExtStartPathFind(vehicleID, ref vehicleData, driverInstanceId, ref ExtCitizenInstanceManager.Instance.ExtInstances[driverInstanceId], startPos, endPos, startBothWays, endBothWays, undergroundTarget)); }
public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays, bool undergroundTarget) { VehicleInfo info = this.m_info; ushort driverInstance = CustomPassengerCarAI.GetDriverInstance(vehicleID, ref vehicleData); if (driverInstance == 0) { return(false); } CitizenManager instance = Singleton <CitizenManager> .instance; CitizenInfo info2 = instance.m_instances.m_buffer[(int)driverInstance].Info; NetInfo.LaneType laneTypes = NetInfo.LaneType.Vehicle | NetInfo.LaneType.Pedestrian; VehicleInfo.VehicleType vehicleType = this.m_info.m_vehicleType; bool allowUnderground = (vehicleData.m_flags & Vehicle.Flags.Underground) != Vehicle.Flags.None; PathUnit.Position startPosA; PathUnit.Position startPosB; float num; float num2; PathUnit.Position endPosA; if (CustomPathManager.FindPathPosition(startPos, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, allowUnderground, false, 32f, out startPosA, out startPosB, out num, out num2) && info2.m_citizenAI.FindPathPosition(driverInstance, ref instance.m_instances.m_buffer[(int)driverInstance], endPos, laneTypes, vehicleType, undergroundTarget, out endPosA)) { if (!startBothWays || num < 10f) { startPosB = default(PathUnit.Position); } PathUnit.Position endPosB = default(PathUnit.Position); SimulationManager instance2 = Singleton <SimulationManager> .instance; uint path; if (Singleton <CustomPathManager> .instance.CreatePath(ExtVehicleType.PassengerCar, out path, ref instance2.m_randomizer, instance2.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, laneTypes, vehicleType, 20000f)) { if (vehicleData.m_path != 0u) { Singleton <PathManager> .instance.ReleasePath(vehicleData.m_path); } vehicleData.m_path = path; vehicleData.m_flags |= Vehicle.Flags.WaitingPath; return(true); } } return(false); }
public bool CustomStartPathFind(ushort vehicleID, ref Vehicle vehicleData, Vector3 startPos, Vector3 endPos, bool startBothWays, bool endBothWays, bool undergroundTarget) { ushort driverInstanceId = CustomPassengerCarAI.GetDriverInstanceId(vehicleID, ref vehicleData); if (driverInstanceId == 0) { return(false); } #if BENCHMARK using (var bm = new Benchmark(null, "ExtStartPathFind")) { #endif return(ExtStartPathFind(vehicleID, ref vehicleData, driverInstanceId, ref ExtCitizenInstanceManager.Instance.ExtInstances[driverInstanceId], startPos, endPos, startBothWays, endBothWays, undergroundTarget)); #if BENCHMARK } #endif }
/// <summary> /// Tries to spawn a parked passenger car for the given citizen <paramref name="citizenId"/> at a building in the vicinity of the given position <paramref name="refPos"/> /// </summary> /// <param name="citizenId">Citizen that requires a parked car</param> /// <param name="homeId">Home building id of the citizen (For residential buildings, parked cars may only spawn at the home building)</param> /// <param name="refPos">Reference position</param> /// <param name="vehicleInfo">Vehicle type to spawn</param> /// <param name="parkPos">Parked vehicle position (output)</param> /// <returns>true if a passenger car could be spawned, false otherwise</returns> protected static bool TrySpawnParkedPassengerCarBuilding(uint citizenId, ushort homeId, Vector3 refPos, VehicleInfo vehicleInfo, out Vector3 parkPos) { #if DEBUG if (GlobalConfig.Instance.DebugSwitches[4] && homeId != 0) { Log._Debug($"Trying to spawn parked passenger car next to building for citizen {citizenId} @ {refPos}"); } #endif parkPos = Vector3.zero; Quaternion parkRot = Quaternion.identity; float parkOffset; if (CustomPassengerCarAI.FindParkingSpaceBuilding(vehicleInfo, homeId, 0, 0, refPos, GlobalConfig.Instance.VicinityParkingSpaceSearchRadius, GlobalConfig.Instance.VicinityParkingSpaceSearchRadius, out parkPos, out parkRot, out parkOffset)) { // position found, spawn a parked vehicle ushort parkedVehicleId; if (Singleton <VehicleManager> .instance.CreateParkedVehicle(out parkedVehicleId, ref Singleton <SimulationManager> .instance.m_randomizer, vehicleInfo, parkPos, parkRot, citizenId)) { Singleton <CitizenManager> .instance.m_citizens.m_buffer[citizenId].SetParkedVehicle(citizenId, parkedVehicleId); Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_flags &= (ushort)(VehicleParked.Flags.All & ~VehicleParked.Flags.Parking); #if DEBUG if (GlobalConfig.Instance.DebugSwitches[4] && homeId != 0) { Log._Debug($"[SUCCESS] Spawned parked passenger car next to building for citizen {citizenId}: {parkedVehicleId}"); } #endif return(true); } } #if DEBUG if (GlobalConfig.Instance.DebugSwitches[2] && homeId != 0) { Log._Debug($"[FAIL] Failed to spawn parked passenger car next to building for citizen {citizenId}"); } #endif return(false); }
/// <summary> /// Lightweight simulation step method. /// This method is occasionally being called for different cars. /// </summary> /// <param name="vehicleId"></param> /// <param name="vehicleData"></param> /// <param name="physicsLodRefPos"></param> public void CustomSimulationStep(ushort vehicleId, ref Vehicle vehicleData, Vector3 physicsLodRefPos) { if ((vehicleData.m_flags & Vehicle.Flags.WaitingPath) != 0) { PathManager pathManager = Singleton <PathManager> .instance; byte pathFindFlags = pathManager.m_pathUnits.m_buffer[vehicleData.m_path].m_pathFindFlags; // NON-STOCK CODE START ExtPathState mainPathState = ExtPathState.Calculating; if ((pathFindFlags & PathUnit.FLAG_FAILED) != 0 || vehicleData.m_path == 0) { mainPathState = ExtPathState.Failed; } else if ((pathFindFlags & PathUnit.FLAG_READY) != 0) { mainPathState = ExtPathState.Ready; } #if BENCHMARK using (var bm = new Benchmark(null, "UpdateCarPathState")) { #endif if (Options.prohibitPocketCars && VehicleStateManager.Instance.VehicleStates[vehicleId].vehicleType == ExtVehicleType.PassengerCar) { mainPathState = AdvancedParkingManager.Instance.UpdateCarPathState(vehicleId, ref vehicleData, ref ExtCitizenInstanceManager.Instance.ExtInstances[CustomPassengerCarAI.GetDriverInstanceId(vehicleId, ref vehicleData)], mainPathState); } #if BENCHMARK } #endif // NON-STOCK CODE END if (mainPathState == ExtPathState.Ready) { vehicleData.m_pathPositionIndex = 255; vehicleData.m_flags &= ~Vehicle.Flags.WaitingPath; vehicleData.m_flags &= ~Vehicle.Flags.Arriving; this.PathfindSuccess(vehicleId, ref vehicleData); this.TrySpawn(vehicleId, ref vehicleData); } else if (mainPathState == ExtPathState.Failed) { vehicleData.m_flags &= ~Vehicle.Flags.WaitingPath; Singleton <PathManager> .instance.ReleasePath(vehicleData.m_path); vehicleData.m_path = 0u; this.PathfindFailure(vehicleId, ref vehicleData); return; } } else { if ((vehicleData.m_flags & Vehicle.Flags.WaitingSpace) != 0) { this.TrySpawn(vehicleId, ref vehicleData); } } // NON-STOCK CODE START #if BENCHMARK using (var bm = new Benchmark(null, "UpdateVehiclePosition")) { #endif VehicleStateManager.Instance.UpdateVehiclePosition(vehicleId, ref vehicleData); #if BENCHMARK } #endif if (!Options.isStockLaneChangerUsed()) { #if BENCHMARK using (var bm = new Benchmark(null, "LogTraffic")) { #endif // Advanced AI traffic measurement VehicleStateManager.Instance.LogTraffic(vehicleId); #if BENCHMARK } #endif } // NON-STOCK CODE END Vector3 lastFramePosition = vehicleData.GetLastFramePosition(); int lodPhysics; if (Vector3.SqrMagnitude(physicsLodRefPos - lastFramePosition) >= 1210000f) { lodPhysics = 2; } else if (Vector3.SqrMagnitude(Singleton <SimulationManager> .instance.m_simulationView.m_position - lastFramePosition) >= 250000f) { lodPhysics = 1; } else { lodPhysics = 0; } this.SimulationStep(vehicleId, ref vehicleData, vehicleId, ref vehicleData, lodPhysics); if (vehicleData.m_leadingVehicle == 0 && vehicleData.m_trailingVehicle != 0) { VehicleManager vehManager = Singleton <VehicleManager> .instance; ushort trailerId = vehicleData.m_trailingVehicle; int numIters = 0; while (trailerId != 0) { ushort trailingVehicle = vehManager.m_vehicles.m_buffer[(int)trailerId].m_trailingVehicle; VehicleInfo info = vehManager.m_vehicles.m_buffer[(int)trailerId].Info; info.m_vehicleAI.SimulationStep(trailerId, ref vehManager.m_vehicles.m_buffer[(int)trailerId], vehicleId, ref vehicleData, lodPhysics); trailerId = trailingVehicle; if (++numIters > 16384) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } } int privateServiceIndex = ItemClass.GetPrivateServiceIndex(this.m_info.m_class.m_service); int maxBlockCounter = (privateServiceIndex == -1) ? 150 : 100; if ((vehicleData.m_flags & (Vehicle.Flags.Spawned | Vehicle.Flags.WaitingPath | Vehicle.Flags.WaitingSpace)) == 0 && vehicleData.m_cargoParent == 0) { Singleton <VehicleManager> .instance.ReleaseVehicle(vehicleId); } else if ((int)vehicleData.m_blockCounter >= maxBlockCounter) { // NON-STOCK CODE START bool mayDespawn = true; #if BENCHMARK using (var bm = new Benchmark(null, "MayDespawn")) { #endif mayDespawn = VehicleBehaviorManager.Instance.MayDespawn(ref vehicleData); #if BENCHMARK } #endif if (mayDespawn) { // NON-STOCK CODE END Singleton <VehicleManager> .instance.ReleaseVehicle(vehicleId); } // NON-STOCK CODE } }
/// <summary> /// Lightweight simulation step method. /// This method is occasionally being called for different cars. /// </summary> /// <param name="vehicleId"></param> /// <param name="vehicleData"></param> /// <param name="physicsLodRefPos"></param> public void CustomSimulationStep(ushort vehicleId, ref Vehicle vehicleData, Vector3 physicsLodRefPos) { #if DEBUG bool vehDebug = (GlobalConfig.Instance.Debug.VehicleId == 0 || GlobalConfig.Instance.Debug.VehicleId == vehicleId); bool debug = GlobalConfig.Instance.Debug.Switches[2] && vehDebug; bool fineDebug = GlobalConfig.Instance.Debug.Switches[4] && vehDebug; #endif if ((vehicleData.m_flags & Vehicle.Flags.WaitingPath) != 0) { PathManager pathManager = Singleton <PathManager> .instance; byte pathFindFlags = pathManager.m_pathUnits.m_buffer[vehicleData.m_path].m_pathFindFlags; // NON-STOCK CODE START ExtPathState mainPathState = ExtPathState.Calculating; if ((pathFindFlags & PathUnit.FLAG_FAILED) != 0 || vehicleData.m_path == 0) { mainPathState = ExtPathState.Failed; } else if ((pathFindFlags & PathUnit.FLAG_READY) != 0) { mainPathState = ExtPathState.Ready; } #if DEBUG if (debug) { Log._Debug($"CustomCarAI.CustomSimulationStep({vehicleId}): Path: {vehicleData.m_path}, mainPathState={mainPathState}"); } #endif ExtSoftPathState finalPathState = ExtSoftPathState.None; #if BENCHMARK using (var bm = new Benchmark(null, "UpdateCarPathState")) { #endif finalPathState = ExtCitizenInstance.ConvertPathStateToSoftPathState(mainPathState); if (Options.prohibitPocketCars && VehicleStateManager.Instance.VehicleStates[vehicleId].vehicleType == ExtVehicleType.PassengerCar) { ushort driverInstanceId = CustomPassengerCarAI.GetDriverInstanceId(vehicleId, ref vehicleData); finalPathState = AdvancedParkingManager.Instance.UpdateCarPathState(vehicleId, ref vehicleData, ref Singleton <CitizenManager> .instance.m_instances.m_buffer[driverInstanceId], ref ExtCitizenInstanceManager.Instance.ExtInstances[driverInstanceId], mainPathState); #if DEBUG if (debug) { Log._Debug($"CustomCarAI.CustomSimulationStep({vehicleId}): Applied Parking AI logic. Path: {vehicleData.m_path}, mainPathState={mainPathState}, finalPathState={finalPathState}"); } #endif } #if BENCHMARK } #endif switch (finalPathState) { case ExtSoftPathState.Ready: #if DEBUG if (debug) { Log._Debug($"CustomCarAI.CustomSimulationStep({vehicleId}): Path-finding succeeded for vehicle {vehicleId} (finalPathState={finalPathState}). Path: {vehicleData.m_path} -- calling CarAI.PathfindSuccess"); } #endif vehicleData.m_pathPositionIndex = 255; vehicleData.m_flags &= ~Vehicle.Flags.WaitingPath; vehicleData.m_flags &= ~Vehicle.Flags.Arriving; this.PathfindSuccess(vehicleId, ref vehicleData); this.TrySpawn(vehicleId, ref vehicleData); break; case ExtSoftPathState.Ignore: #if DEBUG if (debug) { Log._Debug($"CustomCarAI.CustomSimulationStep({vehicleId}): Path-finding result shall be ignored for vehicle {vehicleId} (finalPathState={finalPathState}). Path: {vehicleData.m_path} -- ignoring"); } #endif return; case ExtSoftPathState.Calculating: default: #if DEBUG if (debug) { Log._Debug($"CustomCarAI.CustomSimulationStep({vehicleId}): Path-finding result undetermined for vehicle {vehicleId} (finalPathState={finalPathState}). Path: {vehicleData.m_path} -- continue"); } #endif break; case ExtSoftPathState.FailedHard: #if DEBUG if (debug) { Log._Debug($"CustomCarAI.CustomSimulationStep({vehicleId}): HARD path-finding failure for vehicle {vehicleId} (finalPathState={finalPathState}). Path: {vehicleData.m_path} -- calling CarAI.PathfindFailure"); } #endif vehicleData.m_flags &= ~Vehicle.Flags.WaitingPath; Singleton <PathManager> .instance.ReleasePath(vehicleData.m_path); vehicleData.m_path = 0u; this.PathfindFailure(vehicleId, ref vehicleData); return; case ExtSoftPathState.FailedSoft: #if DEBUG if (debug) { Log._Debug($"CustomCarAI.CustomSimulationStep({vehicleId}): SOFT path-finding failure for vehicle {vehicleId} (finalPathState={finalPathState}). Path: {vehicleData.m_path} -- calling CarAI.InvalidPath"); } #endif // path mode has been updated, repeat path-finding vehicleData.m_flags &= ~Vehicle.Flags.WaitingPath; this.InvalidPath(vehicleId, ref vehicleData, vehicleId, ref vehicleData); break; } // NON-STOCK CODE END } else { if ((vehicleData.m_flags & Vehicle.Flags.WaitingSpace) != 0) { this.TrySpawn(vehicleId, ref vehicleData); } } // NON-STOCK CODE START #if BENCHMARK using (var bm = new Benchmark(null, "UpdateVehiclePosition")) { #endif VehicleStateManager.Instance.UpdateVehiclePosition(vehicleId, ref vehicleData); #if BENCHMARK } #endif if (!Options.isStockLaneChangerUsed() && (vehicleData.m_flags & Vehicle.Flags.Spawned) != 0) { #if BENCHMARK using (var bm = new Benchmark(null, "LogTraffic")) { #endif // Advanced AI traffic measurement VehicleStateManager.Instance.LogTraffic(vehicleId); #if BENCHMARK } #endif } // NON-STOCK CODE END Vector3 lastFramePosition = vehicleData.GetLastFramePosition(); int lodPhysics; if (Vector3.SqrMagnitude(physicsLodRefPos - lastFramePosition) >= 1210000f) { lodPhysics = 2; } else if (Vector3.SqrMagnitude(Singleton <SimulationManager> .instance.m_simulationView.m_position - lastFramePosition) >= 250000f) { lodPhysics = 1; } else { lodPhysics = 0; } this.SimulationStep(vehicleId, ref vehicleData, vehicleId, ref vehicleData, lodPhysics); if (vehicleData.m_leadingVehicle == 0 && vehicleData.m_trailingVehicle != 0) { VehicleManager vehManager = Singleton <VehicleManager> .instance; ushort trailerId = vehicleData.m_trailingVehicle; int numIters = 0; while (trailerId != 0) { ushort trailingVehicle = vehManager.m_vehicles.m_buffer[(int)trailerId].m_trailingVehicle; VehicleInfo info = vehManager.m_vehicles.m_buffer[(int)trailerId].Info; info.m_vehicleAI.SimulationStep(trailerId, ref vehManager.m_vehicles.m_buffer[(int)trailerId], vehicleId, ref vehicleData, lodPhysics); trailerId = trailingVehicle; if (++numIters > 16384) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } } int privateServiceIndex = ItemClass.GetPrivateServiceIndex(this.m_info.m_class.m_service); int maxBlockCounter = (privateServiceIndex == -1) ? 150 : 100; if ((vehicleData.m_flags & (Vehicle.Flags.Spawned | Vehicle.Flags.WaitingPath | Vehicle.Flags.WaitingSpace)) == 0 && vehicleData.m_cargoParent == 0) { Singleton <VehicleManager> .instance.ReleaseVehicle(vehicleId); } else if ((int)vehicleData.m_blockCounter >= maxBlockCounter) { // NON-STOCK CODE START bool mayDespawn = true; #if BENCHMARK using (var bm = new Benchmark(null, "MayDespawn")) { #endif mayDespawn = VehicleBehaviorManager.Instance.MayDespawn(ref vehicleData); #if BENCHMARK } #endif if (mayDespawn) { // NON-STOCK CODE END Singleton <VehicleManager> .instance.ReleaseVehicle(vehicleId); } // NON-STOCK CODE } }
/// <summary> /// Lightweight simulation step method. /// This method is occasionally being called for different cars. /// </summary> /// <param name="vehicleId"></param> /// <param name="vehicleData"></param> /// <param name="physicsLodRefPos"></param> public void CustomSimulationStep(ushort vehicleId, ref Vehicle vehicleData, Vector3 physicsLodRefPos) { PathManager pathMan = Singleton <PathManager> .instance; #if DEBUG /*if (!GlobalConfig.Instance.DebugSwitches[0]) { * Log._Debug($"CustomCarAI.CustomSimulationStep({vehicleId}) called. flags: {vehicleData.m_flags} pfFlags: {pathMan.m_pathUnits.m_buffer[vehicleData.m_path].m_pathFindFlags}"); * }*/ #endif // NON-STOCK CODE START VehicleState state = null; ExtCitizenInstance driverExtInstance = null; bool prohibitPocketCars = Options.prohibitPocketCars; if (prohibitPocketCars) { // check for valid driver and update return path state state = VehicleStateManager.Instance._GetVehicleState(vehicleData.GetFirstVehicle(vehicleId)); if (state.VehicleType == ExtVehicleType.PassengerCar) { driverExtInstance = state.GetDriverExtInstance(); if (driverExtInstance == null) { prohibitPocketCars = false; } else { driverExtInstance.UpdateReturnPathState(); } } else { prohibitPocketCars = false; } } // NON-STOCK CODE END if ((vehicleData.m_flags & Vehicle.Flags.WaitingPath) != 0 && (!prohibitPocketCars || driverExtInstance.ReturnPathState != ExtCitizenInstance.ExtPathState.Calculating)) // NON-STOCK CODE: Parking AI: wait for the return path to be calculated { PathManager pathManager = Singleton <PathManager> .instance; byte pathFindFlags = pathManager.m_pathUnits.m_buffer[vehicleData.m_path].m_pathFindFlags; bool pathFindFailed = (pathFindFlags & PathUnit.FLAG_FAILED) != 0 || vehicleData.m_path == 0; // path == 0: non-stock code! bool pathFindSucceeded = (pathFindFlags & PathUnit.FLAG_READY) != 0; #if USEPATHWAITCOUNTER if ((pathFindFlags & (PathUnit.FLAG_READY | PathUnit.FLAG_FAILED)) != 0) { VehicleState state = VehicleStateManager.Instance._GetVehicleState(vehicleId); state.PathWaitCounter = 0; // NON-STOCK CODE } #endif if (prohibitPocketCars) { if (driverExtInstance.ReturnPathState == ExtPathState.Failed) { // no walking path from parking position to target found. flag main path as 'failed'. #if DEBUG if (GlobalConfig.Instance.DebugSwitches[2]) { Log._Debug($"CustomCarAI.CustomSimulationStep: Return path {driverExtInstance.ReturnPathId} FAILED. Forcing path-finding to fail."); } #endif pathFindSucceeded = false; pathFindFailed = true; } driverExtInstance.ReleaseReturnPath(); if (pathFindSucceeded) { CustomPassengerCarAI.OnPathFindSuccess(vehicleId, ref vehicleData, driverExtInstance); } else if (pathFindFailed) { CustomPassengerCarAI.OnPathFindFailure(driverExtInstance, vehicleId); } } if (pathFindSucceeded) { vehicleData.m_pathPositionIndex = 255; vehicleData.m_flags &= ~Vehicle.Flags.WaitingPath; vehicleData.m_flags &= ~Vehicle.Flags.Arriving; this.PathfindSuccess(vehicleId, ref vehicleData); this.TrySpawn(vehicleId, ref vehicleData); } else if (pathFindFailed) { vehicleData.m_flags &= ~Vehicle.Flags.WaitingPath; Singleton <PathManager> .instance.ReleasePath(vehicleData.m_path); vehicleData.m_path = 0u; this.PathfindFailure(vehicleId, ref vehicleData); return; } #if USEPATHWAITCOUNTER else { VehicleState state = VehicleStateManager.Instance._GetVehicleState(vehicleId); state.PathWaitCounter = (ushort)Math.Min(ushort.MaxValue, (int)state.PathWaitCounter + 1); // NON-STOCK CODE } #endif } else { if ((vehicleData.m_flags & Vehicle.Flags.WaitingSpace) != 0) { this.TrySpawn(vehicleId, ref vehicleData); } } /// NON-STOCK CODE START /// VehicleStateManager vehStateManager = VehicleStateManager.Instance; if (Options.prioritySignsEnabled || Options.timedLightsEnabled) { // update vehicle position for timed traffic lights and priority signs try { vehStateManager.UpdateVehiclePos(vehicleId, ref vehicleData); } catch (Exception e) { Log.Error("CarAI CustomSimulationStep Error: " + e.ToString()); } } if (!Options.isStockLaneChangerUsed()) { // Advanced AI traffic measurement try { vehStateManager.LogTraffic(vehicleId, ref vehicleData, true); } catch (Exception e) { Log.Error("CarAI CustomSimulationStep Error: " + e.ToString()); } } /// NON-STOCK CODE END /// Vector3 lastFramePosition = vehicleData.GetLastFramePosition(); int lodPhysics; if (Vector3.SqrMagnitude(physicsLodRefPos - lastFramePosition) >= 1210000f) { lodPhysics = 2; } else if (Vector3.SqrMagnitude(Singleton <SimulationManager> .instance.m_simulationView.m_position - lastFramePosition) >= 250000f) { lodPhysics = 1; } else { lodPhysics = 0; } this.SimulationStep(vehicleId, ref vehicleData, vehicleId, ref vehicleData, lodPhysics); if (vehicleData.m_leadingVehicle == 0 && vehicleData.m_trailingVehicle != 0) { VehicleManager vehManager = Singleton <VehicleManager> .instance; ushort num = vehicleData.m_trailingVehicle; int num2 = 0; while (num != 0) { ushort trailingVehicle = vehManager.m_vehicles.m_buffer[(int)num].m_trailingVehicle; VehicleInfo info = vehManager.m_vehicles.m_buffer[(int)num].Info; info.m_vehicleAI.SimulationStep(num, ref vehManager.m_vehicles.m_buffer[(int)num], vehicleId, ref vehicleData, lodPhysics); num = trailingVehicle; if (++num2 > 16384) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } } #if PATHRECALC ushort recalcSegmentId = 0; #endif int privateServiceIndex = ItemClass.GetPrivateServiceIndex(this.m_info.m_class.m_service); int maxBlockCounter = (privateServiceIndex == -1) ? 150 : 100; if ((vehicleData.m_flags & (Vehicle.Flags.Spawned | Vehicle.Flags.WaitingPath | Vehicle.Flags.WaitingSpace)) == 0 && vehicleData.m_cargoParent == 0) { Singleton <VehicleManager> .instance.ReleaseVehicle(vehicleId); } else if ((int)vehicleData.m_blockCounter >= maxBlockCounter && Options.enableDespawning) { Singleton <VehicleManager> .instance.ReleaseVehicle(vehicleId); } #if PATHRECALC else if (vehicleData.m_leadingVehicle == 0 && CustomVehicleAI.ShouldRecalculatePath(vehicleId, ref vehicleData, maxBlockCounter, out recalcSegmentId)) { CustomVehicleAI.MarkPathRecalculation(vehicleId, recalcSegmentId); InvalidPath(vehicleId, ref vehicleData, vehicleId, ref vehicleData); } #endif }
/// <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); }