mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-21 10:38:27 -05:00
breaking event/pool changes
This commit is contained in:
parent
d6f0c597f1
commit
19fdaace90
16 changed files with 178 additions and 64 deletions
|
@ -8,8 +8,7 @@
|
|||
|
||||
namespace geode {
|
||||
// Mod interoperability
|
||||
|
||||
GEODE_DLL std::unordered_map<std::string, EventListenerPool*>& dispatchPools();
|
||||
GEODE_DLL EventListenerPool* getDispatchPool(std::string const& id);
|
||||
|
||||
template <class... Args>
|
||||
class DispatchEvent : public Event {
|
||||
|
@ -30,10 +29,7 @@ namespace geode {
|
|||
}
|
||||
|
||||
EventListenerPool* getPool() const override {
|
||||
if (dispatchPools().count(m_id) == 0) {
|
||||
dispatchPools()[m_id] = DefaultEventListenerPool::create();
|
||||
}
|
||||
return dispatchPools()[m_id];
|
||||
return getDispatchPool(m_id);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -46,11 +42,8 @@ namespace geode {
|
|||
using Ev = DispatchEvent<Args...>;
|
||||
using Callback = ListenerResult(Args...);
|
||||
|
||||
EventListenerPool* getPool() const {
|
||||
if (dispatchPools().count(m_id) == 0) {
|
||||
dispatchPools()[m_id] = DefaultEventListenerPool::create();
|
||||
}
|
||||
return dispatchPools()[m_id];
|
||||
EventListenerPool* getPool() const override {
|
||||
return getDispatchPool(m_id);
|
||||
}
|
||||
|
||||
ListenerResult handle(std::function<Callback> fn, Ev* event) {
|
||||
|
|
|
@ -39,19 +39,12 @@ namespace geode {
|
|||
class DispatchFilter;
|
||||
|
||||
class GEODE_DLL DefaultEventListenerPool : public EventListenerPool {
|
||||
protected:
|
||||
// fix this in Geode 4.0.0
|
||||
struct Data {
|
||||
std::atomic_size_t m_locked = 0;
|
||||
std::mutex m_mutex;
|
||||
std::deque<EventListenerProtocol*> m_listeners;
|
||||
std::vector<EventListenerProtocol*> m_toAdd;
|
||||
};
|
||||
std::unique_ptr<Data> m_data;
|
||||
|
||||
private:
|
||||
static DefaultEventListenerPool* create();
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> m_impl;
|
||||
|
||||
DefaultEventListenerPool();
|
||||
~DefaultEventListenerPool() override;
|
||||
|
||||
public:
|
||||
bool add(EventListenerProtocol* listener) override;
|
||||
|
@ -60,11 +53,13 @@ namespace geode {
|
|||
|
||||
static DefaultEventListenerPool* get();
|
||||
|
||||
template <class... Args>
|
||||
friend class DispatchEvent;
|
||||
template <class E>
|
||||
static EventListenerPool* getForEvent() {
|
||||
static std::shared_ptr<DefaultEventListenerPool> pool = DefaultEventListenerPool::create();
|
||||
return pool.get();
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
friend class DispatchFilter;
|
||||
static std::shared_ptr<DefaultEventListenerPool> create();
|
||||
};
|
||||
|
||||
class GEODE_DLL EventListenerProtocol {
|
||||
|
@ -100,20 +95,22 @@ namespace geode {
|
|||
using Callback = ListenerResult(T*);
|
||||
using Event = T;
|
||||
|
||||
ListenerResult handle(std::function<Callback> fn, T* e) {
|
||||
virtual ListenerResult handle(std::function<Callback> fn, T* e) {
|
||||
return fn(e);
|
||||
}
|
||||
|
||||
EventListenerPool* getPool() const {
|
||||
virtual EventListenerPool* getPool() const {
|
||||
return DefaultEventListenerPool::get();
|
||||
}
|
||||
|
||||
void setListener(EventListenerProtocol* listener) {
|
||||
virtual void setListener(EventListenerProtocol* listener) {
|
||||
m_listener = listener;
|
||||
}
|
||||
EventListenerProtocol* getListener() const {
|
||||
virtual EventListenerProtocol* getListener() const {
|
||||
return m_listener;
|
||||
}
|
||||
|
||||
virtual ~EventFilter() = default;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -232,8 +229,9 @@ namespace geode {
|
|||
Mod* sender;
|
||||
|
||||
ListenerResult postFromMod(Mod* sender);
|
||||
template<class = void>
|
||||
ListenerResult post() {
|
||||
|
||||
template <class _ = void>
|
||||
inline ListenerResult post() {
|
||||
return postFromMod(getMod());
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace geode {
|
|||
ModStateEvent(Mod* mod, ModEventType type);
|
||||
ModEventType getType() const;
|
||||
Mod* getMod() const;
|
||||
EventListenerPool* getPool() const override;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -40,6 +41,7 @@ namespace geode {
|
|||
Mod* m_mod;
|
||||
|
||||
public:
|
||||
EventListenerPool* getPool() const override;
|
||||
ListenerResult handle(std::function<Callback> fn, ModStateEvent* event);
|
||||
|
||||
/**
|
||||
|
|
|
@ -646,6 +646,7 @@ namespace geode {
|
|||
SettingChangedEventV3(std::shared_ptr<SettingV3> setting);
|
||||
|
||||
std::shared_ptr<SettingV3> getSetting() const;
|
||||
EventListenerPool* getPool() const override;
|
||||
};
|
||||
class GEODE_DLL SettingChangedFilterV3 final : public EventFilter<SettingChangedEventV3> {
|
||||
private:
|
||||
|
@ -667,6 +668,7 @@ namespace geode {
|
|||
);
|
||||
SettingChangedFilterV3(Mod* mod, std::optional<std::string> const& settingKey);
|
||||
SettingChangedFilterV3(SettingChangedFilterV3 const&);
|
||||
EventListenerPool* getPool() const override;
|
||||
};
|
||||
|
||||
class GEODE_DLL SettingNodeSizeChangeEventV3 : public Event {
|
||||
|
|
|
@ -49,6 +49,12 @@ namespace geode {
|
|||
T* getLayer() const {
|
||||
return static_cast<T*>(this->layer);
|
||||
}
|
||||
std::string const& getID() const {
|
||||
return this->layerID;
|
||||
}
|
||||
EventListenerPool* getPool() const override {
|
||||
return DefaultEventListenerPool::getForEvent<EnterLayerEvent<T>>();
|
||||
}
|
||||
};
|
||||
|
||||
template<class T, class N>
|
||||
|
@ -64,7 +70,12 @@ namespace geode {
|
|||
|
||||
public:
|
||||
ListenerResult handle(std::function<Callback> fn, EnterLayerEvent<N>* event) {
|
||||
if (m_targetID == event->getID()) {
|
||||
if (m_targetID.has_value()) {
|
||||
if (m_targetID.value() == event->getID()) {
|
||||
fn(static_cast<T*>(event));
|
||||
}
|
||||
}
|
||||
else {
|
||||
fn(static_cast<T*>(event));
|
||||
}
|
||||
return ListenerResult::Propagate;
|
||||
|
@ -74,5 +85,8 @@ namespace geode {
|
|||
std::optional<std::string> const& id
|
||||
) : m_targetID(id) {}
|
||||
EnterLayerFilter(EnterLayerFilter const&) = default;
|
||||
EventListenerPool* getPool() const override {
|
||||
return DefaultEventListenerPool::getForEvent<EnterLayerEvent<N>>();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -31,6 +31,9 @@ namespace geode {
|
|||
Popup* getPopup() const {
|
||||
return m_impl->popup;
|
||||
}
|
||||
EventListenerPool* getPool() const override {
|
||||
return DefaultEventListenerPool::getForEvent<CloseEvent>();
|
||||
}
|
||||
};
|
||||
class CloseEventFilter final : public ::geode::EventFilter<CloseEvent> {
|
||||
public:
|
||||
|
@ -57,6 +60,9 @@ namespace geode {
|
|||
}
|
||||
return ListenerResult::Propagate;
|
||||
}
|
||||
EventListenerPool* getPool() const override {
|
||||
return DefaultEventListenerPool::getForEvent<CloseEvent>();
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace geode {
|
|||
cocos2d::ccColor4B color;
|
||||
|
||||
ColorProvidedEvent(std::string const& id, cocos2d::ccColor4B const& color);
|
||||
EventListenerPool* getPool() const override;
|
||||
};
|
||||
|
||||
class GEODE_DLL ColorProvidedFilter final : public EventFilter<ColorProvidedEvent> {
|
||||
|
@ -24,6 +25,7 @@ namespace geode {
|
|||
ListenerResult handle(std::function<Callback> fn, ColorProvidedEvent* event);
|
||||
|
||||
ColorProvidedFilter(std::string const& id);
|
||||
EventListenerPool* getPool() const override;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -270,6 +270,7 @@ namespace geode::utils::file {
|
|||
public:
|
||||
FileWatchEvent(std::filesystem::path const& path);
|
||||
std::filesystem::path getPath() const;
|
||||
EventListenerPool* getPool() const override;
|
||||
};
|
||||
|
||||
class GEODE_DLL FileWatchFilter final : public EventFilter<FileWatchEvent> {
|
||||
|
@ -281,6 +282,7 @@ namespace geode::utils::file {
|
|||
|
||||
ListenerResult handle(std::function<Callback> callback, FileWatchEvent* event);
|
||||
FileWatchFilter(std::filesystem::path const& path);
|
||||
EventListenerPool* getPool() const override;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
|
||||
using namespace geode::prelude;
|
||||
|
||||
std::unordered_map<std::string, EventListenerPool*>& geode::dispatchPools() {
|
||||
static std::unordered_map<std::string, EventListenerPool*> pools;
|
||||
return pools;
|
||||
EventListenerPool* geode::getDispatchPool(std::string const& id) {
|
||||
static std::unordered_map<std::string, std::shared_ptr<DefaultEventListenerPool>> pools;
|
||||
if (pools.count(id) == 0) {
|
||||
pools[id] = DefaultEventListenerPool::create();
|
||||
}
|
||||
return pools[id].get();
|
||||
}
|
|
@ -4,50 +4,59 @@
|
|||
|
||||
using namespace geode::prelude;
|
||||
|
||||
DefaultEventListenerPool::DefaultEventListenerPool() : m_data(new Data) {}
|
||||
class DefaultEventListenerPool::Impl {
|
||||
public:
|
||||
std::atomic_size_t m_locked = 0;
|
||||
std::mutex m_mutex;
|
||||
std::deque<EventListenerProtocol*> m_listeners;
|
||||
std::vector<EventListenerProtocol*> m_toAdd;
|
||||
};
|
||||
|
||||
DefaultEventListenerPool::DefaultEventListenerPool() : m_impl(new Impl) {}
|
||||
DefaultEventListenerPool::~DefaultEventListenerPool() = default;
|
||||
|
||||
bool DefaultEventListenerPool::add(EventListenerProtocol* listener) {
|
||||
if (!m_data) m_data = std::make_unique<Data>();
|
||||
if (!m_impl) m_impl = std::make_unique<Impl>();
|
||||
|
||||
std::unique_lock lock(m_data->m_mutex);
|
||||
if (ranges::contains(m_data->m_listeners, listener) || ranges::contains(m_data->m_toAdd, listener)) {
|
||||
std::unique_lock lock(m_impl->m_mutex);
|
||||
if (ranges::contains(m_impl->m_listeners, listener) || ranges::contains(m_impl->m_toAdd, listener)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_data->m_locked) {
|
||||
m_data->m_toAdd.push_back(listener);
|
||||
if (m_impl->m_locked) {
|
||||
m_impl->m_toAdd.push_back(listener);
|
||||
}
|
||||
else {
|
||||
// insert listeners at the start so new listeners get priority
|
||||
m_data->m_listeners.push_front(listener);
|
||||
m_impl->m_listeners.push_front(listener);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DefaultEventListenerPool::remove(EventListenerProtocol* listener) {
|
||||
if (!m_data) m_data = std::make_unique<Data>();
|
||||
if (!m_impl) m_impl = std::make_unique<Impl>();
|
||||
|
||||
std::unique_lock lock(m_data->m_mutex);
|
||||
if (m_data->m_locked) {
|
||||
for (size_t i = 0 ; i < m_data->m_listeners.size(); i++) {
|
||||
if (m_data->m_listeners[i] == listener) {
|
||||
m_data->m_listeners[i] = nullptr;
|
||||
std::unique_lock lock(m_impl->m_mutex);
|
||||
if (m_impl->m_locked) {
|
||||
for (size_t i = 0 ; i < m_impl->m_listeners.size(); i++) {
|
||||
if (m_impl->m_listeners[i] == listener) {
|
||||
m_impl->m_listeners[i] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ranges::remove(m_data->m_listeners, listener);
|
||||
ranges::remove(m_impl->m_listeners, listener);
|
||||
}
|
||||
ranges::remove(m_data->m_toAdd, listener);
|
||||
ranges::remove(m_impl->m_toAdd, listener);
|
||||
}
|
||||
|
||||
ListenerResult DefaultEventListenerPool::handle(Event* event) {
|
||||
if (!m_data) m_data = std::make_unique<Data>();
|
||||
if (!m_impl) m_impl = std::make_unique<Impl>();
|
||||
|
||||
auto res = ListenerResult::Propagate;
|
||||
m_data->m_locked += 1;
|
||||
std::unique_lock lock(m_data->m_mutex);
|
||||
for (auto h : m_data->m_listeners) {
|
||||
m_impl->m_locked += 1;
|
||||
std::unique_lock lock(m_impl->m_mutex);
|
||||
for (auto h : m_impl->m_listeners) {
|
||||
lock.unlock();
|
||||
if (h && h->handle(event) == ListenerResult::Stop) {
|
||||
res = ListenerResult::Stop;
|
||||
|
@ -56,21 +65,21 @@ ListenerResult DefaultEventListenerPool::handle(Event* event) {
|
|||
}
|
||||
lock.lock();
|
||||
}
|
||||
m_data->m_locked -= 1;
|
||||
m_impl->m_locked -= 1;
|
||||
// only mutate listeners once nothing is iterating
|
||||
// (if there are recursive handle calls)
|
||||
if (m_data->m_locked == 0) {
|
||||
ranges::remove(m_data->m_listeners, nullptr);
|
||||
for (auto listener : m_data->m_toAdd) {
|
||||
m_data->m_listeners.push_front(listener);
|
||||
if (m_impl->m_locked == 0) {
|
||||
ranges::remove(m_impl->m_listeners, nullptr);
|
||||
for (auto listener : m_impl->m_toAdd) {
|
||||
m_impl->m_listeners.push_front(listener);
|
||||
}
|
||||
m_data->m_toAdd.clear();
|
||||
m_impl->m_toAdd.clear();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
DefaultEventListenerPool* DefaultEventListenerPool::create() {
|
||||
return new DefaultEventListenerPool();
|
||||
std::shared_ptr<DefaultEventListenerPool> DefaultEventListenerPool::create() {
|
||||
return std::shared_ptr<DefaultEventListenerPool>(new DefaultEventListenerPool(), [](DefaultEventListenerPool* p) { delete p; });
|
||||
}
|
||||
|
||||
DefaultEventListenerPool* DefaultEventListenerPool::get() {
|
||||
|
|
|
@ -12,6 +12,21 @@ Mod* ModStateEvent::getMod() const {
|
|||
return m_mod;
|
||||
}
|
||||
|
||||
namespace {
|
||||
EventListenerPool* getModEventPool(Mod* mod) {
|
||||
static std::unordered_map<Mod*, std::shared_ptr<DefaultEventListenerPool>> pools;
|
||||
if (pools.count(mod) == 0) {
|
||||
pools[mod] = DefaultEventListenerPool::create();
|
||||
}
|
||||
return pools[mod].get();
|
||||
}
|
||||
}
|
||||
|
||||
EventListenerPool* ModStateEvent::getPool() const {
|
||||
return getModEventPool(m_mod);
|
||||
}
|
||||
|
||||
|
||||
ListenerResult ModStateFilter::handle(std::function<Callback> fn, ModStateEvent* event) {
|
||||
// log::debug("Event mod filter: {}, {}, {}, {}", m_mod, static_cast<int>(m_type), event->getMod(), static_cast<int>(event->getType()));
|
||||
if ((!m_mod || event->getMod() == m_mod) && event->getType() == m_type) {
|
||||
|
@ -21,3 +36,7 @@ ListenerResult ModStateFilter::handle(std::function<Callback> fn, ModStateEvent*
|
|||
}
|
||||
|
||||
ModStateFilter::ModStateFilter(Mod* mod, ModEventType type) : m_mod(mod), m_type(type) {}
|
||||
|
||||
EventListenerPool* ModStateFilter::getPool() const {
|
||||
return getModEventPool(m_mod);
|
||||
}
|
|
@ -440,6 +440,20 @@ ListenerResult SettingChangedFilterV3::handle(std::function<Callback> fn, Settin
|
|||
return ListenerResult::Propagate;
|
||||
}
|
||||
|
||||
namespace {
|
||||
EventListenerPool* getSettingChangedPool(std::string const& modID) {
|
||||
static std::unordered_map<std::string, std::shared_ptr<DefaultEventListenerPool>> pools;
|
||||
if (!pools.count(modID)) {
|
||||
pools[modID] = DefaultEventListenerPool::create();
|
||||
}
|
||||
return pools[modID].get();
|
||||
}
|
||||
}
|
||||
|
||||
EventListenerPool* SettingChangedEventV3::getPool() const {
|
||||
return getSettingChangedPool(m_impl->setting->getModID());
|
||||
}
|
||||
|
||||
SettingChangedFilterV3::SettingChangedFilterV3(
|
||||
std::string const& modID,
|
||||
std::optional<std::string> const& settingKey
|
||||
|
@ -454,6 +468,10 @@ SettingChangedFilterV3::SettingChangedFilterV3(Mod* mod, std::optional<std::stri
|
|||
|
||||
SettingChangedFilterV3::SettingChangedFilterV3(SettingChangedFilterV3 const&) = default;
|
||||
|
||||
EventListenerPool* SettingChangedFilterV3::getPool() const {
|
||||
return getSettingChangedPool(m_impl->modID);
|
||||
}
|
||||
|
||||
EventListener<SettingChangedFilterV3>* geode::listenForAllSettingChangesV3(
|
||||
std::function<void(std::shared_ptr<SettingV3>)> const& callback,
|
||||
Mod* mod
|
||||
|
|
|
@ -9,7 +9,12 @@ AEnterLayerEvent::AEnterLayerEvent(
|
|||
layer(layer) {}
|
||||
|
||||
ListenerResult AEnterLayerFilter::handle(std::function<Callback> fn, AEnterLayerEvent* event) {
|
||||
if (m_targetID == event->layerID) {
|
||||
if (m_targetID.has_value()) {
|
||||
if (event->layerID == m_targetID.value()) {
|
||||
fn(event);
|
||||
}
|
||||
}
|
||||
else {
|
||||
fn(event);
|
||||
}
|
||||
return ListenerResult::Propagate;
|
||||
|
|
|
@ -13,8 +13,26 @@ ListenerResult ColorProvidedFilter::handle(std::function<Callback> fn, ColorProv
|
|||
return ListenerResult::Propagate;
|
||||
}
|
||||
|
||||
namespace {
|
||||
EventListenerPool* getDispatchPool(std::string const& id) {
|
||||
static std::unordered_map<std::string, std::shared_ptr<DefaultEventListenerPool>> pools;
|
||||
if (pools.count(id) == 0) {
|
||||
pools[id] = DefaultEventListenerPool::create();
|
||||
}
|
||||
return pools[id].get();
|
||||
}
|
||||
}
|
||||
|
||||
EventListenerPool* ColorProvidedEvent::getPool() const {
|
||||
return getDispatchPool(id);
|
||||
}
|
||||
|
||||
ColorProvidedFilter::ColorProvidedFilter(std::string const& id) : m_id(id) {}
|
||||
|
||||
EventListenerPool* ColorProvidedFilter::getPool() const {
|
||||
return getDispatchPool(m_id);
|
||||
}
|
||||
|
||||
class ColorProvider::Impl {
|
||||
public:
|
||||
std::unordered_map<std::string, std::pair<ccColor4B, std::optional<ccColor4B>>> colors;
|
||||
|
|
|
@ -697,6 +697,20 @@ std::filesystem::path FileWatchEvent::getPath() const {
|
|||
return m_path;
|
||||
}
|
||||
|
||||
namespace {
|
||||
EventListenerPool* getFileWatchPool(std::filesystem::path const& path) {
|
||||
static std::unordered_map<std::filesystem::path, std::shared_ptr<DefaultEventListenerPool>> pools;
|
||||
if (!pools.count(path)) {
|
||||
pools[path] = DefaultEventListenerPool::create();
|
||||
}
|
||||
return pools[path].get();
|
||||
}
|
||||
}
|
||||
|
||||
EventListenerPool* FileWatchEvent::getPool() const {
|
||||
return getFileWatchPool(m_path);
|
||||
}
|
||||
|
||||
ListenerResult FileWatchFilter::handle(
|
||||
std::function<Callback> callback,
|
||||
FileWatchEvent* event
|
||||
|
@ -711,6 +725,10 @@ ListenerResult FileWatchFilter::handle(
|
|||
FileWatchFilter::FileWatchFilter(std::filesystem::path const& path)
|
||||
: m_path(path) {}
|
||||
|
||||
EventListenerPool* FileWatchFilter::getPool() const {
|
||||
return getFileWatchPool(m_path);
|
||||
}
|
||||
|
||||
// This is a vector because need to use std::filesystem::equivalent for
|
||||
// comparisons and removal is not exactly performance-critical here
|
||||
// (who's going to add and remove 500 file watchers every frame)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <Geode/Loader.hpp>
|
||||
#include <Geode/loader/ModEvent.hpp>
|
||||
#include <Geode/utils/cocos.hpp>
|
||||
#include <Geode/UI.hpp>
|
||||
#include "../dependency/main.hpp"
|
||||
|
||||
using namespace geode::prelude;
|
||||
|
@ -23,6 +24,10 @@ $execute {
|
|||
log::info("Received event: {}", event->getData());
|
||||
s_recievedEvent = event->getData();
|
||||
});
|
||||
|
||||
new EventListener(+[](EnterLayerEvent<MenuLayer>* event) {
|
||||
log::info("Layer entered: {}", event->layerID);
|
||||
}, EnterLayerFilter<MenuLayer>(std::nullopt));
|
||||
}
|
||||
|
||||
#include <Geode/modify/MenuLayer.hpp>
|
||||
|
|
Loading…
Reference in a new issue