Skip to content

Commit

Permalink
Merge pull request #1073 from geode-sdk/settings
Browse files Browse the repository at this point in the history
Settings Rework
  • Loading branch information
HJfod authored Sep 10, 2024
2 parents aedd986 + 361102e commit 67814ec
Show file tree
Hide file tree
Showing 51 changed files with 4,609 additions and 545 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Geode Changelog

## v3.6.0
* Major rework of the entire settings system with lots of new features; see the [docs page](https://docs.geode-sdk.org/mods/settings) for more
* Rework JSON validation; now uses the `JsonExpectedValue` class with the `checkJson` helper (89d1a51)
* Add `Task::cancelled` for creating immediately cancelled Tasks (1a82d12)
* Add function type utilities in `utils/function.hpp` (659c168)
* Add `typeinfo_pointer_cast` for casting `std::shared_ptr`s (28cc6fd)
* Add `GEODE_PLATFORM_SHORT_IDENTIFIER_NOARCH` (1032d9a)
* Add `PlatformID::getCovered` (d5718be)
* Rename `toByteArray` to `toBytes` (6eb0797)
* Improve `AxisLayout::getSizeHint` (85e7b5e)
* Fix issues with file dialogs on Windows (62b6241, 971e3fb)
* Mod incompatibilities may now be platform-specific (9f1c70a)

## v3.5.0
* Move CCLighting to cocos headers (#1036)
* Add new `gd::string` constructor (bae22b4)
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.5.0
3.6.0
53 changes: 48 additions & 5 deletions loader/include/Geode/loader/Mod.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "Hook.hpp"
#include "ModMetadata.hpp"
#include "Setting.hpp"
#include "SettingV3.hpp"
#include "Types.hpp"
#include "Loader.hpp"

Expand All @@ -23,6 +24,8 @@
#include <vector>

namespace geode {
class SettingV3;

template <class T>
struct HandleToSaved : public T {
Mod* m_mod;
Expand Down Expand Up @@ -170,12 +173,32 @@ namespace geode {
*/
std::filesystem::path getConfigDir(bool create = true) const;

/**
* Returns true if this mod has any settings
*/
bool hasSettings() const;
/**
* Get a list of all this mod's setting keys (in the order they were
* declared in `mod.json`)
*/
std::vector<std::string> getSettingKeys() const;
bool hasSetting(std::string_view const key) const;

// todo in v4: remove these
[[deprecated("Use Mod::getSettingV3")]]
std::optional<Setting> getSettingDefinition(std::string_view const key) const;
[[deprecated("Use Mod::getSettingV3")]]
SettingValue* getSetting(std::string_view const key) const;

// todo in v4: possibly rename this to getSetting?
/**
* Get the definition of a setting, or null if the setting was not found,
* or if it's a custom setting that has not yet been registered using
* `Mod::registerCustomSettingType`
* @param key The key of the setting as defined in `mod.json`
*/
std::shared_ptr<SettingV3> getSettingV3(std::string_view const key) const;

/**
* Register a custom setting's value class. See Mod::addCustomSetting
* for a convenience wrapper that creates the value in-place to avoid
Expand All @@ -186,6 +209,7 @@ namespace geode {
* @param value The SettingValue class that shall handle this setting
* @see addCustomSetting
*/
[[deprecated("Use Mod::registerCustomSettingType")]]
void registerCustomSetting(std::string_view const key, std::unique_ptr<SettingValue> value);
/**
* Register a custom setting's value class. The new SettingValue class
Expand All @@ -200,10 +224,21 @@ namespace geode {
* }
*/
template <class T, class V>
[[deprecated("Use Mod::registerCustomSettingType")]]
void addCustomSetting(std::string_view const key, V const& value) {
this->registerCustomSetting(key, std::make_unique<T>(std::string(key), this->getID(), value));
}

/**
* Register a custom setting type. See
* [the setting docs](https://docs.geode-sdk.org/mods/settings) for more
* @param type The type of the setting. This should **not** include the
* `custom:` prefix!
* @param generator A pointer to a function that, when called, returns a
* newly-created instance of the setting type
*/
Result<> registerCustomSettingType(std::string_view type, SettingGenerator generator);

/**
* Returns a prefixed launch argument name. See `Mod::getLaunchArgument`
* for details about mod-specific launch arguments.
Expand Down Expand Up @@ -246,19 +281,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 = cast::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 = cast::typeinfo_pointer_cast<S>(this->getSettingV3(key))) {
auto old = sett->getValue();
sett->setValue(value);
return old;
}
return T();
Expand Down
9 changes: 8 additions & 1 deletion loader/include/Geode/loader/ModMetadata.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,12 @@ namespace geode {
* Mod settings
* @note Not a map because insertion order must be preserved
*/
[[nodiscard]] std::vector<std::pair<std::string, Setting>> getSettings() const;
[[nodiscard, deprecated("Use getSettingsV3")]] std::vector<std::pair<std::string, Setting>> getSettings() const;
/**
* Mod settings
* @note Not a map because insertion order must be preserved
*/
[[nodiscard]] std::vector<std::pair<std::string, matjson::Value>> getSettingsV3() const;
/**
* Get the tags for this mod
*/
Expand Down Expand Up @@ -232,7 +237,9 @@ namespace geode {
void setDependencies(std::vector<Dependency> const& value);
void setIncompatibilities(std::vector<Incompatibility> const& value);
void setSpritesheets(std::vector<std::string> const& value);
[[deprecated("This function does NOTHING")]]
void setSettings(std::vector<std::pair<std::string, Setting>> const& value);
void setSettings(std::vector<std::pair<std::string, matjson::Value>> const& value);
void setTags(std::unordered_set<std::string> const& value);
void setNeedsEarlyLoad(bool const& value);
void setIsAPI(bool const& value);
Expand Down
56 changes: 56 additions & 0 deletions loader/include/Geode/loader/ModSettingsManager.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#pragma once

#include <Geode/DefaultInclude.hpp>
#include "SettingV3.hpp"

namespace geode {
class GEODE_DLL ModSettingsManager final {
private:
class Impl;
std::unique_ptr<Impl> m_impl;

friend class ::geode::SettingV3;

void markRestartRequired();

public:
static ModSettingsManager* from(Mod* mod);

ModSettingsManager(ModMetadata const& metadata);
~ModSettingsManager();

ModSettingsManager(ModSettingsManager&&);
ModSettingsManager(ModSettingsManager const&) = delete;

/**
* Load setting values from savedata.
* The format of the savedata should be an object with the keys being
* setting IDs and then the values the values of the saved settings
* @returns Ok if no horrible errors happened. Note that a setting value
* missing is not considered a horrible error, but will instead just log a
* warning into the console!
*/
Result<> load(matjson::Value const& json);
/**
* Save setting values to savedata.
* The format of the savedata will be an object with the keys being
* setting IDs and then the values the values of the saved settings
* @note If saving a setting fails, it will log a warning to the console
*/
void save(matjson::Value& json);

Result<> registerCustomSettingType(std::string_view type, SettingGenerator generator);
// todo in v4: remove this
Result<> registerLegacyCustomSetting(std::string_view key, std::unique_ptr<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);

/**
* Returns true if any setting with the `"restart-required"` attribute
* has been altered
*/
bool restartRequired() const;
};
}
8 changes: 4 additions & 4 deletions loader/include/Geode/loader/Setting.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand All @@ -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);
};
Expand Down
25 changes: 4 additions & 21 deletions loader/include/Geode/loader/SettingEvent.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@
#include "Loader.hpp"
#include "Setting.hpp"
#include "Mod.hpp"

#include "SettingV3.hpp"
#include <optional>

namespace geode {
struct GEODE_DLL SettingChangedEvent : public Event {
struct GEODE_DLL [[deprecated("Use SettingChangedEventV3 from SettingV3.hpp instead")]] SettingChangedEvent : public Event {
Mod* mod;
SettingValue* value;

SettingChangedEvent(Mod* mod, SettingValue* value);
};

class GEODE_DLL SettingChangedFilter : public EventFilter<SettingChangedEvent> {
class GEODE_DLL [[deprecated("Use SettingChangedEventV3 from SettingV3.hpp instead")]] SettingChangedFilter : public EventFilter<SettingChangedEvent> {
protected:
std::string m_modID;
std::optional<std::string> m_targetKey;
Expand All @@ -40,7 +40,7 @@ namespace geode {
* Listen for built-in setting changes
*/
template<class T>
class GeodeSettingChangedFilter : public SettingChangedFilter {
class [[deprecated("Use SettingChangedEventV3 from SettingV3.hpp instead")]] GeodeSettingChangedFilter : public SettingChangedFilter {
public:
using Callback = void(T);

Expand All @@ -60,21 +60,4 @@ namespace geode {
) : SettingChangedFilter(modID, settingID) {}
GeodeSettingChangedFilter(GeodeSettingChangedFilter const&) = default;
};

template <class T>
std::monostate listenForSettingChanges(
std::string const& settingKey, void (*callback)(T)
) {
(void)new EventListener(
callback, GeodeSettingChangedFilter<T>(getMod()->getID(), settingKey)
);
return std::monostate();
}

static std::monostate listenForAllSettingChanges(void (*callback)(SettingValue*)) {
(void)new EventListener(
callback, SettingChangedFilter(getMod()->getID(), std::nullopt)
);
return std::monostate();
}
}
Loading

0 comments on commit 67814ec

Please sign in to comment.