diff --git a/Source/Core/Core/AchievementManager.cpp b/Source/Core/Core/AchievementManager.cpp index a361d5bf1b5..3853dd1b8c6 100644 --- a/Source/Core/Core/AchievementManager.cpp +++ b/Source/Core/Core/AchievementManager.cpp @@ -122,16 +122,6 @@ picojson::value AchievementManager::LoadApprovedList() return temp; } -void AchievementManager::SetUpdateCallback(UpdateCallback callback) -{ - m_update_callback = std::move(callback); - - if (!m_update_callback) - m_update_callback = [](UpdatedItems) {}; - - m_update_callback(UpdatedItems{.all = true}); -} - void AchievementManager::Login(const std::string& password) { if (!m_client) @@ -354,7 +344,7 @@ void AchievementManager::DoFrame() { m_last_rp_time = current_time; rc_client_get_rich_presence_message(m_client, m_rich_presence.data(), RP_SIZE); - m_update_callback(UpdatedItems{.rich_presence = true}); + UpdateEvent::Trigger(UpdatedItems{.rich_presence = true}); if (Config::Get(Config::RA_DISCORD_PRESENCE_ENABLED)) Discord::UpdateDiscordPresence(); } @@ -753,7 +743,7 @@ void AchievementManager::CloseGame() INFO_LOG_FMT(ACHIEVEMENTS, "Game closed."); } - m_update_callback(UpdatedItems{.all = true}); + UpdateEvent::Trigger(UpdatedItems{.all = true}); } void AchievementManager::Logout() @@ -767,7 +757,7 @@ void AchievementManager::Logout() Config::SetBaseOrCurrent(Config::RA_API_TOKEN, ""); } - m_update_callback(UpdatedItems{.all = true}); + UpdateEvent::Trigger(UpdatedItems{.all = true}); INFO_LOG_FMT(ACHIEVEMENTS, "Logged out from server."); } @@ -910,7 +900,7 @@ void AchievementManager::LoginCallback(int result, const char* error_message, rc { WARN_LOG_FMT(ACHIEVEMENTS, "Failed to login {} to RetroAchievements server.", Config::Get(Config::RA_USERNAME)); - AchievementManager::GetInstance().m_update_callback({.failed_login_code = result}); + UpdateEvent::Trigger({.failed_login_code = result}); return; } @@ -922,7 +912,7 @@ void AchievementManager::LoginCallback(int result, const char* error_message, rc if (!user) { WARN_LOG_FMT(ACHIEVEMENTS, "Failed to retrieve user information from client."); - AchievementManager::GetInstance().m_update_callback({.failed_login_code = RC_INVALID_STATE}); + UpdateEvent::Trigger({.failed_login_code = RC_INVALID_STATE}); return; } @@ -941,7 +931,7 @@ void AchievementManager::LoginCallback(int result, const char* error_message, rc INFO_LOG_FMT(ACHIEVEMENTS, "Attempted to login prior user {}; current user is {}.", user->username, Config::Get(Config::RA_USERNAME)); rc_client_logout(client); - AchievementManager::GetInstance().m_update_callback({.failed_login_code = RC_INVALID_STATE}); + UpdateEvent::Trigger({.failed_login_code = RC_INVALID_STATE}); return; } } @@ -987,7 +977,7 @@ void AchievementManager::LeaderboardEntriesCallback(int result, const char* erro if (static_cast(ix) == list->user_index) leaderboard.player_index = response_entry.rank; } - AchievementManager::GetInstance().m_update_callback({.leaderboards = {*leaderboard_id}}); + UpdateEvent::Trigger({.leaderboards = {*leaderboard_id}}); } void AchievementManager::LoadGameCallback(int result, const char* error_message, @@ -1033,7 +1023,7 @@ void AchievementManager::LoadGameCallback(int result, const char* error_message, rc_client_set_read_memory_function(instance.m_client, MemoryPeeker); instance.FetchGameBadges(); instance.m_system.store(&Core::System::GetInstance(), std::memory_order_release); - instance.m_update_callback({.all = true}); + UpdateEvent::Trigger({.all = true}); // Set this to a value that will immediately trigger RP instance.m_last_rp_time = std::chrono::steady_clock::now() - std::chrono::minutes{2}; @@ -1121,8 +1111,7 @@ void AchievementManager::HandleAchievementTriggeredEvent(const rc_client_event_t (rc_client_get_hardcore_enabled(instance.m_client)) ? OSD::Color::YELLOW : OSD::Color::CYAN, &instance.GetAchievementBadge(client_event->achievement->id, false)); - AchievementManager::GetInstance().m_update_callback( - UpdatedItems{.achievements = {client_event->achievement->id}}); + UpdateEvent::Trigger(UpdatedItems{.achievements = {client_event->achievement->id}}); #ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION switch (rc_client_raintegration_get_achievement_state(instance.m_client, client_event->achievement->id)) @@ -1171,8 +1160,7 @@ void AchievementManager::HandleLeaderboardSubmittedEvent(const rc_client_event_t client_event->leaderboard->title), OSD::Duration::VERY_LONG, OSD::Color::YELLOW); AchievementManager::GetInstance().FetchBoardInfo(client_event->leaderboard->id); - AchievementManager::GetInstance().m_update_callback( - UpdatedItems{.leaderboards = {client_event->leaderboard->id}}); + UpdateEvent::Trigger(UpdatedItems{.leaderboards = {client_event->leaderboard->id}}); } void AchievementManager::HandleLeaderboardTrackerUpdateEvent(const rc_client_event_t* client_event) @@ -1209,7 +1197,7 @@ void AchievementManager::HandleAchievementChallengeIndicatorShowEvent( const auto [iter, inserted] = instance.m_active_challenges.insert(client_event->achievement->id); if (inserted) instance.m_challenges_updated = true; - AchievementManager::GetInstance().m_update_callback(UpdatedItems{.rich_presence = true}); + UpdateEvent::Trigger(UpdatedItems{.rich_presence = true}); } void AchievementManager::HandleAchievementChallengeIndicatorHideEvent( @@ -1219,7 +1207,7 @@ void AchievementManager::HandleAchievementChallengeIndicatorHideEvent( const auto removed = instance.m_active_challenges.erase(client_event->achievement->id); if (removed > 0) instance.m_challenges_updated = true; - AchievementManager::GetInstance().m_update_callback(UpdatedItems{.rich_presence = true}); + UpdateEvent::Trigger(UpdatedItems{.rich_presence = true}); } void AchievementManager::HandleAchievementProgressIndicatorShowEvent( @@ -1235,8 +1223,7 @@ void AchievementManager::HandleAchievementProgressIndicatorShowEvent( OSD::Duration::SHORT, OSD::Color::GREEN, &instance.GetAchievementBadge(client_event->achievement->id, false)); instance.m_last_progress_message = current_time; - AchievementManager::GetInstance().m_update_callback( - UpdatedItems{.achievements = {client_event->achievement->id}}); + UpdateEvent::Trigger(UpdatedItems{.achievements = {client_event->achievement->id}}); } void AchievementManager::HandleGameCompletedEvent(const rc_client_event_t* client_event, @@ -1375,7 +1362,7 @@ void AchievementManager::FetchBadge(AchievementManager::Badge* badge, u32 badge_ { if (!m_client || !HasAPIToken()) { - m_update_callback(callback_data); + UpdateEvent::Trigger(callback_data); if (m_display_welcome_message && badge_type == RC_IMAGE_TYPE_GAME) DisplayWelcomeMessage(); return; @@ -1421,7 +1408,7 @@ void AchievementManager::FetchBadge(AchievementManager::Badge* badge, u32 badge_ "RetroAchievements connection failed on image request.\n URL: {}", api_request.url); rc_api_destroy_request(&api_request); - m_update_callback(callback_data); + UpdateEvent::Trigger(callback_data); return; } @@ -1454,7 +1441,7 @@ void AchievementManager::FetchBadge(AchievementManager::Badge* badge, u32 badge_ } *badge = std::move(tmp_badge); - m_update_callback(callback_data); + UpdateEvent::Trigger(callback_data); if (badge_type == RC_IMAGE_TYPE_ACHIEVEMENT && m_active_challenges.contains(*callback_data.achievements.begin())) { @@ -1530,7 +1517,7 @@ void AchievementManager::LoadIntegrationCallback(int result, const char* error_m rc_client_raintegration_set_event_handler(instance.m_client, RAIntegrationEventHandler); rc_client_raintegration_set_write_memory_function(instance.m_client, MemoryPoker); rc_client_raintegration_set_get_game_name_function(instance.m_client, GameTitleEstimateHandler); - instance.m_dev_menu_callback(); + DevMenuUpdateEvent::Trigger(); // TODO: hook up menu and dll event handlers break; @@ -1552,12 +1539,11 @@ void AchievementManager::LoadIntegrationCallback(int result, const char* error_m void AchievementManager::RAIntegrationEventHandler(const rc_client_raintegration_event_t* event, rc_client_t* client) { - auto& instance = AchievementManager::GetInstance(); switch (event->type) { case RC_CLIENT_RAINTEGRATION_EVENT_MENU_CHANGED: case RC_CLIENT_RAINTEGRATION_EVENT_MENUITEM_CHECKED_CHANGED: - instance.m_dev_menu_callback(); + DevMenuUpdateEvent::Trigger(); break; case RC_CLIENT_RAINTEGRATION_EVENT_PAUSE: { diff --git a/Source/Core/Core/AchievementManager.h b/Source/Core/Core/AchievementManager.h index ad69f03de6b..fa728a31963 100644 --- a/Source/Core/Core/AchievementManager.h +++ b/Source/Core/Core/AchievementManager.h @@ -29,6 +29,7 @@ #include "Common/CommonTypes.h" #include "Common/Config/Config.h" #include "Common/Event.h" +#include "Common/HookableEvent.h" #include "Common/HttpRequest.h" #include "Common/JsonUtil.h" #include "Common/Lazy.h" @@ -119,11 +120,10 @@ public: bool rich_presence = false; int failed_login_code = 0; }; - using UpdateCallback = std::function; + using UpdateEvent = Common::HookableEvent<"AchievementManagerUpdate", const UpdatedItems&>; static AchievementManager& GetInstance(); void Init(void* hwnd); - void SetUpdateCallback(UpdateCallback callback); void Login(const std::string& password); bool HasAPIToken() const; void LoadGame(const DiscIO::Volume* volume); @@ -170,12 +170,9 @@ public: std::vector GetActiveLeaderboards() const; #ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION + using DevMenuUpdateEvent = Common::HookableEvent<"AchievementManagerDevMenuUpdate">; const rc_client_raintegration_menu_t* GetDevelopmentMenu(); u32 ActivateDevMenuItem(u32 menu_item_id); - void SetDevMenuUpdateCallback(std::function callback) - { - m_dev_menu_callback = callback; - } bool CheckForModifications() { return rc_client_raintegration_has_modifications(m_client); } #endif // RC_CLIENT_SUPPORTS_RAINTEGRATION @@ -267,7 +264,6 @@ private: rc_client_t* m_client{}; std::atomic m_system{}; bool m_is_runtime_initialized = false; - UpdateCallback m_update_callback = [](const UpdatedItems&) {}; std::unique_ptr m_loading_volume; Config::ConfigChangedCallbackID m_config_changed_callback_id; Badge m_default_player_badge; @@ -294,7 +290,6 @@ private: bool m_dll_found = false; #ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION - std::function m_dev_menu_callback; std::vector m_cloned_memory; std::recursive_mutex m_memory_lock; std::string m_title_estimate; diff --git a/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp b/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp index a1e17030fc2..1aadb12020c 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp @@ -30,12 +30,16 @@ AchievementsWindow::AchievementsWindow(QWidget* parent) : QDialog(parent) CreateMainLayout(); ConnectWidgets(); - AchievementManager::GetInstance().SetUpdateCallback( + + m_event_hook = AchievementManager::UpdateEvent::Register( [this](AchievementManager::UpdatedItems updated_items) { QueueOnObject(this, [this, updated_items = std::move(updated_items)] { AchievementsWindow::UpdateData(std::move(updated_items)); }); - }); + }, + "AchievementsWindow"); + UpdateData(AchievementManager::UpdatedItems{.all = true}); + connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this] { m_settings_widget->UpdateData(RC_OK); }); } diff --git a/Source/Core/DolphinQt/Achievements/AchievementsWindow.h b/Source/Core/DolphinQt/Achievements/AchievementsWindow.h index 3012707b3df..a676547ed1d 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementsWindow.h +++ b/Source/Core/DolphinQt/Achievements/AchievementsWindow.h @@ -6,6 +6,7 @@ #ifdef USE_RETRO_ACHIEVEMENTS #include +#include "Common/HookableEvent.h" #include "Core/AchievementManager.h" class AchievementHeaderWidget; @@ -35,6 +36,8 @@ private: AchievementProgressWidget* m_progress_widget; AchievementLeaderboardWidget* m_leaderboard_widget; QDialogButtonBox* m_button_box; + + Common::EventHook m_event_hook; }; #endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/DolphinQt/MenuBar.cpp b/Source/Core/DolphinQt/MenuBar.cpp index 6f210302949..35223131b21 100644 --- a/Source/Core/DolphinQt/MenuBar.cpp +++ b/Source/Core/DolphinQt/MenuBar.cpp @@ -294,8 +294,8 @@ void MenuBar::AddToolsMenu() tools_menu->addAction(tr("Achievements"), this, [this] { emit ShowAchievementsWindow(); }); #ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION m_achievements_dev_menu = tools_menu->addMenu(tr("RetroAchievements Development")); - AchievementManager::GetInstance().SetDevMenuUpdateCallback( - [this] { QueueOnObject(this, [this] { this->UpdateAchievementDevelopmentMenu(); }); }); + m_raintegration_event_hook = AchievementManager::DevMenuUpdateEvent::Register( + [this] { QueueOnObject(this, [this] { UpdateAchievementDevelopmentMenu(); }); }, "MenuBar"); m_achievements_dev_menu->menuAction()->setVisible(false); #endif // RC_CLIENT_SUPPORTS_RAINTEGRATION tools_menu->addSeparator(); diff --git a/Source/Core/DolphinQt/MenuBar.h b/Source/Core/DolphinQt/MenuBar.h index 934772e72cb..647870b4408 100644 --- a/Source/Core/DolphinQt/MenuBar.h +++ b/Source/Core/DolphinQt/MenuBar.h @@ -12,6 +12,9 @@ #include #include "Common/CommonTypes.h" +#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION +#include "Common/HookableEvent.h" +#endif // RC_CLIENT_SUPPORTS_RAINTEGRATION class QMenu; class ParallelProgressDialog; @@ -299,4 +302,8 @@ private: QAction* m_jit_register_cache_off; bool m_game_selected = false; + +#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION + Common::EventHook m_raintegration_event_hook; +#endif // RC_CLIENT_SUPPORTS_RAINTEGRATION };