From 41d0dce6e9a717b393ed6a9d5d67e369c6d5385c Mon Sep 17 00:00:00 2001 From: bicarus-dev <202771338+bicarus-dev@users.noreply.github.com> Date: Tue, 22 Apr 2025 00:35:10 -0700 Subject: [PATCH] cfg: use %appdata%\spice2x for new config files (#300) ## Link to GitHub Issue, if one exists n/a ## Description of change For JSON config files of the following features: * patch manager * screen resize * IIDX camera hook * card manager when saving a new file, store them in %appdata%\spice2x instead of %appdata%. On load: 1. If the JSON file exists in %appdata%\spice2x, use that (new path) 1. If the JSON file exists in %appdata%, continue to use that (legacy path) It's common for people to have mixed versions of spicetools/spice2x so we'll continue to read from the %appdata% root if the files are there, but with a preference for the new path. We will not forcibly move files. spicetools.xml will continue to live in the %appdata% root. Moving this will confuse a lot of people, so I'm avoiding this. Also, this fixes `-patchcfgpath` and `-resizecfgpath` to create directories as needed (previously the parent directory must have existed first) ## Testing Tested - * existing config files are continued to be read from %appdata% * new files get created in %appdata%\spice2x\... (both in spicecfg and in overlay) * can provide custom path for `-patchcfgpath` `-resizecfgpath` and observe directories + file created in custom path, try absolute or local relative paths --- src/spice2x/cfg/screen_resize.cpp | 22 ++++---- src/spice2x/games/iidx/camera.cpp | 9 ++-- src/spice2x/launcher/options.cpp | 4 +- src/spice2x/overlay/windows/card_manager.cpp | 13 ++--- src/spice2x/overlay/windows/patch_manager.cpp | 5 +- src/spice2x/util/fileutils.cpp | 50 +++++++++++++++++++ src/spice2x/util/fileutils.h | 3 ++ 7 files changed, 80 insertions(+), 26 deletions(-) diff --git a/src/spice2x/cfg/screen_resize.cpp b/src/spice2x/cfg/screen_resize.cpp index d31040c..e55e130 100644 --- a/src/spice2x/cfg/screen_resize.cpp +++ b/src/spice2x/cfg/screen_resize.cpp @@ -15,12 +15,18 @@ namespace cfg { std::optional SCREEN_RESIZE_CFG_PATH_OVERRIDE; ScreenResize::ScreenResize() { + bool file_exists = false; if (SCREEN_RESIZE_CFG_PATH_OVERRIDE.has_value()) { this->config_path = SCREEN_RESIZE_CFG_PATH_OVERRIDE.value(); + if (fileutils::file_exists(this->config_path)) { + log_info("ScreenResize", "loading config from: {}", this->config_path.string()); + file_exists = true; + } } else { - this->config_path = std::filesystem::path(_wgetenv(L"APPDATA")) / L"spicetools_screen_resize.json"; + this->config_path = + fileutils::get_config_file_path("ScreenResize", "spicetools_screen_resize.json", &file_exists); } - if (fileutils::file_exists(this->config_path)) { + if (file_exists) { this->config_load(); } } @@ -29,12 +35,6 @@ namespace cfg { } void ScreenResize::config_load() { - if (SCREEN_RESIZE_CFG_PATH_OVERRIDE.has_value()) { - log_info("ScreenResize", "loading custom config: {}", this->config_path.string()); - } else { - log_info("ScreenResize", "loading global config from APPDATA"); - } - std::string config = fileutils::text_read(this->config_path); if (config.empty()) { log_info("ScreenResize", "config is empty"); @@ -170,8 +170,6 @@ namespace cfg { } void ScreenResize::config_save() { - log_info("ScreenResize", "saving config: {}", this->config_path.string()); - rapidjson::Document doc; std::string config = fileutils::text_read(this->config_path); if (!config.empty()) { @@ -221,10 +219,10 @@ namespace cfg { doc.Accept(writer); // save to file - if (fileutils::text_write(this->config_path, buffer.GetString())) { + if (fileutils::write_config_file("ScreenResize", this->config_path, buffer.GetString())) { // this->config_dirty = false; } else { - log_warning("ScreenResize", "unable to save config file to {}", this->config_path.string()); + log_warning("ScreenResize", "unable to save config file"); } } } diff --git a/src/spice2x/games/iidx/camera.cpp b/src/spice2x/games/iidx/camera.cpp index 0a17049..a12eecf 100644 --- a/src/spice2x/games/iidx/camera.cpp +++ b/src/spice2x/games/iidx/camera.cpp @@ -60,7 +60,7 @@ namespace games::iidx { static IIDXLocalCamera *front_camera = nullptr; // camera id #1 std::vector LOCAL_CAMERA_LIST = {}; static IDirect3DDeviceManager9 *s_pD3DManager = nullptr; - std::filesystem::path CAMERA_CONFIG_PATH = std::filesystem::path(_wgetenv(L"APPDATA")) / L"spicetools_camera_control.json"; + std::filesystem::path CAMERA_CONFIG_PATH; bool CAMERA_READY = false; bool parse_cmd_params() { @@ -493,7 +493,8 @@ namespace games::iidx { } bool camera_config_load() { - log_info("iidx:camhook", "loading config"); + CAMERA_CONFIG_PATH = + fileutils::get_config_file_path("iidx::camhook", "spicetools_camera_control.json"); try { // read config file @@ -651,9 +652,9 @@ namespace games::iidx { doc.Accept(writer); // save to file - if (fileutils::text_write(CAMERA_CONFIG_PATH, buffer.GetString())) { + if (fileutils::write_config_file("iidx::camhook", CAMERA_CONFIG_PATH, buffer.GetString())) { } else { - log_warning("iidx:camhook", "unable to save config file to {}", CAMERA_CONFIG_PATH.string()); + log_warning("iidx:camhook", "unable to save config file"); } return true; diff --git a/src/spice2x/launcher/options.cpp b/src/spice2x/launcher/options.cpp index d9948a3..d91402d 100644 --- a/src/spice2x/launcher/options.cpp +++ b/src/spice2x/launcher/options.cpp @@ -1088,7 +1088,7 @@ static const std::vector OPTION_DEFINITIONS = { .title = "Screen Resize Config Path", .name = "resizecfgpath", .desc = "Sets a custom file path for screen resize config file. " - "If left empty, %appdata%\\spicetools_screen_resize.json will be used", + "If left empty, %appdata%\\spice2x\\spicetools_screen_resize.json will be used", .type = OptionType::Text, .category = "Paths", }, @@ -1097,7 +1097,7 @@ static const std::vector OPTION_DEFINITIONS = { .title = "Patch Manager Config Path", .name = "patchcfgpath", .desc = "Sets a custom file path for patch manager config file. Can be used to manage 'profiles' for auto-patches. " - "If left empty, %appdata%\\spicetools_patch_manager.json will be used", + "If left empty, %appdata%\\spice2x\\spicetools_patch_manager.json will be used", .type = OptionType::Text, .category = "Paths", }, diff --git a/src/spice2x/overlay/windows/card_manager.cpp b/src/spice2x/overlay/windows/card_manager.cpp index 7aaf1b3..dd22c03 100644 --- a/src/spice2x/overlay/windows/card_manager.cpp +++ b/src/spice2x/overlay/windows/card_manager.cpp @@ -29,8 +29,11 @@ namespace overlay::windows { } this->toggle_button = games::OverlayButtons::ToggleCardManager; - this->config_path = std::filesystem::path(_wgetenv(L"APPDATA")) / L"spicetools_card_manager.json"; - if (fileutils::file_exists(this->config_path)) { + + bool file_exists = false; + this->config_path = + fileutils::get_config_file_path("cardmanager", "spicetools_card_manager.json", &file_exists); + if (file_exists) { this->config_load(); } @@ -434,8 +437,6 @@ namespace overlay::windows { } void CardManager::config_load() { - log_info("cardmanager", "loading config"); - // clear cards this->cards.clear(); @@ -566,10 +567,10 @@ namespace overlay::windows { doc.Accept(writer); // save to file - if (fileutils::text_write(this->config_path, buffer.GetString())) { + if (fileutils::write_config_file("cardmanager", this->config_path, buffer.GetString())) { this->config_dirty = false; } else { - log_warning("cardmanager", "unable to save config file to {}", this->config_path.string()); + log_warning("cardmanager", "unable to save config file"); } } diff --git a/src/spice2x/overlay/windows/patch_manager.cpp b/src/spice2x/overlay/windows/patch_manager.cpp index 54fdaec..21d37b1 100644 --- a/src/spice2x/overlay/windows/patch_manager.cpp +++ b/src/spice2x/overlay/windows/patch_manager.cpp @@ -219,7 +219,8 @@ namespace overlay::windows { this->config_path = PATCH_MANAGER_CFG_PATH_OVERRIDE.value(); log_info("patchmanager", "using custom config file path: {}", this->config_path.string().c_str()); } else { - this->config_path = std::filesystem::path(_wgetenv(L"APPDATA")) / L"spicetools_patch_manager.json"; + this->config_path = + fileutils::get_config_file_path("patchmanager", "spicetools_patch_manager.json"); } if (!ldr_registered) { @@ -1127,7 +1128,7 @@ namespace overlay::windows { doc.Accept(writer); // save to file - if (fileutils::text_write(config_path, buffer.GetString())) { + if (fileutils::write_config_file("patchmanager", config_path, buffer.GetString())) { config_dirty = false; } else { log_warning("patchmanager", "unable to save config file"); diff --git a/src/spice2x/util/fileutils.cpp b/src/spice2x/util/fileutils.cpp index 96d3162..f92b89e 100644 --- a/src/spice2x/util/fileutils.cpp +++ b/src/spice2x/util/fileutils.cpp @@ -264,3 +264,53 @@ std::vector *fileutils::bin_read(const std::filesystem::path &path) { } return contents; } + +std::filesystem::path fileutils::get_config_file_path(const std::string module, const std::string filename, bool* file_exists) { + // try %appdata%\spice2x path first, if it exists + const auto appdata_spice2x = std::filesystem::path(_wgetenv(L"APPDATA")) / "spice2x" / filename; + if (fileutils::file_exists(appdata_spice2x)) { + log_info(module, "loading config from %appdata%\\spice2x\\{}", filename); + if (file_exists) { + *file_exists = true; + } + return appdata_spice2x; + } + + // fallback to older %appdata% path (older spice2x or mainline spicetools), if it exists + const auto appdata = std::filesystem::path(_wgetenv(L"APPDATA")) / filename; + if (fileutils::file_exists(appdata)) { + log_info(module, "loading config from %appdata%\\{}", filename); + if (file_exists) { + *file_exists = true; + } + return appdata; + } + + // prefer new path if no existing file found + if (file_exists) { + *file_exists = false; + } + return appdata_spice2x; +} + +bool fileutils::write_config_file(const std::string_view &module, const std::filesystem::path path, std::string text) { + // attempt to undo %appdata% expansion to hide user name + const auto appdata = std::filesystem::path(_wgetenv(L"APPDATA")).string(); + auto censored = path.string(); + const auto substr_offset = censored.find(appdata); + if (substr_offset != std::string::npos) { + censored.replace(substr_offset, appdata.length(), "%appdata%"); + } + + // create directory path up to where the config file lives + if (!path.parent_path().empty() && !std::filesystem::exists(path.parent_path())) { + log_misc(module, "creating directory path to config file: {}", censored); + if (!fileutils::dir_create_recursive(path.parent_path())) { + return false; + } + } + + // save file + log_info(module, "saving config file: {}", censored); + return fileutils::text_write(path, text); +} \ No newline at end of file diff --git a/src/spice2x/util/fileutils.h b/src/spice2x/util/fileutils.h index c725bd4..db2e51b 100644 --- a/src/spice2x/util/fileutils.h +++ b/src/spice2x/util/fileutils.h @@ -33,4 +33,7 @@ namespace fileutils { std::string text_read(const std::filesystem::path &file_path); bool bin_write(const std::filesystem::path &path, uint8_t *data, size_t len); std::vector *bin_read(const std::filesystem::path &path); + + std::filesystem::path get_config_file_path(const std::string module, const std::string filename, bool* file_exists=nullptr); + bool write_config_file(const std::string_view &module, const std::filesystem::path path, std::string text); }