/// <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 } }
public void CustomSimulationStep(ushort vehicleId, ref Vehicle vehicleData, Vector3 physicsLodRefPos) { #if DEBUG bool vehDebug = DebugSettings.VehicleId == 0 || DebugSettings.VehicleId == vehicleId; bool logParkingAi = DebugSwitch.BasicParkingAILog.Get() && vehDebug; #else var logParkingAi = false; #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 uint logVehiclePath = vehicleData.m_path; Log._DebugIf( logParkingAi, () => $"CustomCarAI.CustomSimulationStep({vehicleId}): " + $"Path: {logVehiclePath}, mainPathState={mainPathState}"); #endif IExtVehicleManager extVehicleManager = Constants.ManagerFactory.ExtVehicleManager; ExtSoftPathState finalPathState = ExtCitizenInstance.ConvertPathStateToSoftPathState(mainPathState); if (Options.parkingAI && extVehicleManager.ExtVehicles[vehicleId].vehicleType == ExtVehicleType.PassengerCar) { ushort driverInstanceId = extVehicleManager.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 (logParkingAi) { Log._Debug($"CustomCarAI.CustomSimulationStep({vehicleId}): " + $"Applied Parking AI logic. Path: {vehicleData.m_path}, " + $"mainPathState={mainPathState}, finalPathState={finalPathState}"); } #endif } switch (finalPathState) { case ExtSoftPathState.Ready: { #if DEBUG if (logParkingAi) { 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; PathfindSuccess(vehicleId, ref vehicleData); TrySpawn(vehicleId, ref vehicleData); break; } case ExtSoftPathState.Ignore: { #if DEBUG if (logParkingAi) { 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 (logParkingAi) { 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 (logParkingAi) { 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; PathfindFailure(vehicleId, ref vehicleData); return; } case ExtSoftPathState.FailedSoft: { #if DEBUG if (logParkingAi) { 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; InvalidPath(vehicleId, ref vehicleData, vehicleId, ref vehicleData); break; } } // NON-STOCK CODE END } else { if ((vehicleData.m_flags & Vehicle.Flags.WaitingSpace) != 0) { TrySpawn(vehicleId, ref vehicleData); } } // NON-STOCK CODE START IExtVehicleManager extVehicleMan = Constants.ManagerFactory.ExtVehicleManager; extVehicleMan.UpdateVehiclePosition(vehicleId, ref vehicleData); if (Options.advancedAI && (vehicleData.m_flags & Vehicle.Flags.Spawned) != 0) { extVehicleMan.LogTraffic(vehicleId, ref vehicleData); } // NON-STOCK CODE END Vector3 lastFramePosition = vehicleData.GetLastFramePosition(); int lodPhysics; if (Vector3.SqrMagnitude(physicsLodRefPos - lastFramePosition) >= 1100f * 1100f) { lodPhysics = 2; } else if (Vector3.SqrMagnitude( Singleton <SimulationManager> .instance.m_simulationView.m_position - lastFramePosition) >= 500f * 500f) { lodPhysics = 1; } else { lodPhysics = 0; } 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[trailerId].m_trailingVehicle; VehicleInfo info = vehManager.m_vehicles.m_buffer[trailerId].Info; info.m_vehicleAI.SimulationStep( trailerId, ref vehManager.m_vehicles.m_buffer[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(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 (vehicleData.m_blockCounter >= maxBlockCounter) { // NON-STOCK CODE START if (VehicleBehaviorManager.Instance.MayDespawn(ref vehicleData)) { // NON-STOCK CODE END Singleton <VehicleManager> .instance.ReleaseVehicle(vehicleId); } // NON-STOCK CODE } }
public void CustomSimulationStep(ushort instanceID, ref CitizenInstance instanceData, Vector3 physicsLodRefPos) { uint citizenId = instanceData.m_citizen; if ((instanceData.m_flags & (CitizenInstance.Flags.Blown | CitizenInstance.Flags.Floating)) != CitizenInstance.Flags.None && (instanceData.m_flags & CitizenInstance.Flags.Character) == CitizenInstance.Flags.None) { Singleton <CitizenManager> .instance.ReleaseCitizenInstance(instanceID); if (citizenId != 0u) { Singleton <CitizenManager> .instance.ReleaseCitizen(citizenId); } return; } if ((instanceData.m_flags & CitizenInstance.Flags.WaitingPath) != CitizenInstance.Flags.None) { PathManager pathManager = Singleton <PathManager> .instance; byte pathFindFlags = pathManager.m_pathUnits.m_buffer[instanceData.m_path].m_pathFindFlags; // NON-STOCK CODE START ExtPathState mainPathState = ExtPathState.Calculating; if ((pathFindFlags & PathUnit.FLAG_FAILED) != 0 || instanceData.m_path == 0) { mainPathState = ExtPathState.Failed; } else if ((pathFindFlags & PathUnit.FLAG_READY) != 0) { mainPathState = ExtPathState.Ready; } #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomHumanAI.CustomSimulationStep({instanceID}): Path: {instanceData.m_path}, mainPathState={mainPathState}"); } #endif ExtSoftPathState finalPathState = ExtSoftPathState.None; #if BENCHMARK using (var bm = new Benchmark(null, "ConvertPathStateToSoftPathState+UpdateCitizenPathState")) { #endif finalPathState = ExtCitizenInstance.ConvertPathStateToSoftPathState(mainPathState); if (Options.prohibitPocketCars) { finalPathState = AdvancedParkingManager.Instance.UpdateCitizenPathState(instanceID, ref instanceData, ref ExtCitizenInstanceManager.Instance.ExtInstances[instanceID], ref Singleton <CitizenManager> .instance.m_citizens.m_buffer[instanceData.m_citizen], mainPathState); #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomHumanAI.CustomSimulationStep({instanceID}): Applied Parking AI logic. Path: {instanceData.m_path}, mainPathState={mainPathState}, finalPathState={finalPathState}, extCitizenInstance={ExtCitizenInstanceManager.Instance.ExtInstances[instanceID]}"); } #endif } #if BENCHMARK } #endif switch (finalPathState) { case ExtSoftPathState.Ready: #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomHumanAI.CustomSimulationStep({instanceID}): Path-finding succeeded for citizen instance {instanceID} (finalPathState={finalPathState}). Path: {instanceData.m_path} -- calling HumanAI.PathfindSuccess"); } #endif this.Spawn(instanceID, ref instanceData); instanceData.m_pathPositionIndex = 255; instanceData.m_flags &= ~CitizenInstance.Flags.WaitingPath; instanceData.m_flags &= ~(CitizenInstance.Flags.HangAround | CitizenInstance.Flags.Panicking | CitizenInstance.Flags.SittingDown | CitizenInstance.Flags.Cheering); // NON-STOCK CODE START (transferred from ResidentAI.PathfindSuccess) if (citizenId != 0 && (Singleton <CitizenManager> .instance.m_citizens.m_buffer[citizenId].m_flags & (Citizen.Flags.Tourist | Citizen.Flags.MovingIn | Citizen.Flags.DummyTraffic)) == Citizen.Flags.MovingIn) { StatisticBase statisticBase = Singleton <StatisticsManager> .instance.Acquire <StatisticInt32>(StatisticType.MoveRate); statisticBase.Add(1); } // NON-STOCK CODE END this.PathfindSuccess(instanceID, ref instanceData); break; case ExtSoftPathState.Ignore: #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomHumanAI.CustomSimulationStep({instanceID}): Path-finding result shall be ignored for citizen instance {instanceID} (finalPathState={finalPathState}). Path: {instanceData.m_path} -- ignoring"); } #endif return; case ExtSoftPathState.Calculating: default: #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomHumanAI.CustomSimulationStep({instanceID}): Path-finding result undetermined for citizen instance {instanceID} (finalPathState={finalPathState}). Path: {instanceData.m_path} -- continue"); } #endif break; case ExtSoftPathState.FailedHard: #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomHumanAI.CustomSimulationStep({instanceID}): HARD path-finding failure for citizen instance {instanceID} (finalPathState={finalPathState}). Path: {instanceData.m_path} -- calling HumanAI.PathfindFailure"); } #endif instanceData.m_flags &= ~CitizenInstance.Flags.WaitingPath; instanceData.m_flags &= ~(CitizenInstance.Flags.HangAround | CitizenInstance.Flags.Panicking | CitizenInstance.Flags.SittingDown | CitizenInstance.Flags.Cheering); Singleton <PathManager> .instance.ReleasePath(instanceData.m_path); instanceData.m_path = 0u; this.PathfindFailure(instanceID, ref instanceData); return; case ExtSoftPathState.FailedSoft: #if DEBUG if (GlobalConfig.Instance.Debug.Switches[2]) { Log._Debug($"CustomHumanAI.CustomSimulationStep({instanceID}): SOFT path-finding failure for citizen instance {instanceID} (finalPathState={finalPathState}). Path: {instanceData.m_path} -- calling HumanAI.InvalidPath"); } #endif // path mode has been updated, repeat path-finding instanceData.m_flags &= ~CitizenInstance.Flags.WaitingPath; instanceData.m_flags &= ~(CitizenInstance.Flags.HangAround | CitizenInstance.Flags.Panicking | CitizenInstance.Flags.SittingDown | CitizenInstance.Flags.Cheering); this.InvalidPath(instanceID, ref instanceData); return; } // NON-STOCK CODE END } // NON-STOCK CODE START #if BENCHMARK using (var bm = new Benchmark(null, "ExtSimulationStep")) { #endif if (Options.prohibitPocketCars) { if (ExtSimulationStep(instanceID, ref instanceData, ref ExtCitizenInstanceManager.Instance.ExtInstances[instanceID], physicsLodRefPos)) { return; } } #if BENCHMARK } #endif // NON-STOCK CODE END base.SimulationStep(instanceID, ref instanceData, physicsLodRefPos); CitizenManager citizenManager = Singleton <CitizenManager> .instance; VehicleManager vehicleManager = Singleton <VehicleManager> .instance; ushort vehicleId = 0; if (instanceData.m_citizen != 0u) { vehicleId = citizenManager.m_citizens.m_buffer[instanceData.m_citizen].m_vehicle; } if (vehicleId != 0) { VehicleInfo vehicleInfo = vehicleManager.m_vehicles.m_buffer[(int)vehicleId].Info; if (vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Bicycle) { vehicleInfo.m_vehicleAI.SimulationStep(vehicleId, ref vehicleManager.m_vehicles.m_buffer[(int)vehicleId], vehicleId, ref vehicleManager.m_vehicles.m_buffer[(int)vehicleId], 0); vehicleId = 0; } } if (vehicleId == 0 && (instanceData.m_flags & (CitizenInstance.Flags.Character | CitizenInstance.Flags.WaitingPath | CitizenInstance.Flags.Blown | CitizenInstance.Flags.Floating)) == CitizenInstance.Flags.None) { instanceData.m_flags &= ~(CitizenInstance.Flags.HangAround | CitizenInstance.Flags.Panicking | CitizenInstance.Flags.SittingDown); this.ArriveAtDestination(instanceID, ref instanceData, false); citizenManager.ReleaseCitizenInstance(instanceID); } }
public void CustomSimulationStep(ushort instanceId, ref CitizenInstance instanceData, Vector3 physicsLodRefPos) { #if DEBUG bool citizenDebug = (DebugSettings.CitizenInstanceId == 0 || DebugSettings.CitizenInstanceId == instanceId) && (DebugSettings.CitizenId == 0 || DebugSettings.CitizenId == instanceData.m_citizen) && (DebugSettings.SourceBuildingId == 0 || DebugSettings.SourceBuildingId == instanceData.m_sourceBuilding) && (DebugSettings.TargetBuildingId == 0 || DebugSettings.TargetBuildingId == instanceData.m_targetBuilding); bool logParkingAi = DebugSwitch.BasicParkingAILog.Get() && citizenDebug; #else var logParkingAi = false; #endif CitizenManager citizenManager = Singleton <CitizenManager> .instance; uint citizenId = instanceData.m_citizen; if ((instanceData.m_flags & (CitizenInstance.Flags.Blown | CitizenInstance.Flags.Floating)) != CitizenInstance.Flags.None && (instanceData.m_flags & CitizenInstance.Flags.Character) == CitizenInstance.Flags.None) { citizenManager.ReleaseCitizenInstance(instanceId); if (citizenId != 0u) { citizenManager.ReleaseCitizen(citizenId); } return; } Citizen[] citizensBuffer = citizenManager.m_citizens.m_buffer; if ((instanceData.m_flags & CitizenInstance.Flags.WaitingPath) != CitizenInstance.Flags.None) { PathManager pathManager = Singleton <PathManager> .instance; byte pathFindFlags = pathManager.m_pathUnits.m_buffer[instanceData.m_path].m_pathFindFlags; // NON-STOCK CODE START ExtPathState mainPathState = ExtPathState.Calculating; if ((pathFindFlags & PathUnit.FLAG_FAILED) != 0 || instanceData.m_path == 0) { mainPathState = ExtPathState.Failed; } else if ((pathFindFlags & PathUnit.FLAG_READY) != 0) { mainPathState = ExtPathState.Ready; } if (logParkingAi) { Log._Debug( $"CustomHumanAI.CustomSimulationStep({instanceId}): " + $"Path: {instanceData.m_path}, mainPathState={mainPathState}"); } ExtSoftPathState finalPathState; using (var bm = Benchmark.MaybeCreateBenchmark( null, "ConvertPathStateToSoftPathState+UpdateCitizenPathState")) { finalPathState = ExtCitizenInstance.ConvertPathStateToSoftPathState(mainPathState); if (Options.parkingAI) { finalPathState = AdvancedParkingManager.Instance.UpdateCitizenPathState( instanceId, ref instanceData, ref ExtCitizenInstanceManager .Instance.ExtInstances[ instanceId], ref ExtCitizenManager .Instance.ExtCitizens[ citizenId], ref citizensBuffer[ instanceData.m_citizen], mainPathState); if (logParkingAi) { Log._Debug( $"CustomHumanAI.CustomSimulationStep({instanceId}): " + $"Applied Parking AI logic. Path: {instanceData.m_path}, " + $"mainPathState={mainPathState}, finalPathState={finalPathState}, " + $"extCitizenInstance={ExtCitizenInstanceManager.Instance.ExtInstances[instanceId]}"); } } // if Options.parkingAi } switch (finalPathState) { case ExtSoftPathState.Ready: { if (logParkingAi) { Log._Debug( $"CustomHumanAI.CustomSimulationStep({instanceId}): Path-finding " + $"succeeded for citizen instance {instanceId} " + $"(finalPathState={finalPathState}). Path: {instanceData.m_path} " + "-- calling HumanAI.PathfindSuccess"); } if (citizenId == 0 || citizensBuffer[instanceData.m_citizen].m_vehicle == 0) { Spawn(instanceId, ref instanceData); } instanceData.m_pathPositionIndex = 255; instanceData.m_flags &= ~CitizenInstance.Flags.WaitingPath; instanceData.m_flags &= ~(CitizenInstance.Flags.HangAround | CitizenInstance.Flags.Panicking | CitizenInstance.Flags.SittingDown | CitizenInstance.Flags.Cheering); // NON-STOCK CODE START (transferred from ResidentAI.PathfindSuccess) const Citizen.Flags CTZ_MASK = Citizen.Flags.Tourist | Citizen.Flags.MovingIn | Citizen.Flags.DummyTraffic; if (citizenId != 0 && (citizensBuffer[citizenId].m_flags & CTZ_MASK) == Citizen.Flags.MovingIn) { StatisticBase statisticBase = Singleton <StatisticsManager> .instance.Acquire <StatisticInt32>(StatisticType.MoveRate); statisticBase.Add(1); } // NON-STOCK CODE END PathfindSuccess(instanceId, ref instanceData); break; } case ExtSoftPathState.Ignore: { if (logParkingAi) { Log._Debug( $"CustomHumanAI.CustomSimulationStep({instanceId}): " + "Path-finding result shall be ignored for citizen instance " + $"{instanceId} (finalPathState={finalPathState}). " + $"Path: {instanceData.m_path} -- ignoring"); } return; } case ExtSoftPathState.Calculating: default: { if (logParkingAi) { Log._Debug( $"CustomHumanAI.CustomSimulationStep({instanceId}): " + $"Path-finding result undetermined for citizen instance {instanceId} " + $"(finalPathState={finalPathState}). " + $"Path: {instanceData.m_path} -- continue"); } break; } case ExtSoftPathState.FailedHard: { if (logParkingAi) { Log._Debug( $"CustomHumanAI.CustomSimulationStep({instanceId}): " + $"HARD path-finding failure for citizen instance {instanceId} " + $"(finalPathState={finalPathState}). Path: {instanceData.m_path} " + "-- calling HumanAI.PathfindFailure"); } instanceData.m_flags &= ~CitizenInstance.Flags.WaitingPath; instanceData.m_flags &= ~(CitizenInstance.Flags.HangAround | CitizenInstance.Flags.Panicking | CitizenInstance.Flags.SittingDown | CitizenInstance.Flags.Cheering); Singleton <PathManager> .instance.ReleasePath(instanceData.m_path); instanceData.m_path = 0u; PathfindFailure(instanceId, ref instanceData); return; } case ExtSoftPathState.FailedSoft: { if (logParkingAi) { Log._Debug( $"CustomHumanAI.CustomSimulationStep({instanceId}): " + $"SOFT path-finding failure for citizen instance {instanceId} " + $"(finalPathState={finalPathState}). Path: {instanceData.m_path} " + "-- calling HumanAI.InvalidPath"); } // path mode has been updated, repeat path-finding instanceData.m_flags &= ~CitizenInstance.Flags.WaitingPath; instanceData.m_flags &= ~(CitizenInstance.Flags.HangAround | CitizenInstance.Flags.Panicking | CitizenInstance.Flags.SittingDown | CitizenInstance.Flags.Cheering); InvalidPath(instanceId, ref instanceData); break; } } // NON-STOCK CODE END } // NON-STOCK CODE START using (var bm = Benchmark.MaybeCreateBenchmark(null, "ExtSimulationStep")) { if (Options.parkingAI) { if (ExtSimulationStep( instanceId, ref instanceData, ref ExtCitizenInstanceManager.Instance.ExtInstances[instanceId], physicsLodRefPos)) { return; } } } // NON-STOCK CODE END base.SimulationStep(instanceId, ref instanceData, physicsLodRefPos); VehicleManager vehicleManager = Singleton <VehicleManager> .instance; ushort vehicleId = 0; if (instanceData.m_citizen != 0u) { vehicleId = citizensBuffer[instanceData.m_citizen].m_vehicle; } if (vehicleId != 0) { Vehicle[] vehiclesBuffer = vehicleManager.m_vehicles.m_buffer; VehicleInfo vehicleInfo = vehiclesBuffer[vehicleId].Info; if (vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Bicycle) { vehicleInfo.m_vehicleAI.SimulationStep( vehicleId, ref vehiclesBuffer[vehicleId], vehicleId, ref vehiclesBuffer[vehicleId], 0); vehicleId = 0; } } if (vehicleId != 0 || (instanceData.m_flags & (CitizenInstance.Flags.Character | CitizenInstance.Flags.WaitingPath | CitizenInstance.Flags.Blown | CitizenInstance.Flags.Floating)) != CitizenInstance.Flags.None) { return; } instanceData.m_flags &= ~(CitizenInstance.Flags.HangAround | CitizenInstance.Flags.Panicking | CitizenInstance.Flags.SittingDown); ArriveAtDestination(instanceId, ref instanceData, false); citizenManager.ReleaseCitizenInstance(instanceId); }
public static bool Prefix(CarAI __instance, ushort vehicleID, ref Vehicle data, Vector3 physicsLodRefPos) { #if DEBUG bool vehDebug = DebugSettings.VehicleId == 0 || DebugSettings.VehicleId == vehicleID; bool logParkingAi = DebugSwitch.BasicParkingAILog.Get() && vehDebug; #else var logParkingAi = false; #endif if ((data.m_flags & Vehicle.Flags.WaitingPath) != 0) { PathManager pathManager = Singleton <PathManager> .instance; byte pathFindFlags = pathManager.m_pathUnits.m_buffer[data.m_path].m_pathFindFlags; // NON-STOCK CODE START ExtPathState mainPathState = ExtPathState.Calculating; if ((pathFindFlags & PathUnit.FLAG_FAILED) != 0 || data.m_path == 0) { mainPathState = ExtPathState.Failed; } else if ((pathFindFlags & PathUnit.FLAG_READY) != 0) { mainPathState = ExtPathState.Ready; } #if DEBUG uint logVehiclePath = data.m_path; Log._DebugIf( logParkingAi, () => $"CustomCarAI.CustomSimulationStep({vehicleID}): " + $"Path: {logVehiclePath}, mainPathState={mainPathState}"); #endif IExtVehicleManager extVehicleManager = Constants.ManagerFactory.ExtVehicleManager; ExtSoftPathState finalPathState = ExtCitizenInstance.ConvertPathStateToSoftPathState(mainPathState); if (Options.parkingAI && extVehicleManager.ExtVehicles[vehicleID].vehicleType == ExtVehicleType.PassengerCar) { ushort driverInstanceId = extVehicleManager.GetDriverInstanceId(vehicleID, ref data); finalPathState = AdvancedParkingManager.Instance.UpdateCarPathState( vehicleID, ref data, ref driverInstanceId.ToCitizenInstance(), ref ExtCitizenInstanceManager.Instance.ExtInstances[driverInstanceId], mainPathState); #if DEBUG if (logParkingAi) { Log._Debug($"CustomCarAI.CustomSimulationStep({vehicleID}): " + $"Applied Parking AI logic. Path: {data.m_path}, " + $"mainPathState={mainPathState}, finalPathState={finalPathState}"); } #endif } switch (finalPathState) { case ExtSoftPathState.Ready: { #if DEBUG if (logParkingAi) { Log._Debug( $"CustomCarAI.CustomSimulationStep({vehicleID}): Path-finding " + $"succeeded for vehicle {vehicleID} (finalPathState={finalPathState}). " + $"Path: {data.m_path} -- calling CarAI.PathfindSuccess"); } #endif data.m_pathPositionIndex = 255; data.m_flags &= ~Vehicle.Flags.WaitingPath; data.m_flags &= ~Vehicle.Flags.Arriving; GameConnectionManager.Instance.VehicleAIConnection.PathfindSuccess(__instance, vehicleID, ref data); __instance.TrySpawn(vehicleID, ref data); break; } case ExtSoftPathState.Ignore: { #if DEBUG if (logParkingAi) { Log._Debug( $"CustomCarAI.CustomSimulationStep({vehicleID}): Path-finding " + $"result shall be ignored for vehicle {vehicleID} " + $"(finalPathState={finalPathState}). Path: {data.m_path} -- ignoring"); } #endif return(false); } case ExtSoftPathState.Calculating: default: { #if DEBUG if (logParkingAi) { Log._Debug( $"CustomCarAI.CustomSimulationStep({vehicleID}): Path-finding " + $"result undetermined for vehicle {vehicleID} (finalPathState={finalPathState}). " + $"Path: {data.m_path} -- continue"); } #endif break; } case ExtSoftPathState.FailedHard: { #if DEBUG if (logParkingAi) { Log._Debug( $"CustomCarAI.CustomSimulationStep({vehicleID}): HARD path-finding " + $"failure for vehicle {vehicleID} (finalPathState={finalPathState}). " + $"Path: {data.m_path} -- calling CarAI.PathfindFailure"); } #endif data.m_flags &= ~Vehicle.Flags.WaitingPath; Singleton <PathManager> .instance.ReleasePath(data.m_path); data.m_path = 0u; GameConnectionManager.Instance.VehicleAIConnection.PathfindFailure(__instance, vehicleID, ref data); return(false); } case ExtSoftPathState.FailedSoft: { #if DEBUG if (logParkingAi) { Log._Debug( $"CustomCarAI.CustomSimulationStep({vehicleID}): SOFT path-finding " + $"failure for vehicle {vehicleID} (finalPathState={finalPathState}). " + $"Path: {data.m_path} -- calling CarAI.InvalidPath"); } #endif // path mode has been updated, repeat path-finding data.m_flags &= ~Vehicle.Flags.WaitingPath; GameConnectionManager.Instance.VehicleAIConnection.InvalidPath(__instance, vehicleID, ref data, vehicleID, ref data); break; } } // NON-STOCK CODE END } else { if ((data.m_flags & Vehicle.Flags.WaitingSpace) != 0) { __instance.TrySpawn(vehicleID, ref data); } } // NON-STOCK CODE START IExtVehicleManager extVehicleMan = Constants.ManagerFactory.ExtVehicleManager; extVehicleMan.UpdateVehiclePosition(vehicleID, ref data); if (Options.advancedAI && (data.m_flags & Vehicle.Flags.Spawned) != 0) { extVehicleMan.LogTraffic(vehicleID, ref data); } // NON-STOCK CODE END Vector3 lastFramePosition = data.GetLastFramePosition(); int lodPhysics; if (Vector3.SqrMagnitude(physicsLodRefPos - lastFramePosition) >= 1100f * 1100f) { lodPhysics = 2; } else if (Vector3.SqrMagnitude( Singleton <SimulationManager> .instance.m_simulationView.m_position - lastFramePosition) >= 500f * 500f) { lodPhysics = 1; } else { lodPhysics = 0; } __instance.SimulationStep(vehicleID, ref data, vehicleID, ref data, lodPhysics); if (data.m_leadingVehicle == 0 && data.m_trailingVehicle != 0) { ushort trailerId = data.m_trailingVehicle; int numIters = 0; while (trailerId != 0) { ref Vehicle trailer = ref trailerId.ToVehicle(); trailer.Info.m_vehicleAI.SimulationStep( trailerId, ref trailer, vehicleID, ref data, lodPhysics); trailerId = trailer.m_trailingVehicle; if (++numIters > 16384) { CODebugBase <LogChannel> .Error( LogChannel.Core, $"Invalid list detected!\n{Environment.StackTrace}"); break; } } }