diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index f026cb939d..5241e40a29 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -99,7 +99,7 @@ static bool s_wants_determinism; // Declarations and definitions static std::thread s_emu_thread; -static std::vector s_on_state_changed_callbacks; +static Common::HookableEvent s_state_changed_event; static bool s_is_throttler_temp_disabled = false; static bool s_frame_step = false; @@ -930,38 +930,14 @@ void Shutdown(Core::System& system) HostDispatchJobs(system); } -int AddOnStateChangedCallback(StateChangedCallbackFunc callback) +Common::EventHook AddOnStateChangedCallback(StateChangedCallbackFunc callback) { - for (size_t i = 0; i < s_on_state_changed_callbacks.size(); ++i) - { - if (!s_on_state_changed_callbacks[i]) - { - s_on_state_changed_callbacks[i] = std::move(callback); - return int(i); - } - } - s_on_state_changed_callbacks.emplace_back(std::move(callback)); - return int(s_on_state_changed_callbacks.size()) - 1; -} - -bool RemoveOnStateChangedCallback(int* handle) -{ - if (handle && *handle >= 0 && s_on_state_changed_callbacks.size() > static_cast(*handle)) - { - s_on_state_changed_callbacks[*handle] = StateChangedCallbackFunc(); - *handle = -1; - return true; - } - return false; + return s_state_changed_event.Register(std::move(callback)); } void NotifyStateChanged(Core::State state) { - for (const StateChangedCallbackFunc& on_state_changed_callback : s_on_state_changed_callbacks) - { - if (on_state_changed_callback) - on_state_changed_callback(state); - } + s_state_changed_event.Trigger(state); g_perf_metrics.OnEmulationStateChanged(state); } diff --git a/Source/Core/Core/Core.h b/Source/Core/Core/Core.h index 68a402772a..a6e40d2257 100644 --- a/Source/Core/Core/Core.h +++ b/Source/Core/Core/Core.h @@ -16,6 +16,7 @@ #include "Common/CommonTypes.h" #include "Common/Functional.h" +#include "Common/HookableEvent.h" struct BootParameters; struct WindowSystemInfo; @@ -165,10 +166,8 @@ void RunOnCPUThread(Core::System& system, Common::MoveOnlyFunction funct // for calling back into UI code without introducing a dependency on it in core using StateChangedCallbackFunc = std::function; -// Returns a handle -int AddOnStateChangedCallback(StateChangedCallbackFunc callback); -// Also invalidates the handle -bool RemoveOnStateChangedCallback(int* handle); + +[[nodiscard]] Common::EventHook AddOnStateChangedCallback(StateChangedCallbackFunc callback); void NotifyStateChanged(Core::State state); // Run on the Host thread when the factors change. [NOT THREADSAFE] diff --git a/Source/Core/Core/CoreTiming.cpp b/Source/Core/Core/CoreTiming.cpp index d7ef5b6092..e16db6a7ee 100644 --- a/Source/Core/Core/CoreTiming.cpp +++ b/Source/Core/Core/CoreTiming.cpp @@ -106,7 +106,7 @@ void CoreTimingManager::Init() m_last_oc_factor = m_config_oc_factor; m_globals.last_OC_factor_inverted = m_config_oc_inv_factor; - m_on_state_changed_handle = Core::AddOnStateChangedCallback([this](Core::State state) { + m_core_state_changed_hook = Core::AddOnStateChangedCallback([this](Core::State state) { if (state == Core::State::Running) { // We don't want Throttle to attempt catch-up for all the time lost while paused. @@ -117,7 +117,7 @@ void CoreTimingManager::Init() void CoreTimingManager::Shutdown() { - Core::RemoveOnStateChangedCallback(&m_on_state_changed_handle); + m_core_state_changed_hook.reset(); std::lock_guard lk(m_ts_write_lock); MoveEvents(); diff --git a/Source/Core/Core/CoreTiming.h b/Source/Core/Core/CoreTiming.h index 25df6d6c90..3a522b8dea 100644 --- a/Source/Core/Core/CoreTiming.h +++ b/Source/Core/Core/CoreTiming.h @@ -23,6 +23,7 @@ #include #include "Common/CommonTypes.h" +#include "Common/HookableEvent.h" #include "Common/SPSCQueue.h" #include "Common/Timer.h" #include "Core/CPUThreadConfigCallback.h" @@ -230,7 +231,7 @@ private: Common::PrecisionTimer m_precision_cpu_timer; Common::PrecisionTimer m_precision_gpu_timer; - int m_on_state_changed_handle; + Common::EventHook m_core_state_changed_hook; }; } // namespace CoreTiming diff --git a/Source/Core/DolphinNoGUI/MainNoGUI.cpp b/Source/Core/DolphinNoGUI/MainNoGUI.cpp index 669daabec0..2a7d7c8113 100644 --- a/Source/Core/DolphinNoGUI/MainNoGUI.cpp +++ b/Source/Core/DolphinNoGUI/MainNoGUI.cpp @@ -288,7 +288,7 @@ int main(const int argc, char* argv[]) return 1; } - Core::AddOnStateChangedCallback([](const Core::State state) { + auto core_state_changed_hook = Core::AddOnStateChangedCallback([](const Core::State state) { if (state == Core::State::Uninitialized) s_platform->Stop(); }); diff --git a/Source/Core/DolphinQt/Settings.cpp b/Source/Core/DolphinQt/Settings.cpp index 2767badbec..dcddf6a21c 100644 --- a/Source/Core/DolphinQt/Settings.cpp +++ b/Source/Core/DolphinQt/Settings.cpp @@ -50,7 +50,7 @@ static std::unique_ptr s_default_palette; Settings::Settings() { qRegisterMetaType(); - Core::AddOnStateChangedCallback([this](Core::State new_state) { + m_core_state_changed_hook = Core::AddOnStateChangedCallback([this](Core::State new_state) { QueueOnObject(this, [this, new_state] { // Avoid signal spam while continuously frame stepping. Will still send a signal for the first // and last framestep. diff --git a/Source/Core/DolphinQt/Settings.h b/Source/Core/DolphinQt/Settings.h index 08921e794f..ff3f88edf3 100644 --- a/Source/Core/DolphinQt/Settings.h +++ b/Source/Core/DolphinQt/Settings.h @@ -236,6 +236,8 @@ private: std::shared_ptr m_server; Common::EventHook m_hotplug_event_hook; Config::ConfigChangedCallbackID m_config_changed_callback_id; + + Common::EventHook m_core_state_changed_hook; }; Q_DECLARE_METATYPE(Core::State);