From 40a28eec7ba9d427a7ca896a3906462c0d688822 Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Wed, 21 Aug 2024 21:41:44 +0300 Subject: [PATCH] make custom settings be based on custom setting types --- loader/include/Geode/loader/Mod.hpp | 10 +- .../Geode/loader/ModSettingsManager.hpp | 46 ++ loader/include/Geode/loader/SettingV3.hpp | 99 ++--- loader/include/Geode/utils/JsonValidation.hpp | 15 +- loader/src/loader/Mod.cpp | 4 +- loader/src/loader/ModImpl.hpp | 2 +- loader/src/loader/ModSettingsManager.cpp | 164 +++++-- loader/src/loader/ModSettingsManager.hpp | 44 -- loader/src/loader/SettingNodeV3.cpp | 15 +- loader/src/loader/SettingNodeV3.hpp | 10 +- loader/src/loader/SettingV3.cpp | 414 +++++++++--------- loader/src/loader/SettingV3Impl.hpp | 18 - 12 files changed, 462 insertions(+), 379 deletions(-) create mode 100644 loader/include/Geode/loader/ModSettingsManager.hpp delete mode 100644 loader/src/loader/ModSettingsManager.hpp delete mode 100644 loader/src/loader/SettingV3Impl.hpp diff --git a/loader/include/Geode/loader/Mod.hpp b/loader/include/Geode/loader/Mod.hpp index 6e28a13c..a5f19187 100644 --- a/loader/include/Geode/loader/Mod.hpp +++ b/loader/include/Geode/loader/Mod.hpp @@ -191,11 +191,6 @@ namespace geode { * @see addCustomSetting */ void registerCustomSetting(std::string_view const key, std::unique_ptr value); - - /** - * Register a custom setting - */ - Result<> registerCustomSettingV3(std::string_view const key, std::shared_ptr value); /** * Register a custom setting's value class. The new SettingValue class * will be created in-place using `std::make_unique`. See @@ -213,6 +208,11 @@ namespace geode { this->registerCustomSetting(key, std::make_unique(std::string(key), this->getID(), value)); } + /** + * Register a custom setting type + */ + Result<> registerCustomSettingType(std::string_view type, SettingGenerator generator); + /** * Returns a prefixed launch argument name. See `Mod::getLaunchArgument` * for details about mod-specific launch arguments. diff --git a/loader/include/Geode/loader/ModSettingsManager.hpp b/loader/include/Geode/loader/ModSettingsManager.hpp new file mode 100644 index 00000000..36b8ac34 --- /dev/null +++ b/loader/include/Geode/loader/ModSettingsManager.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include +#include "SettingV3.hpp" + +namespace geode { + class GEODE_DLL ModSettingsManager final { + private: + class Impl; + std::unique_ptr m_impl; + + public: + static ModSettingsManager* from(Mod* mod); + + ModSettingsManager(ModMetadata const& metadata); + ~ModSettingsManager(); + + ModSettingsManager(ModSettingsManager&&); + ModSettingsManager(ModSettingsManager const&) = delete; + + /** + * Load setting values from savedata. + * The format of the savedata should be an object with the keys being + * setting IDs and then the values the values of the saved settings + * @returns Ok if no horrible errors happened. Note that a setting value + * missing is not considered a horrible error, but will instead just log a + * warning into the console! + */ + Result<> load(matjson::Value const& json); + /** + * Save setting values to savedata. + * The format of the savedata will be an object with the keys being + * setting IDs and then the values the values of the saved settings + * @note If saving a setting fails, it will log a warning to the console + */ + void save(matjson::Value& json); + + Result<> registerCustomSettingType(std::string_view type, SettingGenerator generator); + // todo in v4: remove this + Result<> registerLegacyCustomSetting(std::string_view key, std::unique_ptr&& ptr); + + std::shared_ptr get(std::string_view key); + std::shared_ptr getLegacy(std::string_view key); + std::optional getLegacyDefinition(std::string_view key); + }; +} diff --git a/loader/include/Geode/loader/SettingV3.hpp b/loader/include/Geode/loader/SettingV3.hpp index 42594762..83ff851f 100644 --- a/loader/include/Geode/loader/SettingV3.hpp +++ b/loader/include/Geode/loader/SettingV3.hpp @@ -9,22 +9,22 @@ // this unfortunately has to be included because of C++ templates #include "../utils/JsonValidation.hpp" -// todo in v4: these can be removed as well as the friend decl in UnresolvedCustomSettingV3 -class ModSettingsManager; +// todo in v4: these can be removed as well as the friend decl in LegacyCustomSettingV3 class LegacyCustomSettingToV3Node; namespace geode { + class ModSettingsManager; class SettingNodeV3; class GEODE_DLL SettingV3 : public std::enable_shared_from_this { private: class GeodeImpl; std::shared_ptr m_impl; - + protected: - virtual Result<> onParse( - std::string const& key, std::string const& modID, matjson::Value const& json - ) = 0; + void init(std::string const& key, std::string const& modID); + Result<> parseSharedProperties(std::string const& key, std::string const& modID, matjson::Value const& value); + void parseSharedProperties(std::string const& key, std::string const& modID, JsonExpectedValue& value); public: SettingV3(); @@ -43,8 +43,23 @@ namespace geode { * while the mod is still being initialized */ Mod* getMod() const; + /** + * Get the name of this setting + */ + std::string getName() const; + /** + * Get the description of this setting + */ + std::optional getDescription() const; + /** + * Get the "enable-if" scheme for this setting + */ + std::optional getEnableIf() const; + /** + * Whether this setting requires a restart on change + */ + bool requiresRestart() const; - Result<> parse(std::string const& key, std::string const& modID, matjson::Value const& json); virtual bool load(matjson::Value const& json) = 0; virtual bool save(matjson::Value& json) const = 0; virtual SettingNodeV3* createNode(float width) = 0; @@ -59,26 +74,22 @@ namespace geode { virtual std::optional convertToLegacy() const; [[deprecated("This function will be removed alongside legacy settings in 4.0.0!")]] virtual std::optional> convertToLegacyValue() const; - - static Result> parseBuiltin( - std::string const& key, std::string const& modID, matjson::Value const& json - ); }; + + using SettingGenerator = std::function>( + std::string const& key, + std::string const& modID, + matjson::Value const& json + )>; namespace detail { - class GEODE_DLL GeodeSettingBaseV3 : public SettingV3 { - private: - class Impl; - std::shared_ptr m_impl; - - Result<> parseSharedBase(JsonExpectedValue& json); - + template + class GeodeSettingBaseValueV3 : public SettingV3 { protected: - Result<> isValidShared() const; + virtual T& getValueMut() const = 0; template - Result<> parseShared(JsonExpectedValue& json, T& defaultValue) { - GEODE_UNWRAP(this->parseSharedBase(json)); + void parseDefaultValue(JsonExpectedValue& json, T& defaultValue) { auto value = json.needs("default"); // Check if this is a platform-specific default value if (value.isObject() && value.has(GEODE_PLATFORM_SHORT_IDENTIFIER_NOARCH)) { @@ -87,22 +98,8 @@ namespace geode { else { value.into(defaultValue); } - return Ok(); } - public: - GeodeSettingBaseV3(); - - std::string getName() const; - std::optional getDescription() const; - std::optional getEnableIf() const; - }; - - template - class GeodeSettingBaseValueV3 : public GeodeSettingBaseV3 { - protected: - virtual T& getValueMut() const = 0; - public: using ValueType = T; @@ -130,15 +127,13 @@ namespace geode { class Impl; std::shared_ptr m_impl; - protected: - Result<> onParse(std::string const& key, std::string const& modID, matjson::Value const& json) override; - private: class PrivateMarker {}; friend class SettingV3; public: TitleSettingV3(PrivateMarker); + static Result> parse(std::string const& key, std::string const& modID, matjson::Value const& json); std::string getTitle() const; @@ -150,23 +145,25 @@ namespace geode { void reset() override; }; - class GEODE_DLL UnresolvedCustomSettingV3 final : public SettingV3 { + // todo in v4: remove this class completely + class GEODE_DLL LegacyCustomSettingV3 final : public SettingV3 { private: class Impl; std::shared_ptr m_impl; - friend class ::ModSettingsManager; + friend class ::geode::ModSettingsManager; friend class ::LegacyCustomSettingToV3Node; - protected: - Result<> onParse(std::string const& key, std::string const& modID, matjson::Value const& json) override; - private: class PrivateMarker {}; friend class SettingV3; public: - UnresolvedCustomSettingV3(PrivateMarker); + LegacyCustomSettingV3(PrivateMarker); + static Result> parse(std::string const& key, std::string const& modID, matjson::Value const& json); + + std::shared_ptr getValue() const; + void setValue(std::shared_ptr value); bool load(matjson::Value const& json) override; bool save(matjson::Value& json) const override; @@ -186,7 +183,6 @@ namespace geode { protected: bool& getValueMut() const override; - Result<> onParse(std::string const& key, std::string const& modID, matjson::Value const& json) override; private: class PrivateMarker {}; @@ -194,6 +190,7 @@ namespace geode { public: BoolSettingV3(PrivateMarker); + static Result> parse(std::string const& key, std::string const& modID, matjson::Value const& json); bool getDefaultValue() const override; Result<> isValid(bool value) const override; @@ -213,7 +210,6 @@ namespace geode { protected: int64_t& getValueMut() const override; - Result<> onParse(std::string const& key, std::string const& modID, matjson::Value const& json) override; private: class PrivateMarker {}; @@ -221,6 +217,7 @@ namespace geode { public: IntSettingV3(PrivateMarker); + static Result> parse(std::string const& key, std::string const& modID, matjson::Value const& json); int64_t getDefaultValue() const override; Result<> isValid(int64_t value) const override; @@ -251,7 +248,6 @@ namespace geode { protected: double& getValueMut() const override; - Result<> onParse(std::string const& key, std::string const& modID, matjson::Value const& json) override; private: class PrivateMarker {}; @@ -259,6 +255,7 @@ namespace geode { public: FloatSettingV3(PrivateMarker); + static Result> parse(std::string const& key, std::string const& modID, matjson::Value const& json); double getDefaultValue() const override; Result<> isValid(double value) const override; @@ -289,7 +286,6 @@ namespace geode { protected: std::string& getValueMut() const override; - Result<> onParse(std::string const& key, std::string const& modID, matjson::Value const& json) override; private: class PrivateMarker {}; @@ -297,6 +293,7 @@ namespace geode { public: StringSettingV3(PrivateMarker); + static Result> parse(std::string const& key, std::string const& modID, matjson::Value const& json); std::string getDefaultValue() const override; Result<> isValid(std::string_view value) const override; @@ -320,7 +317,6 @@ namespace geode { protected: std::filesystem::path& getValueMut() const override; - Result<> onParse(std::string const& key, std::string const& modID, matjson::Value const& json) override; private: class PrivateMarker {}; @@ -328,6 +324,7 @@ namespace geode { public: FileSettingV3(PrivateMarker); + static Result> parse(std::string const& key, std::string const& modID, matjson::Value const& json); std::filesystem::path getDefaultValue() const override; Result<> isValid(std::filesystem::path const& value) const override; @@ -349,7 +346,6 @@ namespace geode { protected: cocos2d::ccColor3B& getValueMut() const override; - Result<> onParse(std::string const& key, std::string const& modID, matjson::Value const& json) override; private: class PrivateMarker {}; @@ -357,6 +353,7 @@ namespace geode { public: Color3BSettingV3(PrivateMarker); + static Result> parse(std::string const& key, std::string const& modID, matjson::Value const& json); cocos2d::ccColor3B getDefaultValue() const override; Result<> isValid(cocos2d::ccColor3B value) const override; @@ -376,7 +373,6 @@ namespace geode { protected: cocos2d::ccColor4B& getValueMut() const override; - Result<> onParse(std::string const& key, std::string const& modID, matjson::Value const& json) override; private: class PrivateMarker {}; @@ -384,6 +380,7 @@ namespace geode { public: Color4BSettingV3(PrivateMarker); + static Result> parse(std::string const& key, std::string const& modID, matjson::Value const& json); cocos2d::ccColor4B getDefaultValue() const override; Result<> isValid(cocos2d::ccColor4B value) const override; diff --git a/loader/include/Geode/utils/JsonValidation.hpp b/loader/include/Geode/utils/JsonValidation.hpp index 3f0d6ef8..b17594a0 100644 --- a/loader/include/Geode/utils/JsonValidation.hpp +++ b/loader/include/Geode/utils/JsonValidation.hpp @@ -318,12 +318,17 @@ namespace geode { template std::optional tryGet() { if (this->hasError()) return std::nullopt; - try { - return this->getJSONRef().template as(); + if constexpr (std::is_same_v) { + return this->getJSONRef(); } - // matjson can throw variant exceptions too so you need to do this - catch(std::exception const& e) { - this->setError("invalid json type: {}", e); + else { + try { + return this->getJSONRef().template as(); + } + // matjson can throw variant exceptions too so you need to do this + catch(std::exception const& e) { + this->setError("invalid json type: {}", e); + } } return std::nullopt; } diff --git a/loader/src/loader/Mod.cpp b/loader/src/loader/Mod.cpp index fa54fb97..a4b71515 100644 --- a/loader/src/loader/Mod.cpp +++ b/loader/src/loader/Mod.cpp @@ -173,8 +173,8 @@ void Mod::registerCustomSetting(std::string_view const key, std::unique_ptr Mod::registerCustomSettingV3(std::string_view const key, std::shared_ptr value) { - return m_impl->m_settings->registerCustomSetting(key, value); +Result<> Mod::registerCustomSettingType(std::string_view type, SettingGenerator generator) { + return m_impl->m_settings->registerCustomSettingType(type, generator); } std::vector Mod::getLaunchArgumentNames() const { diff --git a/loader/src/loader/ModImpl.hpp b/loader/src/loader/ModImpl.hpp index 832060be..f33bc0ad 100644 --- a/loader/src/loader/ModImpl.hpp +++ b/loader/src/loader/ModImpl.hpp @@ -4,7 +4,7 @@ #include "ModPatch.hpp" #include #include -#include "ModSettingsManager.hpp" +#include namespace geode { class Mod::Impl { diff --git a/loader/src/loader/ModSettingsManager.cpp b/loader/src/loader/ModSettingsManager.cpp index 6d43ca58..b64fc3a6 100644 --- a/loader/src/loader/ModSettingsManager.cpp +++ b/loader/src/loader/ModSettingsManager.cpp @@ -1,65 +1,161 @@ -#include "ModSettingsManager.hpp" -#include "SettingV3Impl.hpp" +#include #include +#include "ModImpl.hpp" + +using namespace geode::prelude; + +// All setting type generators are put in a shared pool for two reasons: +// #1 no need to duplicate the built-in settings between all mods +// #2 easier lookup of custom settings if a mod uses another mod's custom setting type + +class SharedSettingTypesPool final { +private: + std::unordered_map m_types; + + SharedSettingTypesPool() : m_types({ + // todo in v4: remove this + { "custom", &LegacyCustomSettingV3::parse }, + { "title", &TitleSettingV3::parse }, + { "bool", &BoolSettingV3::parse }, + { "int", &IntSettingV3::parse }, + { "float", &FloatSettingV3::parse }, + { "string", &StringSettingV3::parse }, + { "file", &FileSettingV3::parse }, + { "path", &FileSettingV3::parse }, + { "rgb", &Color3BSettingV3::parse }, + { "color", &Color3BSettingV3::parse }, + { "rgba", &Color4BSettingV3::parse }, + }) {} + +public: + static SharedSettingTypesPool& get() { + static auto inst = SharedSettingTypesPool(); + return inst; + } + + Result<> add(std::string_view modID, std::string_view type, SettingGenerator generator) { + // Limit type to just [a-z0-9\-]+ + if (type.empty() || !std::all_of(type.begin(), type.end(), +[](char c) { + return + ('a' <= c && c <= 'z') || + ('0' <= c && c <= '9') || + (c == '-'); + })) { + return Err("Custom setting types must match the regex [a-z0-9\\-]+"); + } + auto full = fmt::format("{}/{}", modID, type); + if (m_types.contains(full)) { + return Err("Type \"{}\" has already been registered for mod {}", type, modID); + } + m_types.emplace(full, generator); + return Ok(); + } + std::optional find(std::string_view modID, std::string_view fullType) { + auto full = std::string( + fullType.starts_with("custom:") ? + fullType.substr(fullType.find(':') + 1) : + fullType + ); + if (!full.find('/')) { + full = fmt::format("{}/{}", modID, full); + } + if (m_types.contains(full)) { + return m_types.at(full); + } + return std::nullopt; + } +}; class ModSettingsManager::Impl final { public: struct SettingInfo final { - std::shared_ptr v3; + std::string type; + matjson::Value json; + std::shared_ptr v3 = nullptr; // todo: remove in v4 std::shared_ptr legacy = nullptr; }; std::string modID; - std::unordered_map list; + std::unordered_map settings; + + void createSettings() { + for (auto& [key, setting] : settings) { + if (setting.v3) { + continue; + } + auto gen = SharedSettingTypesPool::get().find(modID, setting.type); + // The type was not found, meaning it probably hasn't been registered yet + if (!gen) { + continue; + } + if (auto v3 = (*gen)(key, modID, setting.json)) { + setting.v3 = *v3; + } + else { + log::error( + "Unable to parse setting '{}' for mod {}: {}", + key, modID, v3.unwrapErr() + ); + } + } + } }; +ModSettingsManager* ModSettingsManager::from(Mod* mod) { + return ModImpl::getImpl(mod)->m_settings.get(); +} + ModSettingsManager::ModSettingsManager(ModMetadata const& metadata) : m_impl(std::make_unique()) { m_impl->modID = metadata.getID(); for (auto const& [key, json] : metadata.getSettingsV3()) { - if (auto v3 = SettingV3::parseBuiltin(key, m_impl->modID, json)) { - auto setting = Impl::SettingInfo(); - setting.v3.swap(*v3); - m_impl->list.emplace(key, setting); + auto setting = Impl::SettingInfo(); + setting.json = json; + auto root = checkJson(json, "setting"); + root.needs("type").into(setting.type); + if (root) { + if (setting.type == "custom") { + log::warn( + "Setting \"{}\" in mod {} has the old \"custom\" type - " + "this type has been deprecated and will be removed in Geode v4.0.0. " + "Use the new \"custom:type-name-here\" syntax for defining custom " + "setting types - see more in INSERT TUTORIAL HERE", + key, m_impl->modID + ); + } + m_impl->settings.emplace(key, setting); } else { - log::error("Unable to parse setting '{}' for mod {}: {}", key, m_impl->modID, v3.unwrapErr()); + log::error("Setting '{}' in mod {} is missing type", key, m_impl->modID); } } + m_impl->createSettings(); } ModSettingsManager::~ModSettingsManager() {} - ModSettingsManager::ModSettingsManager(ModSettingsManager&&) = default; -Result<> ModSettingsManager::registerCustomSetting(std::string_view key, std::shared_ptr ptr) { - if (!ptr) { - return Err("Custom settings must not be null!"); - } - auto id = std::string(key); - if (!m_impl->list.count(id)) { - return Err("No such setting '{}' in mod {}", id, m_impl->modID); - } - auto& sett = m_impl->list.at(id); - sett.v3.swap(ptr); +Result<> ModSettingsManager::registerCustomSettingType(std::string_view type, SettingGenerator generator) { + GEODE_UNWRAP(SharedSettingTypesPool::get().add(m_impl->modID, type, generator)); + m_impl->createSettings(); return Ok(); } Result<> ModSettingsManager::registerLegacyCustomSetting(std::string_view key, std::unique_ptr&& ptr) { auto id = std::string(key); - if (!m_impl->list.count(id)) { + if (!m_impl->settings.count(id)) { return Err("No such setting '{}' in mod {}", id, m_impl->modID); } - auto& sett = m_impl->list.at(id); - if (auto custom = typeinfo_pointer_cast(sett.v3)) { - if (!custom->m_impl->legacyValue) { - custom->m_impl->legacyValue = std::move(ptr); + auto& sett = m_impl->settings.at(id); + if (auto custom = typeinfo_pointer_cast(sett.v3)) { + if (!custom->getValue()) { + custom->setValue(std::move(ptr)); } else { return Err("Setting '{}' in mod {} has already been registed", id, m_impl->modID); } } else { - return Err("Setting '{}' in mod {} is not a custom setting", id, m_impl->modID); + return Err("Setting '{}' in mod {} is not a legacy custom setting", id, m_impl->modID); } return Ok(); } @@ -67,9 +163,9 @@ Result<> ModSettingsManager::registerLegacyCustomSetting(std::string_view key, s Result<> ModSettingsManager::load(matjson::Value const& json) { auto root = checkJson(json, "Settings"); for (auto const& [key, value] : root.properties()) { - if (m_impl->list.contains(key)) { + if (m_impl->settings.contains(key)) { try { - if (!m_impl->list.at(key).v3->load(value.json())) { + if (!m_impl->settings.at(key).v3->load(value.json())) { log::error("Unable to load setting '{}' for mod {}", key, m_impl->modID); } } @@ -81,7 +177,7 @@ Result<> ModSettingsManager::load(matjson::Value const& json) { return Ok(); } void ModSettingsManager::save(matjson::Value& json) { - for (auto& [key, sett] : m_impl->list) { + for (auto& [key, sett] : m_impl->settings) { // Store the value in an intermediary so if `save` fails the existing // value loaded from disk isn't overwritten matjson::Value value; @@ -101,18 +197,22 @@ void ModSettingsManager::save(matjson::Value& json) { std::shared_ptr ModSettingsManager::get(std::string_view key) { auto id = std::string(key); - return m_impl->list.count(id) ? m_impl->list.at(id).v3 : nullptr; + return m_impl->settings.count(id) ? m_impl->settings.at(id).v3 : nullptr; } std::shared_ptr ModSettingsManager::getLegacy(std::string_view key) { auto id = std::string(key); - if (!m_impl->list.count(id)) { + if (!m_impl->settings.count(id)) { return nullptr; } - auto& info = m_impl->list.at(id); + auto& info = m_impl->settings.at(id); // If this setting has alreay been given a legacy interface, give that if (info.legacy) { return info.legacy; } + // Uninitialized settings are null + if (!info.v3) { + return nullptr; + } // Generate new legacy interface if (auto legacy = info.v3->convertToLegacyValue()) { info.legacy.swap(*legacy); diff --git a/loader/src/loader/ModSettingsManager.hpp b/loader/src/loader/ModSettingsManager.hpp deleted file mode 100644 index a1593f91..00000000 --- a/loader/src/loader/ModSettingsManager.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include -#include - -using namespace geode::prelude; - -class ModSettingsManager final { -private: - class Impl; - std::unique_ptr m_impl; - -public: - ModSettingsManager(ModMetadata const& metadata); - ~ModSettingsManager(); - - ModSettingsManager(ModSettingsManager&&); - ModSettingsManager(ModSettingsManager const&) = delete; - - /** - * Load setting values from savedata. - * The format of the savedata should be an object with the keys being - * setting IDs and then the values the values of the saved settings - * @returns Ok if no horrible errors happened. Note that a setting value - * missing is not considered a horrible error, but will instead just log a - * warning into the console! - */ - Result<> load(matjson::Value const& json); - /** - * Save setting values to savedata. - * The format of the savedata will be an object with the keys being - * setting IDs and then the values the values of the saved settings - * @note If saving a setting fails, it will log a warning to the console - */ - void save(matjson::Value& json); - - Result<> registerCustomSetting(std::string_view key, std::shared_ptr ptr); - // remove in v4 - Result<> registerLegacyCustomSetting(std::string_view key, std::unique_ptr&& ptr); - - std::shared_ptr get(std::string_view key); - std::shared_ptr getLegacy(std::string_view key); - std::optional getLegacyDefinition(std::string_view key); -}; diff --git a/loader/src/loader/SettingNodeV3.cpp b/loader/src/loader/SettingNodeV3.cpp index 3bdd4d8d..339eb74d 100644 --- a/loader/src/loader/SettingNodeV3.cpp +++ b/loader/src/loader/SettingNodeV3.cpp @@ -1,5 +1,4 @@ #include "SettingNodeV3.hpp" -#include "SettingV3Impl.hpp" #include class SettingNodeSizeChangeEventV3::Impl final { @@ -367,7 +366,7 @@ std::shared_ptr Color4BSettingNodeV3::getSetting() const { // UnresolvedCustomSettingNodeV3 -bool UnresolvedCustomSettingNodeV3::init(std::shared_ptr setting, float width) { +bool UnresolvedCustomSettingNodeV3::init(std::shared_ptr setting, float width) { if (!SettingNodeV3::init(setting, width)) return false; @@ -385,7 +384,7 @@ bool UnresolvedCustomSettingNodeV3::init(std::shared_ptr setting, float width) { +UnresolvedCustomSettingNodeV3* UnresolvedCustomSettingNodeV3::create(std::shared_ptr setting, float width) { auto ret = new UnresolvedCustomSettingNodeV3(); if (ret && ret->init(setting, width)) { ret->autorelease(); @@ -403,17 +402,17 @@ bool UnresolvedCustomSettingNodeV3::hasNonDefaultValue() const { } void UnresolvedCustomSettingNodeV3::resetToDefault() {} -std::shared_ptr UnresolvedCustomSettingNodeV3::getSetting() const { - return std::static_pointer_cast(SettingNodeV3::getSetting()); +std::shared_ptr UnresolvedCustomSettingNodeV3::getSetting() const { + return std::static_pointer_cast(SettingNodeV3::getSetting()); } // LegacyCustomSettingToV3Node -bool LegacyCustomSettingToV3Node::init(std::shared_ptr original, float width) { +bool LegacyCustomSettingToV3Node::init(std::shared_ptr original, float width) { if (!SettingNodeV3::init(original, width)) return false; - m_original = original->m_impl->legacyValue->createNode(width); + m_original = original->getValue()->createNode(width); this->setContentSize({ width, m_original->getContentHeight() }); this->addChildAtPosition(m_original, Anchor::Center); @@ -424,7 +423,7 @@ void LegacyCustomSettingToV3Node::onCommit() { m_original->commit(); } -LegacyCustomSettingToV3Node* LegacyCustomSettingToV3Node::create(std::shared_ptr original, float width) { +LegacyCustomSettingToV3Node* LegacyCustomSettingToV3Node::create(std::shared_ptr original, float width) { auto ret = new LegacyCustomSettingToV3Node(); if (ret && ret->init(original, width)) { ret->autorelease(); diff --git a/loader/src/loader/SettingNodeV3.hpp b/loader/src/loader/SettingNodeV3.hpp index 0c2feefe..f1faa862 100644 --- a/loader/src/loader/SettingNodeV3.hpp +++ b/loader/src/loader/SettingNodeV3.hpp @@ -141,18 +141,18 @@ public: class UnresolvedCustomSettingNodeV3 : public SettingNodeV3 { protected: - bool init(std::shared_ptr setting, float width); + bool init(std::shared_ptr setting, float width); void onCommit() override; public: - static UnresolvedCustomSettingNodeV3* create(std::shared_ptr setting, float width); + static UnresolvedCustomSettingNodeV3* create(std::shared_ptr setting, float width); bool hasUncommittedChanges() const override; bool hasNonDefaultValue() const override; void resetToDefault() override; - std::shared_ptr getSetting() const; + std::shared_ptr getSetting() const; }; // If these classes do get exposed in headers, this SHOULD NOT BE EXPOSED!!!!!! DO NOT DO THAT!!!! @@ -161,12 +161,12 @@ class LegacyCustomSettingToV3Node : public SettingNodeV3 { protected: SettingNode* m_original; - bool init(std::shared_ptr original, float width); + bool init(std::shared_ptr original, float width); void onCommit() override; public: - static LegacyCustomSettingToV3Node* create(std::shared_ptr original, float width); + static LegacyCustomSettingToV3Node* create(std::shared_ptr original, float width); bool hasUncommittedChanges() const override; bool hasNonDefaultValue() const override; diff --git a/loader/src/loader/SettingV3.cpp b/loader/src/loader/SettingV3.cpp index 2e80637f..e7e8039a 100644 --- a/loader/src/loader/SettingV3.cpp +++ b/loader/src/loader/SettingV3.cpp @@ -1,7 +1,6 @@ #include #include #include -#include "SettingV3Impl.hpp" #include "SettingNodeV3.hpp" using namespace geode::prelude; @@ -10,11 +9,32 @@ class SettingV3::GeodeImpl { public: std::string modID; std::string key; + std::optional name; + std::optional description; + std::optional enableIf; + bool requiresRestart = false; }; +SettingV3::SettingV3() : m_impl(std::make_shared()) {} SettingV3::~SettingV3() = default; -SettingV3::SettingV3() : m_impl(std::make_shared()) {} +Result<> SettingV3::parseSharedProperties(std::string const& key, std::string const& modID, matjson::Value const& value) { + auto json = checkJson(value, "SettingV3"); + this->parseSharedProperties(key, modID, json); + return json.ok(); +} +void SettingV3::parseSharedProperties(std::string const& key, std::string const& modID, JsonExpectedValue& value) { + this->init(key, modID); + value.needs("type"); + value.has("name").into(m_impl->name); + value.has("description").into(m_impl->description); + value.has("enable-if").into(m_impl->enableIf); + value.has("requires-restart").into(m_impl->requiresRestart); +} +void SettingV3::init(std::string const& key, std::string const& modID) { + m_impl->key = key; + m_impl->modID = modID; +} std::string SettingV3::getKey() const { return m_impl->key; @@ -22,37 +42,22 @@ std::string SettingV3::getKey() const { std::string SettingV3::getModID() const { return m_impl->modID; } +std::string SettingV3::getName() const { + return m_impl->name.value_or(m_impl->key); +} +std::optional SettingV3::getDescription() const { + return m_impl->description; +} +std::optional SettingV3::getEnableIf() const { + return m_impl->enableIf; +} +bool SettingV3::requiresRestart() const { + return m_impl->requiresRestart; +} Mod* SettingV3::getMod() const { return Loader::get()->getInstalledMod(m_impl->modID); } -Result<> SettingV3::parse(std::string const& key, std::string const& modID, matjson::Value const& json) { - m_impl->key = key; - m_impl->modID = modID; - return this->onParse(key, modID, json); -} - -Result> SettingV3::parseBuiltin(std::string const& key, std::string const& modID, matjson::Value const& json) { - auto root = checkJson(json, "SettingV3"); - std::string type; - root.needs("type").into(type); - std::shared_ptr ret; - switch (hash(type)) { - case hash("bool"): ret = std::make_shared(BoolSettingV3::PrivateMarker()); break; - case hash("int"): ret = std::make_shared(IntSettingV3::PrivateMarker()); break; - case hash("float"): ret = std::make_shared(FloatSettingV3::PrivateMarker()); break; - case hash("string"): ret = std::make_shared(StringSettingV3::PrivateMarker()); break; - case hash("rgb"): case hash("color"): ret = std::make_shared(Color3BSettingV3::PrivateMarker()); break; - case hash("rgba"): ret = std::make_shared(Color4BSettingV3::PrivateMarker()); break; - case hash("path"): case hash("file"): ret = std::make_shared(FileSettingV3::PrivateMarker()); break; - case hash("title"): ret = std::make_shared(TitleSettingV3::PrivateMarker()); break; - default: - case hash("custom"): ret = std::make_shared(UnresolvedCustomSettingV3::PrivateMarker()); break; - } - GEODE_UNWRAP(ret->parse(key, modID, json)); - return root.ok(std::move(ret)); -} - std::optional SettingV3::convertToLegacy() const { return std::nullopt; } @@ -60,41 +65,6 @@ std::optional> SettingV3::convertToLegacyValue() c return std::nullopt; } -class geode::detail::GeodeSettingBaseV3::Impl final { -public: - std::optional name; - std::optional description; - std::optional enableIf; -}; - -geode::detail::GeodeSettingBaseV3::GeodeSettingBaseV3() : m_impl(std::make_shared()) {} - -std::string geode::detail::GeodeSettingBaseV3::getName() const { - return m_impl->name.value_or(this->getKey()); -} -std::optional geode::detail::GeodeSettingBaseV3::getDescription() const { - return m_impl->description; -} -std::optional geode::detail::GeodeSettingBaseV3::getEnableIf() const { - return m_impl->enableIf; -} - -Result<> geode::detail::GeodeSettingBaseV3::parseSharedBase(JsonExpectedValue& json) { - // Mark keys that have been checked before-hand - json.needs("type"); - json.has("platforms"); - - json.has("name").into(m_impl->name); - json.has("description").into(m_impl->description); - json.has("enable-if").into(m_impl->enableIf); - return Ok(); -} -Result<> geode::detail::GeodeSettingBaseV3::isValidShared() const { - // In the future if something like `enable-if` preventing - // programmatic modification of settings it should be added here - return Ok(); -} - class TitleSettingV3::Impl final { public: std::string title; @@ -102,16 +72,19 @@ public: TitleSettingV3::TitleSettingV3(PrivateMarker) : m_impl(std::make_shared()) {} +Result> TitleSettingV3::parse(std::string const& key, std::string const& modID, matjson::Value const& json) { + auto ret = std::make_shared(PrivateMarker()); + auto root = checkJson(json, "TitleSettingV3"); + ret->init(key, modID); + root.needs("title").into(ret->m_impl->title); + root.checkUnknownKeys(); + return root.ok(ret); +} + std::string TitleSettingV3::getTitle() const { return m_impl->title; } -Result<> TitleSettingV3::onParse(std::string const& key, std::string const& modID, matjson::Value const& json) { - auto root = checkJson(json, "TitleSettingV3"); - root.needs("title").into(m_impl->title); - root.checkUnknownKeys(); - return root.ok(); -} bool TitleSettingV3::load(matjson::Value const& json) { return true; } @@ -128,46 +101,56 @@ bool TitleSettingV3::isDefaultValue() const { } void TitleSettingV3::reset() {} -// todo in v4: move the UnresolvedCustomSettingV3::Impl definition from SettingV3Impl.hpp to here -// on this line in particular -// right here -// replace this comment with it -// put it riiiiiight here +class LegacyCustomSettingV3::Impl final { +public: + matjson::Value json; + std::shared_ptr legacyValue = nullptr; +}; -UnresolvedCustomSettingV3::UnresolvedCustomSettingV3(PrivateMarker) : m_impl(std::make_shared()) {} +LegacyCustomSettingV3::LegacyCustomSettingV3(PrivateMarker) : m_impl(std::make_shared()) {} -Result<> UnresolvedCustomSettingV3::onParse(std::string const& key, std::string const& modID, matjson::Value const& json) { - m_impl->json = json; - return Ok(); +Result> LegacyCustomSettingV3::parse(std::string const& key, std::string const& modID, matjson::Value const& json) { + auto ret = std::make_shared(PrivateMarker()); + ret->init(key, modID); + ret->m_impl->json = json; + return Ok(ret); } -bool UnresolvedCustomSettingV3::load(matjson::Value const& json) { + +std::shared_ptr LegacyCustomSettingV3::getValue() const { + return m_impl->legacyValue; +} +void LegacyCustomSettingV3::setValue(std::shared_ptr value) { + m_impl->legacyValue = value; +} + +bool LegacyCustomSettingV3::load(matjson::Value const& json) { return true; } -bool UnresolvedCustomSettingV3::save(matjson::Value& json) const { +bool LegacyCustomSettingV3::save(matjson::Value& json) const { return true; } -SettingNodeV3* UnresolvedCustomSettingV3::createNode(float width) { +SettingNodeV3* LegacyCustomSettingV3::createNode(float width) { if (m_impl->legacyValue) { return LegacyCustomSettingToV3Node::create( - std::static_pointer_cast(shared_from_this()), width + std::static_pointer_cast(shared_from_this()), width ); } return UnresolvedCustomSettingNodeV3::create( - std::static_pointer_cast(shared_from_this()), width + std::static_pointer_cast(shared_from_this()), width ); } -bool UnresolvedCustomSettingV3::isDefaultValue() const { +bool LegacyCustomSettingV3::isDefaultValue() const { return true; } -void UnresolvedCustomSettingV3::reset() {} +void LegacyCustomSettingV3::reset() {} -std::optional UnresolvedCustomSettingV3::convertToLegacy() const { +std::optional LegacyCustomSettingV3::convertToLegacy() const { return Setting(this->getKey(), this->getModID(), SettingKind(CustomSetting { .json = std::make_shared(m_impl->json) })); } -std::optional> UnresolvedCustomSettingV3::convertToLegacyValue() const { +std::optional> LegacyCustomSettingV3::convertToLegacyValue() const { return m_impl->legacyValue ? std::optional(m_impl->legacyValue) : std::nullopt; } @@ -179,6 +162,18 @@ public: BoolSettingV3::BoolSettingV3(PrivateMarker) : m_impl(std::make_shared()) {} +Result> BoolSettingV3::parse(std::string const& key, std::string const& modID, matjson::Value const& json) { + auto ret = std::make_shared(PrivateMarker()); + + auto root = checkJson(json, "BoolSettingV3"); + ret->parseSharedProperties(key, modID, root); + ret->parseDefaultValue(root, ret->m_impl->defaultValue); + ret->m_impl->value = ret->m_impl->defaultValue; + + root.checkUnknownKeys(); + return root.ok(ret); +} + bool& BoolSettingV3::getValueMut() const { return m_impl->value; } @@ -186,19 +181,9 @@ bool BoolSettingV3::getDefaultValue() const { return m_impl->defaultValue; } Result<> BoolSettingV3::isValid(bool value) const { - GEODE_UNWRAP(this->isValidShared()); return Ok(); } -Result<> BoolSettingV3::onParse(std::string const& key, std::string const& modID, matjson::Value const& json) { - auto root = checkJson(json, "BoolSettingV3"); - - GEODE_UNWRAP(this->parseShared(root, m_impl->defaultValue)); - m_impl->value = m_impl->defaultValue; - - root.checkUnknownKeys(); - return root.ok(); -} bool BoolSettingV3::load(matjson::Value const& json) { if (json.is_bool()) { m_impl->value = json.as_bool(); @@ -244,6 +229,35 @@ public: } controls; }; +Result> IntSettingV3::parse(std::string const& key, std::string const& modID, matjson::Value const& json) { + auto ret = std::make_shared(PrivateMarker()); + + auto root = checkJson(json, "IntSettingV3"); + ret->parseSharedProperties(key, modID, root); + ret->parseDefaultValue(root, ret->m_impl->defaultValue); + ret->m_impl->value = ret->m_impl->defaultValue; + + root.has("min").into(ret->m_impl->minValue); + root.has("max").into(ret->m_impl->maxValue); + if (auto controls = root.has("control")) { + controls.has("arrow-step").into(ret->m_impl->controls.arrowStepSize); + if (!controls.has("arrows").template get()) { + ret->m_impl->controls.arrowStepSize = 0; + } + controls.has("big-arrow-step").into(ret->m_impl->controls.bigArrowStepSize); + if (!controls.has("big-arrows").template get()) { + ret->m_impl->controls.bigArrowStepSize = 0; + } + controls.has("slider").into(ret->m_impl->controls.sliderEnabled); + controls.has("slider-step").into(ret->m_impl->controls.sliderSnap); + controls.has("input").into(ret->m_impl->controls.textInputEnabled); + controls.checkUnknownKeys(); + } + + root.checkUnknownKeys(); + return root.ok(ret); +} + IntSettingV3::IntSettingV3(PrivateMarker) : m_impl(std::make_shared()) {} int64_t& IntSettingV3::getValueMut() const { @@ -253,7 +267,6 @@ int64_t IntSettingV3::getDefaultValue() const { return m_impl->defaultValue; } Result<> IntSettingV3::isValid(int64_t value) const { - GEODE_UNWRAP(this->isValidShared()); if (m_impl->minValue && value < *m_impl->minValue) { return Err("value must be at least {}", *m_impl->minValue); } @@ -292,32 +305,6 @@ bool IntSettingV3::isInputEnabled() const { return m_impl->controls.textInputEnabled; } -Result<> IntSettingV3::onParse(std::string const& key, std::string const& modID, matjson::Value const& json) { - auto root = checkJson(json, "IntSettingV3"); - - GEODE_UNWRAP(this->parseShared(root, m_impl->defaultValue)); - m_impl->value = m_impl->defaultValue; - - root.has("min").into(m_impl->minValue); - root.has("max").into(m_impl->maxValue); - if (auto controls = root.has("control")) { - controls.has("arrow-step").into(m_impl->controls.arrowStepSize); - if (!controls.has("arrows").template get()) { - m_impl->controls.arrowStepSize = 0; - } - controls.has("big-arrow-step").into(m_impl->controls.bigArrowStepSize); - if (!controls.has("big-arrows").template get()) { - m_impl->controls.bigArrowStepSize = 0; - } - controls.has("slider").into(m_impl->controls.sliderEnabled); - controls.has("slider-step").into(m_impl->controls.sliderSnap); - controls.has("input").into(m_impl->controls.textInputEnabled); - controls.checkUnknownKeys(); - } - - root.checkUnknownKeys(); - return root.ok(); -} bool IntSettingV3::load(matjson::Value const& json) { if (json.is_number()) { m_impl->value = json.as_int(); @@ -376,6 +363,35 @@ public: FloatSettingV3::FloatSettingV3(PrivateMarker) : m_impl(std::make_shared()) {} +Result> FloatSettingV3::parse(std::string const& key, std::string const& modID, matjson::Value const& json) { + auto ret = std::make_shared(PrivateMarker()); + + auto root = checkJson(json, "FloatSettingV3"); + ret->parseSharedProperties(key, modID, root); + ret->parseDefaultValue(root, ret->m_impl->defaultValue); + ret->m_impl->value = ret->m_impl->defaultValue; + + root.has("min").into(ret->m_impl->minValue); + root.has("max").into(ret->m_impl->maxValue); + if (auto controls = root.has("control")) { + controls.has("arrow-step").into(ret->m_impl->controls.arrowStepSize); + if (!controls.has("arrows").template get()) { + ret->m_impl->controls.arrowStepSize = 0; + } + controls.has("big-arrow-step").into(ret->m_impl->controls.bigArrowStepSize); + if (!controls.has("big-arrows").template get()) { + ret->m_impl->controls.bigArrowStepSize = 0; + } + controls.has("slider").into(ret->m_impl->controls.sliderEnabled); + controls.has("slider-step").into(ret->m_impl->controls.sliderSnap); + controls.has("input").into(ret->m_impl->controls.textInputEnabled); + controls.checkUnknownKeys(); + } + + root.checkUnknownKeys(); + return root.ok(ret); +} + double& FloatSettingV3::getValueMut() const { return m_impl->value; } @@ -383,7 +399,6 @@ double FloatSettingV3::getDefaultValue() const { return m_impl->defaultValue; } Result<> FloatSettingV3::isValid(double value) const { - GEODE_UNWRAP(this->isValidShared()); if (m_impl->minValue && value < *m_impl->minValue) { return Err("value must be at least {}", *m_impl->minValue); } @@ -422,32 +437,6 @@ bool FloatSettingV3::isInputEnabled() const { return m_impl->controls.textInputEnabled; } -Result<> FloatSettingV3::onParse(std::string const& key, std::string const& modID, matjson::Value const& json) { - auto root = checkJson(json, "FloatSettingV3"); - - GEODE_UNWRAP(this->parseShared(root, m_impl->defaultValue)); - m_impl->value = m_impl->defaultValue; - - root.has("min").into(m_impl->minValue); - root.has("max").into(m_impl->maxValue); - if (auto controls = root.has("control")) { - controls.has("arrow-step").into(m_impl->controls.arrowStepSize); - if (!controls.has("arrows").template get()) { - m_impl->controls.arrowStepSize = 0; - } - controls.has("big-arrow-step").into(m_impl->controls.bigArrowStepSize); - if (!controls.has("big-arrows").template get()) { - m_impl->controls.bigArrowStepSize = 0; - } - controls.has("slider").into(m_impl->controls.sliderEnabled); - controls.has("slider-step").into(m_impl->controls.sliderSnap); - controls.has("input").into(m_impl->controls.textInputEnabled); - controls.checkUnknownKeys(); - } - - root.checkUnknownKeys(); - return root.ok(); -} bool FloatSettingV3::load(matjson::Value const& json) { if (json.is_number()) { m_impl->value = json.as_double(); @@ -498,6 +487,22 @@ public: StringSettingV3::StringSettingV3(PrivateMarker) : m_impl(std::make_shared()) {} +Result> StringSettingV3::parse(std::string const& key, std::string const& modID, matjson::Value const& json) { + auto ret = std::make_shared(PrivateMarker()); + + auto root = checkJson(json, "StringSettingV3"); + ret->parseSharedProperties(key, modID, root); + ret->parseDefaultValue(root, ret->m_impl->defaultValue); + ret->m_impl->value = ret->m_impl->defaultValue; + + root.has("match").into(ret->m_impl->match); + root.has("filter").into(ret->m_impl->filter); + root.has("one-of").into(ret->m_impl->oneOf); + + root.checkUnknownKeys(); + return root.ok(ret); +} + std::string& StringSettingV3::getValueMut() const { return m_impl->value; } @@ -505,7 +510,6 @@ std::string StringSettingV3::getDefaultValue() const { return m_impl->defaultValue; } Result<> StringSettingV3::isValid(std::string_view value) const { - GEODE_UNWRAP(this->isValidShared()); if (m_impl->match) { if (!std::regex_match(std::string(value), std::regex(*m_impl->match))) { return Err("value must match regex {}", *m_impl->match); @@ -529,19 +533,6 @@ std::optional> StringSettingV3::getEnumOptions() const return m_impl->oneOf; } -Result<> StringSettingV3::onParse(std::string const& key, std::string const& modID, matjson::Value const& json) { - auto root = checkJson(json, "StringSettingV3"); - - GEODE_UNWRAP(this->parseShared(root, m_impl->defaultValue)); - m_impl->value = m_impl->defaultValue; - - root.has("match").into(m_impl->match); - root.has("filter").into(m_impl->filter); - root.has("one-of").into(m_impl->oneOf); - - root.checkUnknownKeys(); - return root.ok(); -} bool StringSettingV3::load(matjson::Value const& json) { if (json.is_string()) { m_impl->value = json.as_string(); @@ -582,30 +573,18 @@ public: FileSettingV3::FileSettingV3(PrivateMarker) : m_impl(std::make_shared()) {} -std::filesystem::path& FileSettingV3::getValueMut() const { - return m_impl->value; -} -std::filesystem::path FileSettingV3::getDefaultValue() const { - return m_impl->defaultValue; -} -Result<> FileSettingV3::isValid(std::filesystem::path const& value) const { - GEODE_UNWRAP(this->isValidShared()); - return Ok(); -} +Result> FileSettingV3::parse(std::string const& key, std::string const& modID, matjson::Value const& json) { + auto ret = std::make_shared(PrivateMarker()); -std::optional> FileSettingV3::getFilters() const { - return m_impl->filters; -} - -Result<> FileSettingV3::onParse(std::string const& key, std::string const& modID, matjson::Value const& json) { auto root = checkJson(json, "FileSettingV3"); - - GEODE_UNWRAP(this->parseShared(root, m_impl->defaultValue)); + ret->parseSharedProperties(key, modID, root); + ret->parseDefaultValue(root, ret->m_impl->defaultValue); + ret->m_impl->value = ret->m_impl->defaultValue; // Replace known paths like `{gd-save-dir}/` try { - m_impl->defaultValue = fmt::format( - fmt::runtime(m_impl->defaultValue.string()), + ret->m_impl->defaultValue = fmt::format( + fmt::runtime(ret->m_impl->defaultValue.string()), fmt::arg("gd-save-dir", dirs::getSaveDir()), fmt::arg("gd-game-dir", dirs::getGameDir()), fmt::arg("mod-config-dir", dirs::getModConfigDir() / modID), @@ -616,7 +595,7 @@ Result<> FileSettingV3::onParse(std::string const& key, std::string const& modID catch(fmt::format_error const&) { return Err("Invalid format string for file setting path"); } - m_impl->value = m_impl->defaultValue; + ret->m_impl->value = ret->m_impl->defaultValue; if (auto controls = root.has("control")) { auto filters = std::vector(); @@ -627,13 +606,28 @@ Result<> FileSettingV3::onParse(std::string const& key, std::string const& modID filters.push_back(filter); } if (!filters.empty()) { - m_impl->filters.emplace(filters); + ret->m_impl->filters.emplace(filters); } } root.checkUnknownKeys(); - return root.ok(); + return root.ok(ret); } + +std::filesystem::path& FileSettingV3::getValueMut() const { + return m_impl->value; +} +std::filesystem::path FileSettingV3::getDefaultValue() const { + return m_impl->defaultValue; +} +Result<> FileSettingV3::isValid(std::filesystem::path const& value) const { + return Ok(); +} + +std::optional> FileSettingV3::getFilters() const { + return m_impl->filters; +} + bool FileSettingV3::load(matjson::Value const& json) { if (json.is_string()) { m_impl->value = json.as_string(); @@ -671,6 +665,18 @@ public: Color3BSettingV3::Color3BSettingV3(PrivateMarker) : m_impl(std::make_shared()) {} +Result> Color3BSettingV3::parse(std::string const& key, std::string const& modID, matjson::Value const& json) { + auto ret = std::make_shared(PrivateMarker()); + + auto root = checkJson(json, "Color3BSettingV3"); + ret->parseSharedProperties(key, modID, root); + ret->parseDefaultValue(root, ret->m_impl->defaultValue); + ret->m_impl->value = ret->m_impl->defaultValue; + + root.checkUnknownKeys(); + return root.ok(ret); +} + ccColor3B& Color3BSettingV3::getValueMut() const { return m_impl->value; } @@ -678,19 +684,9 @@ ccColor3B Color3BSettingV3::getDefaultValue() const { return m_impl->defaultValue; } Result<> Color3BSettingV3::isValid(ccColor3B value) const { - GEODE_UNWRAP(this->isValidShared()); return Ok(); } -Result<> Color3BSettingV3::onParse(std::string const& key, std::string const& modID, matjson::Value const& json) { - auto root = checkJson(json, "Color3BSettingV3"); - - GEODE_UNWRAP(this->parseShared(root, m_impl->defaultValue)); - m_impl->value = m_impl->defaultValue; - - root.checkUnknownKeys(); - return root.ok(); -} bool Color3BSettingV3::load(matjson::Value const& json) { if (json.template is()) { m_impl->value = json.template as(); @@ -727,6 +723,18 @@ public: Color4BSettingV3::Color4BSettingV3(PrivateMarker) : m_impl(std::make_shared()) {} +Result> Color4BSettingV3::parse(std::string const& key, std::string const& modID, matjson::Value const& json) { + auto ret = std::make_shared(PrivateMarker()); + + auto root = checkJson(json, "Color4BSettingV3"); + ret->parseSharedProperties(key, modID, root); + ret->parseDefaultValue(root, ret->m_impl->defaultValue); + ret->m_impl->value = ret->m_impl->defaultValue; + + root.checkUnknownKeys(); + return root.ok(ret); +} + ccColor4B& Color4BSettingV3::getValueMut() const { return m_impl->value; } @@ -734,19 +742,9 @@ ccColor4B Color4BSettingV3::getDefaultValue() const { return m_impl->defaultValue; } Result<> Color4BSettingV3::isValid(ccColor4B value) const { - GEODE_UNWRAP(this->isValidShared()); return Ok(); } -Result<> Color4BSettingV3::onParse(std::string const& key, std::string const& modID, matjson::Value const& json) { - auto root = checkJson(json, "Color4BSettingV3"); - - GEODE_UNWRAP(this->parseShared(root, m_impl->defaultValue)); - m_impl->value = m_impl->defaultValue; - - root.checkUnknownKeys(); - return root.ok(); -} bool Color4BSettingV3::load(matjson::Value const& json) { if (json.template is()) { m_impl->value = json.template as(); diff --git a/loader/src/loader/SettingV3Impl.hpp b/loader/src/loader/SettingV3Impl.hpp deleted file mode 100644 index 227c1615..00000000 --- a/loader/src/loader/SettingV3Impl.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include - -using namespace geode::prelude; - -// todo in v4: this header can be fully removed and the impl moved back into SettingV3.cpp -// for now it has to be exposed for ModSettingsManager legacy compatibility - -class UnresolvedCustomSettingV3::Impl final { -public: - matjson::Value json; - // todo: remove in v4 - // this is for compatability with legacy custom settings - // in v3 settings custom settings just replace the definition fully like a normal person - std::shared_ptr legacyValue = nullptr; -}; -