config: implemented saving

This commit is contained in:
Hyper 2024-10-21 16:51:47 +01:00
parent 5578e84069
commit cf8bba788b
9 changed files with 272 additions and 126 deletions

View file

@ -2,7 +2,7 @@ void Config::Load()
{
try
{
auto toml = toml::parse_file((GetUserPath() / TOML_FILE).string());
auto toml = toml::parse_file(GetConfigPath().string());
TOML_BEGIN_SECTION("System")
{
@ -61,10 +61,38 @@ void Config::Load()
printf("Failed to parse configuration: %s\n", err.what());
}
ResolutionScale = std::clamp(ResolutionScale, 0.25f, 2.0f);
ResolutionScale = std::clamp(ResolutionScale.Value, 0.25f, 2.0f);
}
void Config::Save()
{
// TODO
std::string result;
std::string section;
for (auto def : Definitions)
{
auto isFirstSection = section.empty();
auto isDefWithSection = section != def->GetSection();
auto tomlDef = def->GetDefinition(isDefWithSection);
section = def->GetSection();
// Don't output prefix space for first section.
if (!isFirstSection && isDefWithSection)
result += '\n';
result += tomlDef + '\n';
}
std::ofstream out(GetConfigPath());
if (out.is_open())
{
out << result;
out.close();
}
else
{
printf("Failed to write configuration.\n");
}
}

View file

@ -1,116 +1,47 @@
#pragma once
#define USER_DIRECTORY "SWA"
#define TOML_FILE "config.toml"
#define TOML_BEGIN_SECTION(name) if (auto pSection = toml[name].as_table()) { const auto& section = *pSection;
#define TOML_END_SECTION() }
#define TOML_READ_STRING(var) var = section[#var].value_or<std::string>(var);
#define TOML_READ_BOOLEAN(var) var = section[#var].value_or(var);
#define TOML_READ_FLOAT(var) var = section[#var].value_or(var);
#define TOML_READ_INTEGER(var) var = section[#var].value_or(var);
#define TOML_READ_DOUBLE(var) var = section[#var].value_or(var);
#define TOML_READ_ENUM(type, var) var = (type)section[#var].value_or(var);
#define CONFIG_DEFINE(type, name, defaultValue) \
static const type name##_Default = defaultValue; \
inline static type name = name##_Default;
#define CONFIG_GET_DEFAULT(name) Config::name##_Default
#define CONFIG_SET_DEFAULT(name) Config::name = CONFIG_GET_DEFAULT(name)
enum ELanguage
{
ELanguage_English = 1,
ELanguage_Japanese,
ELanguage_German,
ELanguage_French,
ELanguage_Spanish,
ELanguage_Italian
};
enum EScoreBehaviour
{
EScoreBehaviour_CheckpointReset,
EScoreBehaviour_CheckpointRetain
};
enum EVoiceLanguage
{
EVoiceLanguage_English,
EVoiceLanguage_Japanese
};
enum EGraphicsAPI
{
EGraphicsAPI_D3D12,
EGraphicsAPI_Vulkan
};
enum EGITextureFiltering
{
EGITextureFiltering_Linear,
EGITextureFiltering_Bicubic
};
enum EMovieScaleMode
{
EMovieScaleMode_Stretch,
EMovieScaleMode_Fit,
EMovieScaleMode_Fill
};
enum EUIScaleMode
{
EUIScaleMode_Stretch,
EUIScaleMode_Edge,
EUIScaleMode_Centre
};
#include "config_detail.h"
class Config
{
public:
// System
CONFIG_DEFINE(ELanguage, Language, ELanguage_English);
CONFIG_DEFINE(bool, Hints, true);
CONFIG_DEFINE(EScoreBehaviour, ScoreBehaviour, EScoreBehaviour_CheckpointReset);
CONFIG_DEFINE(bool, UnleashOutOfControlDrain, true);
CONFIG_DEFINE(bool, WerehogHubTransformVideo, true);
CONFIG_DEFINE(bool, LogoSkip, false);
inline static std::vector<std::shared_ptr<ConfigDefBase>> Definitions{};
// Controls
CONFIG_DEFINE(bool, CameraXInvert, false);
CONFIG_DEFINE(bool, CameraYInvert, false);
CONFIG_DEFINE(bool, XButtonHoming, true);
CONFIG_DEFINE(bool, UnleashCancel, false);
CONFIG_DEFINE("System", ELanguage, Language, ELanguage_English);
CONFIG_DEFINE("System", bool, Hints, true);
CONFIG_DEFINE("System", EScoreBehaviour, ScoreBehaviour, EScoreBehaviour_CheckpointReset);
CONFIG_DEFINE("System", bool, UnleashOutOfControlDrain, true);
CONFIG_DEFINE("System", bool, WerehogHubTransformVideo, true);
CONFIG_DEFINE("System", bool, LogoSkip, false);
// Audio
CONFIG_DEFINE(float, MusicVolume, 1.0f);
CONFIG_DEFINE(float, SEVolume, 1.0f);
CONFIG_DEFINE(EVoiceLanguage, VoiceLanguage, EVoiceLanguage_English);
CONFIG_DEFINE(bool, Subtitles, true);
CONFIG_DEFINE(bool, WerehogBattleMusic, true);
CONFIG_DEFINE("Controls", bool, CameraXInvert, false);
CONFIG_DEFINE("Controls", bool, CameraYInvert, false);
CONFIG_DEFINE("Controls", bool, XButtonHoming, true);
CONFIG_DEFINE("Controls", bool, UnleashCancel, false);
// Video
CONFIG_DEFINE(EGraphicsAPI, GraphicsAPI, EGraphicsAPI_D3D12);
CONFIG_DEFINE(size_t, WindowWidth, 1280);
CONFIG_DEFINE(size_t, WindowHeight, 720);
CONFIG_DEFINE(float, ResolutionScale, 1.0f);
CONFIG_DEFINE(bool, Fullscreen, false);
CONFIG_DEFINE(bool, VSync, true);
CONFIG_DEFINE(size_t, BufferCount, 3);
CONFIG_DEFINE(size_t, FPS, 60);
CONFIG_DEFINE(float, Brightness, 0.5f);
CONFIG_DEFINE(size_t, MSAA, 4);
CONFIG_DEFINE(size_t, AnisotropicFiltering, 16);
CONFIG_DEFINE(int32_t, ShadowResolution, 4096);
CONFIG_DEFINE(EGITextureFiltering, GITextureFiltering, EGITextureFiltering_Bicubic);
CONFIG_DEFINE(bool, AlphaToCoverage, false);
CONFIG_DEFINE(bool, Xbox360ColorCorrection, false);
CONFIG_DEFINE(EMovieScaleMode, MovieScaleMode, EMovieScaleMode_Fit);
CONFIG_DEFINE(EUIScaleMode, UIScaleMode, EUIScaleMode_Centre);
CONFIG_DEFINE("Audio", float, MusicVolume, 1.0f);
CONFIG_DEFINE("Audio", float, SEVolume, 1.0f);
CONFIG_DEFINE("Audio", EVoiceLanguage, VoiceLanguage, EVoiceLanguage_English);
CONFIG_DEFINE("Audio", bool, Subtitles, true);
CONFIG_DEFINE("Audio", bool, WerehogBattleMusic, true);
CONFIG_DEFINE("Video", EGraphicsAPI, GraphicsAPI, EGraphicsAPI_D3D12);
CONFIG_DEFINE("Video", size_t, WindowWidth, 1280);
CONFIG_DEFINE("Video", size_t, WindowHeight, 720);
CONFIG_DEFINE("Video", float, ResolutionScale, 1.0f);
CONFIG_DEFINE("Video", bool, Fullscreen, false);
CONFIG_DEFINE("Video", bool, VSync, true);
CONFIG_DEFINE("Video", size_t, BufferCount, 3);
CONFIG_DEFINE("Video", size_t, FPS, 60);
CONFIG_DEFINE("Video", float, Brightness, 0.5f);
CONFIG_DEFINE("Video", size_t, MSAA, 4);
CONFIG_DEFINE("Video", size_t, AnisotropicFiltering, 16);
CONFIG_DEFINE("Video", int32_t, ShadowResolution, 4096);
CONFIG_DEFINE("Video", EGITextureFiltering, GITextureFiltering, EGITextureFiltering_Bicubic);
CONFIG_DEFINE("Video", bool, AlphaToCoverage, false);
CONFIG_DEFINE("Video", bool, Xbox360ColorCorrection, false);
CONFIG_DEFINE("Video", EMovieScaleMode, MovieScaleMode, EMovieScaleMode_Fit);
CONFIG_DEFINE("Video", EUIScaleMode, UIScaleMode, EUIScaleMode_Centre);
static std::filesystem::path GetUserPath()
{
@ -129,6 +60,11 @@ public:
return userPath;
}
static std::filesystem::path GetConfigPath()
{
return GetUserPath() / TOML_FILE;
}
static void Load();
static void Save();
};

View file

@ -0,0 +1,181 @@
#pragma once
#define USER_DIRECTORY "SWA"
#define TOML_FILE "config.toml"
#define TOML_BEGIN_SECTION(name) if (auto pSection = toml[name].as_table()) { const auto& section = *pSection;
#define TOML_END_SECTION() }
#define TOML_READ_STRING(var) var.Value = section[#var].value_or<std::string>(var.DefaultValue);
#define TOML_READ_BOOLEAN(var) var.Value = section[#var].value_or(var.DefaultValue);
#define TOML_READ_FLOAT(var) var.Value = section[#var].value_or(var.DefaultValue);
#define TOML_READ_INTEGER(var) var.Value = section[#var].value_or(var.DefaultValue);
#define TOML_READ_DOUBLE(var) var.Value = section[#var].value_or(var.DefaultValue);
#define TOML_READ_ENUM(type, var) var.Value = (type)section[#var].value_or(var.DefaultValue);
#define CONFIG_DEFINE(section, type, name, defaultValue) inline static ConfigDef<type> name{section, #name, defaultValue};
#define CONFIG_VALUE(name) Config::name.Value
#define CONFIG_GET_DEFAULT(name) Config::name.DefaultValue
#define CONFIG_SET_DEFAULT(name) Config::name.MakeDefault();
class ConfigDefBase
{
public:
virtual ~ConfigDefBase() = default;
virtual void MakeDefault() = 0;
virtual std::string GetSection() const = 0;
virtual std::string GetName() const = 0;
virtual std::string GetDefinition(bool withSection = false) const = 0;
virtual std::string ToString() const = 0;
};
template<typename T>
class ConfigDef : public ConfigDefBase
{
public:
std::string Section;
std::string Name;
T DefaultValue{};
T Value{ DefaultValue };
ConfigDef(std::string section, std::string name, T defaultValue) : Section(section), Name(name), DefaultValue(defaultValue)
{
Config::Definitions.emplace_back(this);
}
void MakeDefault() override
{
Value = DefaultValue;
}
std::string GetSection() const override
{
return Section;
}
std::string GetName() const override
{
return Name;
}
std::string GetDefinition(bool withSection = false) const override
{
std::string result;
if (withSection)
result += "[" + Section + "]\n";
result += Name + " = " + ToString();
return result;
}
std::string ToString() const override
{
if constexpr (std::is_same<T, std::string>::value)
{
return Value;
}
else if constexpr (std::is_same<T, bool>::value)
{
return Value ? "true" : "false";
}
std::ostringstream oss;
oss << Value;
return oss.str();
}
ConfigDef& operator=(const ConfigDef& other)
{
if (this != &other)
Value = other.Value;
return *this;
}
void operator=(const T& other)
{
Value = other;
}
bool operator==(const T& other) const
{
return Value == other;
}
bool operator!=(const T& other) const
{
return Value != other;
}
bool operator<(const T& other) const
{
return Value < other;
}
bool operator>(const T& other) const
{
return Value > other;
}
bool operator<=(const T& other) const
{
return Value <= other;
}
bool operator>=(const T& other) const
{
return Value >= other;
}
};
enum ELanguage
{
ELanguage_English = 1,
ELanguage_Japanese,
ELanguage_German,
ELanguage_French,
ELanguage_Spanish,
ELanguage_Italian
};
enum EScoreBehaviour
{
EScoreBehaviour_CheckpointReset,
EScoreBehaviour_CheckpointRetain
};
enum EVoiceLanguage
{
EVoiceLanguage_English,
EVoiceLanguage_Japanese
};
enum EGraphicsAPI
{
EGraphicsAPI_D3D12,
EGraphicsAPI_Vulkan
};
enum EGITextureFiltering
{
EGITextureFiltering_Linear,
EGITextureFiltering_Bicubic
};
enum EMovieScaleMode
{
EMovieScaleMode_Stretch,
EMovieScaleMode_Fit,
EMovieScaleMode_Fill
};
enum EUIScaleMode
{
EUIScaleMode_Stretch,
EUIScaleMode_Edge,
EUIScaleMode_Centre
};

View file

@ -119,7 +119,7 @@ PPC_FUNC(sub_824DCF38)
{
/* Force the Werehog transition ID
to use a different transition. */
if (!Config::WerehogHubTransformVideo)
if (!Config::WerehogHubTransformVideo.Value)
{
/*
0 - Tails Electric NOW LOADING
@ -160,12 +160,12 @@ PPC_FUNC(sub_823AF7A8)
m_lastDarkGaiaEnergy = pEvilSonicContext->m_DarkGaiaEnergy;
// Don't drain energy if out of control.
if (!Config::UnleashOutOfControlDrain && pEvilSonicContext->m_OutOfControlCount && ctx.f1.f64 < 0.0)
if (!Config::UnleashOutOfControlDrain.Value && pEvilSonicContext->m_OutOfControlCount && ctx.f1.f64 < 0.0)
return;
__imp__sub_823AF7A8(ctx, base);
if (!Config::UnleashCancel)
if (!Config::UnleashCancel.Value)
return;
auto pInputState = SWA::CInputState::GetInstance();
@ -198,12 +198,12 @@ void PostUnleashMidAsmHook(PPCRegister& r30)
bool DisableHintsMidAsmHook()
{
return !Config::Hints;
return !Config::Hints.Value;
}
void SetXButtonHomingMidAsmHook(PPCRegister& r30)
{
r30.u32 = Config::XButtonHoming;
r30.u32 = Config::XButtonHoming.Value;
}
/* Hook function that gets the game region
@ -240,7 +240,7 @@ void GetStageIDMidAsmHook(PPCRegister& r5)
PPC_FUNC_IMPL(__imp__sub_82547DF0);
PPC_FUNC(sub_82547DF0)
{
if (Config::LogoSkip)
if (Config::LogoSkip.Value)
{
ctx.r4.u64 = 0;
ctx.r5.u64 = 0;

View file

@ -1171,7 +1171,7 @@ static GuestSurface* CreateSurface(uint32_t width, uint32_t height, uint32_t for
desc.depth = 1;
desc.mipLevels = 1;
desc.arraySize = 1;
desc.multisampling.sampleCount = multiSample != 0 && Config::MSAA > 1 ? Config::MSAA : RenderSampleCount::COUNT_1;
desc.multisampling.sampleCount = multiSample != 0 && Config::MSAA > 1 ? Config::MSAA.Value : RenderSampleCount::COUNT_1;
desc.format = ConvertFormat(format);
desc.flags = desc.format == RenderFormat::D32_FLOAT ? RenderTextureFlag::DEPTH_TARGET : RenderTextureFlag::RENDER_TARGET;
@ -2614,7 +2614,7 @@ void IndexBufferLengthMidAsmHook(PPCRegister& r3)
void SetShadowResolutionMidAsmHook(PPCRegister& r11)
{
if (Config::ShadowResolution > 0)
r11.u64 = Config::ShadowResolution;
r11.u64 = Config::ShadowResolution.Value;
}
void Primitive2DHalfPixelOffsetMidAsmHook(PPCRegister& f13)
@ -2624,8 +2624,8 @@ void Primitive2DHalfPixelOffsetMidAsmHook(PPCRegister& f13)
static void SetResolution(be<uint32_t>* device)
{
uint32_t width = uint32_t(g_swapChain->getWidth() * Config::ResolutionScale);
uint32_t height = uint32_t(g_swapChain->getHeight() * Config::ResolutionScale);
uint32_t width = uint32_t(g_swapChain->getWidth() * Config::ResolutionScale.Value);
uint32_t height = uint32_t(g_swapChain->getHeight() * Config::ResolutionScale.Value);
device[46] = width == 0 ? 880 : width;
device[47] = height == 0 ? 720 : height;
}

View file

@ -191,7 +191,7 @@ void XamShowMessageBoxUIEx()
uint32_t XGetLanguage()
{
// printf("!!! STUB !!! XGetLanguage\n");
return Config::Language;
return Config::Language.Value;
}
uint32_t XGetAVPack()
@ -336,7 +336,7 @@ uint32_t ExGetXConfigSetting(uint16_t Category, uint16_t Setting, void* Buffer,
// XCONFIG_USER_LANGUAGE
case 0x0009:
data[0] = std::byteswap((uint32_t)Config::Language);
data[0] = std::byteswap((uint32_t)Config::Language.Value);
break;
// XCONFIG_USER_VIDEO_FLAGS

View file

@ -7,6 +7,7 @@
#include <algorithm>
#include <mutex>
#include <filesystem>
#include <fstream>
#include <vector>
#include <string>
#include <cassert>

View file

@ -92,8 +92,8 @@ void Window::Init()
s_window = SDL_CreateWindow(title,
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
Config::WindowWidth,
Config::WindowHeight,
Config::WindowWidth.Value,
Config::WindowHeight.Value,
SDL_WINDOW_RESIZABLE);
if (auto icon = GetIconSurface())
@ -103,7 +103,7 @@ void Window::Init()
}
SetWindowDimensions();
SetFullscreen(Config::Fullscreen);
SetFullscreen(Config::Fullscreen.Value);
SDL_SysWMinfo info;
SDL_VERSION(&info.version);

View file

@ -29,8 +29,8 @@ public:
static bool IsDisplayResolution(int w, int h, bool isExact = true)
{
auto width = w <= 0 ? Config::WindowWidth : w;
auto height = h <= 0 ? Config::WindowHeight : h;
auto width = w <= 0 ? Config::WindowWidth.Value : w;
auto height = h <= 0 ? Config::WindowHeight.Value : h;
SDL_Rect displayRect;
if (SDL_GetDisplayBounds(SDL_GetWindowDisplayIndex(s_window), &displayRect) == ERROR_SUCCESS)
@ -83,8 +83,8 @@ public:
static void SetWindowDimensions(int w = -1, int h = -1)
{
auto width = w <= 0 ? Config::WindowWidth : w;
auto height = h <= 0 ? Config::WindowHeight : h;
auto width = w <= 0 ? Config::WindowWidth.Value : w;
auto height = h <= 0 ? Config::WindowHeight.Value : h;
auto isPendingMaximise = false;
if (IsDisplayResolution(width, height))