diff --git a/Utilities/Config.cpp b/Utilities/Config.cpp index def495da74..962a36385b 100644 --- a/Utilities/Config.cpp +++ b/Utilities/Config.cpp @@ -17,8 +17,8 @@ namespace cfg } } - _base::_base(type _type, node* owner, const std::string& name) - : m_type(_type) + _base::_base(type _type, node* owner, const std::string& name, bool dynamic) + : m_type(_type), m_dynamic(dynamic) { for (const auto& pair : owner->m_nodes) { @@ -31,7 +31,7 @@ namespace cfg owner->m_nodes.emplace_back(name, this); } - bool _base::from_string(const std::string&) + bool _base::from_string(const std::string&, bool) { fmt::throw_exception("from_string() purecall" HERE); } @@ -46,7 +46,7 @@ namespace cfg // Incrementally load config entries from YAML::Node. // The config value is preserved if the corresponding YAML node doesn't exist. - static void decode(const YAML::Node& data, class _base& rhs); + static void decode(const YAML::Node& data, class _base& rhs, bool dynamic = false); } std::vector cfg::make_int_range(s64 min, s64 max) @@ -212,8 +212,13 @@ void cfg::encode(YAML::Emitter& out, const cfg::_base& rhs) } } -void cfg::decode(const YAML::Node& data, cfg::_base& rhs) +void cfg::decode(const YAML::Node& data, cfg::_base& rhs, bool dynamic) { + if (dynamic && !rhs.get_is_dynamic()) + { + return; + } + switch (rhs.get_type()) { case type::node: @@ -232,7 +237,7 @@ void cfg::decode(const YAML::Node& data, cfg::_base& rhs) { if (_pair.first == pair.first.Scalar()) { - decode(pair.second, *_pair.second); + decode(pair.second, *_pair.second, dynamic); } } } @@ -295,9 +300,9 @@ std::string cfg::node::to_string() const return {out.c_str(), out.size()}; } -bool cfg::node::from_string(const std::string& value) try +bool cfg::node::from_string(const std::string& value, bool dynamic) try { - cfg::decode(YAML::Load(value), *this); + cfg::decode(YAML::Load(value), *this, dynamic); return true; } catch (const std::exception& e) diff --git a/Utilities/Config.h b/Utilities/Config.h index e05e692db5..2a5686a64b 100644 --- a/Utilities/Config.h +++ b/Utilities/Config.h @@ -42,11 +42,13 @@ namespace cfg const type m_type; protected: + bool m_dynamic = true; + // Ownerless entry constructor _base(type _type); // Owned entry constructor - _base(type _type, class node* owner, const std::string& name); + _base(type _type, class node* owner, const std::string& name, bool dynamic = true); public: _base(const _base&) = delete; @@ -56,6 +58,9 @@ namespace cfg // Get type type get_type() const { return m_type; } + // Get dynamic property for reloading configs during games + bool get_is_dynamic() const { return m_dynamic; }; + // Reset defaults virtual void from_default() = 0; @@ -66,7 +71,7 @@ namespace cfg } // Try to convert from string (optional) - virtual bool from_string(const std::string&); + virtual bool from_string(const std::string&, bool /*dynamic*/ = false); // Get string list (optional) virtual std::vector to_list() const @@ -93,8 +98,8 @@ namespace cfg } // Registered node constructor - node(node* owner, const std::string& name) - : _base(type::node, owner, name) + node(node* owner, const std::string& name, bool dynamic = true) + : _base(type::node, owner, name, dynamic) { } @@ -108,7 +113,7 @@ namespace cfg std::string to_string() const override; // Deserialize node - bool from_string(const std::string& value) override; + bool from_string(const std::string& value, bool dynamic = false) override; // Set default values void from_default() override; @@ -121,8 +126,8 @@ namespace cfg public: bool def; - _bool(node* owner, const std::string& name, bool def = false) - : _base(type::_bool, owner, name) + _bool(node* owner, const std::string& name, bool def = false, bool dynamic = false) + : _base(type::_bool, owner, name, dynamic) , m_value(def) , def(def) { @@ -145,7 +150,7 @@ namespace cfg return m_value ? "true" : "false"; } - bool from_string(const std::string& value) override + bool from_string(const std::string& value, bool /*dynamic*/ = false) override { if (value == "false") m_value = false; @@ -172,8 +177,8 @@ namespace cfg public: const T def; - _enum(node* owner, const std::string& name, T value = {}) - : _base(type::_enum, owner, name) + _enum(node* owner, const std::string& name, T value = {}, bool dynamic = false) + : _base(type::_enum, owner, name, dynamic) , m_value(value) , def(value) { @@ -201,7 +206,7 @@ namespace cfg return result; // TODO: ??? } - bool from_string(const std::string& value) override + bool from_string(const std::string& value, bool /*dynamic*/ = false) override { u64 result; @@ -239,8 +244,8 @@ namespace cfg static const s64 max = Max; static const s64 min = Min; - _int(node* owner, const std::string& name, int_type def = std::min(Max, std::max(Min, 0))) - : _base(type::_int, owner, name) + _int(node* owner, const std::string& name, int_type def = std::min(Max, std::max(Min, 0)), bool dynamic = false) + : _base(type::_int, owner, name, dynamic) , m_value(def) , def(def) { @@ -266,7 +271,7 @@ namespace cfg return std::to_string(m_value); } - bool from_string(const std::string& value) override + bool from_string(const std::string& value, bool /*dynamic*/ = false) override { s64 result; if (try_to_int64(&result, value, Min, Max)) @@ -304,8 +309,8 @@ namespace cfg public: std::string def; - string(node* owner, const std::string& name, const std::string& def = {}) - : _base(type::string, owner, name) + string(node* owner, const std::string& name, const std::string& def = {}, bool dynamic = false) + : _base(type::string, owner, name, dynamic) , m_name(name) , m_value(def) , def(def) @@ -339,7 +344,7 @@ namespace cfg return m_value; } - bool from_string(const std::string& value) override + bool from_string(const std::string& value, bool /*dynamic*/ = false) override { m_value = value; return true; @@ -353,8 +358,8 @@ namespace cfg public: // Default value is empty list in current implementation - set_entry(node* owner, const std::string& name) - : _base(type::set, owner, name) + set_entry(node* owner, const std::string& name, bool dynamic = false) + : _base(type::set, owner, name, dynamic) { } diff --git a/rpcs3/Crypto/unself.cpp b/rpcs3/Crypto/unself.cpp index 0b0f6f23b4..961e30591f 100644 --- a/rpcs3/Crypto/unself.cpp +++ b/rpcs3/Crypto/unself.cpp @@ -1081,7 +1081,7 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size) // If not, the data has no NPDRM layer. if (!ctrl) { - LOG_NOTICE(LOADER, "SELF: No NPDRM control info found!"); + LOG_TRACE(LOADER, "SELF: No NPDRM control info found!"); return true; } diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 72d7f5370d..60bb91feb9 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -331,6 +331,7 @@ void Emulator::Init() if (const fs::file cfg_file{cfg_path, fs::read + fs::create}) { g_cfg.from_string(cfg_file.to_string()); + g_cfg.name = cfg_path; } else { @@ -1021,6 +1022,7 @@ void Emulator::Load(const std::string& title_id, bool add_only, bool force_globa { LOG_NOTICE(LOADER, "Applying custom config: %s", config_path_new); g_cfg.from_string(cfg_file.to_string()); + g_cfg.name = config_path_new; } // Load custom config-3 diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 42b7bebbcb..bc9e2dad4c 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -514,23 +514,23 @@ struct cfg_root : cfg::node { node_perf_overlay(cfg::node* _this) : cfg::node(_this, "Performance Overlay") {} - cfg::_bool perf_overlay_enabled{this, "Enabled", false}; - cfg::_bool framerate_graph_enabled{ this, "Enable Framerate Graph", false }; - cfg::_bool frametime_graph_enabled{ this, "Enable Frametime Graph", false }; - cfg::_enum level{this, "Detail level", detail_level::medium}; - cfg::_int<30, 5000> update_interval{ this, "Metrics update interval (ms)", 350 }; - cfg::_int<4, 36> font_size{ this, "Font size (px)", 10 }; - cfg::_enum position{this, "Position", screen_quadrant::top_left}; - cfg::string font{this, "Font", "n023055ms.ttf"}; - cfg::_int<0, 1280> margin_x{this, "Horizontal Margin (px)", 50}; // horizontal distance to the screen border relative to the screen_quadrant in px - cfg::_int<0, 720> margin_y{this, "Vertical Margin (px)", 50}; // vertical distance to the screen border relative to the screen_quadrant in px - cfg::_bool center_x{ this, "Center Horizontally", false }; - cfg::_bool center_y{ this, "Center Vertically", false }; - cfg::_int<0, 100> opacity{this, "Opacity (%)", 70}; - cfg::string color_body{ this, "Body Color (hex)", "#FFE138FF" }; - cfg::string background_body{ this, "Body Background (hex)", "#002339FF" }; - cfg::string color_title{ this, "Title Color (hex)", "#F26C24FF" }; - cfg::string background_title{ this, "Title Background (hex)", "#00000000" }; + cfg::_bool perf_overlay_enabled{ this, "Enabled", false, true }; + cfg::_bool framerate_graph_enabled{ this, "Enable Framerate Graph", false, true }; + cfg::_bool frametime_graph_enabled{ this, "Enable Frametime Graph", false, true }; + cfg::_enum level{ this, "Detail level", detail_level::medium, true }; + cfg::_int<30, 5000> update_interval{ this, "Metrics update interval (ms)", 350, true }; + cfg::_int<4, 36> font_size{ this, "Font size (px)", 10, true }; + cfg::_enum position{ this, "Position", screen_quadrant::top_left, true }; + cfg::string font{ this, "Font", "n023055ms.ttf", true }; + cfg::_int<0, 1280> margin_x{ this, "Horizontal Margin (px)", 50, true }; // horizontal distance to the screen border relative to the screen_quadrant in px + cfg::_int<0, 720> margin_y{ this, "Vertical Margin (px)", 50, true }; // vertical distance to the screen border relative to the screen_quadrant in px + cfg::_bool center_x{ this, "Center Horizontally", false, true }; + cfg::_bool center_y{ this, "Center Vertically", false, true }; + cfg::_int<0, 100> opacity{ this, "Opacity (%)", 70, true }; + cfg::string color_body{ this, "Body Color (hex)", "#FFE138FF", true }; + cfg::string background_body{ this, "Body Background (hex)", "#002339FF", true }; + cfg::string color_title{ this, "Title Color (hex)", "#F26C24FF", true }; + cfg::string background_title{ this, "Title Background (hex)", "#00000000", true }; } perf_overlay{this}; @@ -538,8 +538,8 @@ struct cfg_root : cfg::node { node_shader_compilation_hint(cfg::node* _this) : cfg::node(_this, "Shader Compilation Hint") {} - cfg::_int<0, 1280> pos_x{this, "Position X (px)", 20}; // horizontal position starting from the upper border in px - cfg::_int<0, 720> pos_y{this, "Position Y (px)", 690}; // vertical position starting from the left border in px + cfg::_int<0, 1280> pos_x{ this, "Position X (px)", 20, true }; // horizontal position starting from the upper border in px + cfg::_int<0, 720> pos_y{ this, "Position Y (px)", 690, true }; // vertical position starting from the left border in px } shader_compilation_hint{this}; @@ -547,9 +547,9 @@ struct cfg_root : cfg::node { node_shader_preloading_dialog(cfg::node* _this) : cfg::node(_this, "Shader Loading Dialog"){} - cfg::_bool use_custom_background{this, "Allow custom background", true}; - cfg::_int<0, 100> darkening_strength{this, "Darkening effect strength", 30}; - cfg::_int<0, 100> blur_strength{this, "Blur effect strength", 0}; + cfg::_bool use_custom_background{ this, "Allow custom background", true, true }; + cfg::_int<0, 100> darkening_strength{ this, "Darkening effect strength", 30, true }; + cfg::_int<0, 100> blur_strength{ this, "Blur effect strength", 0, true }; } shader_preloading_dialog{this}; @@ -581,7 +581,6 @@ struct cfg_root : cfg::node cfg::_enum keyboard{this, "Keyboard", keyboard_handler::null}; cfg::_enum mouse{this, "Mouse", mouse_handler::basic}; - cfg::_enum pad{this, "Pad", pad_handler::keyboard}; cfg::_enum camera{this, "Camera", camera_handler::null}; cfg::_enum camera_type{this, "Camera type", fake_camera_type::unknown}; cfg::_enum move{this, "Move", move_handler::null}; @@ -610,19 +609,21 @@ struct cfg_root : cfg::node { node_misc(cfg::node* _this) : cfg::node(_this, "Miscellaneous") {} - cfg::_bool autostart{this, "Automatically start games after boot", true}; - cfg::_bool autoexit{this, "Exit RPCS3 when process finishes"}; - cfg::_bool start_fullscreen{ this, "Start games in fullscreen mode" }; + cfg::_bool autostart{ this, "Automatically start games after boot", true, true }; + cfg::_bool autoexit{ this, "Exit RPCS3 when process finishes", false, true }; + cfg::_bool start_fullscreen{ this, "Start games in fullscreen mode", false, true }; cfg::_bool prevent_display_sleep{ this, "Prevent display sleep while running games", true}; - cfg::_bool show_fps_in_title{ this, "Show FPS counter in window title", true}; - cfg::_bool show_trophy_popups{ this, "Show trophy popups", true}; - cfg::_bool show_shader_compilation_hint{ this, "Show shader compilation hint", true }; + cfg::_bool show_fps_in_title{ this, "Show FPS counter in window title", true, true }; + cfg::_bool show_trophy_popups{ this, "Show trophy popups", true, true }; + cfg::_bool show_shader_compilation_hint{ this, "Show shader compilation hint", true, true }; cfg::_bool use_native_interface{ this, "Use native user interface", true }; cfg::string gdb_server{this, "GDB Server", "127.0.0.1:2345"}; } misc{this}; cfg::log_entry log{this, "Log"}; + + std::string name; }; extern cfg_root g_cfg; diff --git a/rpcs3/rpcs3qt/emu_settings.cpp b/rpcs3/rpcs3qt/emu_settings.cpp index 864b4e6bf2..28dde5dfa9 100644 --- a/rpcs3/rpcs3qt/emu_settings.cpp +++ b/rpcs3/rpcs3qt/emu_settings.cpp @@ -296,19 +296,36 @@ void emu_settings::SaveSettings() YAML::Emitter out; emitData(out, m_currentSettings); - if (!m_title_id.empty()) + std::string config_name; + + if (m_title_id.empty()) { - config = fs::file(Emulator::GetCustomConfigPath(m_title_id), fs::read + fs::write + fs::create); + config_name = fs::get_config_dir() + "/config.yml"; } else { - config = fs::file(fs::get_config_dir() + "/config.yml", fs::read + fs::write + fs::create); + config_name = Emulator::GetCustomConfigPath(m_title_id); } + config = fs::file(config_name, fs::read + fs::write + fs::create); + // Save config config.seek(0); config.trunc(0); config.write(out.c_str(), out.size()); + + // Check if the running config/title is the same as the edited config/title. + if (config_name == g_cfg.name || m_title_id == Emu.GetTitleID()) + { + // Update current config + g_cfg.from_string(config.to_string(), true); + + if (!Emu.IsStopped()) // Don't spam the log while emulation is stopped. The config will be logged on boot anyway. + { + LOG_NOTICE(LOADER, "Updated configuration:\n%s\n", g_cfg.to_string()); + } + } + config.close(); } diff --git a/rpcs3/rpcs3qt/game_list_frame.cpp b/rpcs3/rpcs3qt/game_list_frame.cpp index 156a3fc374..dc7517e705 100644 --- a/rpcs3/rpcs3qt/game_list_frame.cpp +++ b/rpcs3/rpcs3qt/game_list_frame.cpp @@ -967,10 +967,14 @@ void game_list_frame::ShowContextMenu(const QPoint &pos) connect(configure, &QAction::triggered, [=] { settings_dialog dlg(m_gui_settings, m_emu_settings, 0, this, &currGame); - if (dlg.exec() == QDialog::Accepted && !gameinfo->hasCustomConfig) + if (dlg.exec() == QDialog::Accepted) { - gameinfo->hasCustomConfig = true; - ShowCustomConfigIcon(item); + if (!gameinfo->hasCustomConfig) + { + gameinfo->hasCustomConfig = true; + ShowCustomConfigIcon(item); + } + Q_EMIT NotifyEmuSettingsChange(); } }); connect(pad_configure, &QAction::triggered, [=] diff --git a/rpcs3/rpcs3qt/game_list_frame.h b/rpcs3/rpcs3qt/game_list_frame.h index 31e82346a8..7d9696e6dd 100644 --- a/rpcs3/rpcs3qt/game_list_frame.h +++ b/rpcs3/rpcs3qt/game_list_frame.h @@ -230,6 +230,7 @@ Q_SIGNALS: void GameListFrameClosed(); void RequestBoot(const game_info& game, bool force_global_config = false); void RequestIconSizeChange(const int& val); + void NotifyEmuSettingsChange(); protected: /** Override inherited method from Qt to allow signalling when close happened.*/ void closeEvent(QCloseEvent* event) override; diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 67f567b246..f941a7a2a5 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -1593,6 +1593,8 @@ void main_window::CreateDockWindows() { Boot(game->info.path, game->info.serial, false, false, force_global_config); }); + + connect(m_gameListFrame, &game_list_frame::NotifyEmuSettingsChange, this, &main_window::NotifyEmuSettingsChange); } void main_window::ConfigureGuiFromSettings(bool configure_all)