mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-04-25 16:21:11 -05:00
AchievementManager: Use HookableEvent instead of std::function callbacks
The callback mechanism AchievementManager had until now only supported one caller registering a callback, and it didn't have any synchronization. This isn't a problem for DolphinQt, but the PR to add Android support for RetroAchievements exposes these problems. Let's replace it with HookableEvent, which can handle all of this.
This commit is contained in:
parent
0c7fe651bb
commit
de98c3b96f
|
|
@ -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<int32_t>(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,
|
||||
|
|
@ -1030,7 +1020,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};
|
||||
|
||||
|
|
@ -1118,8 +1108,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))
|
||||
|
|
@ -1168,8 +1157,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)
|
||||
|
|
@ -1206,7 +1194,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(
|
||||
|
|
@ -1216,7 +1204,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(
|
||||
|
|
@ -1232,8 +1220,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,
|
||||
|
|
@ -1372,7 +1359,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;
|
||||
|
|
@ -1418,7 +1405,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;
|
||||
}
|
||||
|
||||
|
|
@ -1451,7 +1438,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()))
|
||||
{
|
||||
|
|
@ -1527,7 +1514,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;
|
||||
|
||||
|
|
@ -1549,12 +1536,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:
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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<void(const UpdatedItems&)>;
|
||||
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<std::string> 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<void(void)> 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<Core::System*> m_system{};
|
||||
bool m_is_runtime_initialized = false;
|
||||
UpdateCallback m_update_callback = [](const UpdatedItems&) {};
|
||||
std::unique_ptr<DiscIO::Volume> 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<void(void)> m_dev_menu_callback;
|
||||
std::vector<u8> m_cloned_memory;
|
||||
std::recursive_mutex m_memory_lock;
|
||||
std::string m_title_estimate;
|
||||
|
|
|
|||
|
|
@ -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); });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
#include <QDialog>
|
||||
|
||||
#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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
#include <QPointer>
|
||||
|
||||
#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
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user