From ea4933abe51ffb951fa90427d3259221b98abf84 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 6 Dec 2025 15:27:24 +1000 Subject: [PATCH] Achievements: Add progress to progress database refresh That way there's some indication in the UI that the operation is happening. --- src/core/achievements.cpp | 31 ++++++++++++------- src/core/achievements.h | 5 +-- src/core/fullscreenui_settings.cpp | 30 ++++++++++++++---- src/core/fullscreenui_strings.h | 3 +- src/duckstation-mini/mini_host.cpp | 5 --- .../achievementsettingswidget.cpp | 2 +- src/duckstation-qt/mainwindow.cpp | 30 ++++++++++++------ src/duckstation-qt/mainwindow.h | 2 +- src/duckstation-qt/qthost.cpp | 21 ------------- src/duckstation-qt/qthost.h | 2 -- src/duckstation-regtest/regtest_host.cpp | 5 --- 11 files changed, 70 insertions(+), 66 deletions(-) diff --git a/src/core/achievements.cpp b/src/core/achievements.cpp index d92f1e625..bb87d67c9 100644 --- a/src/core/achievements.cpp +++ b/src/core/achievements.cpp @@ -2704,12 +2704,11 @@ void Achievements::FinishRefreshHashDatabase() // update game list, we might have some new games that weren't in the seed database GameList::UpdateAllAchievementData(); - - Host::OnAchievementsAllProgressRefreshed(); } -bool Achievements::RefreshAllProgressDatabase(Error* error) +bool Achievements::RefreshAllProgressDatabase(ProgressCallback* progress, Error* error) { + auto lock = GetLock(); if (!IsLoggedIn()) { Error::SetStringView(error, TRANSLATE_SV("Achievements", "User is not logged in.")); @@ -2723,8 +2722,15 @@ bool Achievements::RefreshAllProgressDatabase(Error* error) } // refresh in progress + progress->SetStatusText(TRANSLATE_SV("Achievements", "Refreshing achievement progress...")); + progress->SetProgressRange(0); + progress->SetProgressValue(0); + + std::pair result = {false, error}; s_state.refresh_all_progress_request = rc_client_begin_fetch_all_user_progress(s_state.client, RC_CONSOLE_PLAYSTATION, - RefreshAllProgressCallback, nullptr); + RefreshAllProgressCallback, &result); + while (s_state.refresh_all_progress_request) + WaitForHTTPRequestsWithYield(lock); return true; } @@ -2735,11 +2741,16 @@ void Achievements::RefreshAllProgressCallback(int result, const char* error_mess { s_state.refresh_all_progress_request = nullptr; + std::pair* result_ud = static_cast*>(callback_userdata); if (result != RC_OK) { - Host::ReportErrorAsync(TRANSLATE_SV("Achievements", "Error"), - fmt::format("{}: {}\n{}", TRANSLATE_SV("Achievements", "Refresh all progress failed"), - rc_error_str(result), error_message)); + if (result_ud) + { + result_ud->first = false; + result_ud->second->SetStringFmt("{}: {}\n{}", TRANSLATE_SV("Achievements", "Refresh all progress failed"), + rc_error_str(result), error_message); + } + return; } @@ -2748,10 +2759,8 @@ void Achievements::RefreshAllProgressCallback(int result, const char* error_mess GameList::UpdateAllAchievementData(); - Host::OnAchievementsAllProgressRefreshed(); - - FullscreenUI::ShowToast(OSDMessageType::Quick, {}, - TRANSLATE_STR("Achievements", "Updated achievement progress database.")); + if (result_ud) + result_ud->first = true; } void Achievements::BuildHashDatabase(const rc_client_hash_library_t* hashlib, diff --git a/src/core/achievements.h b/src/core/achievements.h index 6387e5c6e..6f30fd5bf 100644 --- a/src/core/achievements.h +++ b/src/core/achievements.h @@ -81,7 +81,7 @@ void UpdateSettings(const Settings& old_config); void Shutdown(); /// Call to refresh the all-progress database. -bool RefreshAllProgressDatabase(Error* error); +bool RefreshAllProgressDatabase(ProgressCallback* progress, Error* error); /// Called when the system is start. Engages hardcore mode if enabled. void OnSystemStarting(CDImage* image, bool disable_hardcore_mode); @@ -219,9 +219,6 @@ void OnAchievementsActiveChanged(bool active); /// Called whenever hardcore mode is toggled. void OnAchievementsHardcoreModeChanged(bool enabled); -/// Called whenever all progress is manually refreshed and completed. -void OnAchievementsAllProgressRefreshed(); - #ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION /// Called when the RAIntegration menu changes. diff --git a/src/core/fullscreenui_settings.cpp b/src/core/fullscreenui_settings.cpp index 08640d301..fb6899abb 100644 --- a/src/core/fullscreenui_settings.cpp +++ b/src/core/fullscreenui_settings.cpp @@ -98,6 +98,7 @@ static void DrawPatchesOrCheatsSettingsPage(bool cheats); static void DrawCoverDownloaderWindow(); static void DrawAchievementsLoginWindow(); +static void StartAchievementsProgressRefresh(); static void StartAchievementsGameIconDownload(); static bool ShouldShowAdvancedSettings(); @@ -4773,14 +4774,12 @@ void FullscreenUI::DrawAchievementsSettingsPage(std::unique_lock& se if (!IsEditingGameSettings(bsi)) { - if (MenuButton(FSUI_ICONVSTR(ICON_FA_ARROWS_ROTATE, "Update Progress"), + MenuHeading(FSUI_VSTR("Operations")); + + if (MenuButton(FSUI_ICONVSTR(ICON_FA_ARROWS_ROTATE, "Refresh Achievement Progress"), FSUI_VSTR("Updates the progress database for achievements shown in the game list."))) { - Host::RunOnCPUThread([]() { - Error error; - if (!Achievements::RefreshAllProgressDatabase(&error)) - ShowToast(OSDMessageType::Error, FSUI_STR("Failed to update progress database"), error.TakeDescription()); - }); + StartAchievementsProgressRefresh(); } if (MenuButton(FSUI_ICONVSTR(ICON_FA_DOWNLOAD, "Download Game Icons"), @@ -4915,6 +4914,25 @@ void FullscreenUI::DrawAchievementsLoginWindow() EndFixedPopupDialog(); } +void FullscreenUI::StartAchievementsProgressRefresh() +{ + auto progress = OpenModalProgressDialog(FSUI_STR("Refresh Achievement Progress")); + + System::QueueAsyncTask([progress = progress.release()]() { + Error error; + const bool result = Achievements::RefreshAllProgressDatabase(progress, &error); + Host::RunOnCPUThread([error = std::move(error), progress, result]() mutable { + GPUThread::RunOnThread([error = std::move(error), progress, result]() mutable { + delete progress; + if (result) + ShowToast(OSDMessageType::Info, {}, FSUI_STR("Progress database updated.")); + else + FullscreenUI::OpenInfoMessageDialog(FSUI_STR("Update Progress"), error.TakeDescription()); + }); + }); + }); +} + void FullscreenUI::StartAchievementsGameIconDownload() { auto progress = OpenModalProgressDialog(FSUI_STR("Download Game Icons")); diff --git a/src/core/fullscreenui_strings.h b/src/core/fullscreenui_strings.h index 3049adec4..7890100d2 100644 --- a/src/core/fullscreenui_strings.h +++ b/src/core/fullscreenui_strings.h @@ -350,7 +350,6 @@ TRANSLATE_NOOP("FullscreenUI", "Failed to delete {}."); TRANSLATE_NOOP("FullscreenUI", "Failed to load '{}'."); TRANSLATE_NOOP("FullscreenUI", "Failed to load shader {}. It may be invalid.\nError was:"); TRANSLATE_NOOP("FullscreenUI", "Failed to save controller preset '{}'."); -TRANSLATE_NOOP("FullscreenUI", "Failed to update progress database"); TRANSLATE_NOOP("FullscreenUI", "Fast Boot"); TRANSLATE_NOOP("FullscreenUI", "Fast Forward Boot"); TRANSLATE_NOOP("FullscreenUI", "Fast Forward Memory Card Access"); @@ -553,6 +552,7 @@ TRANSLATE_NOOP("FullscreenUI", "Pressure"); TRANSLATE_NOOP("FullscreenUI", "Prevents the emulator from producing any audible sound."); TRANSLATE_NOOP("FullscreenUI", "Prevents the screen saver from activating and the host from sleeping while emulation is running."); TRANSLATE_NOOP("FullscreenUI", "Progress Indicators"); +TRANSLATE_NOOP("FullscreenUI", "Progress database updated."); TRANSLATE_NOOP("FullscreenUI", "Provides vibration and LED control support over Bluetooth."); TRANSLATE_NOOP("FullscreenUI", "Purple Rain"); TRANSLATE_NOOP("FullscreenUI", "Push a controller button or axis now."); @@ -567,6 +567,7 @@ TRANSLATE_NOOP("FullscreenUI", "Reduces hitches in emulation by reading/decompre TRANSLATE_NOOP("FullscreenUI", "Reduces input latency by delaying the start of frame until closer to the presentation time."); TRANSLATE_NOOP("FullscreenUI", "Reduces polygon Z-fighting through depth testing. Low compatibility with games."); TRANSLATE_NOOP("FullscreenUI", "Reduces the size of save states by compressing the data before saving."); +TRANSLATE_NOOP("FullscreenUI", "Refresh Achievement Progress"); TRANSLATE_NOOP("FullscreenUI", "Region"); TRANSLATE_NOOP("FullscreenUI", "Region: "); TRANSLATE_NOOP("FullscreenUI", "Release Date: "); diff --git a/src/duckstation-mini/mini_host.cpp b/src/duckstation-mini/mini_host.cpp index 122811c4d..a2160bf6f 100644 --- a/src/duckstation-mini/mini_host.cpp +++ b/src/duckstation-mini/mini_host.cpp @@ -1105,11 +1105,6 @@ void Host::OnAchievementsHardcoreModeChanged(bool enabled) // noop } -void Host::OnAchievementsAllProgressRefreshed() -{ - // noop -} - #ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION void Host::OnRAIntegrationMenuChanged() diff --git a/src/duckstation-qt/achievementsettingswidget.cpp b/src/duckstation-qt/achievementsettingswidget.cpp index 602dabeef..9b88779b0 100644 --- a/src/duckstation-qt/achievementsettingswidget.cpp +++ b/src/duckstation-qt/achievementsettingswidget.cpp @@ -96,7 +96,7 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsWindow* dialog, QWi { connect(m_ui.loginButton, &QPushButton::clicked, this, &AchievementSettingsWidget::onLoginLogoutPressed); connect(m_ui.viewProfile, &QPushButton::clicked, this, &AchievementSettingsWidget::onViewProfilePressed); - connect(m_ui.refreshProgress, &QPushButton::clicked, g_emu_thread, &EmuThread::refreshAchievementsAllProgress); + connect(m_ui.refreshProgress, &QPushButton::clicked, g_main_window, &MainWindow::refreshAchievementProgress); connect(g_emu_thread, &EmuThread::achievementsRefreshed, this, &AchievementSettingsWidget::onAchievementsRefreshed); updateLoginState(); diff --git a/src/duckstation-qt/mainwindow.cpp b/src/duckstation-qt/mainwindow.cpp index 98467e75c..5c19677f9 100644 --- a/src/duckstation-qt/mainwindow.cpp +++ b/src/duckstation-qt/mainwindow.cpp @@ -2480,8 +2480,8 @@ void MainWindow::connectSignals() connect(m_ui.actionCoverDownloader, &QAction::triggered, this, &MainWindow::onToolsCoverDownloaderTriggered); connect(m_ui.actionToolsDownloadAchievementGameIcons, &QAction::triggered, this, &MainWindow::onToolsDownloadAchievementGameIconsTriggered); - connect(m_ui.actionToolsRefreshAchievementProgress, &QAction::triggered, g_emu_thread, - &EmuThread::refreshAchievementsAllProgress); + connect(m_ui.actionToolsRefreshAchievementProgress, &QAction::triggered, g_main_window, + &MainWindow::refreshAchievementProgress); connect(m_ui.actionMediaCapture, &QAction::triggered, this, &MainWindow::onToolsMediaCaptureTriggered); connect(m_ui.actionCaptureGPUFrame, &QAction::triggered, g_emu_thread, &EmuThread::captureGPUFrameDump); connect(m_ui.actionCPUDebugger, &QAction::triggered, this, &MainWindow::openCPUDebugger); @@ -2535,8 +2535,6 @@ void MainWindow::connectSignals() connect(g_emu_thread, &EmuThread::achievementsActiveChanged, this, &MainWindow::onAchievementsActiveChanged); connect(g_emu_thread, &EmuThread::achievementsHardcoreModeChanged, this, &MainWindow::onAchievementsHardcoreModeChanged); - connect(g_emu_thread, &EmuThread::achievementsAllProgressRefreshed, this, - &MainWindow::onAchievementsAllProgressRefreshed); connect(g_emu_thread, &EmuThread::onCreateAuxiliaryRenderWindow, this, &MainWindow::onCreateAuxiliaryRenderWindow, Qt::BlockingQueuedConnection); connect(g_emu_thread, &EmuThread::onDestroyAuxiliaryRenderWindow, this, &MainWindow::onDestroyAuxiliaryRenderWindow, @@ -3231,11 +3229,6 @@ void MainWindow::onAchievementsHardcoreModeChanged(bool enabled) updateEmulationActions(); } -void MainWindow::onAchievementsAllProgressRefreshed() -{ - m_ui.statusBar->showMessage(tr("RA: Updated achievement progress database.")); -} - bool MainWindow::onCreateAuxiliaryRenderWindow(RenderAPI render_api, qint32 x, qint32 y, quint32 width, quint32 height, const QString& title, const QString& icon_name, Host::AuxiliaryRenderWindowUserData userdata, @@ -3309,6 +3302,25 @@ void MainWindow::onToolsDownloadAchievementGameIconsTriggered() }); } +void MainWindow::refreshAchievementProgress() +{ + QtAsyncTaskWithProgressDialog::create( + this, TRANSLATE_STR("MainWindow", "Refresh Achievement Progress"), {}, true, 0, 0, 0.0f, + [](ProgressCallback* progress) { + Error error; + const bool result = Achievements::RefreshAllProgressDatabase(progress, &error); + return [error = std::move(error), result]() { + if (!result) + { + g_main_window->reportError(tr("Error"), QString::fromStdString(error.GetDescription())); + } + + g_main_window->m_ui.statusBar->showMessage(tr("RA: Updated achievement progress database.")); + g_main_window->refreshGameListModel(); + }; + }); +} + void MainWindow::onToolsMediaCaptureTriggered(bool checked) { if (!s_locals.system_valid) diff --git a/src/duckstation-qt/mainwindow.h b/src/duckstation-qt/mainwindow.h index 27f28e404..ced2da94b 100644 --- a/src/duckstation-qt/mainwindow.h +++ b/src/duckstation-qt/mainwindow.h @@ -125,6 +125,7 @@ public: QIcon getIconForGame(const QString& path); void invalidateCoverCacheForPath(const std::string& path); void refreshGameGridCovers(); + void refreshAchievementProgress(); void runOnUIThread(const std::function& func); void requestShutdown(bool allow_confirm, bool allow_save_to_state, bool save_state, bool check_safety, @@ -245,7 +246,6 @@ private: void onAchievementsLoginSuccess(const QString& username, quint32 points, quint32 sc_points, quint32 unread_messages); void onAchievementsActiveChanged(bool active); void onAchievementsHardcoreModeChanged(bool enabled); - void onAchievementsAllProgressRefreshed(); bool onCreateAuxiliaryRenderWindow(RenderAPI render_api, qint32 x, qint32 y, quint32 width, quint32 height, const QString& title, const QString& icon_name, Host::AuxiliaryRenderWindowUserData userdata, diff --git a/src/duckstation-qt/qthost.cpp b/src/duckstation-qt/qthost.cpp index e907003f5..83604b005 100644 --- a/src/duckstation-qt/qthost.cpp +++ b/src/duckstation-qt/qthost.cpp @@ -1673,22 +1673,6 @@ void EmuThread::saveScreenshot() System::SaveScreenshot(); } -void EmuThread::refreshAchievementsAllProgress() -{ - if (!isCurrentThread()) - { - QMetaObject::invokeMethod(this, &EmuThread::refreshAchievementsAllProgress, Qt::QueuedConnection); - return; - } - - Error error; - if (!Achievements::RefreshAllProgressDatabase(&error)) - { - emit errorReported(tr("Error"), QString::fromStdString(error.GetDescription())); - return; - } -} - void Host::OnAchievementsLoginRequested(Achievements::LoginRequestReason reason) { emit g_emu_thread->achievementsLoginRequested(reason); @@ -1737,11 +1721,6 @@ void Host::OnAchievementsHardcoreModeChanged(bool enabled) emit g_emu_thread->achievementsHardcoreModeChanged(enabled); } -void Host::OnAchievementsAllProgressRefreshed() -{ - emit g_emu_thread->achievementsAllProgressRefreshed(); -} - bool Host::ShouldPreferHostFileSelector() { #ifdef __linux__ diff --git a/src/duckstation-qt/qthost.h b/src/duckstation-qt/qthost.h index 0222f6edf..08955aef0 100644 --- a/src/duckstation-qt/qthost.h +++ b/src/duckstation-qt/qthost.h @@ -123,7 +123,6 @@ Q_SIGNALS: void achievementsRefreshed(quint32 id, const QString& game_info_string); void achievementsActiveChanged(bool active); void achievementsHardcoreModeChanged(bool enabled); - void achievementsAllProgressRefreshed(); void mediaCaptureStarted(); void mediaCaptureStopped(); @@ -148,7 +147,6 @@ public: void startFullscreenUI(); void stopFullscreenUI(); void exitFullscreenUI(); - void refreshAchievementsAllProgress(); void bootSystem(std::shared_ptr params); void resumeSystemFromMostRecentState(); void shutdownSystem(bool save_state, bool check_memcard_busy); diff --git a/src/duckstation-regtest/regtest_host.cpp b/src/duckstation-regtest/regtest_host.cpp index 62cc0c349..b1576a17b 100644 --- a/src/duckstation-regtest/regtest_host.cpp +++ b/src/duckstation-regtest/regtest_host.cpp @@ -640,11 +640,6 @@ void Host::OnAchievementsHardcoreModeChanged(bool enabled) // noop } -void Host::OnAchievementsAllProgressRefreshed() -{ - // noop -} - #ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION void Host::OnRAIntegrationMenuChanged()