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; } } }