297 lines
8.5 KiB
C++
297 lines
8.5 KiB
C++
// 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 <https://www.gnu.org/licenses/>.
|
|
|
|
#include <Corrade/Containers/Optional.h>
|
|
#include <Corrade/Containers/Pair.h>
|
|
#include <Corrade/Containers/ScopeGuard.h>
|
|
#include <Corrade/Utility/Path.h>
|
|
#include <Corrade/Utility/Unicode.h>
|
|
|
|
#include <combaseapi.h>
|
|
#include <knownfolders.h>
|
|
#include <shlobj.h>
|
|
|
|
#include "../Logger/Logger.h"
|
|
#include "../Utilities/Temp.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<int>("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<float>("fps_cap");
|
|
}
|
|
else {
|
|
_conf.setValue("fps_cap", 60.0f);
|
|
}
|
|
|
|
if(_conf.hasValue("cheat_mode")) {
|
|
_cheatMode = _conf.value<bool>("cheat_mode");
|
|
}
|
|
else {
|
|
_conf.setValue("cheat_mode", _cheatMode);
|
|
}
|
|
|
|
if(_conf.hasValue("advanced_mode")) {
|
|
_advancedMode = _conf.value<bool>("advanced_mode");
|
|
}
|
|
else {
|
|
_conf.setValue("advanced_mode", _advancedMode);
|
|
}
|
|
|
|
if(_conf.hasValue("startup_update_check")) {
|
|
_checkUpdatesOnStartup = _conf.value<bool>("startup_update_check");
|
|
}
|
|
else {
|
|
_conf.setValue("startup_update_check", _checkUpdatesOnStartup);
|
|
}
|
|
|
|
if(_conf.hasValue("skip_disclaimer")) {
|
|
_skipDisclaimer = _conf.value<bool>("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<char*>(&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");
|
|
_directories.temp = Utility::Path::join(executable_location, "temp");
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
if(!Utility::Path::exists(_directories.temp)) {
|
|
LOG_WARNING("Temporary directory not found, creating...");
|
|
if(!Utility::Path::make(_directories.temp)) {
|
|
LOG_ERROR(_lastError = "Couldn't create the temporary directory.");
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
Utilities::emptyTempDir();
|
|
}
|
|
|
|
_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();
|
|
}
|
|
|
|
}
|