#include "config.hpp" #include #include #include #include #include "helpers.hpp" #include "toml.hpp" // Largely based on https://github.com/nba-emu/NanoBoyAdvance/blob/master/src/platform/core/src/config.cpp // We are legally allowed, as per the author's wish, to use the above code without any licensing restrictions // However we still want to follow the license as closely as possible and offer the proper attributions. EmulatorConfig::EmulatorConfig(const std::filesystem::path& path) : filePath(path) { load(); } void EmulatorConfig::load() { const std::filesystem::path& path = filePath; // If the configuration file does not exist, create it and return std::error_code error; if (!std::filesystem::exists(path, error)) { save(); return; } toml::value data; try { data = toml::parse(path); } catch (std::exception& ex) { Helpers::warn("Got exception trying to load config file. Exception: %s\n", ex.what()); return; } if (data.contains("General")) { auto generalResult = toml::expect(data.at("General")); if (generalResult.is_ok()) { auto general = generalResult.unwrap(); discordRpcEnabled = toml::find_or(general, "EnableDiscordRPC", false); usePortableBuild = toml::find_or(general, "UsePortableBuild", false); defaultRomPath = toml::find_or(general, "DefaultRomPath", ""); printAppVersion = toml::find_or(general, "PrintAppVersion", true); appVersionOnWindow = toml::find_or(general, "AppVersionOnWindow", false); } } if (data.contains("GPU")) { auto gpuResult = toml::expect(data.at("GPU")); if (gpuResult.is_ok()) { auto gpu = gpuResult.unwrap(); // Get renderer auto rendererName = toml::find_or(gpu, "Renderer", "OpenGL"); auto configRendererType = Renderer::typeFromString(rendererName); if (configRendererType.has_value()) { rendererType = configRendererType.value(); } else { Helpers::warn("Invalid renderer specified: %s\n", rendererName.c_str()); rendererType = RendererType::OpenGL; } shaderJitEnabled = toml::find_or(gpu, "EnableShaderJIT", shaderJitDefault); vsyncEnabled = toml::find_or(gpu, "EnableVSync", true); useUbershaders = toml::find_or(gpu, "UseUbershaders", ubershaderDefault); accurateShaderMul = toml::find_or(gpu, "AccurateShaderMultiplication", false); forceShadergenForLights = toml::find_or(gpu, "ForceShadergenForLighting", true); lightShadergenThreshold = toml::find_or(gpu, "ShadergenLightThreshold", 1); enableRenderdoc = toml::find_or(gpu, "EnableRenderdoc", false); } } if (data.contains("Audio")) { auto audioResult = toml::expect(data.at("Audio")); if (audioResult.is_ok()) { auto audio = audioResult.unwrap(); auto dspCoreName = toml::find_or(audio, "DSPEmulation", "Null"); dspType = Audio::DSPCore::typeFromString(dspCoreName); audioEnabled = toml::find_or(audio, "EnableAudio", false); } } if (data.contains("Battery")) { auto batteryResult = toml::expect(data.at("Battery")); if (batteryResult.is_ok()) { auto battery = batteryResult.unwrap(); chargerPlugged = toml::find_or(battery, "ChargerPlugged", true); batteryPercentage = toml::find_or(battery, "BatteryPercentage", 3); // Clamp battery % to [0, 100] to make sure it's a valid value batteryPercentage = std::clamp(batteryPercentage, 0, 100); } } if (data.contains("SD")) { auto sdResult = toml::expect(data.at("SD")); if (sdResult.is_ok()) { auto sd = sdResult.unwrap(); sdCardInserted = toml::find_or(sd, "UseVirtualSD", true); sdWriteProtected = toml::find_or(sd, "WriteProtectVirtualSD", false); } } } void EmulatorConfig::save() { toml::basic_value data; const std::filesystem::path& path = filePath; std::error_code error; if (std::filesystem::exists(path, error)) { try { data = toml::parse(path); } catch (const std::exception& ex) { Helpers::warn("Exception trying to parse config file. Exception: %s\n", ex.what()); return; } } else { if (error) { Helpers::warn("Filesystem error accessing %s (error: %s)\n", path.string().c_str(), error.message().c_str()); } printf("Saving new configuration file %s\n", path.string().c_str()); } data["General"]["EnableDiscordRPC"] = discordRpcEnabled; data["General"]["UsePortableBuild"] = usePortableBuild; data["General"]["DefaultRomPath"] = defaultRomPath.string(); data["General"]["PrintAppVersion"] = printAppVersion; data["General"]["AppVersionOnWindow"] = appVersionOnWindow; data["GPU"]["EnableShaderJIT"] = shaderJitEnabled; data["GPU"]["Renderer"] = std::string(Renderer::typeToString(rendererType)); data["GPU"]["EnableVSync"] = vsyncEnabled; data["GPU"]["AccurateShaderMultiplication"] = accurateShaderMul; data["GPU"]["UseUbershaders"] = useUbershaders; data["GPU"]["ForceShadergenForLighting"] = forceShadergenForLights; data["GPU"]["ShadergenLightThreshold"] = lightShadergenThreshold; data["GPU"]["EnableRenderdoc"] = enableRenderdoc; data["Audio"]["DSPEmulation"] = std::string(Audio::DSPCore::typeToString(dspType)); data["Audio"]["EnableAudio"] = audioEnabled; data["Battery"]["ChargerPlugged"] = chargerPlugged; data["Battery"]["BatteryPercentage"] = batteryPercentage; data["SD"]["UseVirtualSD"] = sdCardInserted; data["SD"]["WriteProtectVirtualSD"] = sdWriteProtected; std::ofstream file(path, std::ios::out); file << data; file.close(); }