// MassBuilderSaveTool // Copyright (C) 2021-2024 Guillaume Jacquemin // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #include #include #include #include #include #include #include #include #include "../Logger/Logger.h" #include "Configuration.h" namespace mbst { Configuration::Configuration() { Containers::String exe_path = Utility::Path::split(*Utility::Path::executableLocation()).first(); _conf = Utility::Configuration{Utility::Path::join(exe_path, "MassBuilderSaveTool.ini")}; if(_conf.hasValue("swap_interval")) { _swapInterval = _conf.value("swap_interval"); } else { _conf.setValue("swap_interval", 1); } if(_conf.hasValue("frame_limit")) { std::string frame_limit = _conf.value("frame_limit"); if(frame_limit == "half_vsync") { _swapInterval = 2; } _conf.removeValue("frame_limit"); } if(_conf.hasValue("fps_cap")) { _fpsCap = _conf.value("fps_cap"); } else { _conf.setValue("fps_cap", 60.0f); } if(_conf.hasValue("cheat_mode")) { _cheatMode = _conf.value("cheat_mode"); } else { _conf.setValue("cheat_mode", _cheatMode); } if(_conf.hasValue("advanced_mode")) { _advancedMode = _conf.value("advanced_mode"); } else { _conf.setValue("advanced_mode", _advancedMode); } if(_conf.hasValue("startup_update_check")) { _checkUpdatesOnStartup = _conf.value("startup_update_check"); } else { _conf.setValue("startup_update_check", _checkUpdatesOnStartup); } if(_conf.hasValue("skip_disclaimer")) { _skipDisclaimer = _conf.value("skip_disclaimer"); } else { _conf.setValue("skip_disclaimer", _skipDisclaimer); } LOG_INFO("Searching for the game's save directory."); wchar_t* localappdata_path = nullptr; Containers::ScopeGuard guard{localappdata_path, CoTaskMemFree}; auto result = SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_DEFAULT, nullptr, &localappdata_path); if(result != S_OK) { char* message_buffer = nullptr; auto size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, result, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), reinterpret_cast(&message_buffer), 0, nullptr); String message{message_buffer, size}; LocalFree(message_buffer); _lastError = Utility::format("SHGetKnownFolderPath() failed with error code {}: {}", result, message); LOG_ERROR(_lastError); return; } auto game_data_dir = Utility::Path::join( Utility::Path::fromNativeSeparators(Utility::Unicode::narrow(localappdata_path)), "MASS_Builder/Saved"_s ); if(!Utility::Path::exists(game_data_dir)) { LOG_ERROR(_lastError = game_data_dir + " wasn't found. Make sure to play the game at least once."_s); return; } _directories.gameConfig = Utility::Path::join(game_data_dir, "Config/WindowsNoEditor"_s); _directories.gameSaves = Utility::Path::join(game_data_dir, "SaveGames"_s); _directories.gameScreenshots = Utility::Path::join(game_data_dir, "Screenshots/WindowsNoEditor"_s); LOG_INFO("Initialising Save Tool directories."); Containers::String executable_location = Utility::Path::split(*Utility::Path::executableLocation()).first(); _directories.backups = Utility::Path::join(executable_location, "backups"); _directories.staging = Utility::Path::join(executable_location, "staging"); auto armoury_dir = Utility::Path::join(executable_location, "armoury"); _directories.armours = Utility::Path::join(armoury_dir, "armours"); _directories.weapons = Utility::Path::join(armoury_dir, "weapons"); _directories.styles = Utility::Path::join(armoury_dir, "styles"); if(!Utility::Path::exists(_directories.backups)) { LOG_WARNING("Backups directory not found, creating..."); if(!Utility::Path::make(_directories.backups)) { LOG_ERROR(_lastError = "Couldn't create the backups directory."); return; } } if(!Utility::Path::exists(_directories.staging)) { LOG_WARNING("Staging directory not found, creating..."); if(!Utility::Path::make(_directories.staging)) { LOG_ERROR(_lastError = "Couldn't create the staging directory."); return; } } if(!Utility::Path::exists(_directories.armours)) { LOG_WARNING("Armours directory not found, creating..."); if(!Utility::Path::make(_directories.armours)) { LOG_ERROR(_lastError = "Couldn't create the armours directory."); return; } } if(!Utility::Path::exists(_directories.weapons)) { LOG_WARNING("Weapons directory not found, creating..."); if(!Utility::Path::make(_directories.weapons)) { LOG_ERROR(_lastError = "Couldn't create the weapons directory."); return; } } if(!Utility::Path::exists(_directories.styles)) { LOG_WARNING("Styles directory not found, creating..."); if(!Utility::Path::make(_directories.styles)) { LOG_ERROR(_lastError = "Couldn't create the styles directory."); return; } } _valid = true; } Configuration::~Configuration() { save(); } bool Configuration::valid() const { return _valid; } Containers::StringView Configuration::lastError() const { return _lastError; } void Configuration::save() { _conf.save(); } int Configuration::swapInterval() const { return _swapInterval; } void Configuration::setSwapInterval(int interval) { _swapInterval = interval; _conf.setValue("swap_interval", _swapInterval); _conf.save(); } float Configuration::fpsCap() const { return _fpsCap; } void Configuration::setFpsCap(float cap) { _fpsCap = cap; _conf.setValue("fps_cap", _fpsCap); _conf.save(); } bool Configuration::cheatMode() const { return _cheatMode; } void Configuration::setCheatMode(bool enabled) { _cheatMode = enabled; _conf.setValue("cheat_mode", _cheatMode); _conf.save(); } bool Configuration::advancedMode() const { return _advancedMode; } void Configuration::setAdvancedMode(bool enabled) { _advancedMode = enabled; _conf.setValue("advanced_mode", _advancedMode); _conf.save(); } bool Configuration::checkUpdatesOnStartup() const { return _checkUpdatesOnStartup; } void Configuration::setCheckUpdatesOnStartup(bool mode) { _checkUpdatesOnStartup = mode; _conf.setValue("startup_update_check", _checkUpdatesOnStartup); _conf.save(); } bool Configuration::skipDisclaimer() const { return _skipDisclaimer; } void Configuration::setSkipDisclaimer(bool mode) { _skipDisclaimer = mode; _conf.setValue("skip_disclaimer", _skipDisclaimer); _conf.save(); } bool Configuration::isRunningInWine() const { return _isRunningInWine; } void Configuration::setRunningInWine(bool wine) { _isRunningInWine = wine; } Configuration::Directories const& Configuration::directories() const { return _directories; } Configuration& Configuration::instance() { static Configuration conf{}; return conf; } Configuration& conf() { return Configuration::instance(); } }