diff --git a/Source/Core/Core/AchievementManager.cpp b/Source/Core/Core/AchievementManager.cpp index 1c10b3b67e..2386cb25f8 100644 --- a/Source/Core/Core/AchievementManager.cpp +++ b/Source/Core/Core/AchievementManager.cpp @@ -61,9 +61,9 @@ void AchievementManager::SetUpdateCallback(UpdateCallback callback) m_update_callback = std::move(callback); if (!m_update_callback) - m_update_callback = [] {}; + m_update_callback = [](UpdatedItems) {}; - m_update_callback(); + m_update_callback(UpdatedItems{.all = true}); } void AchievementManager::Login(const std::string& password) @@ -147,22 +147,26 @@ bool AchievementManager::IsGameLoaded() const void AchievementManager::FetchPlayerBadge() { - FetchBadge(&m_player_badge, RC_IMAGE_TYPE_USER, [](const AchievementManager& manager) { - auto* user_info = rc_client_get_user_info(manager.m_client); - if (!user_info) - return std::string(""); - return std::string(user_info->display_name); - }); + FetchBadge(&m_player_badge, RC_IMAGE_TYPE_USER, + [](const AchievementManager& manager) { + auto* user_info = rc_client_get_user_info(manager.m_client); + if (!user_info) + return std::string(""); + return std::string(user_info->display_name); + }, + {.player_icon = true}); } void AchievementManager::FetchGameBadges() { - FetchBadge(&m_game_badge, RC_IMAGE_TYPE_GAME, [](const AchievementManager& manager) { - auto* game_info = rc_client_get_game_info(manager.m_client); - if (!game_info) - return std::string(""); - return std::string(game_info->badge_name); - }); + FetchBadge(&m_game_badge, RC_IMAGE_TYPE_GAME, + [](const AchievementManager& manager) { + auto* game_info = rc_client_get_game_info(manager.m_client); + if (!game_info) + return std::string(""); + return std::string(game_info->badge_name); + }, + {.game_icon = true}); if (!rc_client_has_achievements(m_client)) return; @@ -188,7 +192,8 @@ void AchievementManager::FetchGameBadges() return std::string(""); return std::string( rc_client_get_achievement_info(manager.m_client, achievement_id)->badge_name); - }); + }, + {.achievements = {achievement_id}}); FetchBadge( &m_locked_badges[achievement_id], RC_IMAGE_TYPE_ACHIEVEMENT_LOCKED, [achievement_id](const AchievementManager& manager) { @@ -196,7 +201,8 @@ void AchievementManager::FetchGameBadges() return std::string(""); return std::string( rc_client_get_achievement_info(manager.m_client, achievement_id)->badge_name); - }); + }, + {.achievements = {achievement_id}}); } } rc_client_destroy_achievement_list(achievement_list); @@ -226,7 +232,7 @@ void AchievementManager::DoFrame() GenerateRichPresence(Core::CPUThreadGuard{*m_system}); m_queue.EmplaceItem([this] { PingRichPresence(m_rich_presence); }); m_last_ping_time = current_time; - m_update_callback(); + m_update_callback(UpdatedItems{.rich_presence = true}); } } @@ -394,13 +400,13 @@ void AchievementManager::SetDisabled(bool disable) INFO_LOG_FMT(ACHIEVEMENTS, "Achievement Manager has been disabled."); OSD::AddMessage("Please close all games to re-enable achievements.", OSD::Duration::VERY_LONG, OSD::Color::RED); - m_update_callback(); + m_update_callback(UpdatedItems{.all = true}); } if (previously_disabled && !disable) { INFO_LOG_FMT(ACHIEVEMENTS, "Achievement Manager has been re-enabled."); - m_update_callback(); + m_update_callback(UpdatedItems{.all = true}); } }; @@ -481,7 +487,7 @@ void AchievementManager::CloseGame() } } - m_update_callback(); + m_update_callback(UpdatedItems{.all = true}); INFO_LOG_FMT(ACHIEVEMENTS, "Game closed."); } @@ -495,7 +501,7 @@ void AchievementManager::Logout() Config::SetBaseOrCurrent(Config::RA_API_TOKEN, ""); } - m_update_callback(); + m_update_callback(UpdatedItems{.all = true}); INFO_LOG_FMT(ACHIEVEMENTS, "Logged out from server."); } @@ -655,7 +661,7 @@ void AchievementManager::LeaderboardEntriesCallback(int result, const char* erro memcpy(map_entry.score.data(), response_entry.display, FORMAT_SIZE); map_entry.rank = response_entry.rank; } - AchievementManager::GetInstance().m_update_callback(); + AchievementManager::GetInstance().m_update_callback({.leaderboards = {leaderboard_id}}); } void AchievementManager::GenerateRichPresence(const Core::CPUThreadGuard& guard) @@ -701,6 +707,7 @@ void AchievementManager::LoadGameCallback(int result, const char* error_message, AchievementManager::GetInstance().FetchGameBadges(); AchievementManager::GetInstance().m_system = &Core::System::GetInstance(); + AchievementManager::GetInstance().m_update_callback({.all = true}); } void AchievementManager::DisplayWelcomeMessage() @@ -987,15 +994,17 @@ u32 AchievementManager::MemoryPeeker(u32 address, u8* buffer, u32 num_bytes, rc_ } void AchievementManager::FetchBadge(AchievementManager::BadgeStatus* badge, u32 badge_type, - const AchievementManager::BadgeNameFunction function) + const AchievementManager::BadgeNameFunction function, + const UpdatedItems callback_data) { if (!m_client || !HasAPIToken() || !Config::Get(Config::RA_BADGES_ENABLED)) { - m_update_callback(); + m_update_callback(callback_data); return; } - m_image_queue.EmplaceItem([this, badge, badge_type, function = std::move(function)] { + m_image_queue.EmplaceItem([this, badge, badge_type, function = std::move(function), + callback_data = std::move(callback_data)] { std::string name_to_fetch; { std::lock_guard lg{m_lock}; @@ -1019,7 +1028,7 @@ void AchievementManager::FetchBadge(AchievementManager::BadgeStatus* badge, u32 WARN_LOG_FMT(ACHIEVEMENTS, "RetroAchievements connection failed on image request.\n URL: {}", api_request.url); rc_api_destroy_request(&api_request); - m_update_callback(); + m_update_callback(callback_data); return; } @@ -1036,7 +1045,7 @@ void AchievementManager::FetchBadge(AchievementManager::BadgeStatus* badge, u32 badge->badge = std::move(fetched_badge); badge->name = std::move(name_to_fetch); - m_update_callback(); + m_update_callback(callback_data); }); } diff --git a/Source/Core/Core/AchievementManager.h b/Source/Core/Core/AchievementManager.h index 9283401461..da816df6a5 100644 --- a/Source/Core/Core/AchievementManager.h +++ b/Source/Core/Core/AchievementManager.h @@ -50,7 +50,6 @@ public: UNKNOWN_FAILURE }; using ResponseCallback = std::function; - using UpdateCallback = std::function; using BadgeNameFunction = std::function; struct PointSpread @@ -116,6 +115,19 @@ public: std::unordered_map entries; }; + struct UpdatedItems + { + bool all = false; + bool player_icon = false; + bool game_icon = false; + bool all_achievements = false; + std::set achievements{}; + bool all_leaderboards = false; + std::set leaderboards{}; + bool rich_presence = false; + }; + using UpdateCallback = std::function; + static AchievementManager& GetInstance(); void Init(); void SetUpdateCallback(UpdateCallback callback); @@ -213,14 +225,15 @@ private: static void RequestV2(const rc_api_request_t* request, rc_client_server_callback_t callback, void* callback_data, rc_client_t* client); static u32 MemoryPeeker(u32 address, u8* buffer, u32 num_bytes, rc_client_t* client); - void FetchBadge(BadgeStatus* badge, u32 badge_type, const BadgeNameFunction function); + void FetchBadge(BadgeStatus* badge, u32 badge_type, const BadgeNameFunction function, + const UpdatedItems callback_data); static void EventHandler(const rc_client_event_t* event, rc_client_t* client); rc_runtime_t m_runtime{}; rc_client_t* m_client{}; Core::System* m_system{}; bool m_is_runtime_initialized = false; - UpdateCallback m_update_callback = [] {}; + UpdateCallback m_update_callback = [](const UpdatedItems&) {}; std::unique_ptr m_loading_volume; bool m_disabled = false; BadgeStatus m_player_badge; diff --git a/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp b/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp index bf151a77a1..5ae4f72676 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp @@ -62,13 +62,11 @@ AchievementHeaderWidget::AchievementHeaderWidget(QWidget* parent) : QWidget(pare m_total->setContentsMargins(0, 0, 0, 0); m_total->setAlignment(Qt::AlignTop); setLayout(m_total); - - std::lock_guard lg{AchievementManager::GetInstance().GetLock()}; - UpdateData(); } void AchievementHeaderWidget::UpdateData() { + std::lock_guard lg{AchievementManager::GetInstance().GetLock()}; auto& instance = AchievementManager::GetInstance(); if (!instance.HasAPIToken()) { diff --git a/Source/Core/DolphinQt/Achievements/AchievementLeaderboardWidget.cpp b/Source/Core/DolphinQt/Achievements/AchievementLeaderboardWidget.cpp index 6cb1892643..d2a52970f8 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementLeaderboardWidget.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementLeaderboardWidget.cpp @@ -24,8 +24,6 @@ AchievementLeaderboardWidget::AchievementLeaderboardWidget(QWidget* parent) : QW m_common_box = new QGroupBox(); m_common_layout = new QGridLayout(); - UpdateData(true); - m_common_box->setLayout(m_common_layout); auto* layout = new QVBoxLayout; diff --git a/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.cpp b/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.cpp index 548bd5b9c1..0164ee6a78 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.cpp @@ -27,8 +27,6 @@ AchievementProgressWidget::AchievementProgressWidget(QWidget* parent) : QWidget( m_common_box = new QGroupBox(); m_common_layout = new QVBoxLayout(); - UpdateData(true); - m_common_box->setLayout(m_common_layout); auto* layout = new QVBoxLayout; diff --git a/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp b/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp index 6f26811a49..b796b9dc3e 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp @@ -28,11 +28,13 @@ AchievementsWindow::AchievementsWindow(QWidget* parent) : QDialog(parent) CreateMainLayout(); ConnectWidgets(); AchievementManager::GetInstance().SetUpdateCallback( - [this] { QueueOnObject(this, &AchievementsWindow::UpdateData); }); + [this](AchievementManager::UpdatedItems updated_items) { + QueueOnObject(this, [this, updated_items = std::move(updated_items)] { + AchievementsWindow::UpdateData(std::move(updated_items)); + }); + }); connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, - &AchievementsWindow::UpdateData); - - UpdateData(); + [this] { AchievementsWindow::UpdateData({.all = true}); }); } void AchievementsWindow::showEvent(QShowEvent* event) @@ -71,19 +73,38 @@ void AchievementsWindow::ConnectWidgets() connect(m_button_box, &QDialogButtonBox::rejected, this, &QDialog::reject); } -void AchievementsWindow::UpdateData() +void AchievementsWindow::UpdateData(AchievementManager::UpdatedItems updated_items) { + m_settings_widget->UpdateData(); + if (updated_items.all) + { + m_header_widget->UpdateData(); + m_progress_widget->UpdateData(true); + m_leaderboard_widget->UpdateData(true); + } + else + { + if (updated_items.player_icon || updated_items.game_icon || updated_items.rich_presence || + updated_items.all_achievements || updated_items.achievements.size() > 0) + { + m_header_widget->UpdateData(); + } + if (updated_items.all_achievements) + m_progress_widget->UpdateData(false); + else if (updated_items.achievements.size() > 0) + m_progress_widget->UpdateData(updated_items.achievements); + if (updated_items.all_leaderboards) + m_leaderboard_widget->UpdateData(false); + else if (updated_items.leaderboards.size() > 0) + m_leaderboard_widget->UpdateData(updated_items.leaderboards); + } + { auto& instance = AchievementManager::GetInstance(); std::lock_guard lg{instance.GetLock()}; const bool is_game_loaded = instance.IsGameLoaded(); - - m_header_widget->UpdateData(); m_header_widget->setVisible(instance.HasAPIToken()); - m_settings_widget->UpdateData(); - m_progress_widget->UpdateData(true); m_tab_widget->setTabVisible(1, is_game_loaded); - m_leaderboard_widget->UpdateData(true); m_tab_widget->setTabVisible(2, is_game_loaded); } update(); diff --git a/Source/Core/DolphinQt/Achievements/AchievementsWindow.h b/Source/Core/DolphinQt/Achievements/AchievementsWindow.h index 751749fbc3..3012707b3d 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementsWindow.h +++ b/Source/Core/DolphinQt/Achievements/AchievementsWindow.h @@ -6,6 +6,8 @@ #ifdef USE_RETRO_ACHIEVEMENTS #include +#include "Core/AchievementManager.h" + class AchievementHeaderWidget; class AchievementLeaderboardWidget; class AchievementSettingsWidget; @@ -19,7 +21,7 @@ class AchievementsWindow : public QDialog Q_OBJECT public: explicit AchievementsWindow(QWidget* parent); - void UpdateData(); + void UpdateData(AchievementManager::UpdatedItems updated_items); void ForceSettingsTab(); private: diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index aacf4f933b..f1c6951595 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -2005,6 +2005,7 @@ void MainWindow::ShowAchievementsWindow() m_achievements_window->show(); m_achievements_window->raise(); m_achievements_window->activateWindow(); + m_achievements_window->UpdateData(AchievementManager::UpdatedItems{.all = true}); } void MainWindow::ShowAchievementSettings()