From 93adb2bb95b34c0e8fde640a3794926a05a428e6 Mon Sep 17 00:00:00 2001 From: "Herman S." <429230+has207@users.noreply.github.com> Date: Thu, 6 Nov 2025 09:42:28 +0900 Subject: [PATCH] [Config] Gracefully handle type mismatches in cvars. Detect cvar type mismatch and reset to default value, as well as show message to the user that the cvar from the config has been updated. --- src/xenia/base/cvar.cc | 1 + src/xenia/base/cvar.h | 25 +++++++++++++++++++++++-- src/xenia/config.cc | 21 +++++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/xenia/base/cvar.cc b/src/xenia/base/cvar.cc index ad092a78b..3289df94f 100644 --- a/src/xenia/base/cvar.cc +++ b/src/xenia/base/cvar.cc @@ -30,6 +30,7 @@ cxxopts::Options options("xenia", "Xbox 360 Emulator"); std::map* CmdVars; std::map* ConfigVars; std::multimap* IConfigVarUpdate::updates_; +std::vector* config_type_mismatch_warnings = nullptr; void PrintHelpAndExit() { std::cout << options.help({""}) << std::endl; diff --git a/src/xenia/base/cvar.h b/src/xenia/base/cvar.h index 6c3357836..6b139bda7 100644 --- a/src/xenia/base/cvar.h +++ b/src/xenia/base/cvar.h @@ -33,6 +33,9 @@ namespace toml_internal { std::string EscapeString(const std::string_view str); } +// Track config values that had type mismatches during loading +extern std::vector* config_type_mismatch_warnings; + class ICommandVar { public: virtual ~ICommandVar() = default; @@ -147,7 +150,16 @@ inline void CommandVar::LoadFromLaunchOptions( } template void ConfigVar::LoadConfigValue(const toml::node* result) { - SetConfigValue(result->value().value()); + auto value_opt = result->value(); + if (value_opt) { + SetConfigValue(value_opt.value()); + } else { + // Type mismatch - track for warning + if (!config_type_mismatch_warnings) { + config_type_mismatch_warnings = new std::vector(); + } + config_type_mismatch_warnings->push_back(this->name_); + } } template <> inline void ConfigVar::LoadConfigValue( @@ -157,7 +169,16 @@ inline void ConfigVar::LoadConfigValue( } template void ConfigVar::LoadGameConfigValue(const toml::node* result) { - SetGameConfigValue(result->value().value()); + auto value_opt = result->value(); + if (value_opt) { + SetGameConfigValue(value_opt.value()); + } else { + // Type mismatch - track for warning + if (!config_type_mismatch_warnings) { + config_type_mismatch_warnings = new std::vector(); + } + config_type_mismatch_warnings->push_back(this->name_); + } } template <> inline void ConfigVar::LoadGameConfigValue( diff --git a/src/xenia/config.cc b/src/xenia/config.cc index a0b32e652..e64b8922c 100644 --- a/src/xenia/config.cc +++ b/src/xenia/config.cc @@ -16,6 +16,7 @@ #include "xenia/base/logging.h" #include "xenia/base/string.h" #include "xenia/base/string_buffer.h" +#include "xenia/base/system.h" toml::parse_result ParseFile(const std::filesystem::path& filename) { return toml::parse_file(xe::path_to_utf8(filename)); @@ -118,6 +119,26 @@ void ReadConfig(const std::filesystem::path& file_path, cvar::IConfigVarUpdate::ApplyUpdates(config_defaults_date); } + // Check for type mismatch warnings + if (cvar::config_type_mismatch_warnings && + !cvar::config_type_mismatch_warnings->empty()) { + std::string warning_message = + "The following config values had invalid types and have been reset to " + "defaults:\n\n"; + for (const auto& name : *cvar::config_type_mismatch_warnings) { + warning_message += " - " + name + "\n"; + } + warning_message += + "\nPlease check your config file. The config will be saved with the " + "correct types."; + + xe::ShowSimpleMessageBox(xe::SimpleMessageBoxType::Warning, + warning_message); + + // Clear warnings + cvar::config_type_mismatch_warnings->clear(); + } + XELOGI("Loaded config: {}", file_path); }