mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-14 19:15:05 -05:00
setting events & restart stuff
This commit is contained in:
parent
659c168a14
commit
6eb079735f
11 changed files with 185 additions and 25 deletions
|
@ -9,6 +9,10 @@ namespace geode {
|
|||
class Impl;
|
||||
std::unique_ptr<Impl> m_impl;
|
||||
|
||||
friend class ::geode::SettingV3;
|
||||
|
||||
void markRestartRequired();
|
||||
|
||||
public:
|
||||
static ModSettingsManager* from(Mod* mod);
|
||||
|
||||
|
@ -42,5 +46,11 @@ namespace geode {
|
|||
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;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "../utils/cocos.hpp"
|
||||
// this unfortunately has to be included because of C++ templates
|
||||
#include "../utils/JsonValidation.hpp"
|
||||
#include "../utils/function.hpp"
|
||||
|
||||
// todo in v4: this can be removed as well as the friend decl in LegacyCustomSettingV3
|
||||
class LegacyCustomSettingToV3Node;
|
||||
|
@ -16,6 +17,8 @@ class ModSettingsPopup;
|
|||
namespace geode {
|
||||
class ModSettingsManager;
|
||||
class SettingNodeV3;
|
||||
// todo in v4: remove this
|
||||
class SettingValue;
|
||||
|
||||
class GEODE_DLL SettingV3 : public std::enable_shared_from_this<SettingV3> {
|
||||
private:
|
||||
|
@ -27,6 +30,14 @@ namespace geode {
|
|||
Result<> parseSharedProperties(std::string const& key, std::string const& modID, matjson::Value const& value, bool onlyNameAndDesc = false);
|
||||
void parseSharedProperties(std::string const& key, std::string const& modID, JsonExpectedValue& value, bool onlyNameAndDesc = false);
|
||||
|
||||
/**
|
||||
* Mark that the value of this setting has changed. This should be
|
||||
* ALWAYS called on every setter that can modify the setting's state!
|
||||
*/
|
||||
void markChanged();
|
||||
|
||||
friend class ::geode::SettingValue;
|
||||
|
||||
public:
|
||||
SettingV3();
|
||||
virtual ~SettingV3();
|
||||
|
@ -120,6 +131,7 @@ namespace geode {
|
|||
}
|
||||
void setValue(V value) {
|
||||
this->getValueMut() = this->isValid(value) ? value : this->getDefaultValue();
|
||||
this->markChanged();
|
||||
}
|
||||
virtual Result<> isValid(V value) const = 0;
|
||||
|
||||
|
@ -452,6 +464,38 @@ namespace geode {
|
|||
std::shared_ptr<SettingV3> getSetting() const;
|
||||
};
|
||||
|
||||
class GEODE_DLL SettingChangedEventV3 final : public Event {
|
||||
private:
|
||||
class Impl;
|
||||
std::shared_ptr<Impl> m_impl;
|
||||
|
||||
public:
|
||||
SettingChangedEventV3(std::shared_ptr<SettingV3> setting);
|
||||
|
||||
std::shared_ptr<SettingV3> getSetting() const;
|
||||
};
|
||||
class GEODE_DLL SettingChangedFilterV3 final : public EventFilter<SettingChangedEventV3> {
|
||||
private:
|
||||
class Impl;
|
||||
std::shared_ptr<Impl> m_impl;
|
||||
|
||||
public:
|
||||
using Callback = void(std::shared_ptr<SettingV3>);
|
||||
|
||||
ListenerResult handle(utils::MiniFunction<Callback> fn, SettingChangedEventV3* event);
|
||||
/**
|
||||
* Listen to changes on a setting, or all settings
|
||||
* @param modID Mod whose settings to listen to
|
||||
* @param settingKey Setting to listen to, or all settings if nullopt
|
||||
*/
|
||||
SettingChangedFilterV3(
|
||||
std::string const& modID,
|
||||
std::optional<std::string> const& settingKey
|
||||
);
|
||||
SettingChangedFilterV3(Mod* mod, std::optional<std::string> const& settingKey);
|
||||
SettingChangedFilterV3(SettingChangedFilterV3 const&);
|
||||
};
|
||||
|
||||
class GEODE_DLL SettingNodeSizeChangeEventV3 : public Event {
|
||||
private:
|
||||
class Impl;
|
||||
|
@ -512,4 +556,25 @@ namespace geode {
|
|||
struct SettingTypeForValueType<cocos2d::ccColor4B> {
|
||||
using SettingType = Color4BSettingV3;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
EventListener<SettingChangedFilterV3>* listenForSettingChanges(std::string_view settingKey, auto&& callback, Mod* mod = getMod()) {
|
||||
using Ty = typename SettingTypeForValueType<T>::SettingType;
|
||||
return new EventListener(
|
||||
[callback = std::move(callback)](std::shared_ptr<SettingV3> setting) {
|
||||
if (auto ty = typeinfo_pointer_cast<Ty>(setting)) {
|
||||
callback(ty->getValue());
|
||||
}
|
||||
},
|
||||
SettingChangedFilterV3(mod, std::string(settingKey))
|
||||
);
|
||||
}
|
||||
EventListener<SettingChangedFilterV3>* listenForSettingChanges(std::string_view settingKey, auto&& callback, Mod* mod = getMod()) {
|
||||
using T = std::remove_cvref_t<utils::function::Arg<0, decltype(callback)>>;
|
||||
return listenForSettingChanges<T>(settingKey, std::move(callback), mod);
|
||||
}
|
||||
GEODE_DLL EventListener<SettingChangedFilterV3>* listenForAllSettingChanges(
|
||||
std::function<void(std::shared_ptr<SettingV3>)> const& callback,
|
||||
Mod* mod = getMod()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -17,13 +17,22 @@
|
|||
namespace geode {
|
||||
using ByteVector = std::vector<uint8_t>;
|
||||
|
||||
// todo in v4: remove this
|
||||
template <typename T>
|
||||
[[deprecated("Use geode::toBytes instead")]]
|
||||
ByteVector toByteArray(T const& a) {
|
||||
ByteVector out;
|
||||
out.resize(sizeof(T));
|
||||
std::memcpy(out.data(), &a, sizeof(T));
|
||||
return out;
|
||||
}
|
||||
template <typename T>
|
||||
ByteVector toBytes(T const& a) {
|
||||
ByteVector out;
|
||||
out.resize(sizeof(T));
|
||||
std::memcpy(out.data(), &a, sizeof(T));
|
||||
return out;
|
||||
}
|
||||
|
||||
namespace utils {
|
||||
// helper for std::visit
|
||||
|
|
|
@ -78,6 +78,7 @@ public:
|
|||
};
|
||||
std::string modID;
|
||||
std::unordered_map<std::string, SettingInfo> settings;
|
||||
bool restartRequired = false;
|
||||
|
||||
void createSettings() {
|
||||
for (auto& [key, setting] : settings) {
|
||||
|
@ -103,6 +104,7 @@ public:
|
|||
};
|
||||
|
||||
ModSettingsManager* ModSettingsManager::from(Mod* mod) {
|
||||
if (!mod) return nullptr;
|
||||
return ModImpl::getImpl(mod)->m_settings.get();
|
||||
}
|
||||
|
||||
|
@ -136,6 +138,10 @@ ModSettingsManager::ModSettingsManager(ModMetadata const& metadata)
|
|||
ModSettingsManager::~ModSettingsManager() {}
|
||||
ModSettingsManager::ModSettingsManager(ModSettingsManager&&) = default;
|
||||
|
||||
void ModSettingsManager::markRestartRequired() {
|
||||
m_impl->restartRequired = true;
|
||||
}
|
||||
|
||||
Result<> ModSettingsManager::registerCustomSettingType(std::string_view type, SettingGenerator generator) {
|
||||
GEODE_UNWRAP(SharedSettingTypesPool::get().add(m_impl->modID, type, generator));
|
||||
m_impl->createSettings();
|
||||
|
@ -230,3 +236,7 @@ std::optional<Setting> ModSettingsManager::getLegacyDefinition(std::string_view
|
|||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool ModSettingsManager::restartRequired() const {
|
||||
return m_impl->restartRequired;
|
||||
}
|
||||
|
|
|
@ -280,10 +280,10 @@ std::string SettingValue::getModID() const {
|
|||
}
|
||||
|
||||
void SettingValue::valueChanged() {
|
||||
// this is actually p neat because now if the mod gets disabled this wont
|
||||
// post the event so that side-effect is automatically handled :3
|
||||
if (auto mod = Loader::get()->getLoadedMod(m_modID)) {
|
||||
SettingChangedEvent(mod, this).post();
|
||||
if (auto sett = mod->getSettingV3(m_key)) {
|
||||
sett->markChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@ void SettingNodeV3::updateState() {
|
|||
m_impl->errorLabel->setString(desc->c_str());
|
||||
}
|
||||
}
|
||||
if (m_impl->setting->requiresRestart() && (this->hasUncommittedChanges() || m_impl->committed)) {
|
||||
if (m_impl->setting->requiresRestart() && m_impl->committed) {
|
||||
m_impl->errorLabel->setVisible(true);
|
||||
m_impl->errorLabel->setColor("mod-list-restart-required-label"_cc3b);
|
||||
m_impl->errorLabel->setString("Restart Required");
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#include <Geode/loader/SettingV3.hpp>
|
||||
#include <Geode/loader/SettingEvent.hpp>
|
||||
#include <Geode/loader/ModSettingsManager.hpp>
|
||||
#include <Geode/utils/JsonValidation.hpp>
|
||||
#include <regex>
|
||||
#include "SettingNodeV3.hpp"
|
||||
|
@ -397,6 +399,63 @@ namespace enable_if_parsing {
|
|||
};
|
||||
}
|
||||
|
||||
class SettingChangedEventV3::Impl final {
|
||||
public:
|
||||
std::shared_ptr<SettingV3> setting;
|
||||
};
|
||||
|
||||
SettingChangedEventV3::SettingChangedEventV3(std::shared_ptr<SettingV3> setting)
|
||||
: m_impl(std::make_shared<Impl>())
|
||||
{
|
||||
m_impl->setting = setting;
|
||||
}
|
||||
|
||||
std::shared_ptr<SettingV3> SettingChangedEventV3::getSetting() const {
|
||||
return m_impl->setting;
|
||||
}
|
||||
|
||||
class SettingChangedFilterV3::Impl final {
|
||||
public:
|
||||
std::string modID;
|
||||
std::optional<std::string> settingKey;
|
||||
};
|
||||
|
||||
ListenerResult SettingChangedFilterV3::handle(utils::MiniFunction<Callback> fn, SettingChangedEventV3* event) {
|
||||
if (
|
||||
event->getSetting()->getModID() == m_impl->modID &&
|
||||
!m_impl->settingKey || event->getSetting()->getKey() == m_impl->settingKey
|
||||
) {
|
||||
fn(event->getSetting());
|
||||
}
|
||||
return ListenerResult::Propagate;
|
||||
}
|
||||
|
||||
SettingChangedFilterV3::SettingChangedFilterV3(
|
||||
std::string const& modID,
|
||||
std::optional<std::string> const& settingKey
|
||||
) : m_impl(std::make_shared<Impl>())
|
||||
{
|
||||
m_impl->modID = modID;
|
||||
m_impl->settingKey = settingKey;
|
||||
}
|
||||
|
||||
SettingChangedFilterV3::SettingChangedFilterV3(Mod* mod, std::optional<std::string> const& settingKey)
|
||||
: SettingChangedFilterV3(mod->getID(), settingKey) {}
|
||||
|
||||
SettingChangedFilterV3::SettingChangedFilterV3(SettingChangedFilterV3 const&) = default;
|
||||
|
||||
EventListener<SettingChangedFilterV3>* geode::listenForAllSettingChanges(
|
||||
std::function<void(std::shared_ptr<SettingV3>)> const& callback,
|
||||
Mod* mod
|
||||
) {
|
||||
return new EventListener(
|
||||
[callback](std::shared_ptr<SettingV3> setting) {
|
||||
callback(setting);
|
||||
},
|
||||
SettingChangedFilterV3(mod->getID(), std::nullopt)
|
||||
);
|
||||
}
|
||||
|
||||
class SettingV3::GeodeImpl {
|
||||
public:
|
||||
std::string modID;
|
||||
|
@ -485,6 +544,19 @@ Mod* SettingV3::getMod() const {
|
|||
return Loader::get()->getInstalledMod(m_impl->modID);
|
||||
}
|
||||
|
||||
void SettingV3::markChanged() {
|
||||
auto manager = ModSettingsManager::from(this->getMod());
|
||||
if (m_impl->requiresRestart) {
|
||||
manager->markRestartRequired();
|
||||
}
|
||||
SettingChangedEventV3(shared_from_this()).post();
|
||||
if (manager) {
|
||||
// Use ModSettingsManager rather than convertToLegacyValue since it
|
||||
// caches the result and we want to have that for performance
|
||||
SettingChangedEvent(this->getMod(), manager->getLegacy(this->getKey()).get()).post();
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<Setting> SettingV3::convertToLegacy() const {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
|
|
@ -90,6 +90,11 @@ bool ModsStatusNode::init() {
|
|||
|
||||
m_downloadListener.bind([this](auto) { this->updateState(); });
|
||||
|
||||
m_settingNodeListener.bind([this](SettingNodeValueChangeEventV3* ev) {
|
||||
this->updateState();
|
||||
return ListenerResult::Propagate;
|
||||
});
|
||||
|
||||
this->updateState();
|
||||
|
||||
return true;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "sources/ModListSource.hpp"
|
||||
#include "UpdateModListState.hpp"
|
||||
#include <server/DownloadManager.hpp>
|
||||
#include <Geode/loader/SettingV3.hpp>
|
||||
|
||||
using namespace geode::prelude;
|
||||
|
||||
|
@ -39,6 +40,7 @@ protected:
|
|||
EventListener<UpdateModListStateFilter> m_updateStateListener;
|
||||
EventListener<server::ModDownloadFilter> m_downloadListener;
|
||||
DownloadState m_lastState = DownloadState::None;
|
||||
EventListener<EventFilter<SettingNodeValueChangeEventV3>> m_settingNodeListener;
|
||||
|
||||
bool init();
|
||||
void updateState();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "ModListSource.hpp"
|
||||
#include <server/DownloadManager.hpp>
|
||||
#include <Geode/loader/ModSettingsManager.hpp>
|
||||
|
||||
#define FTS_FUZZY_MATCH_IMPLEMENTATION
|
||||
#include <Geode/external/fts/fts_fuzzy_match.h>
|
||||
|
@ -90,6 +91,9 @@ bool ModListSource::isRestartRequired() {
|
|||
if (mod->getRequestedAction() != ModRequestedAction::None) {
|
||||
return true;
|
||||
}
|
||||
if (ModSettingsManager::from(mod)->restartRequired()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (server::ModDownloadManager::get()->wantsRestart()) {
|
||||
return true;
|
||||
|
|
Loading…
Reference in a new issue