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
This commit is contained in:
bicarus-dev
2025-04-22 00:35:10 -07:00
committed by GitHub
parent 598422b701
commit 41d0dce6e9
7 changed files with 80 additions and 26 deletions
+11 -13
View File
@@ -15,12 +15,18 @@ namespace cfg {
std::optional<std::string> 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();
} else {
this->config_path = std::filesystem::path(_wgetenv(L"APPDATA")) / L"spicetools_screen_resize.json";
}
if (fileutils::file_exists(this->config_path)) {
log_info("ScreenResize", "loading config from: {}", this->config_path.string());
file_exists = true;
}
} else {
this->config_path =
fileutils::get_config_file_path("ScreenResize", "spicetools_screen_resize.json", &file_exists);
}
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");
}
}
}
+5 -4
View File
@@ -60,7 +60,7 @@ namespace games::iidx {
static IIDXLocalCamera *front_camera = nullptr; // camera id #1
std::vector<IIDXLocalCamera*> 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;
+2 -2
View File
@@ -1088,7 +1088,7 @@ static const std::vector<OptionDefinition> 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<OptionDefinition> 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",
},
+7 -6
View File
@@ -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");
}
}
@@ -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");
+50
View File
@@ -264,3 +264,53 @@ std::vector<uint8_t> *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);
}
+3
View File
@@ -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<uint8_t> *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);
}