mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-14 19:15:05 -05:00
new settings should work now
This commit is contained in:
parent
05a4daf794
commit
f37c903160
22 changed files with 1282 additions and 495 deletions
|
@ -10,6 +10,7 @@
|
|||
#include "Hook.hpp"
|
||||
#include "ModMetadata.hpp"
|
||||
#include "Setting.hpp"
|
||||
#include "SettingV3.hpp"
|
||||
#include "Types.hpp"
|
||||
#include "Loader.hpp"
|
||||
|
||||
|
@ -23,6 +24,8 @@
|
|||
#include <vector>
|
||||
|
||||
namespace geode {
|
||||
class SettingV3;
|
||||
|
||||
template <class T>
|
||||
struct HandleToSaved : public T {
|
||||
Mod* m_mod;
|
||||
|
@ -175,6 +178,7 @@ namespace geode {
|
|||
bool hasSetting(std::string_view const key) const;
|
||||
std::optional<Setting> getSettingDefinition(std::string_view const key) const;
|
||||
SettingValue* getSetting(std::string_view const key) const;
|
||||
std::shared_ptr<SettingV3> getSettingV3(std::string_view const key) const;
|
||||
|
||||
/**
|
||||
* Register a custom setting's value class. See Mod::addCustomSetting
|
||||
|
@ -187,6 +191,11 @@ namespace geode {
|
|||
* @see addCustomSetting
|
||||
*/
|
||||
void registerCustomSetting(std::string_view const key, std::unique_ptr<SettingValue> value);
|
||||
|
||||
/**
|
||||
* Register a custom setting
|
||||
*/
|
||||
Result<> registerCustomSettingV3(std::string_view const key, std::shared_ptr<SettingV3> value);
|
||||
/**
|
||||
* Register a custom setting's value class. The new SettingValue class
|
||||
* will be created in-place using `std::make_unique`. See
|
||||
|
@ -246,19 +255,27 @@ namespace geode {
|
|||
matjson::Value& getSaveContainer();
|
||||
matjson::Value& getSavedSettingsData();
|
||||
|
||||
/**
|
||||
* Get the value of a [setting](https://docs.geode-sdk.org/mods/settings).
|
||||
* To use this for custom settings, first specialize the
|
||||
* `SettingTypeForValueType` class, and then make sure your custom
|
||||
* setting type has a `getValue` function which returns the value
|
||||
*/
|
||||
template <class T>
|
||||
T getSettingValue(std::string_view const key) const {
|
||||
if (auto sett = this->getSetting(key)) {
|
||||
return SettingValueSetter<T>::get(sett);
|
||||
using S = typename SettingTypeForValueType<T>::SettingType;
|
||||
if (auto sett = typeinfo_pointer_cast<S>(this->getSettingV3(key))) {
|
||||
return sett->getValue();
|
||||
}
|
||||
return T();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T setSettingValue(std::string_view const key, T const& value) {
|
||||
if (auto sett = this->getSetting(key)) {
|
||||
auto old = this->getSettingValue<T>(key);
|
||||
SettingValueSetter<T>::set(sett, value);
|
||||
using S = typename SettingTypeForValueType<T>::SettingType;
|
||||
if (auto sett = typeinfo_pointer_cast<S>(this->getSettingV3(key))) {
|
||||
auto old = sett->getValue();
|
||||
sett->setValue(value);
|
||||
return old;
|
||||
}
|
||||
return T();
|
||||
|
|
|
@ -286,9 +286,7 @@ namespace geode {
|
|||
return Setting(m_key, m_modID, m_definition);
|
||||
}
|
||||
|
||||
ValueType getValue() const {
|
||||
return m_value;
|
||||
}
|
||||
GEODE_DLL ValueType getValue() const;
|
||||
GEODE_DLL void setValue(ValueType const& value);
|
||||
GEODE_DLL Result<> validate(ValueType const& value) const;
|
||||
};
|
||||
|
@ -301,8 +299,10 @@ namespace geode {
|
|||
using ColorSettingValue = GeodeSettingValue<ColorSetting>;
|
||||
using ColorAlphaSettingValue = GeodeSettingValue<ColorAlphaSetting>;
|
||||
|
||||
// todo: remove in v3
|
||||
|
||||
template<class T>
|
||||
struct GEODE_DLL SettingValueSetter {
|
||||
struct [[deprecated("Use SettingTypeForValueType from SettingV3 instead")]] GEODE_DLL SettingValueSetter {
|
||||
static T get(SettingValue* setting);
|
||||
static void set(SettingValue* setting, T const& value);
|
||||
};
|
||||
|
|
|
@ -5,18 +5,28 @@
|
|||
#include <cocos2d.h>
|
||||
// todo: remove this header in 4.0.0
|
||||
#include "Setting.hpp"
|
||||
#include "../utils/cocos.hpp"
|
||||
|
||||
// todo in v4: these can be removed as well as the friend decl in UnresolvedCustomSettingV3
|
||||
class ModSettingsManager;
|
||||
class LegacyCustomSettingToV3Node;
|
||||
|
||||
namespace geode {
|
||||
class SettingNodeV3;
|
||||
class JsonExpectedValue;
|
||||
|
||||
class GEODE_DLL SettingV3 {
|
||||
class GEODE_DLL SettingV3 : public std::enable_shared_from_this<SettingV3> {
|
||||
private:
|
||||
class GeodeImpl;
|
||||
std::shared_ptr<GeodeImpl> m_impl;
|
||||
|
||||
protected:
|
||||
virtual Result<> onParse(
|
||||
std::string const& key, std::string const& modID, matjson::Value const& json
|
||||
) = 0;
|
||||
|
||||
public:
|
||||
SettingV3(std::string const& key, std::string const& modID);
|
||||
SettingV3();
|
||||
virtual ~SettingV3();
|
||||
|
||||
/**
|
||||
|
@ -33,7 +43,7 @@ namespace geode {
|
|||
*/
|
||||
Mod* getMod() const;
|
||||
|
||||
virtual Result<> parse(std::string const& modID, matjson::Value const& json) = 0;
|
||||
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;
|
||||
|
@ -47,9 +57,11 @@ namespace geode {
|
|||
[[deprecated("This function will be removed alongside legacy settings in 4.0.0!")]]
|
||||
virtual std::optional<Setting> convertToLegacy() const;
|
||||
[[deprecated("This function will be removed alongside legacy settings in 4.0.0!")]]
|
||||
virtual std::optional<std::unique_ptr<SettingValue>> convertToLegacyValue() const;
|
||||
virtual std::optional<std::shared_ptr<SettingValue>> convertToLegacyValue() const;
|
||||
|
||||
static Result<std::shared_ptr<SettingV3>> parseBuiltin(std::string const& modID, matjson::Value const& json);
|
||||
static Result<std::shared_ptr<SettingV3>> parseBuiltin(
|
||||
std::string const& key, std::string const& modID, matjson::Value const& json
|
||||
);
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
@ -67,6 +79,32 @@ namespace geode {
|
|||
std::optional<std::string> getDescription() const;
|
||||
std::optional<std::string> getEnableIf() const;
|
||||
};
|
||||
|
||||
template <class T, class V = T>
|
||||
class GeodeSettingBaseValueV3 : public GeodeSettingBaseV3 {
|
||||
protected:
|
||||
virtual T& getValueMut() const = 0;
|
||||
|
||||
public:
|
||||
using ValueType = T;
|
||||
|
||||
virtual T getDefaultValue() const = 0;
|
||||
|
||||
T getValue() const {
|
||||
return this->getValueMut();
|
||||
}
|
||||
void setValue(V value) {
|
||||
this->getValueMut() = this->isValid(value) ? value : this->getDefaultValue();
|
||||
}
|
||||
virtual Result<> isValid(V value) const = 0;
|
||||
|
||||
bool isDefaultValue() const override {
|
||||
return this->getValue() == this->getDefaultValue();
|
||||
}
|
||||
void reset() {
|
||||
this->setValue(this->getDefaultValue());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class GEODE_DLL TitleSettingV3 final : public SettingV3 {
|
||||
|
@ -74,10 +112,12 @@ namespace geode {
|
|||
class Impl;
|
||||
std::shared_ptr<Impl> m_impl;
|
||||
|
||||
protected:
|
||||
Result<> onParse(std::string const& key, std::string const& modID, matjson::Value const& json) override;
|
||||
|
||||
public:
|
||||
std::string getTitle() const;
|
||||
|
||||
Result<> parse(std::string const& modID, matjson::Value const& json) override;
|
||||
bool load(matjson::Value const& json) override;
|
||||
bool save(matjson::Value& json) const override;
|
||||
SettingNodeV3* createNode(float width) override;
|
||||
|
@ -91,8 +131,13 @@ namespace geode {
|
|||
class Impl;
|
||||
std::shared_ptr<Impl> m_impl;
|
||||
|
||||
friend class ModSettingsManager;
|
||||
friend class LegacyCustomSettingToV3Node;
|
||||
|
||||
protected:
|
||||
Result<> onParse(std::string const& key, std::string const& modID, matjson::Value const& json) override;
|
||||
|
||||
public:
|
||||
Result<> parse(std::string const& modID, matjson::Value const& json) override;
|
||||
bool load(matjson::Value const& json) override;
|
||||
bool save(matjson::Value& json) const override;
|
||||
SettingNodeV3* createNode(float width) override;
|
||||
|
@ -101,44 +146,43 @@ namespace geode {
|
|||
void reset() override;
|
||||
|
||||
std::optional<Setting> convertToLegacy() const override;
|
||||
std::optional<std::unique_ptr<SettingValue>> convertToLegacyValue() const override;
|
||||
std::optional<std::shared_ptr<SettingValue>> convertToLegacyValue() const override;
|
||||
};
|
||||
|
||||
class GEODE_DLL BoolSettingV3 final : public detail::GeodeSettingBaseV3 {
|
||||
class GEODE_DLL BoolSettingV3 final : public detail::GeodeSettingBaseValueV3<bool> {
|
||||
private:
|
||||
class Impl;
|
||||
std::shared_ptr<Impl> m_impl;
|
||||
|
||||
protected:
|
||||
bool& getValueMut() const override;
|
||||
Result<> onParse(std::string const& key, std::string const& modID, matjson::Value const& json) override;
|
||||
|
||||
public:
|
||||
bool getValue() const;
|
||||
void setValue(bool value);
|
||||
Result<> isValid(bool value) const;
|
||||
bool getDefaultValue() const override;
|
||||
Result<> isValid(bool value) const override;
|
||||
|
||||
bool getDefaultValue() const;
|
||||
|
||||
Result<> parse(std::string const& modID, matjson::Value const& json) override;
|
||||
bool load(matjson::Value const& json) override;
|
||||
bool save(matjson::Value& json) const override;
|
||||
SettingNodeV3* createNode(float width) override;
|
||||
|
||||
bool isDefaultValue() const override;
|
||||
void reset() override;
|
||||
|
||||
std::optional<Setting> convertToLegacy() const override;
|
||||
std::optional<std::unique_ptr<SettingValue>> convertToLegacyValue() const override;
|
||||
std::optional<std::shared_ptr<SettingValue>> convertToLegacyValue() const override;
|
||||
};
|
||||
|
||||
class GEODE_DLL IntSettingV3 final : public detail::GeodeSettingBaseV3 {
|
||||
class GEODE_DLL IntSettingV3 final : public detail::GeodeSettingBaseValueV3<int64_t> {
|
||||
private:
|
||||
class Impl;
|
||||
std::shared_ptr<Impl> m_impl;
|
||||
|
||||
public:
|
||||
int64_t getValue() const;
|
||||
void setValue(int64_t value);
|
||||
Result<> isValid(int64_t value) const;
|
||||
protected:
|
||||
int64_t& getValueMut() const override;
|
||||
Result<> onParse(std::string const& key, std::string const& modID, matjson::Value const& json) override;
|
||||
|
||||
public:
|
||||
int64_t getDefaultValue() const override;
|
||||
Result<> isValid(int64_t value) const override;
|
||||
|
||||
int64_t getDefaultValue() const;
|
||||
std::optional<int64_t> getMinValue() const;
|
||||
std::optional<int64_t> getMaxValue() const;
|
||||
|
||||
|
@ -150,29 +194,27 @@ namespace geode {
|
|||
std::optional<int64_t> getSliderSnap() const;
|
||||
bool isInputEnabled() const;
|
||||
|
||||
Result<> parse(std::string const& modID, matjson::Value const& json) override;
|
||||
bool load(matjson::Value const& json) override;
|
||||
bool save(matjson::Value& json) const override;
|
||||
SettingNodeV3* createNode(float width) override;
|
||||
|
||||
bool isDefaultValue() const override;
|
||||
void reset() override;
|
||||
|
||||
std::optional<Setting> convertToLegacy() const override;
|
||||
std::optional<std::unique_ptr<SettingValue>> convertToLegacyValue() const override;
|
||||
std::optional<std::shared_ptr<SettingValue>> convertToLegacyValue() const override;
|
||||
};
|
||||
|
||||
class GEODE_DLL FloatSettingV3 final : public detail::GeodeSettingBaseV3 {
|
||||
class GEODE_DLL FloatSettingV3 final : public detail::GeodeSettingBaseValueV3<double> {
|
||||
private:
|
||||
class Impl;
|
||||
std::shared_ptr<Impl> m_impl;
|
||||
|
||||
public:
|
||||
double getValue() const;
|
||||
void setValue(double value);
|
||||
Result<> isValid(double value) const;
|
||||
protected:
|
||||
double& getValueMut() const override;
|
||||
Result<> onParse(std::string const& key, std::string const& modID, matjson::Value const& json) override;
|
||||
|
||||
public:
|
||||
double getDefaultValue() const override;
|
||||
Result<> isValid(double value) const override;
|
||||
|
||||
double getDefaultValue() const;
|
||||
std::optional<double> getMinValue() const;
|
||||
std::optional<double> getMaxValue() const;
|
||||
|
||||
|
@ -184,122 +226,111 @@ namespace geode {
|
|||
std::optional<double> getSliderSnap() const;
|
||||
bool isInputEnabled() const;
|
||||
|
||||
Result<> parse(std::string const& modID, matjson::Value const& json) override;
|
||||
bool load(matjson::Value const& json) override;
|
||||
bool save(matjson::Value& json) const override;
|
||||
SettingNodeV3* createNode(float width) override;
|
||||
|
||||
bool isDefaultValue() const override;
|
||||
void reset() override;
|
||||
|
||||
std::optional<Setting> convertToLegacy() const override;
|
||||
std::optional<std::unique_ptr<SettingValue>> convertToLegacyValue() const override;
|
||||
std::optional<std::shared_ptr<SettingValue>> convertToLegacyValue() const override;
|
||||
};
|
||||
|
||||
class GEODE_DLL StringSettingV3 final : public detail::GeodeSettingBaseV3 {
|
||||
class GEODE_DLL StringSettingV3 final : public detail::GeodeSettingBaseValueV3<std::string, std::string_view> {
|
||||
private:
|
||||
class Impl;
|
||||
std::shared_ptr<Impl> m_impl;
|
||||
|
||||
public:
|
||||
std::string getValue() const;
|
||||
void setValue(std::string_view value);
|
||||
Result<> isValid(std::string_view value) const;
|
||||
protected:
|
||||
std::string& getValueMut() const override;
|
||||
Result<> onParse(std::string const& key, std::string const& modID, matjson::Value const& json) override;
|
||||
|
||||
std::string getDefaultValue() const;
|
||||
public:
|
||||
std::string getDefaultValue() const override;
|
||||
Result<> isValid(std::string_view value) const override;
|
||||
|
||||
std::optional<std::string> getRegexValidator() const;
|
||||
std::optional<std::string> getAllowedCharacters() const;
|
||||
std::optional<std::vector<std::string>> getEnumOptions() const;
|
||||
|
||||
Result<> parse(std::string const& modID, matjson::Value const& json) override;
|
||||
bool load(matjson::Value const& json) override;
|
||||
bool save(matjson::Value& json) const override;
|
||||
SettingNodeV3* createNode(float width) override;
|
||||
|
||||
bool isDefaultValue() const override;
|
||||
void reset() override;
|
||||
|
||||
std::optional<Setting> convertToLegacy() const override;
|
||||
std::optional<std::unique_ptr<SettingValue>> convertToLegacyValue() const override;
|
||||
std::optional<std::shared_ptr<SettingValue>> convertToLegacyValue() const override;
|
||||
};
|
||||
|
||||
class GEODE_DLL FileSettingV3 final : public detail::GeodeSettingBaseV3 {
|
||||
class GEODE_DLL FileSettingV3 final : public detail::GeodeSettingBaseValueV3<std::filesystem::path, std::filesystem::path const&> {
|
||||
private:
|
||||
class Impl;
|
||||
std::shared_ptr<Impl> m_impl;
|
||||
|
||||
public:
|
||||
std::filesystem::path getValue() const;
|
||||
void setValue(std::filesystem::path const& value);
|
||||
Result<> isValid(std::filesystem::path value) const;
|
||||
protected:
|
||||
std::filesystem::path& getValueMut() const override;
|
||||
Result<> onParse(std::string const& key, std::string const& modID, matjson::Value const& json) override;
|
||||
|
||||
public:
|
||||
std::filesystem::path getDefaultValue() const override;
|
||||
Result<> isValid(std::filesystem::path const& value) const override;
|
||||
|
||||
std::filesystem::path getDefaultValue() const;
|
||||
std::optional<std::vector<utils::file::FilePickOptions::Filter>> getFilters() const;
|
||||
|
||||
Result<> parse(std::string const& modID, matjson::Value const& json) override;
|
||||
bool load(matjson::Value const& json) override;
|
||||
bool save(matjson::Value& json) const override;
|
||||
SettingNodeV3* createNode(float width) override;
|
||||
|
||||
bool isDefaultValue() const override;
|
||||
void reset() override;
|
||||
|
||||
std::optional<Setting> convertToLegacy() const override;
|
||||
std::optional<std::unique_ptr<SettingValue>> convertToLegacyValue() const override;
|
||||
std::optional<std::shared_ptr<SettingValue>> convertToLegacyValue() const override;
|
||||
};
|
||||
|
||||
class GEODE_DLL Color3BSettingV3 final : public detail::GeodeSettingBaseV3 {
|
||||
class GEODE_DLL Color3BSettingV3 final : public detail::GeodeSettingBaseValueV3<cocos2d::ccColor3B> {
|
||||
private:
|
||||
class Impl;
|
||||
std::shared_ptr<Impl> m_impl;
|
||||
|
||||
protected:
|
||||
cocos2d::ccColor3B& getValueMut() const override;
|
||||
Result<> onParse(std::string const& key, std::string const& modID, matjson::Value const& json) override;
|
||||
|
||||
public:
|
||||
cocos2d::ccColor3B getValue() const;
|
||||
void setValue(cocos2d::ccColor3B value);
|
||||
Result<> isValid(cocos2d::ccColor3B value) const;
|
||||
cocos2d::ccColor3B getDefaultValue() const override;
|
||||
Result<> isValid(cocos2d::ccColor3B value) const override;
|
||||
|
||||
cocos2d::ccColor3B getDefaultValue() const;
|
||||
|
||||
Result<> parse(std::string const& modID, matjson::Value const& json) override;
|
||||
bool load(matjson::Value const& json) override;
|
||||
bool save(matjson::Value& json) const override;
|
||||
SettingNodeV3* createNode(float width) override;
|
||||
|
||||
bool isDefaultValue() const override;
|
||||
void reset() override;
|
||||
|
||||
std::optional<Setting> convertToLegacy() const override;
|
||||
std::optional<std::unique_ptr<SettingValue>> convertToLegacyValue() const override;
|
||||
std::optional<std::shared_ptr<SettingValue>> convertToLegacyValue() const override;
|
||||
};
|
||||
|
||||
class GEODE_DLL Color4BSettingV3 final : public detail::GeodeSettingBaseV3 {
|
||||
class GEODE_DLL Color4BSettingV3 final : public detail::GeodeSettingBaseValueV3<cocos2d::ccColor4B> {
|
||||
private:
|
||||
class Impl;
|
||||
std::shared_ptr<Impl> m_impl;
|
||||
|
||||
protected:
|
||||
cocos2d::ccColor4B& getValueMut() const override;
|
||||
Result<> onParse(std::string const& key, std::string const& modID, matjson::Value const& json) override;
|
||||
|
||||
public:
|
||||
cocos2d::ccColor4B getValue() const;
|
||||
void setValue(cocos2d::ccColor4B value);
|
||||
Result<> isValid(cocos2d::ccColor4B value) const;
|
||||
cocos2d::ccColor4B getDefaultValue() const override;
|
||||
Result<> isValid(cocos2d::ccColor4B value) const override;
|
||||
|
||||
cocos2d::ccColor4B getDefaultValue() const;
|
||||
|
||||
Result<> parse(std::string const& modID, matjson::Value const& json) override;
|
||||
bool load(matjson::Value const& json) override;
|
||||
bool save(matjson::Value& json) const override;
|
||||
SettingNodeV3* createNode(float width) override;
|
||||
|
||||
bool isDefaultValue() const override;
|
||||
void reset() override;
|
||||
|
||||
std::optional<Setting> convertToLegacy() const override;
|
||||
std::optional<std::unique_ptr<SettingValue>> convertToLegacyValue() const override;
|
||||
std::optional<std::shared_ptr<SettingValue>> convertToLegacyValue() const override;
|
||||
};
|
||||
|
||||
class GEODE_DLL SettingNodeV3 : public cocos2d::CCNode {
|
||||
private:
|
||||
class Impl;
|
||||
std::shared_ptr<Impl> m_impl;
|
||||
|
||||
protected:
|
||||
bool init();
|
||||
bool init(std::shared_ptr<SettingV3> setting, float width);
|
||||
|
||||
/**
|
||||
* Mark this setting as changed. This updates the UI for committing
|
||||
|
@ -314,13 +345,74 @@ namespace geode {
|
|||
*/
|
||||
virtual void onCommit() = 0;
|
||||
|
||||
void dispatchChanged();
|
||||
void dispatchCommitted();
|
||||
public:
|
||||
void commit();
|
||||
virtual bool hasUncommittedChanges() const = 0;
|
||||
virtual bool hasNonDefaultValue() const = 0;
|
||||
virtual void resetToDefault() = 0;
|
||||
|
||||
void setContentSize(cocos2d::CCSize const& size) override;
|
||||
|
||||
std::shared_ptr<SettingV3> getSetting() const;
|
||||
};
|
||||
|
||||
class GEODE_DLL SettingNodeSizeChangeEventV3 : public Event {
|
||||
private:
|
||||
class Impl;
|
||||
std::shared_ptr<Impl> m_impl;
|
||||
|
||||
public:
|
||||
virtual void commit() = 0;
|
||||
virtual bool hasUncommittedChanges() = 0;
|
||||
virtual bool hasNonDefaultValue() = 0;
|
||||
virtual void resetToDefault() = 0;
|
||||
SettingNodeSizeChangeEventV3(SettingNodeV3* node);
|
||||
virtual ~SettingNodeSizeChangeEventV3();
|
||||
|
||||
SettingNodeV3* getTargetNode() const;
|
||||
};
|
||||
class GEODE_DLL SettingNodeValueChangeEventV3 : public Event {
|
||||
private:
|
||||
class Impl;
|
||||
std::shared_ptr<Impl> m_impl;
|
||||
|
||||
public:
|
||||
SettingNodeValueChangeEventV3(bool commit);
|
||||
virtual ~SettingNodeValueChangeEventV3();
|
||||
|
||||
bool isCommit() const;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct SettingTypeForValueType {
|
||||
static_assert(
|
||||
!std::is_same_v<T, T>,
|
||||
"specialize the SettingTypeForValueType class to use Mod::getSettingValue for custom settings"
|
||||
);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct SettingTypeForValueType<bool> {
|
||||
using SettingType = BoolSettingV3;
|
||||
};
|
||||
template <>
|
||||
struct SettingTypeForValueType<int64_t> {
|
||||
using SettingType = IntSettingV3;
|
||||
};
|
||||
template <>
|
||||
struct SettingTypeForValueType<double> {
|
||||
using SettingType = FloatSettingV3;
|
||||
};
|
||||
template <>
|
||||
struct SettingTypeForValueType<std::string> {
|
||||
using SettingType = StringSettingV3;
|
||||
};
|
||||
template <>
|
||||
struct SettingTypeForValueType<std::filesystem::path> {
|
||||
using SettingType = FileSettingV3;
|
||||
};
|
||||
template <>
|
||||
struct SettingTypeForValueType<cocos2d::ccColor3B> {
|
||||
using SettingType = Color3BSettingV3;
|
||||
};
|
||||
template <>
|
||||
struct SettingTypeForValueType<cocos2d::ccColor4B> {
|
||||
using SettingType = Color4BSettingV3;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <cstring>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <memory>
|
||||
|
||||
namespace geode {
|
||||
struct PlatformInfo {
|
||||
|
@ -129,4 +130,11 @@ namespace geode::cast {
|
|||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
std::shared_ptr<T> typeinfo_pointer_cast(std::shared_ptr<U> const& r) noexcept {
|
||||
// https://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast
|
||||
auto p = typeinfo_cast<typename std::shared_ptr<T>::element_type*>(r.get());
|
||||
return std::shared_ptr<T>(r, p);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -405,7 +405,7 @@ namespace geode {
|
|||
} {
|
||||
if (this->hasError()) return *this;
|
||||
if (auto v = this->template tryGet<T>()) {
|
||||
if (!predicate(v)) {
|
||||
if (!predicate(*v)) {
|
||||
this->setError("json value is not {}", name);
|
||||
}
|
||||
}
|
||||
|
@ -463,12 +463,12 @@ namespace geode {
|
|||
|
||||
Result<> ok();
|
||||
template <class T>
|
||||
Result<T> ok(T&& value) {
|
||||
Result<T> ok(T value) {
|
||||
auto ok = this->ok();
|
||||
if (!ok) {
|
||||
return Err(ok.unwrapErr());
|
||||
}
|
||||
return Ok(std::move(value));
|
||||
return Ok(std::forward<T>(value));
|
||||
}
|
||||
};
|
||||
GEODE_DLL JsonExpectedValue checkJson(matjson::Value const& json, std::string_view rootScopeName);
|
||||
|
|
|
@ -185,6 +185,7 @@ int geodeEntry(void* platformData) {
|
|||
log::popNest();
|
||||
|
||||
// download and install new loader update in the background
|
||||
|
||||
if (Mod::get()->getSettingValue<bool>("auto-check-updates")) {
|
||||
log::info("Starting loader update check");
|
||||
updater::checkForLoaderUpdates();
|
||||
|
|
|
@ -9,7 +9,7 @@ Loader::Loader() : m_impl(new Impl) {}
|
|||
Loader::~Loader() {}
|
||||
|
||||
Loader* Loader::get() {
|
||||
static auto g_geode = new Loader;
|
||||
static auto g_geode = new Loader();
|
||||
return g_geode;
|
||||
}
|
||||
|
||||
|
|
|
@ -156,15 +156,27 @@ bool Mod::hasSetting(std::string_view const key) const {
|
|||
}
|
||||
|
||||
std::optional<Setting> Mod::getSettingDefinition(std::string_view const key) const {
|
||||
return m_impl->getSettingDefinition(key);
|
||||
return m_impl->m_settings->getLegacyDefinition(std::string(key));
|
||||
}
|
||||
|
||||
SettingValue* Mod::getSetting(std::string_view const key) const {
|
||||
return m_impl->getSetting(key);
|
||||
return m_impl->m_settings->getLegacy(std::string(key)).get();
|
||||
}
|
||||
|
||||
std::shared_ptr<SettingV3> Mod::getSettingV3(std::string_view const key) const {
|
||||
auto sett = m_impl->m_settings->get(std::string(key));
|
||||
(void)file::writeString(".AAAAAk2", fmt::format("got it: {}, {}", key, fmt::ptr(sett)));
|
||||
return sett;
|
||||
}
|
||||
|
||||
void Mod::registerCustomSetting(std::string_view const key, std::unique_ptr<SettingValue> value) {
|
||||
return m_impl->registerCustomSetting(key, std::move(value));
|
||||
auto reg = m_impl->m_settings->registerLegacyCustomSetting(key, std::move(value));
|
||||
if (!reg) {
|
||||
log::error("Unable to register custom setting: {}", reg.unwrapErr());
|
||||
}
|
||||
}
|
||||
Result<> Mod::registerCustomSettingV3(std::string_view const key, std::shared_ptr<SettingV3> value) {
|
||||
return m_impl->m_settings->registerCustomSetting(key, value);
|
||||
}
|
||||
|
||||
std::vector<std::string> Mod::getLaunchArgumentNames() const {
|
||||
|
|
|
@ -53,7 +53,7 @@ Result<> Mod::Impl::setup() {
|
|||
// always create temp dir for all mods, even if disabled, so resources can be loaded
|
||||
GEODE_UNWRAP(this->createTempDir().expect("Unable to create temp dir: {error}"));
|
||||
|
||||
this->setupSettings();
|
||||
m_settings = std::make_unique<ModSettingsManager>(m_metadata);
|
||||
auto loadRes = this->loadData();
|
||||
if (!loadRes) {
|
||||
log::warn("Unable to load data for \"{}\": {}", m_metadata.getID(), loadRes.unwrapErr());
|
||||
|
@ -182,49 +182,11 @@ Result<> Mod::Impl::loadData() {
|
|||
// Check if settings exist
|
||||
auto settingPath = m_saveDirPath / "settings.json";
|
||||
if (std::filesystem::exists(settingPath)) {
|
||||
GEODE_UNWRAP_INTO(auto settingData, utils::file::readString(settingPath));
|
||||
// parse settings.json
|
||||
std::string error;
|
||||
auto res = matjson::parse(settingData, error);
|
||||
if (error.size() > 0) {
|
||||
return Err("Unable to parse settings.json: " + error);
|
||||
}
|
||||
auto json = res.value();
|
||||
|
||||
JsonChecker checker(json);
|
||||
auto root = checker.root(fmt::format("[{}/settings.json]", this->getID()));
|
||||
|
||||
GEODE_UNWRAP_INTO(auto json, utils::file::readJson(settingPath));
|
||||
m_savedSettingsData = json;
|
||||
|
||||
for (auto& [key, value] : root.items()) {
|
||||
// check if this is a known setting
|
||||
if (auto setting = this->getSetting(key)) {
|
||||
// load its value
|
||||
if (!setting->load(value.json())) {
|
||||
log::logImpl(
|
||||
Severity::Error,
|
||||
m_self,
|
||||
"{}: Unable to load value for setting \"{}\"",
|
||||
m_metadata.getID(),
|
||||
key
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (auto definition = this->getSettingDefinition(key)) {
|
||||
// Found a definition for this setting, it's most likely a custom setting
|
||||
// Don't warn it, as it's expected to be loaded by the mod
|
||||
}
|
||||
else {
|
||||
log::logImpl(
|
||||
Severity::Warning,
|
||||
m_self,
|
||||
"Encountered unknown setting \"{}\" while loading "
|
||||
"settings",
|
||||
key
|
||||
);
|
||||
}
|
||||
}
|
||||
auto load = m_settings->load(json);
|
||||
if (!load) {
|
||||
log::warn("Unable to load settings: {}", load.unwrapErr());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,104 +215,45 @@ Result<> Mod::Impl::saveData() {
|
|||
return Ok();
|
||||
}
|
||||
|
||||
// saveData is expected to be synchronous, and always called from GD thread
|
||||
ModStateEvent(m_self, ModEventType::DataSaved).post();
|
||||
|
||||
// Data saving should be fully fail-safe
|
||||
|
||||
std::unordered_set<std::string> coveredSettings;
|
||||
|
||||
// Settings
|
||||
matjson::Value json = matjson::Object();
|
||||
for (auto& [key, value] : m_settings) {
|
||||
coveredSettings.insert(key);
|
||||
if (!value->save(json[key])) {
|
||||
log::error("Unable to save setting \"{}\"", key);
|
||||
}
|
||||
}
|
||||
|
||||
// if some settings weren't provided a custom settings handler (for example,
|
||||
// If some settings weren't provided a custom settings handler (for example,
|
||||
// the mod was not loaded) then make sure to save their previous state in
|
||||
// order to not lose data
|
||||
log::debug("Check covered");
|
||||
if (!m_savedSettingsData.is_object()) {
|
||||
m_savedSettingsData = matjson::Object();
|
||||
}
|
||||
for (auto& [key, value] : m_savedSettingsData.as_object()) {
|
||||
log::debug("Check if {} is saved", key);
|
||||
if (!coveredSettings.contains(key)) {
|
||||
json[key] = value;
|
||||
}
|
||||
}
|
||||
matjson::Value json = m_savedSettingsData;
|
||||
m_settings->save(json);
|
||||
|
||||
std::string settingsStr = json.dump();
|
||||
std::string savedStr = m_saved.dump();
|
||||
|
||||
auto res = utils::file::writeString(m_saveDirPath / "settings.json", settingsStr);
|
||||
auto res = utils::file::writeString(m_saveDirPath / "settings.json", json.dump());
|
||||
if (!res) {
|
||||
log::error("Unable to save settings: {}", res.unwrapErr());
|
||||
}
|
||||
|
||||
auto res2 = utils::file::writeString(m_saveDirPath / "saved.json", savedStr);
|
||||
auto res2 = utils::file::writeString(m_saveDirPath / "saved.json", m_saved.dump());
|
||||
if (!res2) {
|
||||
log::error("Unable to save values: {}", res2.unwrapErr());
|
||||
}
|
||||
|
||||
// saveData is expected to be synchronous, and always called from GD thread
|
||||
ModStateEvent(m_self, ModEventType::DataSaved).post();
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
void Mod::Impl::setupSettings() {
|
||||
for (auto& [key, sett] : m_metadata.getSettings()) {
|
||||
if (auto value = sett.createDefaultValue()) {
|
||||
m_settings.emplace(key, std::move(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Mod::Impl::registerCustomSetting(std::string_view const key, std::unique_ptr<SettingValue> value) {
|
||||
auto keystr = std::string(key);
|
||||
if (!m_settings.count(keystr)) {
|
||||
// load data
|
||||
if (m_savedSettingsData.contains(key)) {
|
||||
value->load(m_savedSettingsData[key]);
|
||||
}
|
||||
m_settings.emplace(keystr, std::move(value));
|
||||
}
|
||||
}
|
||||
|
||||
bool Mod::Impl::hasSettings() const {
|
||||
return m_metadata.getSettings().size();
|
||||
return m_metadata.getSettingsV3().size();
|
||||
}
|
||||
|
||||
std::vector<std::string> Mod::Impl::getSettingKeys() const {
|
||||
std::vector<std::string> keys;
|
||||
for (auto& [key, _] : m_metadata.getSettings()) {
|
||||
for (auto& [key, _] : m_metadata.getSettingsV3()) {
|
||||
keys.push_back(key);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
std::optional<Setting> Mod::Impl::getSettingDefinition(std::string_view const key) const {
|
||||
for (auto& setting : m_metadata.getSettings()) {
|
||||
if (setting.first == key) {
|
||||
return setting.second;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
SettingValue* Mod::Impl::getSetting(std::string_view const key) const {
|
||||
auto keystr = std::string(key);
|
||||
if (m_settings.count(keystr)) {
|
||||
if (auto value = m_settings.at(keystr)->convertToLegacyValue()) {
|
||||
return value->get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Mod::Impl::hasSetting(std::string_view const key) const {
|
||||
for (auto& setting : m_metadata.getSettings()) {
|
||||
for (auto& setting : m_metadata.getSettingsV3()) {
|
||||
if (setting.first == key) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace geode {
|
|||
/**
|
||||
* Setting values. This is behind unique_ptr for interior mutability
|
||||
*/
|
||||
std::unique_ptr<ModSettingsManager> m_settings = std::make_unique<ModSettingsManager>();
|
||||
std::unique_ptr<ModSettingsManager> m_settings = nullptr;
|
||||
/**
|
||||
* Settings save data. Stored for efficient loading of custom settings
|
||||
*/
|
||||
|
@ -75,6 +75,8 @@ namespace geode {
|
|||
|
||||
Impl(Mod* self, ModMetadata const& metadata);
|
||||
~Impl();
|
||||
Impl(Impl const&) = delete;
|
||||
Impl(Impl&&) = delete;
|
||||
|
||||
Result<> setup();
|
||||
|
||||
|
@ -84,8 +86,6 @@ namespace geode {
|
|||
// called on a separate thread
|
||||
Result<> unzipGeodeFile(ModMetadata metadata);
|
||||
|
||||
void setupSettings();
|
||||
|
||||
std::string getID() const;
|
||||
std::string getName() const;
|
||||
std::vector<std::string> getDevelopers() const;
|
||||
|
@ -117,9 +117,6 @@ namespace geode {
|
|||
bool hasSettings() const;
|
||||
std::vector<std::string> getSettingKeys() const;
|
||||
bool hasSetting(std::string_view const key) const;
|
||||
std::optional<Setting> getSettingDefinition(std::string_view const key) const;
|
||||
SettingValue* getSetting(std::string_view const key) const;
|
||||
void registerCustomSetting(std::string_view const key, std::unique_ptr<SettingValue> value);
|
||||
|
||||
std::string getLaunchArgumentName(std::string_view const name) const;
|
||||
std::vector<std::string> getLaunchArgumentNames() const;
|
||||
|
|
|
@ -125,6 +125,8 @@ Result<ModMetadata> ModMetadata::Impl::createFromSchemaV010(ModJson const& rawJs
|
|||
}
|
||||
catch (...) { }
|
||||
|
||||
return Ok(info);
|
||||
|
||||
auto root = checkJson(impl->m_rawJSON, checkerRoot);
|
||||
root.needs("geode").into(impl->m_geodeVersion);
|
||||
|
||||
|
@ -249,9 +251,7 @@ Result<ModMetadata> ModMetadata::Impl::createFromSchemaV010(ModJson const& rawJs
|
|||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
GEODE_UNWRAP_INTO(auto sett, SettingV3::parseBuiltin(impl->m_id, value.json()));
|
||||
impl->m_settings.emplace_back(key, sett);
|
||||
impl->m_settings.emplace_back(key, value.json());
|
||||
}
|
||||
|
||||
if (auto resources = root.has("resources")) {
|
||||
|
|
|
@ -1,11 +1,126 @@
|
|||
#include "ModSettingsManager.hpp"
|
||||
#include "SettingV3Impl.hpp"
|
||||
#include <Geode/utils/JsonValidation.hpp>
|
||||
|
||||
SettingV3* ModSettingsManager::get(std::string const& id) {}
|
||||
class ModSettingsManager::Impl final {
|
||||
public:
|
||||
struct SettingInfo final {
|
||||
std::shared_ptr<SettingV3> v3;
|
||||
// todo: remove in v4
|
||||
std::shared_ptr<SettingValue> legacy = nullptr;
|
||||
};
|
||||
std::string modID;
|
||||
std::unordered_map<std::string, SettingInfo> list;
|
||||
};
|
||||
|
||||
SettingValue* ModSettingsManager::getLegacy(std::string const& id) {
|
||||
ModSettingsManager::ModSettingsManager(ModMetadata const& metadata)
|
||||
: m_impl(std::make_unique<Impl>())
|
||||
{
|
||||
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);
|
||||
}
|
||||
else {
|
||||
log::error("Unable to parse setting '{}' for mod {}: {}", key, m_impl->modID, v3.unwrapErr());
|
||||
}
|
||||
}
|
||||
}
|
||||
ModSettingsManager::~ModSettingsManager() {}
|
||||
|
||||
Result<> ModSettingsManager::registerCustomSetting(std::string_view key, std::shared_ptr<SettingV3> 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);
|
||||
return Ok();
|
||||
}
|
||||
Result<> ModSettingsManager::registerLegacyCustomSetting(std::string_view key, std::unique_ptr<SettingValue>&& ptr) {
|
||||
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);
|
||||
if (auto custom = typeinfo_pointer_cast<UnresolvedCustomSettingV3>(sett.v3)) {
|
||||
if (!custom->m_impl->legacyValue) {
|
||||
custom->m_impl->legacyValue = 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 Ok();
|
||||
}
|
||||
|
||||
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)) {
|
||||
try {
|
||||
if (!m_impl->list.at(key).v3->load(value.json())) {
|
||||
log::error("Unable to load setting '{}' for mod {}", key, m_impl->modID);
|
||||
}
|
||||
}
|
||||
catch(matjson::JsonException const& e) {
|
||||
log::error("Unable to load setting '{}' for mod {} (JSON exception): {}", key, m_impl->modID, e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
void ModSettingsManager::save(matjson::Value& json) {
|
||||
for (auto& [key, sett] : m_impl->list) {
|
||||
// Store the value in an intermediary so if `save` fails the existing
|
||||
// value loaded from disk isn't overwritten
|
||||
matjson::Value value;
|
||||
try {
|
||||
if (sett.v3->save(value)) {
|
||||
json[key] = value;
|
||||
}
|
||||
else {
|
||||
log::error("Unable to save setting '{}' for mod {}", key, m_impl->modID);
|
||||
}
|
||||
}
|
||||
catch(matjson::JsonException const& e) {
|
||||
log::error("Unable to save setting '{}' for mod {} (JSON exception): {}", key, m_impl->modID, e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<SettingV3> ModSettingsManager::get(std::string_view key) {
|
||||
auto id = std::string(key);
|
||||
return m_impl->list.count(id) ? m_impl->list.at(id).v3 : nullptr;
|
||||
}
|
||||
std::shared_ptr<SettingValue> ModSettingsManager::getLegacy(std::string_view key) {
|
||||
auto id = std::string(key);
|
||||
if (!m_impl->list.count(id)) {
|
||||
return nullptr;
|
||||
}
|
||||
auto& info = m_impl->list.at(id);
|
||||
// If this setting has alreay been given a legacy interface, give that
|
||||
if (m_legacy.count(id)) {
|
||||
return m_legacy.at(id).get();
|
||||
if (info.legacy) {
|
||||
return info.legacy;
|
||||
}
|
||||
if (m_v3.count(id)) {}
|
||||
// Generate new legacy interface
|
||||
if (auto legacy = info.v3->convertToLegacyValue()) {
|
||||
info.legacy.swap(*legacy);
|
||||
return info.legacy;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
std::optional<Setting> ModSettingsManager::getLegacyDefinition(std::string_view key) {
|
||||
if (auto s = this->get(key)) {
|
||||
return s->convertToLegacy();
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
|
|
@ -5,21 +5,22 @@
|
|||
|
||||
using namespace geode::prelude;
|
||||
|
||||
// This class should NEVER be exposed in a header!!!
|
||||
// It is an implementation detail!!!
|
||||
|
||||
class ModSettingsManager final {
|
||||
private:
|
||||
struct SettingInfo final {
|
||||
std::unique_ptr<SettingV3> v3;
|
||||
std::unique_ptr<SettingValue> legacy;
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, std::unique_ptr<SettingV3>> m_v3;
|
||||
// todo: remove in v4
|
||||
std::unordered_map<std::string, std::unique_ptr<SettingValue>> m_legacy;
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> m_impl;
|
||||
|
||||
public:
|
||||
SettingV3* get(std::string const& id);
|
||||
SettingValue* getLegacy(std::string const& id);
|
||||
ModSettingsManager(ModMetadata const& metadata);
|
||||
~ModSettingsManager();
|
||||
|
||||
Result<> load(matjson::Value const& json);
|
||||
void save(matjson::Value& json);
|
||||
|
||||
Result<> registerCustomSetting(std::string_view key, std::shared_ptr<SettingV3> ptr);
|
||||
Result<> registerLegacyCustomSetting(std::string_view key, std::unique_ptr<SettingValue>&& ptr);
|
||||
|
||||
std::shared_ptr<SettingV3> get(std::string_view key);
|
||||
std::shared_ptr<SettingValue> getLegacy(std::string_view key);
|
||||
std::optional<Setting> getLegacyDefinition(std::string_view key);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <ui/mods/settings/GeodeSettingNode.hpp>
|
||||
#include <Geode/loader/Mod.hpp>
|
||||
#include <Geode/loader/Setting.hpp>
|
||||
#include <Geode/loader/SettingV3.hpp>
|
||||
#include <Geode/loader/SettingEvent.hpp>
|
||||
#include <Geode/loader/SettingNode.hpp>
|
||||
#include <Geode/utils/general.hpp>
|
||||
|
@ -296,19 +297,36 @@ void SettingValue::valueChanged() {
|
|||
return type_##SettingNode::create(this, width); \
|
||||
} \
|
||||
template<> \
|
||||
typename GeodeSettingValue<type_##Setting>::ValueType \
|
||||
GeodeSettingValue<type_##Setting>::getValue() const { \
|
||||
using S = typename SettingTypeForValueType<ValueType>::SettingType; \
|
||||
if (auto mod = Loader::get()->getInstalledMod(m_modID)) { \
|
||||
if (auto setting = typeinfo_pointer_cast<S>(mod->getSettingV3(m_key))) {\
|
||||
return setting->getValue(); \
|
||||
} \
|
||||
} \
|
||||
return m_value; \
|
||||
} \
|
||||
template<> \
|
||||
void GeodeSettingValue< \
|
||||
type_##Setting \
|
||||
>::setValue(ValueType const& value) { \
|
||||
m_value = this->toValid(value).first; \
|
||||
this->valueChanged(); \
|
||||
using S = typename SettingTypeForValueType<ValueType>::SettingType; \
|
||||
if (auto mod = Loader::get()->getInstalledMod(m_modID)) { \
|
||||
if (auto setting = typeinfo_pointer_cast<S>(mod->getSettingV3(m_key))) {\
|
||||
return setting->setValue(value); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
template<> \
|
||||
Result<> GeodeSettingValue< \
|
||||
type_##Setting \
|
||||
>::validate(ValueType const& value) const { \
|
||||
auto reason = this->toValid(value).second; \
|
||||
if (reason.has_value()) { \
|
||||
return Err(static_cast<std::string>(reason.value())); \
|
||||
using S = typename SettingTypeForValueType<ValueType>::SettingType; \
|
||||
if (auto mod = Loader::get()->getInstalledMod(m_modID)) { \
|
||||
if (auto setting = typeinfo_pointer_cast<S>(mod->getSettingV3(m_key))) {\
|
||||
return setting->isValid(value); \
|
||||
} \
|
||||
} \
|
||||
return Ok(); \
|
||||
} \
|
||||
|
@ -316,8 +334,11 @@ void SettingValue::valueChanged() {
|
|||
typename type_##Setting::ValueType SettingValueSetter< \
|
||||
typename type_##Setting::ValueType \
|
||||
>::get(SettingValue* setting) { \
|
||||
if (auto b = typeinfo_cast<type_##SettingValue*>(setting)) { \
|
||||
return b->getValue(); \
|
||||
using S = typename SettingTypeForValueType<typename type_##Setting::ValueType>::SettingType; \
|
||||
if (auto mod = Loader::get()->getInstalledMod(setting->getModID())) { \
|
||||
if (auto sett = typeinfo_pointer_cast<S>(mod->getSettingV3(setting->getKey()))) { \
|
||||
return sett->getValue(); \
|
||||
} \
|
||||
} \
|
||||
return typename type_##Setting::ValueType(); \
|
||||
} \
|
||||
|
@ -328,8 +349,11 @@ void SettingValue::valueChanged() {
|
|||
SettingValue* setting, \
|
||||
typename type_##Setting::ValueType const& value \
|
||||
) { \
|
||||
if (auto b = typeinfo_cast<type_##SettingValue*>(setting)) { \
|
||||
b->setValue(value); \
|
||||
using S = typename SettingTypeForValueType<typename type_##Setting::ValueType>::SettingType; \
|
||||
if (auto mod = Loader::get()->getInstalledMod(setting->getModID())) { \
|
||||
if (auto sett = typeinfo_pointer_cast<S>(mod->getSettingV3(setting->getKey()))) { \
|
||||
return sett->setValue(value); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
|
|
445
loader/src/loader/SettingNodeV3.cpp
Normal file
445
loader/src/loader/SettingNodeV3.cpp
Normal file
|
@ -0,0 +1,445 @@
|
|||
#include "SettingNodeV3.hpp"
|
||||
#include "SettingV3Impl.hpp"
|
||||
#include <Geode/loader/SettingNode.hpp>
|
||||
|
||||
class SettingNodeSizeChangeEventV3::Impl final {
|
||||
public:
|
||||
SettingNodeV3* node;
|
||||
};
|
||||
|
||||
SettingNodeSizeChangeEventV3::SettingNodeSizeChangeEventV3(SettingNodeV3* node)
|
||||
: m_impl(std::make_shared<Impl>())
|
||||
{
|
||||
m_impl->node = node;
|
||||
}
|
||||
SettingNodeSizeChangeEventV3::~SettingNodeSizeChangeEventV3() = default;
|
||||
|
||||
SettingNodeV3* SettingNodeSizeChangeEventV3::getTargetNode() const {
|
||||
return m_impl->node;
|
||||
}
|
||||
|
||||
class SettingNodeValueChangeEventV3::Impl final {
|
||||
public:
|
||||
bool commit = false;
|
||||
};
|
||||
|
||||
SettingNodeValueChangeEventV3::SettingNodeValueChangeEventV3(bool commit)
|
||||
: m_impl(std::make_shared<Impl>())
|
||||
{
|
||||
m_impl->commit = commit;
|
||||
}
|
||||
SettingNodeValueChangeEventV3::~SettingNodeValueChangeEventV3() = default;
|
||||
|
||||
bool SettingNodeValueChangeEventV3::isCommit() const {
|
||||
return m_impl->commit;
|
||||
}
|
||||
|
||||
class SettingNodeV3::Impl final {
|
||||
public:
|
||||
std::shared_ptr<SettingV3> setting;
|
||||
};
|
||||
|
||||
bool SettingNodeV3::init(std::shared_ptr<SettingV3> setting, float width) {
|
||||
if (!CCNode::init())
|
||||
return false;
|
||||
|
||||
m_impl = std::make_shared<Impl>();
|
||||
m_impl->setting = setting;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SettingNodeV3::markChanged() {
|
||||
SettingNodeValueChangeEventV3(false).post();
|
||||
}
|
||||
|
||||
void SettingNodeV3::commit() {
|
||||
this->onCommit();
|
||||
SettingNodeValueChangeEventV3(true).post();
|
||||
}
|
||||
|
||||
void SettingNodeV3::setContentSize(CCSize const& size) {
|
||||
CCNode::setContentSize(size);
|
||||
SettingNodeSizeChangeEventV3(this).post();
|
||||
}
|
||||
|
||||
std::shared_ptr<SettingV3> SettingNodeV3::getSetting() const {
|
||||
return m_impl->setting;
|
||||
}
|
||||
|
||||
// TitleSettingNodeV3
|
||||
|
||||
bool TitleSettingNodeV3::init(std::shared_ptr<TitleSettingV3> setting, float width) {
|
||||
if (!SettingNodeV3::init(setting, width))
|
||||
return false;
|
||||
|
||||
this->setContentHeight(20);
|
||||
|
||||
auto label = CCLabelBMFont::create(setting->getTitle().c_str(), "goldFont.fnt");
|
||||
label->limitLabelWidth(width - m_obContentSize.height, .7f, .1f);
|
||||
this->addChildAtPosition(label, Anchor::Left, ccp(m_obContentSize.height / 2, 0));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TitleSettingNodeV3::onCommit() {}
|
||||
|
||||
TitleSettingNodeV3* TitleSettingNodeV3::create(std::shared_ptr<TitleSettingV3> setting, float width) {
|
||||
auto ret = new TitleSettingNodeV3();
|
||||
if (ret && ret->init(setting, width)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool TitleSettingNodeV3::hasUncommittedChanges() const {
|
||||
return false;
|
||||
}
|
||||
bool TitleSettingNodeV3::hasNonDefaultValue() const {
|
||||
return false;
|
||||
}
|
||||
void TitleSettingNodeV3::resetToDefault() {}
|
||||
|
||||
std::shared_ptr<TitleSettingV3> TitleSettingNodeV3::getSetting() const {
|
||||
return std::static_pointer_cast<TitleSettingV3>(SettingNodeV3::getSetting());
|
||||
}
|
||||
|
||||
// BoolSettingNodeV3
|
||||
|
||||
bool BoolSettingNodeV3::init(std::shared_ptr<BoolSettingV3> setting, float width) {
|
||||
if (!SettingNodeV3::init(setting, width))
|
||||
return false;
|
||||
|
||||
this->setContentHeight(30);
|
||||
|
||||
auto label = CCLabelBMFont::create(setting->getName().c_str(), "bigFont.fnt");
|
||||
label->limitLabelWidth(width - m_obContentSize.height * 1.5f, .5f, .1f);
|
||||
this->addChildAtPosition(label, Anchor::Left, ccp(m_obContentSize.height / 2, 0));
|
||||
|
||||
m_toggle = CCMenuItemToggler::createWithStandardSprites(
|
||||
this, nullptr, .8f
|
||||
);
|
||||
this->addChildAtPosition(m_toggle, Anchor::Right, ccp(-m_obContentSize.height / 2, 0));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BoolSettingNodeV3::onCommit() {
|
||||
this->getSetting()->setValue(m_toggle->isToggled());
|
||||
}
|
||||
|
||||
BoolSettingNodeV3* BoolSettingNodeV3::create(std::shared_ptr<BoolSettingV3> setting, float width) {
|
||||
auto ret = new BoolSettingNodeV3();
|
||||
if (ret && ret->init(setting, width)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool BoolSettingNodeV3::hasUncommittedChanges() const {
|
||||
return m_toggle->isToggled() != this->getSetting()->getValue();
|
||||
}
|
||||
bool BoolSettingNodeV3::hasNonDefaultValue() const {
|
||||
return m_toggle->isToggled() != this->getSetting()->getDefaultValue();
|
||||
}
|
||||
void BoolSettingNodeV3::resetToDefault() {
|
||||
this->getSetting()->reset();
|
||||
m_toggle->toggle(this->getSetting()->getDefaultValue());
|
||||
}
|
||||
|
||||
std::shared_ptr<BoolSettingV3> BoolSettingNodeV3::getSetting() const {
|
||||
return std::static_pointer_cast<BoolSettingV3>(SettingNodeV3::getSetting());
|
||||
}
|
||||
|
||||
// IntSettingNodeV3
|
||||
|
||||
bool IntSettingNodeV3::init(std::shared_ptr<IntSettingV3> setting, float width) {
|
||||
if (!SettingNodeV3::init(setting, width))
|
||||
return false;
|
||||
|
||||
// todo
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void IntSettingNodeV3::onCommit() {}
|
||||
|
||||
IntSettingNodeV3* IntSettingNodeV3::create(std::shared_ptr<IntSettingV3> setting, float width) {
|
||||
auto ret = new IntSettingNodeV3();
|
||||
if (ret && ret->init(setting, width)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool IntSettingNodeV3::hasUncommittedChanges() const {
|
||||
return false;
|
||||
}
|
||||
bool IntSettingNodeV3::hasNonDefaultValue() const {
|
||||
return false;
|
||||
}
|
||||
void IntSettingNodeV3::resetToDefault() {}
|
||||
|
||||
std::shared_ptr<IntSettingV3> IntSettingNodeV3::getSetting() const {
|
||||
return std::static_pointer_cast<IntSettingV3>(SettingNodeV3::getSetting());
|
||||
}
|
||||
|
||||
// FloatSettingNodeV3
|
||||
|
||||
bool FloatSettingNodeV3::init(std::shared_ptr<FloatSettingV3> setting, float width) {
|
||||
if (!SettingNodeV3::init(setting, width))
|
||||
return false;
|
||||
|
||||
// todo
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FloatSettingNodeV3::onCommit() {}
|
||||
|
||||
FloatSettingNodeV3* FloatSettingNodeV3::create(std::shared_ptr<FloatSettingV3> setting, float width) {
|
||||
auto ret = new FloatSettingNodeV3();
|
||||
if (ret && ret->init(setting, width)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool FloatSettingNodeV3::hasUncommittedChanges() const {
|
||||
return false;
|
||||
}
|
||||
bool FloatSettingNodeV3::hasNonDefaultValue() const {
|
||||
return false;
|
||||
}
|
||||
void FloatSettingNodeV3::resetToDefault() {}
|
||||
|
||||
std::shared_ptr<FloatSettingV3> FloatSettingNodeV3::getSetting() const {
|
||||
return std::static_pointer_cast<FloatSettingV3>(SettingNodeV3::getSetting());
|
||||
}
|
||||
|
||||
// StringSettingNodeV3
|
||||
|
||||
bool StringSettingNodeV3::init(std::shared_ptr<StringSettingV3> setting, float width) {
|
||||
if (!SettingNodeV3::init(setting, width))
|
||||
return false;
|
||||
|
||||
// todo
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void StringSettingNodeV3::onCommit() {}
|
||||
|
||||
StringSettingNodeV3* StringSettingNodeV3::create(std::shared_ptr<StringSettingV3> setting, float width) {
|
||||
auto ret = new StringSettingNodeV3();
|
||||
if (ret && ret->init(setting, width)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool StringSettingNodeV3::hasUncommittedChanges() const {
|
||||
return false;
|
||||
}
|
||||
bool StringSettingNodeV3::hasNonDefaultValue() const {
|
||||
return false;
|
||||
}
|
||||
void StringSettingNodeV3::resetToDefault() {}
|
||||
|
||||
std::shared_ptr<StringSettingV3> StringSettingNodeV3::getSetting() const {
|
||||
return std::static_pointer_cast<StringSettingV3>(SettingNodeV3::getSetting());
|
||||
}
|
||||
|
||||
// FileSettingNodeV3
|
||||
|
||||
bool FileSettingNodeV3::init(std::shared_ptr<FileSettingV3> setting, float width) {
|
||||
if (!SettingNodeV3::init(setting, width))
|
||||
return false;
|
||||
|
||||
// todo
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileSettingNodeV3::onCommit() {}
|
||||
|
||||
FileSettingNodeV3* FileSettingNodeV3::create(std::shared_ptr<FileSettingV3> setting, float width) {
|
||||
auto ret = new FileSettingNodeV3();
|
||||
if (ret && ret->init(setting, width)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool FileSettingNodeV3::hasUncommittedChanges() const {
|
||||
return false;
|
||||
}
|
||||
bool FileSettingNodeV3::hasNonDefaultValue() const {
|
||||
return false;
|
||||
}
|
||||
void FileSettingNodeV3::resetToDefault() {}
|
||||
|
||||
std::shared_ptr<FileSettingV3> FileSettingNodeV3::getSetting() const {
|
||||
return std::static_pointer_cast<FileSettingV3>(SettingNodeV3::getSetting());
|
||||
}
|
||||
|
||||
// Color3BSettingNodeV3
|
||||
|
||||
bool Color3BSettingNodeV3::init(std::shared_ptr<Color3BSettingV3> setting, float width) {
|
||||
if (!SettingNodeV3::init(setting, width))
|
||||
return false;
|
||||
|
||||
// todo
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Color3BSettingNodeV3::onCommit() {}
|
||||
|
||||
Color3BSettingNodeV3* Color3BSettingNodeV3::create(std::shared_ptr<Color3BSettingV3> setting, float width) {
|
||||
auto ret = new Color3BSettingNodeV3();
|
||||
if (ret && ret->init(setting, width)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Color3BSettingNodeV3::hasUncommittedChanges() const {
|
||||
return false;
|
||||
}
|
||||
bool Color3BSettingNodeV3::hasNonDefaultValue() const {
|
||||
return false;
|
||||
}
|
||||
void Color3BSettingNodeV3::resetToDefault() {}
|
||||
|
||||
std::shared_ptr<Color3BSettingV3> Color3BSettingNodeV3::getSetting() const {
|
||||
return std::static_pointer_cast<Color3BSettingV3>(SettingNodeV3::getSetting());
|
||||
}
|
||||
|
||||
// Color4BSettingNodeV3
|
||||
|
||||
bool Color4BSettingNodeV3::init(std::shared_ptr<Color4BSettingV3> setting, float width) {
|
||||
if (!SettingNodeV3::init(setting, width))
|
||||
return false;
|
||||
|
||||
// todo
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Color4BSettingNodeV3::onCommit() {}
|
||||
|
||||
Color4BSettingNodeV3* Color4BSettingNodeV3::create(std::shared_ptr<Color4BSettingV3> setting, float width) {
|
||||
auto ret = new Color4BSettingNodeV3();
|
||||
if (ret && ret->init(setting, width)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Color4BSettingNodeV3::hasUncommittedChanges() const {
|
||||
return false;
|
||||
}
|
||||
bool Color4BSettingNodeV3::hasNonDefaultValue() const {
|
||||
return false;
|
||||
}
|
||||
void Color4BSettingNodeV3::resetToDefault() {}
|
||||
|
||||
std::shared_ptr<Color4BSettingV3> Color4BSettingNodeV3::getSetting() const {
|
||||
return std::static_pointer_cast<Color4BSettingV3>(SettingNodeV3::getSetting());
|
||||
}
|
||||
|
||||
// UnresolvedCustomSettingNodeV3
|
||||
|
||||
bool UnresolvedCustomSettingNodeV3::init(std::shared_ptr<UnresolvedCustomSettingV3> setting, float width) {
|
||||
if (!SettingNodeV3::init(setting, width))
|
||||
return false;
|
||||
|
||||
this->setContentHeight(30);
|
||||
|
||||
auto label = CCLabelBMFont::create(
|
||||
fmt::format("Missing setting '{}'", setting->getKey()).c_str(),
|
||||
"bigFont.fnt"
|
||||
);
|
||||
label->limitLabelWidth(width - m_obContentSize.height, .5f, .1f);
|
||||
this->addChildAtPosition(label, Anchor::Left, ccp(m_obContentSize.height / 2, 0));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UnresolvedCustomSettingNodeV3::onCommit() {}
|
||||
|
||||
UnresolvedCustomSettingNodeV3* UnresolvedCustomSettingNodeV3::create(std::shared_ptr<UnresolvedCustomSettingV3> setting, float width) {
|
||||
auto ret = new UnresolvedCustomSettingNodeV3();
|
||||
if (ret && ret->init(setting, width)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool UnresolvedCustomSettingNodeV3::hasUncommittedChanges() const {
|
||||
return false;
|
||||
}
|
||||
bool UnresolvedCustomSettingNodeV3::hasNonDefaultValue() const {
|
||||
return false;
|
||||
}
|
||||
void UnresolvedCustomSettingNodeV3::resetToDefault() {}
|
||||
|
||||
std::shared_ptr<UnresolvedCustomSettingV3> UnresolvedCustomSettingNodeV3::getSetting() const {
|
||||
return std::static_pointer_cast<UnresolvedCustomSettingV3>(SettingNodeV3::getSetting());
|
||||
}
|
||||
|
||||
// LegacyCustomSettingToV3Node
|
||||
|
||||
bool LegacyCustomSettingToV3Node::init(std::shared_ptr<UnresolvedCustomSettingV3> original, float width) {
|
||||
if (!SettingNodeV3::init(original, width))
|
||||
return false;
|
||||
|
||||
m_original = original->m_impl->legacyValue->createNode(width);
|
||||
this->setContentSize({ width, m_original->getContentHeight() });
|
||||
this->addChildAtPosition(m_original, Anchor::Center);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LegacyCustomSettingToV3Node::onCommit() {
|
||||
m_original->commit();
|
||||
}
|
||||
|
||||
LegacyCustomSettingToV3Node* LegacyCustomSettingToV3Node::create(std::shared_ptr<UnresolvedCustomSettingV3> original, float width) {
|
||||
auto ret = new LegacyCustomSettingToV3Node();
|
||||
if (ret && ret->init(original, width)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool LegacyCustomSettingToV3Node::hasUncommittedChanges() const {
|
||||
return m_original->hasUncommittedChanges();
|
||||
}
|
||||
bool LegacyCustomSettingToV3Node::hasNonDefaultValue() const {
|
||||
return m_original->hasNonDefaultValue();
|
||||
}
|
||||
void LegacyCustomSettingToV3Node::resetToDefault() {
|
||||
m_original->resetToDefault();
|
||||
}
|
174
loader/src/loader/SettingNodeV3.hpp
Normal file
174
loader/src/loader/SettingNodeV3.hpp
Normal file
|
@ -0,0 +1,174 @@
|
|||
#pragma once
|
||||
|
||||
#include <Geode/loader/SettingV3.hpp>
|
||||
#include <Geode/binding/CCMenuItemToggler.hpp>
|
||||
|
||||
using namespace geode::prelude;
|
||||
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
// !! If these classes are ever exposed in a public header, make sure to pimpl EVERYTHING! !!
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
class TitleSettingNodeV3 : public SettingNodeV3 {
|
||||
protected:
|
||||
bool init(std::shared_ptr<TitleSettingV3> setting, float width);
|
||||
|
||||
void onCommit() override;
|
||||
|
||||
public:
|
||||
static TitleSettingNodeV3* create(std::shared_ptr<TitleSettingV3> setting, float width);
|
||||
|
||||
bool hasUncommittedChanges() const override;
|
||||
bool hasNonDefaultValue() const override;
|
||||
void resetToDefault() override;
|
||||
|
||||
std::shared_ptr<TitleSettingV3> getSetting() const;
|
||||
};
|
||||
|
||||
class BoolSettingNodeV3 : public SettingNodeV3 {
|
||||
protected:
|
||||
CCMenuItemToggler* m_toggle;
|
||||
|
||||
bool init(std::shared_ptr<BoolSettingV3> setting, float width);
|
||||
|
||||
void onCommit() override;
|
||||
|
||||
public:
|
||||
static BoolSettingNodeV3* create(std::shared_ptr<BoolSettingV3> setting, float width);
|
||||
|
||||
bool hasUncommittedChanges() const override;
|
||||
bool hasNonDefaultValue() const override;
|
||||
void resetToDefault() override;
|
||||
|
||||
std::shared_ptr<BoolSettingV3> getSetting() const;
|
||||
};
|
||||
|
||||
class IntSettingNodeV3 : public SettingNodeV3 {
|
||||
protected:
|
||||
bool init(std::shared_ptr<IntSettingV3> setting, float width);
|
||||
|
||||
void onCommit() override;
|
||||
|
||||
public:
|
||||
static IntSettingNodeV3* create(std::shared_ptr<IntSettingV3> setting, float width);
|
||||
|
||||
bool hasUncommittedChanges() const override;
|
||||
bool hasNonDefaultValue() const override;
|
||||
void resetToDefault() override;
|
||||
|
||||
std::shared_ptr<IntSettingV3> getSetting() const;
|
||||
};
|
||||
|
||||
class FloatSettingNodeV3 : public SettingNodeV3 {
|
||||
protected:
|
||||
bool init(std::shared_ptr<FloatSettingV3> setting, float width);
|
||||
|
||||
void onCommit() override;
|
||||
|
||||
public:
|
||||
static FloatSettingNodeV3* create(std::shared_ptr<FloatSettingV3> setting, float width);
|
||||
|
||||
bool hasUncommittedChanges() const override;
|
||||
bool hasNonDefaultValue() const override;
|
||||
void resetToDefault() override;
|
||||
|
||||
std::shared_ptr<FloatSettingV3> getSetting() const;
|
||||
};
|
||||
|
||||
class StringSettingNodeV3 : public SettingNodeV3 {
|
||||
protected:
|
||||
bool init(std::shared_ptr<StringSettingV3> setting, float width);
|
||||
|
||||
void onCommit() override;
|
||||
|
||||
public:
|
||||
static StringSettingNodeV3* create(std::shared_ptr<StringSettingV3> setting, float width);
|
||||
|
||||
bool hasUncommittedChanges() const override;
|
||||
bool hasNonDefaultValue() const override;
|
||||
void resetToDefault() override;
|
||||
|
||||
std::shared_ptr<StringSettingV3> getSetting() const;
|
||||
};
|
||||
|
||||
class FileSettingNodeV3 : public SettingNodeV3 {
|
||||
protected:
|
||||
bool init(std::shared_ptr<FileSettingV3> setting, float width);
|
||||
|
||||
void onCommit() override;
|
||||
|
||||
public:
|
||||
static FileSettingNodeV3* create(std::shared_ptr<FileSettingV3> setting, float width);
|
||||
|
||||
bool hasUncommittedChanges() const override;
|
||||
bool hasNonDefaultValue() const override;
|
||||
void resetToDefault() override;
|
||||
|
||||
std::shared_ptr<FileSettingV3> getSetting() const;
|
||||
};
|
||||
|
||||
class Color3BSettingNodeV3 : public SettingNodeV3 {
|
||||
protected:
|
||||
bool init(std::shared_ptr<Color3BSettingV3> setting, float width);
|
||||
|
||||
void onCommit() override;
|
||||
|
||||
public:
|
||||
static Color3BSettingNodeV3* create(std::shared_ptr<Color3BSettingV3> setting, float width);
|
||||
|
||||
bool hasUncommittedChanges() const override;
|
||||
bool hasNonDefaultValue() const override;
|
||||
void resetToDefault() override;
|
||||
|
||||
std::shared_ptr<Color3BSettingV3> getSetting() const;
|
||||
};
|
||||
|
||||
class Color4BSettingNodeV3 : public SettingNodeV3 {
|
||||
protected:
|
||||
bool init(std::shared_ptr<Color4BSettingV3> setting, float width);
|
||||
|
||||
void onCommit() override;
|
||||
|
||||
public:
|
||||
static Color4BSettingNodeV3* create(std::shared_ptr<Color4BSettingV3> setting, float width);
|
||||
|
||||
bool hasUncommittedChanges() const override;
|
||||
bool hasNonDefaultValue() const override;
|
||||
void resetToDefault() override;
|
||||
|
||||
std::shared_ptr<Color4BSettingV3> getSetting() const;
|
||||
};
|
||||
|
||||
class UnresolvedCustomSettingNodeV3 : public SettingNodeV3 {
|
||||
protected:
|
||||
bool init(std::shared_ptr<UnresolvedCustomSettingV3> setting, float width);
|
||||
|
||||
void onCommit() override;
|
||||
|
||||
public:
|
||||
static UnresolvedCustomSettingNodeV3* create(std::shared_ptr<UnresolvedCustomSettingV3> setting, float width);
|
||||
|
||||
bool hasUncommittedChanges() const override;
|
||||
bool hasNonDefaultValue() const override;
|
||||
void resetToDefault() override;
|
||||
|
||||
std::shared_ptr<UnresolvedCustomSettingV3> getSetting() const;
|
||||
};
|
||||
|
||||
// If these classes do get exposed in headers, this SHOULD NOT BE EXPOSED!!!!!! DO NOT DO THAT!!!!
|
||||
|
||||
class LegacyCustomSettingToV3Node : public SettingNodeV3 {
|
||||
protected:
|
||||
SettingNode* m_original;
|
||||
|
||||
bool init(std::shared_ptr<UnresolvedCustomSettingV3> original, float width);
|
||||
|
||||
void onCommit() override;
|
||||
|
||||
public:
|
||||
static LegacyCustomSettingToV3Node* create(std::shared_ptr<UnresolvedCustomSettingV3> original, float width);
|
||||
|
||||
bool hasUncommittedChanges() const override;
|
||||
bool hasNonDefaultValue() const override;
|
||||
void resetToDefault() override;
|
||||
};
|
|
@ -1,5 +1,8 @@
|
|||
#include <Geode/loader/SettingV3.hpp>
|
||||
#include <Geode/utils/JsonValidation.hpp>
|
||||
#include <regex>
|
||||
#include "SettingV3Impl.hpp"
|
||||
#include "SettingNodeV3.hpp"
|
||||
|
||||
using namespace geode::prelude;
|
||||
|
||||
|
@ -11,12 +14,7 @@ public:
|
|||
|
||||
SettingV3::~SettingV3() = default;
|
||||
|
||||
SettingV3::SettingV3(std::string const& key, std::string const& modID)
|
||||
: m_impl(std::make_shared<GeodeImpl>())
|
||||
{
|
||||
m_impl->key = key;
|
||||
m_impl->modID = modID;
|
||||
}
|
||||
SettingV3::SettingV3() : m_impl(std::make_shared<GeodeImpl>()) {}
|
||||
|
||||
std::string SettingV3::getKey() const {
|
||||
return m_impl->key;
|
||||
|
@ -28,7 +26,13 @@ Mod* SettingV3::getMod() const {
|
|||
return Loader::get()->getInstalledMod(m_impl->modID);
|
||||
}
|
||||
|
||||
Result<std::shared_ptr<SettingV3>> SettingV3::parseBuiltin(std::string const& modID, matjson::Value const& json) {
|
||||
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<std::shared_ptr<SettingV3>> 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);
|
||||
|
@ -41,29 +45,30 @@ Result<std::shared_ptr<SettingV3>> SettingV3::parseBuiltin(std::string const& mo
|
|||
case hash("rgb"): case hash("color"): ret = std::make_shared<Color3BSettingV3>(); break;
|
||||
case hash("rgba"): ret = std::make_shared<Color4BSettingV3>(); break;
|
||||
case hash("path"): case hash("file"): ret = std::make_shared<FileSettingV3>(); break;
|
||||
case hash("custom"): ret = std::make_shared<UnresolvedCustomSettingV3>(); break;
|
||||
case hash("title"): ret = std::make_shared<TitleSettingV3>(); break;
|
||||
default:
|
||||
case hash("custom"): ret = std::make_shared<UnresolvedCustomSettingV3>(); break;
|
||||
}
|
||||
GEODE_UNWRAP(ret->parse(modID, json));
|
||||
return root.ok(ret);
|
||||
GEODE_UNWRAP(ret->parse(key, modID, json));
|
||||
return root.ok(std::move(ret));
|
||||
}
|
||||
|
||||
std::optional<Setting> SettingV3::convertToLegacy() const {
|
||||
return std::nullopt;
|
||||
}
|
||||
std::optional<std::unique_ptr<SettingValue>> SettingV3::convertToLegacyValue() const {
|
||||
std::optional<std::shared_ptr<SettingValue>> SettingV3::convertToLegacyValue() const {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
class geode::detail::GeodeSettingBaseV3::Impl final {
|
||||
public:
|
||||
std::string name;
|
||||
std::optional<std::string> name;
|
||||
std::optional<std::string> description;
|
||||
std::optional<std::string> enableIf;
|
||||
};
|
||||
|
||||
std::string geode::detail::GeodeSettingBaseV3::getName() const {
|
||||
return m_impl->name;
|
||||
return m_impl->name.value_or(this->getKey());
|
||||
}
|
||||
std::optional<std::string> geode::detail::GeodeSettingBaseV3::getDescription() const {
|
||||
return m_impl->description;
|
||||
|
@ -73,9 +78,9 @@ std::optional<std::string> geode::detail::GeodeSettingBaseV3::getEnableIf() cons
|
|||
}
|
||||
|
||||
Result<> geode::detail::GeodeSettingBaseV3::parseShared(JsonExpectedValue& json) {
|
||||
json.needs("name").into(m_impl->name);
|
||||
json.needs("description").into(m_impl->description);
|
||||
json.needs("enable-if").into(m_impl->enableIf);
|
||||
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 {
|
||||
|
@ -93,7 +98,7 @@ std::string TitleSettingV3::getTitle() const {
|
|||
return m_impl->title;
|
||||
}
|
||||
|
||||
Result<> TitleSettingV3::parse(std::string const& modID, matjson::Value const& json) {
|
||||
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();
|
||||
|
@ -106,19 +111,22 @@ bool TitleSettingV3::save(matjson::Value&) const {
|
|||
return true;
|
||||
}
|
||||
SettingNodeV3* TitleSettingV3::createNode(float width) {
|
||||
// todo
|
||||
return TitleSettingNodeV3::create(
|
||||
std::static_pointer_cast<TitleSettingV3>(shared_from_this()), width
|
||||
);
|
||||
}
|
||||
bool TitleSettingV3::isDefaultValue() const {
|
||||
return true;
|
||||
}
|
||||
void TitleSettingV3::reset() {}
|
||||
|
||||
class UnresolvedCustomSettingV3::Impl final {
|
||||
public:
|
||||
matjson::Value json;
|
||||
};
|
||||
// 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
|
||||
|
||||
Result<> UnresolvedCustomSettingV3::parse(std::string const& modID, matjson::Value const& json) {
|
||||
Result<> UnresolvedCustomSettingV3::onParse(std::string const& key, std::string const& modID, matjson::Value const& json) {
|
||||
m_impl->json = json;
|
||||
return Ok();
|
||||
}
|
||||
|
@ -129,7 +137,14 @@ bool UnresolvedCustomSettingV3::save(matjson::Value& json) const {
|
|||
return true;
|
||||
}
|
||||
SettingNodeV3* UnresolvedCustomSettingV3::createNode(float width) {
|
||||
// todo
|
||||
if (m_impl->legacyValue) {
|
||||
return LegacyCustomSettingToV3Node::create(
|
||||
std::static_pointer_cast<UnresolvedCustomSettingV3>(shared_from_this()), width
|
||||
);
|
||||
}
|
||||
return UnresolvedCustomSettingNodeV3::create(
|
||||
std::static_pointer_cast<UnresolvedCustomSettingV3>(shared_from_this()), width
|
||||
);
|
||||
}
|
||||
|
||||
bool UnresolvedCustomSettingV3::isDefaultValue() const {
|
||||
|
@ -142,8 +157,8 @@ std::optional<Setting> UnresolvedCustomSettingV3::convertToLegacy() const {
|
|||
.json = std::make_shared<ModJson>(m_impl->json)
|
||||
}));
|
||||
}
|
||||
std::optional<std::unique_ptr<SettingValue>> UnresolvedCustomSettingV3::convertToLegacyValue() const {
|
||||
return std::nullopt;
|
||||
std::optional<std::shared_ptr<SettingValue>> UnresolvedCustomSettingV3::convertToLegacyValue() const {
|
||||
return m_impl->legacyValue ? std::optional(m_impl->legacyValue) : std::nullopt;
|
||||
}
|
||||
|
||||
class BoolSettingV3::Impl final {
|
||||
|
@ -152,22 +167,18 @@ public:
|
|||
bool defaultValue;
|
||||
};
|
||||
|
||||
bool BoolSettingV3::getValue() const {
|
||||
bool& BoolSettingV3::getValueMut() const {
|
||||
return m_impl->value;
|
||||
}
|
||||
void BoolSettingV3::setValue(bool value) {
|
||||
m_impl->value = value;
|
||||
bool BoolSettingV3::getDefaultValue() const {
|
||||
return m_impl->defaultValue;
|
||||
}
|
||||
Result<> BoolSettingV3::isValid(bool value) const {
|
||||
GEODE_UNWRAP(this->isValidShared());
|
||||
return Ok();
|
||||
}
|
||||
|
||||
bool BoolSettingV3::getDefaultValue() const {
|
||||
return m_impl->defaultValue;
|
||||
}
|
||||
|
||||
Result<> BoolSettingV3::parse(std::string const& modID, matjson::Value const& json) {
|
||||
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));
|
||||
|
@ -189,13 +200,9 @@ bool BoolSettingV3::save(matjson::Value& json) const {
|
|||
return true;
|
||||
}
|
||||
SettingNodeV3* BoolSettingV3::createNode(float width) {
|
||||
// todo
|
||||
}
|
||||
bool BoolSettingV3::isDefaultValue() const {
|
||||
return m_impl->value == m_impl->defaultValue;
|
||||
}
|
||||
void BoolSettingV3::reset() {
|
||||
m_impl->value = m_impl->defaultValue;
|
||||
return BoolSettingNodeV3::create(
|
||||
std::static_pointer_cast<BoolSettingV3>(shared_from_this()), width
|
||||
);
|
||||
}
|
||||
|
||||
std::optional<Setting> BoolSettingV3::convertToLegacy() const {
|
||||
|
@ -205,8 +212,8 @@ std::optional<Setting> BoolSettingV3::convertToLegacy() const {
|
|||
.defaultValue = this->getDefaultValue(),
|
||||
}));
|
||||
}
|
||||
std::optional<std::unique_ptr<SettingValue>> BoolSettingV3::convertToLegacyValue() const {
|
||||
return std::make_unique<BoolSettingValue>(this->getKey(), this->getModID(), *this->convertToLegacy());
|
||||
std::optional<std::shared_ptr<SettingValue>> BoolSettingV3::convertToLegacyValue() const {
|
||||
return this->convertToLegacy()->createDefaultValue();
|
||||
}
|
||||
|
||||
class IntSettingV3::Impl final {
|
||||
|
@ -226,6 +233,30 @@ public:
|
|||
} controls;
|
||||
};
|
||||
|
||||
int64_t& IntSettingV3::getValueMut() const {
|
||||
return m_impl->value;
|
||||
}
|
||||
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);
|
||||
}
|
||||
if (m_impl->maxValue && value > *m_impl->maxValue) {
|
||||
return Err("value must be at most {}", *m_impl->maxValue);
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
|
||||
std::optional<int64_t> IntSettingV3::getMinValue() const {
|
||||
return m_impl->minValue;
|
||||
}
|
||||
std::optional<int64_t> IntSettingV3::getMaxValue() const {
|
||||
return m_impl->maxValue;
|
||||
}
|
||||
|
||||
bool IntSettingV3::isArrowsEnabled() const {
|
||||
return m_impl->controls.arrowStepSize > 0;
|
||||
}
|
||||
|
@ -248,27 +279,7 @@ bool IntSettingV3::isInputEnabled() const {
|
|||
return m_impl->controls.textInputEnabled;
|
||||
}
|
||||
|
||||
int64_t IntSettingV3::getValue() const {
|
||||
return m_impl->value;
|
||||
}
|
||||
void IntSettingV3::setValue(int64_t value) {
|
||||
m_impl->value = clamp(
|
||||
value,
|
||||
m_impl->minValue.value_or(std::numeric_limits<int64_t>::min()),
|
||||
m_impl->maxValue.value_or(std::numeric_limits<int64_t>::max())
|
||||
);
|
||||
}
|
||||
int64_t IntSettingV3::getDefaultValue() const {
|
||||
return m_impl->defaultValue;
|
||||
}
|
||||
std::optional<int64_t> IntSettingV3::getMinValue() const {
|
||||
return m_impl->minValue;
|
||||
}
|
||||
std::optional<int64_t> IntSettingV3::getMaxValue() const {
|
||||
return m_impl->maxValue;
|
||||
}
|
||||
|
||||
Result<> IntSettingV3::parse(std::string const& modID, matjson::Value const& json) {
|
||||
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));
|
||||
|
@ -307,14 +318,9 @@ bool IntSettingV3::save(matjson::Value& json) const {
|
|||
return true;
|
||||
}
|
||||
SettingNodeV3* IntSettingV3::createNode(float width) {
|
||||
// todo
|
||||
}
|
||||
|
||||
bool IntSettingV3::isDefaultValue() const {
|
||||
return m_impl->value == m_impl->defaultValue;
|
||||
}
|
||||
void IntSettingV3::reset() {
|
||||
m_impl->value = m_impl->defaultValue;
|
||||
return IntSettingNodeV3::create(
|
||||
std::static_pointer_cast<IntSettingV3>(shared_from_this()), width
|
||||
);
|
||||
}
|
||||
|
||||
std::optional<Setting> IntSettingV3::convertToLegacy() const {
|
||||
|
@ -335,8 +341,8 @@ std::optional<Setting> IntSettingV3::convertToLegacy() const {
|
|||
},
|
||||
}));
|
||||
}
|
||||
std::optional<std::unique_ptr<SettingValue>> IntSettingV3::convertToLegacyValue() const {
|
||||
return std::make_unique<IntSettingValue>(this->getKey(), this->getModID(), *this->convertToLegacy());
|
||||
std::optional<std::shared_ptr<SettingValue>> IntSettingV3::convertToLegacyValue() const {
|
||||
return this->convertToLegacy()->createDefaultValue();
|
||||
}
|
||||
|
||||
class FloatSettingV3::Impl final {
|
||||
|
@ -356,6 +362,30 @@ public:
|
|||
} controls;
|
||||
};
|
||||
|
||||
double& FloatSettingV3::getValueMut() const {
|
||||
return m_impl->value;
|
||||
}
|
||||
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);
|
||||
}
|
||||
if (m_impl->maxValue && value > *m_impl->maxValue) {
|
||||
return Err("value must be at most {}", *m_impl->maxValue);
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
|
||||
std::optional<double> FloatSettingV3::getMinValue() const {
|
||||
return m_impl->minValue;
|
||||
}
|
||||
std::optional<double> FloatSettingV3::getMaxValue() const {
|
||||
return m_impl->maxValue;
|
||||
}
|
||||
|
||||
bool FloatSettingV3::isArrowsEnabled() const {
|
||||
return m_impl->controls.arrowStepSize > 0;
|
||||
}
|
||||
|
@ -378,30 +408,7 @@ bool FloatSettingV3::isInputEnabled() const {
|
|||
return m_impl->controls.textInputEnabled;
|
||||
}
|
||||
|
||||
double FloatSettingV3::getValue() const {
|
||||
return m_impl->value;
|
||||
}
|
||||
Result<> FloatSettingV3::setValue(double value) {
|
||||
if (m_impl->minValue && value < *m_impl->minValue) {
|
||||
return Err("Value must be under ");
|
||||
}
|
||||
m_impl->value = clamp(
|
||||
value,
|
||||
m_impl->minValue.value_or(std::numeric_limits<double>::min()),
|
||||
m_impl->maxValue.value_or(std::numeric_limits<double>::max())
|
||||
);
|
||||
}
|
||||
double FloatSettingV3::getDefaultValue() const {
|
||||
return m_impl->defaultValue;
|
||||
}
|
||||
std::optional<double> FloatSettingV3::getMinValue() const {
|
||||
return m_impl->minValue;
|
||||
}
|
||||
std::optional<double> FloatSettingV3::getMaxValue() const {
|
||||
return m_impl->maxValue;
|
||||
}
|
||||
|
||||
Result<> FloatSettingV3::parse(std::string const& modID, matjson::Value const& json) {
|
||||
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));
|
||||
|
@ -440,14 +447,9 @@ bool FloatSettingV3::save(matjson::Value& json) const {
|
|||
return true;
|
||||
}
|
||||
SettingNodeV3* FloatSettingV3::createNode(float width) {
|
||||
// todo
|
||||
}
|
||||
|
||||
bool FloatSettingV3::isDefaultValue() const {
|
||||
return m_impl->value == m_impl->defaultValue;
|
||||
}
|
||||
void FloatSettingV3::reset() {
|
||||
m_impl->value = m_impl->defaultValue;
|
||||
return FloatSettingNodeV3::create(
|
||||
std::static_pointer_cast<FloatSettingV3>(shared_from_this()), width
|
||||
);
|
||||
}
|
||||
|
||||
std::optional<Setting> FloatSettingV3::convertToLegacy() const {
|
||||
|
@ -468,8 +470,8 @@ std::optional<Setting> FloatSettingV3::convertToLegacy() const {
|
|||
},
|
||||
}));
|
||||
}
|
||||
std::optional<std::unique_ptr<SettingValue>> FloatSettingV3::convertToLegacyValue() const {
|
||||
return std::make_unique<FloatSettingValue>(this->getKey(), this->getModID(), *this->convertToLegacy());
|
||||
std::optional<std::shared_ptr<SettingValue>> FloatSettingV3::convertToLegacyValue() const {
|
||||
return this->convertToLegacy()->createDefaultValue();
|
||||
}
|
||||
|
||||
class StringSettingV3::Impl final {
|
||||
|
@ -481,15 +483,26 @@ public:
|
|||
std::optional<std::vector<std::string>> oneOf;
|
||||
};
|
||||
|
||||
std::string StringSettingV3::getValue() const {
|
||||
std::string& StringSettingV3::getValueMut() const {
|
||||
return m_impl->value;
|
||||
}
|
||||
Result<> StringSettingV3::setValue(std::string_view value) {
|
||||
m_impl->value = value;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
else if (m_impl->oneOf) {
|
||||
if (!ranges::contains(*m_impl->oneOf, std::string(value))) {
|
||||
return Err("value must be one of {}", fmt::join(*m_impl->oneOf, ", "));
|
||||
}
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
|
||||
std::optional<std::string> StringSettingV3::getRegexValidator() const {
|
||||
return m_impl->match;
|
||||
|
@ -501,7 +514,7 @@ std::optional<std::vector<std::string>> StringSettingV3::getEnumOptions() const
|
|||
return m_impl->oneOf;
|
||||
}
|
||||
|
||||
Result<> StringSettingV3::parse(std::string const& modID, matjson::Value const& json) {
|
||||
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));
|
||||
|
@ -527,14 +540,9 @@ bool StringSettingV3::save(matjson::Value& json) const {
|
|||
return true;
|
||||
}
|
||||
SettingNodeV3* StringSettingV3::createNode(float width) {
|
||||
// todo
|
||||
}
|
||||
|
||||
bool StringSettingV3::isDefaultValue() const {
|
||||
return m_impl->value == m_impl->defaultValue;
|
||||
}
|
||||
void StringSettingV3::reset() {
|
||||
m_impl->value = m_impl->defaultValue;
|
||||
return StringSettingNodeV3::create(
|
||||
std::static_pointer_cast<StringSettingV3>(shared_from_this()), width
|
||||
);
|
||||
}
|
||||
|
||||
std::optional<Setting> StringSettingV3::convertToLegacy() const {
|
||||
|
@ -547,8 +555,8 @@ std::optional<Setting> StringSettingV3::convertToLegacy() const {
|
|||
setting.controls->options = this->getEnumOptions();
|
||||
return Setting(this->getKey(), this->getModID(), SettingKind(setting));
|
||||
}
|
||||
std::optional<std::unique_ptr<SettingValue>> StringSettingV3::convertToLegacyValue() const {
|
||||
return std::make_unique<StringSettingValue>(this->getKey(), this->getModID(), *this->convertToLegacy());
|
||||
std::optional<std::shared_ptr<SettingValue>> StringSettingV3::convertToLegacyValue() const {
|
||||
return this->convertToLegacy()->createDefaultValue();
|
||||
}
|
||||
|
||||
class FileSettingV3::Impl final {
|
||||
|
@ -558,17 +566,22 @@ public:
|
|||
std::optional<std::vector<utils::file::FilePickOptions::Filter>> filters;
|
||||
};
|
||||
|
||||
std::filesystem::path& FileSettingV3::getValueMut() const {
|
||||
return m_impl->value;
|
||||
}
|
||||
std::filesystem::path FileSettingV3::getDefaultValue() const {
|
||||
return m_impl->defaultValue;
|
||||
}
|
||||
std::filesystem::path FileSettingV3::getValue() const {
|
||||
return m_impl->value;
|
||||
Result<> FileSettingV3::isValid(std::filesystem::path const& value) const {
|
||||
GEODE_UNWRAP(this->isValidShared());
|
||||
return Ok();
|
||||
}
|
||||
|
||||
std::optional<std::vector<utils::file::FilePickOptions::Filter>> FileSettingV3::getFilters() const {
|
||||
return m_impl->filters;
|
||||
}
|
||||
|
||||
Result<> FileSettingV3::parse(std::string const& modID, matjson::Value const& json) {
|
||||
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));
|
||||
|
@ -618,15 +631,10 @@ bool FileSettingV3::save(matjson::Value& json) const {
|
|||
json = m_impl->value;
|
||||
return true;
|
||||
}
|
||||
SettingNodeV3* createNode(float width) {
|
||||
// todo
|
||||
}
|
||||
|
||||
bool FileSettingV3::isDefaultValue() const {
|
||||
return m_impl->value == m_impl->defaultValue;
|
||||
}
|
||||
void FileSettingV3::reset() {
|
||||
m_impl->value = m_impl->defaultValue;
|
||||
SettingNodeV3* FileSettingV3::createNode(float width) {
|
||||
return FileSettingNodeV3::create(
|
||||
std::static_pointer_cast<FileSettingV3>(shared_from_this()), width
|
||||
);
|
||||
}
|
||||
|
||||
std::optional<Setting> FileSettingV3::convertToLegacy() const {
|
||||
|
@ -637,8 +645,8 @@ std::optional<Setting> FileSettingV3::convertToLegacy() const {
|
|||
setting.controls.filters = this->getFilters().value_or(std::vector<utils::file::FilePickOptions::Filter>());
|
||||
return Setting(this->getKey(), this->getModID(), SettingKind(setting));
|
||||
}
|
||||
std::optional<std::unique_ptr<SettingValue>> FileSettingV3::convertToLegacyValue() const {
|
||||
return std::make_unique<FileSettingValue>(this->getKey(), this->getModID(), *this->convertToLegacy());
|
||||
std::optional<std::shared_ptr<SettingValue>> FileSettingV3::convertToLegacyValue() const {
|
||||
return this->convertToLegacy()->createDefaultValue();
|
||||
}
|
||||
|
||||
class Color3BSettingV3::Impl final {
|
||||
|
@ -647,14 +655,18 @@ public:
|
|||
ccColor3B defaultValue;
|
||||
};
|
||||
|
||||
ccColor3B& Color3BSettingV3::getValueMut() const {
|
||||
return m_impl->value;
|
||||
}
|
||||
ccColor3B Color3BSettingV3::getDefaultValue() const {
|
||||
return m_impl->defaultValue;
|
||||
}
|
||||
ccColor3B Color3BSettingV3::getValue() const {
|
||||
return m_impl->value;
|
||||
Result<> Color3BSettingV3::isValid(ccColor3B value) const {
|
||||
GEODE_UNWRAP(this->isValidShared());
|
||||
return Ok();
|
||||
}
|
||||
|
||||
Result<> Color3BSettingV3::parse(std::string const& modID, matjson::Value const& json) {
|
||||
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));
|
||||
|
@ -676,15 +688,9 @@ bool Color3BSettingV3::save(matjson::Value& json) const {
|
|||
return true;
|
||||
}
|
||||
SettingNodeV3* Color3BSettingV3::createNode(float width) {
|
||||
// todo
|
||||
}
|
||||
|
||||
bool Color3BSettingV3::isDefaultValue() const {
|
||||
return m_impl->value == m_impl->defaultValue;
|
||||
|
||||
}
|
||||
void Color3BSettingV3::reset() {
|
||||
m_impl->value = m_impl->defaultValue;
|
||||
return Color3BSettingNodeV3::create(
|
||||
std::static_pointer_cast<Color3BSettingV3>(shared_from_this()), width
|
||||
);
|
||||
}
|
||||
|
||||
std::optional<Setting> Color3BSettingV3::convertToLegacy() const {
|
||||
|
@ -694,8 +700,8 @@ std::optional<Setting> Color3BSettingV3::convertToLegacy() const {
|
|||
setting.defaultValue = this->getDefaultValue();
|
||||
return Setting(this->getKey(), this->getModID(), SettingKind(setting));
|
||||
}
|
||||
std::optional<std::unique_ptr<SettingValue>> Color3BSettingV3::convertToLegacyValue() const {
|
||||
return std::make_unique<ColorSettingValue>(this->getKey(), this->getModID(), *this->convertToLegacy());
|
||||
std::optional<std::shared_ptr<SettingValue>> Color3BSettingV3::convertToLegacyValue() const {
|
||||
return this->convertToLegacy()->createDefaultValue();
|
||||
}
|
||||
|
||||
class Color4BSettingV3::Impl final {
|
||||
|
@ -704,14 +710,18 @@ public:
|
|||
ccColor4B defaultValue;
|
||||
};
|
||||
|
||||
ccColor4B& Color4BSettingV3::getValueMut() const {
|
||||
return m_impl->value;
|
||||
}
|
||||
ccColor4B Color4BSettingV3::getDefaultValue() const {
|
||||
return m_impl->defaultValue;
|
||||
}
|
||||
ccColor4B Color4BSettingV3::getValue() const {
|
||||
return m_impl->value;
|
||||
Result<> Color4BSettingV3::isValid(ccColor4B value) const {
|
||||
GEODE_UNWRAP(this->isValidShared());
|
||||
return Ok();
|
||||
}
|
||||
|
||||
Result<> Color4BSettingV3::parse(std::string const& modID, matjson::Value const& json) {
|
||||
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));
|
||||
|
@ -733,15 +743,9 @@ bool Color4BSettingV3::save(matjson::Value& json) const {
|
|||
return true;
|
||||
}
|
||||
SettingNodeV3* Color4BSettingV3::createNode(float width) {
|
||||
// todo
|
||||
}
|
||||
|
||||
bool Color4BSettingV3::isDefaultValue() const {
|
||||
return m_impl->value == m_impl->defaultValue;
|
||||
|
||||
}
|
||||
void Color4BSettingV3::reset() {
|
||||
m_impl->value = m_impl->defaultValue;
|
||||
return Color4BSettingNodeV3::create(
|
||||
std::static_pointer_cast<Color4BSettingV3>(shared_from_this()), width
|
||||
);
|
||||
}
|
||||
|
||||
std::optional<Setting> Color4BSettingV3::convertToLegacy() const {
|
||||
|
@ -751,6 +755,6 @@ std::optional<Setting> Color4BSettingV3::convertToLegacy() const {
|
|||
setting.defaultValue = this->getDefaultValue();
|
||||
return Setting(this->getKey(), this->getModID(), SettingKind(setting));
|
||||
}
|
||||
std::optional<std::unique_ptr<SettingValue>> Color4BSettingV3::convertToLegacyValue() const {
|
||||
return std::make_unique<ColorAlphaSettingValue>(this->getKey(), this->getModID(), *this->convertToLegacy());
|
||||
std::optional<std::shared_ptr<SettingValue>> Color4BSettingV3::convertToLegacyValue() const {
|
||||
return this->convertToLegacy()->createDefaultValue();
|
||||
}
|
||||
|
|
18
loader/src/loader/SettingV3Impl.hpp
Normal file
18
loader/src/loader/SettingV3Impl.hpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include <Geode/loader/SettingV3.hpp>
|
||||
|
||||
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<SettingValue> legacyValue = nullptr;
|
||||
};
|
||||
|
|
@ -19,8 +19,8 @@ enum class GeodePopupStyle {
|
|||
template <class... Args>
|
||||
class GeodePopup : public Popup<Args...> {
|
||||
protected:
|
||||
bool init(float width, float height, Args... args, GeodePopupStyle style = GeodePopupStyle::Default) {
|
||||
const bool geodeTheme = Mod::get()->template getSettingValue<bool>("enable-geode-theme");
|
||||
bool init(float width, float height, Args... args, GeodePopupStyle style = GeodePopupStyle::Default, bool forceDisableTheme = false) {
|
||||
const bool geodeTheme = !forceDisableTheme && Mod::get()->template getSettingValue<bool>("enable-geode-theme");
|
||||
const char* bg;
|
||||
switch (style) {
|
||||
default:
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
#include "ModSettingsPopup.hpp"
|
||||
|
||||
#include <Geode/binding/ButtonSprite.hpp>
|
||||
#include <Geode/loader/Mod.hpp>
|
||||
#include <Geode/loader/Setting.hpp>
|
||||
#include <Geode/ui/ScrollLayer.hpp>
|
||||
#include <Geode/utils/cocos.hpp>
|
||||
#include <Geode/ui/General.hpp>
|
||||
#include "GeodeSettingNode.hpp"
|
||||
|
||||
bool ModSettingsPopup::setup(Mod* mod) {
|
||||
m_noElasticity = true;
|
||||
|
@ -25,56 +23,41 @@ bool ModSettingsPopup::setup(Mod* mod) {
|
|||
auto layer = ScrollLayer::create(layerSize);
|
||||
layer->setTouchEnabled(true);
|
||||
|
||||
float totalHeight = .0f;
|
||||
std::vector<CCNode*> rendered;
|
||||
bool hasBG = true;
|
||||
bool hasBG = false;
|
||||
for (auto& key : mod->getSettingKeys()) {
|
||||
SettingNode* node;
|
||||
if (auto sett = mod->getSetting(key)) {
|
||||
hasBG = !hasBG;
|
||||
|
||||
auto bg = CCLayerColor::create({ 0, 0, 0, 50 });
|
||||
bg->setOpacity(hasBG ? 50 : 0);
|
||||
|
||||
SettingNodeV3* node;
|
||||
if (auto sett = mod->getSettingV3(key)) {
|
||||
node = sett->createNode(layerSize.width);
|
||||
}
|
||||
else {
|
||||
node = CustomSettingPlaceholderNode::create(key, layerSize.width);
|
||||
// todo: placeholder node
|
||||
continue;
|
||||
}
|
||||
node->setDelegate(this);
|
||||
|
||||
totalHeight += node->getScaledContentSize().height;
|
||||
|
||||
if (hasBG) {
|
||||
auto bg = CCLayerColor::create({ 0, 0, 0, 50 });
|
||||
bg->setContentSize(node->getScaledContentSize());
|
||||
bg->setPosition(0.f, -totalHeight);
|
||||
bg->setZOrder(-10);
|
||||
layer->m_contentLayer->addChild(bg);
|
||||
bg->addChildAtPosition(node, Anchor::Center);
|
||||
|
||||
rendered.push_back(bg);
|
||||
auto separator = CCLayerColor::create({ 0, 0, 0, 50 }, layerSize.width, 1.f);
|
||||
separator->setOpacity(hasBG ? 100 : 50);
|
||||
bg->addChildAtPosition(separator, Anchor::Bottom);
|
||||
|
||||
hasBG = false;
|
||||
}
|
||||
else {
|
||||
hasBG = true;
|
||||
}
|
||||
|
||||
node->setPosition(0.f, -totalHeight);
|
||||
layer->m_contentLayer->addChild(node);
|
||||
|
||||
auto separator = CCLayerColor::create(
|
||||
{ 0, 0, 0, static_cast<GLubyte>(hasBG ? 100 : 50) }, layerSize.width, 1.f
|
||||
);
|
||||
separator->setPosition(0.f, -totalHeight);
|
||||
layer->m_contentLayer->addChild(separator);
|
||||
rendered.push_back(separator);
|
||||
|
||||
rendered.push_back(node);
|
||||
m_settings.push_back(node);
|
||||
|
||||
layer->m_contentLayer->addChild(bg);
|
||||
}
|
||||
if (totalHeight < layerSize.height) {
|
||||
totalHeight = layerSize.height;
|
||||
}
|
||||
for (auto& node : rendered) {
|
||||
node->setPositionY(node->getPositionY() + totalHeight);
|
||||
}
|
||||
layer->m_contentLayer->setContentSize({ layerSize.width, totalHeight });
|
||||
layer->m_contentLayer->setLayout(
|
||||
ColumnLayout::create()
|
||||
->setAxisReverse(true)
|
||||
->setAutoGrowAxis(layerSize.height)
|
||||
->setCrossAxisOverflow(false)
|
||||
->setAxisAlignment(AxisAlignment::End)
|
||||
->setGap(0)
|
||||
);
|
||||
layer->moveToTop();
|
||||
|
||||
layerBG->addChild(layer);
|
||||
|
@ -109,7 +92,11 @@ bool ModSettingsPopup::setup(Mod* mod) {
|
|||
);
|
||||
m_buttonMenu->addChildAtPosition(openDirBtn, Anchor::BottomRight, ccp(-53, 20));
|
||||
|
||||
this->settingValueChanged(nullptr);
|
||||
m_changeListener.bind([this](auto) {
|
||||
this->updateState();
|
||||
return ListenerResult::Propagate;
|
||||
});
|
||||
this->updateState();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -143,18 +130,7 @@ void ModSettingsPopup::onResetAll(CCObject*) {
|
|||
);
|
||||
}
|
||||
|
||||
void ModSettingsPopup::settingValueCommitted(SettingNode*) {
|
||||
if (this->hasUncommitted()) {
|
||||
m_applyBtnSpr->setColor({0xff, 0xff, 0xff});
|
||||
m_applyBtn->setEnabled(true);
|
||||
}
|
||||
else {
|
||||
m_applyBtnSpr->setColor({0x44, 0x44, 0x44});
|
||||
m_applyBtn->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ModSettingsPopup::settingValueChanged(SettingNode*) {
|
||||
void ModSettingsPopup::updateState() {
|
||||
if (this->hasUncommitted()) {
|
||||
m_applyBtnSpr->setColor({0xff, 0xff, 0xff});
|
||||
m_applyBtn->setEnabled(true);
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include <Geode/loader/SettingNode.hpp>
|
||||
#include <Geode/loader/SettingV3.hpp>
|
||||
#include <Geode/ui/Popup.hpp>
|
||||
#include <Geode/utils/cocos.hpp>
|
||||
#include "../GeodeStyle.hpp"
|
||||
|
||||
using namespace geode::prelude;
|
||||
|
||||
class ModSettingsPopup : public GeodePopup<Mod*>, public SettingNodeDelegate {
|
||||
class ModSettingsPopup : public GeodePopup<Mod*> {
|
||||
protected:
|
||||
Mod* m_mod;
|
||||
std::vector<SettingNode*> m_settings;
|
||||
std::vector<SettingNodeV3*> m_settings;
|
||||
CCMenuItemSpriteExtra* m_applyBtn;
|
||||
ButtonSprite* m_applyBtnSpr;
|
||||
|
||||
void settingValueChanged(SettingNode*) override;
|
||||
void settingValueCommitted(SettingNode*) override;
|
||||
EventListener<EventFilter<SettingNodeValueChangeEventV3>> m_changeListener;
|
||||
|
||||
bool setup(Mod* mod) override;
|
||||
void updateState();
|
||||
void onChangeEvent(SettingNodeValueChangeEventV3* event);
|
||||
bool hasUncommitted() const;
|
||||
void onClose(CCObject*) override;
|
||||
void onApply(CCObject*);
|
||||
|
|
|
@ -224,7 +224,7 @@ JsonExpectedValue::JsonExpectedValue(Impl* from, matjson::Value& scope, std::str
|
|||
: m_impl(std::make_unique<Impl>(from, scope, key))
|
||||
{}
|
||||
JsonExpectedValue::JsonExpectedValue(matjson::Value const& json, std::string_view rootScopeName)
|
||||
: m_impl(std::make_unique<Impl>(std::make_shared<matjson::Value>(json, rootScopeName)))
|
||||
: m_impl(std::make_unique<Impl>(std::make_shared<Impl::Shared>(json, rootScopeName)))
|
||||
{}
|
||||
JsonExpectedValue::~JsonExpectedValue() {}
|
||||
|
||||
|
@ -389,7 +389,7 @@ std::vector<JsonExpectedValue> JsonExpectedValue::items() {
|
|||
if (this->hasError()) {
|
||||
return std::vector<JsonExpectedValue>();
|
||||
}
|
||||
if (!this->assertIs(matjson::Type::Object)) {
|
||||
if (!this->assertIs(matjson::Type::Array)) {
|
||||
return std::vector<JsonExpectedValue>();
|
||||
}
|
||||
std::vector<JsonExpectedValue> res;
|
||||
|
|
Loading…
Reference in a new issue