diff --git a/.gitmodules b/.gitmodules index 305705b06a..0a317a8386 100644 --- a/.gitmodules +++ b/.gitmodules @@ -107,4 +107,7 @@ [submodule "3rdparty/GPUOpen/VulkanMemoryAllocator"] path = 3rdparty/GPUOpen/VulkanMemoryAllocator url = ../../Megamouse/VulkanMemoryAllocator.git +[submodule "3rdparty/json"] + path = 3rdparty/json + url = ../../nlohmann/json.git ignore = dirty diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt index cb0909e978..a7ab53aa0a 100644 --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -353,6 +353,10 @@ add_subdirectory(opencv EXCLUDE_FROM_ALL) # FUSION add_subdirectory(fusion EXCLUDE_FROM_ALL) +# nlohmann json +add_library(3rdparty_json INTERFACE) +target_include_directories(3rdparty_json INTERFACE json/include) + # add nice ALIAS targets for ease of use if(USE_SYSTEM_LIBUSB) add_library(3rdparty::libusb ALIAS usb-1.0-shared) @@ -385,3 +389,4 @@ add_library(3rdparty::miniupnpc ALIAS libminiupnpc-static) add_library(3rdparty::rtmidi ALIAS rtmidi) add_library(3rdparty::opencv ALIAS ${OPENCV_TARGET}) add_library(3rdparty::fusion ALIAS Fusion) +add_library(3rdparty::json ALIAS 3rdparty_json) diff --git a/Utilities/Config.cpp b/Utilities/Config.cpp index 0c2a1fa2aa..d9798e7076 100644 --- a/Utilities/Config.cpp +++ b/Utilities/Config.cpp @@ -531,6 +531,54 @@ std::string cfg::node::to_string() const return {out.c_str(), out.size()}; } +nlohmann::json cfg::node::to_json() const +{ + auto result = nlohmann::json::object(); + + for (const auto& node : get_nodes()) + { + result[node->get_name()] = node->to_json(); + } + + return result; +} + +bool cfg::node::from_json(const nlohmann::json &json, bool dynamic) +{ + if (!json.is_object()) + { + return false; + } + + auto find_node = [this](std::string_view name) -> _base * + { + for (const auto& node : get_nodes()) + { + if (node->get_name() == name) + { + return node; + } + } + + return nullptr; + }; + + + for (auto &[key, value] : json.get()) + { + auto keyNode = find_node(key); + + if (keyNode == nullptr || (dynamic && !keyNode->get_is_dynamic())) + { + continue; + } + + keyNode->from_json(value, dynamic); + } + + return false; +} + bool cfg::node::from_string(std::string_view value, bool dynamic) { auto [result, error] = yaml_load(std::string(value)); diff --git a/Utilities/Config.h b/Utilities/Config.h index bd05c25220..09fdb527b1 100644 --- a/Utilities/Config.h +++ b/Utilities/Config.h @@ -5,6 +5,7 @@ #include "util/logs.hpp" #include "util/atomic.hpp" #include "util/shared_ptr.hpp" +#include "nlohmann/json.hpp" #include #include @@ -96,6 +97,9 @@ namespace cfg return {}; } + virtual nlohmann::json to_json() const = 0; + virtual bool from_json(const nlohmann::json &, bool dynamic = false) = 0; + // Convert default to string (optional) virtual std::string def_to_string() const { @@ -145,9 +149,11 @@ namespace cfg // Serialize node std::string to_string() const override; + nlohmann::json to_json() const override; // Deserialize node bool from_string(std::string_view value, bool dynamic = false) override; + bool from_json(const nlohmann::json &, bool dynamic = false) override; // Set default values void from_default() override; @@ -184,6 +190,16 @@ namespace cfg return m_value ? "true" : "false"; } + nlohmann::json to_json() const override + { + return + { + {"type", "bool"}, + {"value", m_value.load()}, + {"default", def}, + }; + } + std::string def_to_string() const override { return def ? "true" : "false"; @@ -209,6 +225,17 @@ namespace cfg return true; } + bool from_json(const nlohmann::json &json, bool) override + { + if (!json.is_boolean()) + { + return false; + } + + m_value = json.get(); + return true; + } + void set(const bool& value) { m_value = value; @@ -263,6 +290,17 @@ namespace cfg return result; // TODO: ??? } + nlohmann::json to_json() const override + { + return + { + {"type", "enum"}, + {"value", to_string()}, + {"default", def_to_string()}, + {"variants", to_list()}, + }; + } + std::string def_to_string() const override { std::string result; @@ -284,6 +322,16 @@ namespace cfg return false; } + bool from_json(const nlohmann::json &json, bool dynamic) override + { + if (!json.is_string()) + { + return false; + } + + return from_string(json.get(), dynamic); + } + std::vector to_list() const override { return try_to_enum_list(&fmt_class_string::format); @@ -335,6 +383,18 @@ namespace cfg return std::to_string(m_value); } + nlohmann::json to_json() const override + { + return + { + {"type", "int"}, + {"value", m_value.load()}, + {"default", def}, + {"min", min}, + {"man", max}, + }; + } + std::string def_to_string() const override { return std::to_string(def); @@ -352,6 +412,23 @@ namespace cfg return false; } + bool from_json(const nlohmann::json &json, bool) override + { + if (!json.is_number_integer()) + { + return false; + } + + auto value = json.get(); + if (value < min || value > max) + { + return false; + } + + m_value = value; + return true; + } + void set(const s64& value) { ensure(value >= Min && value <= Max); @@ -413,6 +490,18 @@ namespace cfg return "0.0"; } + nlohmann::json to_json() const override + { + return + { + {"type", "float"}, + {"value", m_value.load()}, + {"default", def}, + {"min", min}, + {"man", max}, + }; + } + std::string def_to_string() const override { std::string result; @@ -436,6 +525,23 @@ namespace cfg return false; } + bool from_json(const nlohmann::json &json, bool) override + { + if (!json.is_number_float()) + { + return false; + } + + auto value = json.get(); + if (value < min || value > max) + { + return false; + } + + m_value = value; + return true; + } + void set(const f64& value) { ensure(value >= Min && value <= Max); @@ -499,6 +605,18 @@ namespace cfg return std::to_string(m_value); } + nlohmann::json to_json() const override + { + return + { + {"type", "uint"}, + {"value", m_value.load()}, + {"default", def}, + {"min", min}, + {"man", max}, + }; + } + std::string def_to_string() const override { return std::to_string(def); @@ -516,6 +634,23 @@ namespace cfg return false; } + bool from_json(const nlohmann::json &json, bool) override + { + if (!json.is_number_unsigned()) + { + return false; + } + + auto value = json.get(); + if (value < min || value > max) + { + return false; + } + + m_value = value; + return true; + } + void set(const u64& value) { ensure(value >= Min && value <= Max); @@ -561,6 +696,16 @@ namespace cfg return *m_value.load().get(); } + nlohmann::json to_json() const override + { + return + { + {"type", "string"}, + {"value", to_string()}, + {"default", def_to_string()}, + }; + } + std::string def_to_string() const override { return def; @@ -571,6 +716,17 @@ namespace cfg m_value = std::string(value); return true; } + + bool from_json(const nlohmann::json &json, bool) override + { + if (!json.is_string()) + { + return false; + } + + m_value = json.get(); + return true; + } }; // Simple set entry (TODO: template for various types) @@ -602,12 +758,46 @@ namespace cfg return { m_set.begin(), m_set.end() }; } + nlohmann::json to_json() const override + { + return + { + {"type", "set"}, + {"value", to_list()}, + }; + } + bool from_list(std::vector&& list) override { m_set = { std::make_move_iterator(list.begin()), std::make_move_iterator(list.end()) }; return true; } + + bool from_json(const nlohmann::json &json, bool) override + { + if (!json.is_array()) + { + return false; + } + + auto array = json.get(); + + std::vector string_array; + string_array.reserve(array.size()); + + for (auto &elem : array) + { + if (!elem.is_string()) + { + return false; + } + + string_array.push_back(elem.get()); + } + + return from_list(std::move(string_array)); + } }; template @@ -628,6 +818,31 @@ namespace cfg return m_map; } + nlohmann::json to_json() const override + { + return + { + {"type", "map"}, + {"value", m_map}, + }; + } + + + bool from_json(const nlohmann::json &json, bool) override + { + if (!json.is_object()) + { + return false; + } + + for (auto &elem : json.get()) + { + set_value(elem.first, elem.second); + } + + return true; + } + std::string get_value(std::string_view key); void set_value(std::string key, std::string value); @@ -662,6 +877,57 @@ namespace cfg return m_map; } + nlohmann::json to_json() const override + { + auto levels = try_to_enum_list(&fmt_class_string::format); + auto values = nlohmann::json::object(); + for (auto [key, level] : m_map) + { + std::string level_string; + fmt_class_string::format(level_string, fmt_unveil::get(level)); + values[key] = level_string; + } + + return + { + {"type", "log_map"}, + {"values", values}, + {"levels", levels}, + }; + } + + bool from_json(const nlohmann::json &json, bool) override + { + if (!json.is_object()) + { + return false; + } + + for (auto [key, valueString] : json.get()) + { + if (!valueString.is_string()) + { + continue; + } + + logs::level value; + + if (u64 int_value; + try_to_enum_value(&int_value, &fmt_class_string::format, valueString.get())) + { + value = static_cast(static_cast>(int_value)); + } + else + { + continue; + } + + m_map[key] = value; + } + + return true; + } + void set_map(map_of_type&& map); void from_default() override; @@ -674,6 +940,61 @@ namespace cfg std::string vid; std::string pid; std::pair get_usb_ids() const; + + nlohmann::json to_json() const + { + return { + {"path", path}, + {"serial", serial}, + {"vid", vid}, + {"pid", pid}, + }; + } + + bool from_json(const nlohmann::json &json) + { + if (json.contains("path")) + { + if (!json["path"].is_string()) + { + return false; + } + + path = json["path"]; + } + + if (json.contains("serial")) + { + if (!json["serial"].is_string()) + { + return false; + } + + path = json["serial"]; + } + + if (json.contains("vid")) + { + if (!json["vid"].is_string()) + { + return false; + } + + path = json["vid"]; + } + + if (json.contains("pid")) + { + if (!json["pid"].is_string()) + { + return false; + } + + path = json["pid"]; + } + + return true; + } }; class device_entry final : public _base @@ -689,6 +1010,16 @@ namespace cfg m_default = m_map; } + nlohmann::json to_json() const override + { + return {}; + } + + bool from_json(const nlohmann::json &, bool) override + { + return false; + } + const map_of_type& get_map() const { return m_map; diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index 743b6c88d3..87981f3437 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -173,19 +173,12 @@ endif() target_link_libraries(rpcs3_emu PUBLIC - 3rdparty::openal) - -target_link_libraries(rpcs3_emu - PUBLIC - 3rdparty::cubeb) - -target_link_libraries(rpcs3_emu - PUBLIC - 3rdparty::soundtouch) - -target_link_libraries(rpcs3_emu - PUBLIC - 3rdparty::miniupnpc) + 3rdparty::openal + 3rdparty::cubeb + 3rdparty::soundtouch + 3rdparty::miniupnpc + 3rdparty::json +) # Cell target_sources(rpcs3_emu PRIVATE