diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b8feb221..4e92bfd5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -870,8 +870,6 @@ set(CORE src/core/aerolib/stubs.cpp src/core/tls.h src/core/emulator_state.cpp src/core/emulator_state.h - src/core/emulator_settings.cpp - src/core/emulator_settings.h ) if (ARCHITECTURE STREQUAL "x86_64") diff --git a/src/common/config.cpp b/src/common/config.cpp index 34d1ca361..a5eea0a64 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -5,9 +5,8 @@ #include #include #include -#include -#include #include +#include // for wstring support #include #include "common/assert.h" @@ -476,7 +475,7 @@ void setShowFpsCounter(bool enable, bool is_game_specific) { showFpsCounter.set(enable, is_game_specific); } -static bool isLoggingEnabled() { +bool isLoggingEnabled() { return logEnabled.get(); } @@ -1022,7 +1021,7 @@ void load(const std::filesystem::path& path, bool is_game_specific) { } } -static void sortTomlSections(toml::ordered_value& data) { +void sortTomlSections(toml::ordered_value& data) { toml::ordered_value ordered_data; std::vector section_order = {"General", "Input", "Audio", "GPU", "Vulkan", "Debug", "Keys", "GUI", "Settings"}; @@ -1310,7 +1309,7 @@ constexpr std::string_view GetDefaultGlobalConfig() { )"; } -static constexpr std::string_view GetDefaultInputConfig() { +constexpr std::string_view GetDefaultInputConfig() { return R"(#Feeling lost? Check out the Help section! # Keyboard bindings diff --git a/src/common/config.h b/src/common/config.h index 6aaec7c5d..a9e0f7010 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -4,9 +4,6 @@ #pragma once #include -#include -#include -#include #include #include "types.h" diff --git a/src/core/emulator_settings.cpp b/src/core/emulator_settings.cpp deleted file mode 100644 index fbbdf5be6..000000000 --- a/src/core/emulator_settings.cpp +++ /dev/null @@ -1,293 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2025-2026 shadPS4 Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include -#include -#include -#include -#include "emulator_settings.h" - -using json = nlohmann::json; - -std::shared_ptr EmulatorSettings::s_instance = nullptr; -std::mutex EmulatorSettings::s_mutex; - -namespace nlohmann { -template <> -struct adl_serializer { - static void to_json(json& j, const std::filesystem::path& p) { - j = p.string(); - } - static void from_json(const json& j, std::filesystem::path& p) { - p = j.get(); - } -}; -} // namespace nlohmann - -// -------------------- -// Print summary -// -------------------- -void EmulatorSettings::PrintChangedSummary(const std::vector& changed) { - if (changed.empty()) { - std::cout << "[Settings] No game-specific overrides applied\n"; - return; - } - std::cout << "[Settings] Game-specific overrides applied:\n"; - for (const auto& k : changed) - std::cout << " * " << k << "\n"; -} - -// -------------------- -// ctor/dtor + singleton -// -------------------- -EmulatorSettings::EmulatorSettings() { - // Load(); -} -EmulatorSettings::~EmulatorSettings() { - Save(); -} - -std::shared_ptr EmulatorSettings::GetInstance() { - std::lock_guard lock(s_mutex); - if (!s_instance) - s_instance = std::make_shared(); - return s_instance; -} - -void EmulatorSettings::SetInstance(std::shared_ptr instance) { - std::lock_guard lock(s_mutex); - s_instance = instance; -} - -// -------------------- -// General helpers -// -------------------- - -std::filesystem::path EmulatorSettings::GetSysFontsDir() { - if (m_general.sys_fonts_dir.value.empty()) { - return Common::FS::GetUserPath(Common::FS::PathType::FontsDir); - } - return m_general.sys_fonts_dir.value; -} - -void EmulatorSettings::SetSysFontsDir(const std::filesystem::path& dir) { - m_general.sys_fonts_dir.value = dir; -} - -// -------------------- -// Save -// -------------------- -bool EmulatorSettings::Save(const std::string& serial) const { - try { - if (!serial.empty()) { - const std::filesystem::path cfgDir = - Common::FS::GetUserPath(Common::FS::PathType::CustomConfigs); - std::filesystem::create_directories(cfgDir); - const std::filesystem::path path = cfgDir / (serial + ".json"); - - json j = json::object(); - - // Only write overrideable fields for each group - json generalObj = json::object(); - for (auto& item : m_general.GetOverrideableFields()) { - json whole = m_general; - if (whole.contains(item.key)) - generalObj[item.key] = whole[item.key]; - } - j["General"] = generalObj; - - // Debug - /* json debugObj = json::object(); - for (auto& item : m_debug.GetOverrideableFields()) { - json whole = m_debug; - if (whole.contains(item.key)) - debugObj[item.key] = whole[item.key]; - } - j["Debug"] = debugObj; - - // Input - json inputObj = json::object(); - for (auto& item : m_input.GetOverrideableFields()) { - json whole = m_input; - if (whole.contains(item.key)) - inputObj[item.key] = whole[item.key]; - } - j["Input"] = inputObj; - - // Audio - json audioObj = json::object(); - for (auto& item : m_audio.GetOverrideableFields()) { - json whole = m_audio; - if (whole.contains(item.key)) - audioObj[item.key] = whole[item.key]; - } - j["Audio"] = audioObj; - - // GPU - json gpuObj = json::object(); - for (auto& item : m_gpu.GetOverrideableFields()) { - json whole = m_gpu; - if (whole.contains(item.key)) - gpuObj[item.key] = whole[item.key]; - } - j["GPU"] = gpuObj; - - // Vulkan - json vulkanObj = json::object(); - for (auto& item : m_vulkan.GetOverrideableFields()) { - json whole = m_vulkan; - if (whole.contains(item.key)) - vulkanObj[item.key] = whole[item.key]; - } - j["Vulkan"] = vulkanObj;*/ - - std::ofstream out(path); - if (!out.is_open()) { - std::cerr << "Failed to open file for writing: " << path << std::endl; - return false; - } - out << std::setw(4) << j; - out.flush(); - if (out.fail()) { - std::cerr << "Failed to write settings to: " << path << std::endl; - return false; - } - return true; - } else { - const std::filesystem::path path = - Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "config.json"; - json j; - j["General"] = m_general; - /* j["Debug"] = m_debug; - j["Input"] = m_input; - j["Audio"] = m_audio; - j["GPU"] = m_gpu; - j["Vulkan"] = m_vulkan; - j["Users"] = m_userManager.GetUsers();*/ - - std::ofstream out(path); - if (!out.is_open()) { - std::cerr << "Failed to open file for writing: " << path << std::endl; - return false; - } - out << std::setw(4) << j; - out.flush(); - if (out.fail()) { - std::cerr << "Failed to write settings to: " << path << std::endl; - return false; - } - return true; - } - } catch (const std::exception& e) { - std::cerr << "Error saving settings: " << e.what() << std::endl; - return false; - } -} - -// -------------------- -// Load -// -------------------- -bool EmulatorSettings::Load(const std::string& serial) { - try { - const std::filesystem::path userDir = - Common::FS::GetUserPath(Common::FS::PathType::UserDir); - const std::filesystem::path configPath = userDir / "config.json"; - - // Load global config if exists - if (std::ifstream globalIn{configPath}; globalIn.good()) { - json gj; - globalIn >> gj; - if (gj.contains("General")) { - json current = m_general; // JSON from existing struct with all defaults - current.update(gj.at("General")); // merge only fields present in file - m_general = current.get(); // convert back - } - /* if (gj.contains("Debug")) { - json current = m_debug; - current.update(gj.at("Debug")); - m_debug = current.get(); - } - if (gj.contains("Input")) { - json current = m_input; - current.update(gj.at("Input")); - m_input = current.get(); - } - if (gj.contains("Audio")) { - json current = m_audio; - current.update(gj.at("Audio")); - m_audio = current.get(); - } - if (gj.contains("GPU")) { - json current = m_gpu; - current.update(gj.at("GPU")); - m_gpu = current.get(); - } - if (gj.contains("Vulkan")) { - json current = m_vulkan; - current.update(gj.at("Vulkan")); - m_vulkan = current.get(); - } - if (gj.contains("Users")) - m_userManager.GetUsers() = gj.at("Users").get();*/ - } else { - SetDefaultValues(); - // ensure a default user exists - /* if (m_userManager.GetUsers().user.empty()) - m_userManager.GetUsers().user = m_userManager.CreateDefaultUser();*/ - Save(); - } - - // Load per-game overrides and apply - if (!serial.empty()) { - const std::filesystem::path gamePath = - Common::FS::GetUserPath(Common::FS::PathType::CustomConfigs) / (serial + ".json"); - if (!std::filesystem::exists(gamePath)) - return false; - - std::ifstream in(gamePath); - if (!in.is_open()) - return false; - - json gj; - in >> gj; - - std::vector changed; - - if (gj.contains("General")) { - ApplyGroupOverrides(m_general, gj.at("General"), changed); - } - if (gj.contains("Debug")) { - ApplyGroupOverrides(m_debug, gj.at("Debug"), changed); - } - if (gj.contains("Input")) { - ApplyGroupOverrides(m_input, gj.at("Input"), changed); - } - if (gj.contains("Audio")) { - ApplyGroupOverrides(m_audio, gj.at("Audio"), changed); - } - if (gj.contains("GPU")) { - ApplyGroupOverrides(m_gpu, gj.at("GPU"), changed); - } - if (gj.contains("Vulkan")) { - ApplyGroupOverrides(m_vulkan, gj.at("Vulkan"), changed); - } - - PrintChangedSummary(changed); - return true; - } - - return true; - } catch (const std::exception& e) { - std::cerr << "Error loading settings: " << e.what() << std::endl; - return false; - } -} - -void EmulatorSettings::SetDefaultValues() { - m_general = GeneralSettings{}; - m_debug = DebugSettings{}; - m_input = InputSettings{}; - m_audio = AudioSettings{}; - m_gpu = GPUSettings{}; - m_vulkan = VulkanSettings{}; -} diff --git a/src/core/emulator_settings.h b/src/core/emulator_settings.h deleted file mode 100644 index 71b581611..000000000 --- a/src/core/emulator_settings.h +++ /dev/null @@ -1,194 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2025-2026 shadPS4 Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include "common/types.h" - -// ------------------------------- -// Generic Setting wrapper -// ------------------------------- -template -struct Setting { - T value{}; -}; - -template -void to_json(nlohmann::json& j, const Setting& s) { - j = s.value; -} - -template -void from_json(const nlohmann::json& j, Setting& s) { - s.value = j.get(); -} - -// ------------------------------- -// Helper to describe a per-field override action -// ------------------------------- -struct OverrideItem { - const char* key; - // apply(basePtrToStruct, jsonEntry, changedFields) - std::function&)> apply; -}; - -// Helper factory: create an OverrideItem binding a pointer-to-member -template -inline OverrideItem make_override(const char* key, Setting Struct::* member) { - return OverrideItem{key, [member, key](void* base, const nlohmann::json& entry, - std::vector& changed) { - if (!entry.is_object()) - return; - - Struct* obj = reinterpret_cast(base); - Setting& dst = obj->*member; - - Setting tmp = entry.get>(); - - if (dst.value != tmp.value) { - changed.push_back(std::string(key) + " ( " + - nlohmann::json(dst.value).dump() + " → " + - nlohmann::json(tmp.value).dump() + " )"); - } - - dst.value = tmp.value; - }}; -} - -// ------------------------------- -// General settings -// ------------------------------- -struct GeneralSettings { - Setting sys_fonts_dir; - std::vector GetOverrideableFields() const { - return std::vector{}; - } -}; - -NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(GeneralSettings, sys_fonts_dir) - -// ------------------------------- -// Debug settings -// ------------------------------- -struct DebugSettings { - std::vector GetOverrideableFields() const { - return std::vector{}; - } -}; -// NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(DebugSettings) - -// ------------------------------- -// Input settings -// ------------------------------- - -struct InputSettings { - std::vector GetOverrideableFields() const { - return std::vector{}; - } -}; -// NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(InputSettings) - -// ------------------------------- -// Audio settings -// ------------------------------- -struct AudioSettings { - std::vector GetOverrideableFields() const { - return std::vector{}; - } -}; - -// NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(AudioSettings) - -// ------------------------------- -// GPU settings -// ------------------------------- -struct GPUSettings { - std::vector GetOverrideableFields() const { - return std::vector{}; - } -}; -// NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(GPUSettings) -// ------------------------------- -// Vulkan settings -// ------------------------------- -struct VulkanSettings { - std::vector GetOverrideableFields() const { - return std::vector{}; - } -}; -// NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(VulkanSettings) - -// ------------------------------- -// Main manager -// ------------------------------- -class EmulatorSettings { -public: - EmulatorSettings(); - ~EmulatorSettings(); - - static std::shared_ptr GetInstance(); - static void SetInstance(std::shared_ptr instance); - - bool Save(const std::string& serial = "") const; - bool Load(const std::string& serial = ""); - void SetDefaultValues(); - - // general accessors - std::filesystem::path GetSysFontsDir(); - void SetSysFontsDir(const std::filesystem::path& dir); - -private: - GeneralSettings m_general{}; - DebugSettings m_debug{}; - InputSettings m_input{}; - AudioSettings m_audio{}; - GPUSettings m_gpu{}; - VulkanSettings m_vulkan{}; - // UserManager m_userManager; - - static std::shared_ptr s_instance; - static std::mutex s_mutex; - - // Generic helper that applies override descriptors for a specific group - template - void ApplyGroupOverrides(Group& group, const nlohmann::json& groupJson, - std::vector& changed) { - for (auto& item : group.GetOverrideableFields()) { - if (!groupJson.contains(item.key)) - continue; - item.apply(&group, groupJson.at(item.key), changed); - } - } - - static void PrintChangedSummary(const std::vector& changed); - -public: -#define SETTING_FORWARD(group, Name, field) \ - auto Get##Name() const { \ - return group.field.value; \ - } \ - void Set##Name(const decltype(group.field.value)& v) { \ - group.field.value = v; \ - } -#define SETTING_FORWARD_BOOL(group, Name, field) \ - auto Is##Name() const { \ - return group.field.value; \ - } \ - void Set##Name(const decltype(group.field.value)& v) { \ - group.field.value = v; \ - } -#define SETTING_FORWARD_BOOL_READONLY(group, Name, field) \ - auto Is##Name() const { \ - return group.field.value; \ - } - -#undef SETTING_FORWARD -#undef SETTING_FORWARD_BOOL -}; diff --git a/src/main.cpp b/src/main.cpp index 2bfb06520..d3799e2ec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,8 +23,6 @@ #ifdef _WIN32 #include #endif -#include -#include int main(int argc, char* argv[]) { #ifdef _WIN32 @@ -32,13 +30,9 @@ int main(int argc, char* argv[]) { #endif IPC::Instance().Init(); - // Init emulator state + auto emu_state = std::make_shared(); EmulatorState::SetInstance(emu_state); - // Load configurations - std::shared_ptr emu_settings = std::make_shared(); - EmulatorSettings::SetInstance(emu_settings); - emu_settings->Load(); const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir); Config::load(user_dir / "config.toml");