From 5735eccacf50f0eb1db5f8c3b50d898a9544f053 Mon Sep 17 00:00:00 2001 From: Satori Date: Sat, 2 Oct 2021 15:32:46 +0100 Subject: [PATCH] [Base] Add CommandVar listener interface --- src/xenia/base/cvar.h | 28 +++++++++++++++++++++++----- src/xenia/base/cvar.inc | 20 ++++++++++++++++++++ 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/xenia/base/cvar.h b/src/xenia/base/cvar.h index 209852051..ef8a441bd 100644 --- a/src/xenia/base/cvar.h +++ b/src/xenia/base/cvar.h @@ -18,6 +18,7 @@ #include "cpptoml/include/cpptoml.h" #include "cxxopts/include/cxxopts.hpp" +#include "xenia/base/delegate.h" #include "xenia/base/filesystem.h" #include "xenia/base/string_util.h" #include "xenia/config.h" @@ -29,9 +30,16 @@ namespace toml { std::string EscapeString(const std::string_view view); } +class ICommandVar; + template class ConfigVar; +class ICommandVarListener { + public: + virtual void OnValueUpdated(const ICommandVar& var) = 0; +}; + class ICommandVar { public: virtual ~ICommandVar() = default; @@ -40,6 +48,8 @@ class ICommandVar { virtual void UpdateValue() = 0; virtual void AddToLaunchOptions(cxxopts::Options* options) = 0; virtual void LoadFromLaunchOptions(cxxopts::ParseResult* result) = 0; + virtual void RegisterListener(ICommandVarListener* listener) = 0; + virtual void RemoveListener(ICommandVarListener* listener) = 0; }; class IConfigVar : virtual public ICommandVar { @@ -69,12 +79,18 @@ class CommandVar : virtual public ICommandVar { void AddToLaunchOptions(cxxopts::Options* options) override; void LoadFromLaunchOptions(cxxopts::ParseResult* result) override; + void RegisterListener(ICommandVarListener* listener) override; + void RemoveListener(ICommandVarListener* listener) override; + T* current_value() { return current_value_; } T* command_line_value() { return commandline_value_.get(); } const T& default_value() const { return default_value_; } protected: - void set_current_value(const T& val) { *current_value_ = val; } + void set_current_value(const T& val) { + *current_value_ = val; + for (const auto& listener : listeners_) listener->OnValueUpdated(*this); + } void set_command_line_value(const T& val) { commandline_value_ = std::make_unique(val); @@ -93,6 +109,8 @@ class CommandVar : virtual public ICommandVar { T* current_value_; std::unique_ptr commandline_value_; std::string description_; + std::mutex listener_mtx_; + std::vector listeners_; }; #pragma warning(push) #pragma warning(disable : 4250) @@ -218,7 +236,7 @@ CommandVar* register_commandvar(std::string_view name, T* default_value, requires_restart, type) \ namespace xe::cvars { \ type name = default_value; \ - extern "C" xe::cvar::ConfigVar* cv_##name = \ + extern "C" xe::cvar::ConfigVar* cv_##name = \ xe::cvar::register_configvar(#name, &cvars::name, description, \ category, is_transient, \ requires_restart); \ @@ -244,9 +262,9 @@ CommandVar* register_commandvar(std::string_view name, T* default_value, #define DECLARE_path(name) DECLARE_CVar(name, std::filesystem::path) -#define DECLARE_CVar(name, type) \ - namespace xe::cvars { \ - extern type name; \ +#define DECLARE_CVar(name, type) \ + namespace xe::cvars { \ + extern type name; \ extern "C" xe::cvar::ConfigVar* cv_##name; \ } diff --git a/src/xenia/base/cvar.inc b/src/xenia/base/cvar.inc index 523070917..2994a0139 100644 --- a/src/xenia/base/cvar.inc +++ b/src/xenia/base/cvar.inc @@ -80,6 +80,26 @@ void CommandVar::UpdateValue() { if (commandline_value_) return set_current_value(*commandline_value_); return set_current_value(default_value_); } +template +void CommandVar::RegisterListener(ICommandVarListener* listener) { + std::lock_guard guard(listener_mtx_); + assert_true(listener != nullptr, "null pointer provided to RegisterListener"); + listeners_.push_back(listener); +} + +template +void CommandVar::RemoveListener(ICommandVarListener* listener) { + std::lock_guard guard(listener_mtx_); + auto it = std::find_if(listeners_.begin(), listeners_.end(), [listener](ICommandVarListener* l2) { + if (l2 == listener) return true; + return false; + }); + if (it != listeners_.end()) { + listeners_.erase(it); + } +} + + template void ConfigVar::UpdateValue() { if (this->command_line_value()) {