From da1de36cb9b46a13cff4cd610516d19e3799923f Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Wed, 12 Apr 2023 08:51:51 -0400 Subject: [PATCH] Added LoadUnlockData and ActivateDeactivateAchievements to AchievementManager LoadUnlockData and ActivateDeactivateAchievements are the public API components responding to the FetchUnlocks and A/DAchievement (singular) private methods. LoadUnlockData is asynchronous and performs both a hardcore and a softcore unlock call, updating the unlock map and the active status of any achievements returned from these calls. ActivateDeactivateAchievements calls ActivateDeactivateAchievement on every achievement ID found in m_game_data, initializing the unlock map for each ID if not already found. Both of these are currently called in LoadGameByFilenameAsync once the game has been loaded properly. There's a lock around this, to ensure that the unlock map is initialized properly by ActivateDeactivate Achievements before FetchUnlockData makes modifications to it without stalling the async portions of FetchUnlockData. --- Source/Core/Core/AchievementManager.cpp | 39 +++++++++++++++++++++++++ Source/Core/Core/AchievementManager.h | 2 ++ 2 files changed, 41 insertions(+) diff --git a/Source/Core/Core/AchievementManager.cpp b/Source/Core/Core/AchievementManager.cpp index e6b5df8bd9..11061073fe 100644 --- a/Source/Core/Core/AchievementManager.cpp +++ b/Source/Core/Core/AchievementManager.cpp @@ -131,16 +131,55 @@ void AchievementManager::LoadGameByFilenameAsync(const std::string& iso_path, const auto fetch_game_data_response = FetchGameData(); m_is_game_loaded = fetch_game_data_response == ResponseType::SUCCESS; + + // Claim the lock, then queue the fetch unlock data calls, then initialize the unlock map in + // ActivateDeactiveAchievements. This allows the calls to process while initializing the + // unlock map but then forces them to wait until it's initialized before making modifications to + // it. + { + std::lock_guard lg{m_lock}; + LoadUnlockData([](ResponseType r_type) {}); + ActivateDeactivateAchievements(); + } + callback(fetch_game_data_response); }); } +void AchievementManager::LoadUnlockData(const ResponseCallback& callback) +{ + m_queue.EmplaceItem([this, callback] { + const auto hardcore_unlock_response = FetchUnlockData(true); + if (hardcore_unlock_response != ResponseType::SUCCESS) + { + callback(hardcore_unlock_response); + return; + } + + callback(FetchUnlockData(false)); + }); +} + +void AchievementManager::ActivateDeactivateAchievements() +{ + bool enabled = Config::Get(Config::RA_ACHIEVEMENTS_ENABLED); + bool unofficial = Config::Get(Config::RA_UNOFFICIAL_ENABLED); + bool encore = Config::Get(Config::RA_ENCORE_ENABLED); + for (u32 ix = 0; ix < m_game_data.num_achievements; ix++) + { + auto iter = + m_unlock_map.insert({m_game_data.achievements[ix].id, UnlockStatus{.game_data_index = ix}}); + ActivateDeactivateAchievement(iter.first->first, enabled, unofficial, encore); + } +} + void AchievementManager::CloseGame() { m_is_game_loaded = false; m_game_id = 0; m_queue.Cancel(); m_unlock_map.clear(); + ActivateDeactivateAchievements(); } void AchievementManager::Logout() diff --git a/Source/Core/Core/AchievementManager.h b/Source/Core/Core/AchievementManager.h index 0e0c2668d9..7eb6397e49 100644 --- a/Source/Core/Core/AchievementManager.h +++ b/Source/Core/Core/AchievementManager.h @@ -39,6 +39,8 @@ public: bool IsLoggedIn() const; void LoadGameByFilenameAsync(const std::string& iso_path, const ResponseCallback& callback); + void LoadUnlockData(const ResponseCallback& callback); + void ActivateDeactivateAchievements(); void CloseGame(); void Logout(); void Shutdown();