breaking event/pool changes

This commit is contained in:
altalk23 2024-11-16 12:20:43 +03:00
parent d6f0c597f1
commit 19fdaace90
16 changed files with 178 additions and 64 deletions

View file

@ -8,8 +8,7 @@
namespace geode { namespace geode {
// Mod interoperability // Mod interoperability
GEODE_DLL EventListenerPool* getDispatchPool(std::string const& id);
GEODE_DLL std::unordered_map<std::string, EventListenerPool*>& dispatchPools();
template <class... Args> template <class... Args>
class DispatchEvent : public Event { class DispatchEvent : public Event {
@ -30,10 +29,7 @@ namespace geode {
} }
EventListenerPool* getPool() const override { EventListenerPool* getPool() const override {
if (dispatchPools().count(m_id) == 0) { return getDispatchPool(m_id);
dispatchPools()[m_id] = DefaultEventListenerPool::create();
}
return dispatchPools()[m_id];
} }
}; };
@ -46,11 +42,8 @@ namespace geode {
using Ev = DispatchEvent<Args...>; using Ev = DispatchEvent<Args...>;
using Callback = ListenerResult(Args...); using Callback = ListenerResult(Args...);
EventListenerPool* getPool() const { EventListenerPool* getPool() const override {
if (dispatchPools().count(m_id) == 0) { return getDispatchPool(m_id);
dispatchPools()[m_id] = DefaultEventListenerPool::create();
}
return dispatchPools()[m_id];
} }
ListenerResult handle(std::function<Callback> fn, Ev* event) { ListenerResult handle(std::function<Callback> fn, Ev* event) {

View file

@ -39,19 +39,12 @@ namespace geode {
class DispatchFilter; class DispatchFilter;
class GEODE_DLL DefaultEventListenerPool : public EventListenerPool { 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: private:
static DefaultEventListenerPool* create(); class Impl;
std::unique_ptr<Impl> m_impl;
DefaultEventListenerPool(); DefaultEventListenerPool();
~DefaultEventListenerPool() override;
public: public:
bool add(EventListenerProtocol* listener) override; bool add(EventListenerProtocol* listener) override;
@ -60,11 +53,13 @@ namespace geode {
static DefaultEventListenerPool* get(); static DefaultEventListenerPool* get();
template <class... Args> template <class E>
friend class DispatchEvent; static EventListenerPool* getForEvent() {
static std::shared_ptr<DefaultEventListenerPool> pool = DefaultEventListenerPool::create();
return pool.get();
}
template <class... Args> static std::shared_ptr<DefaultEventListenerPool> create();
friend class DispatchFilter;
}; };
class GEODE_DLL EventListenerProtocol { class GEODE_DLL EventListenerProtocol {
@ -100,20 +95,22 @@ namespace geode {
using Callback = ListenerResult(T*); using Callback = ListenerResult(T*);
using Event = T; using Event = T;
ListenerResult handle(std::function<Callback> fn, T* e) { virtual ListenerResult handle(std::function<Callback> fn, T* e) {
return fn(e); return fn(e);
} }
EventListenerPool* getPool() const { virtual EventListenerPool* getPool() const {
return DefaultEventListenerPool::get(); return DefaultEventListenerPool::get();
} }
void setListener(EventListenerProtocol* listener) { virtual void setListener(EventListenerProtocol* listener) {
m_listener = listener; m_listener = listener;
} }
EventListenerProtocol* getListener() const { virtual EventListenerProtocol* getListener() const {
return m_listener; return m_listener;
} }
virtual ~EventFilter() = default;
}; };
template <typename T> template <typename T>
@ -232,8 +229,9 @@ namespace geode {
Mod* sender; Mod* sender;
ListenerResult postFromMod(Mod* sender); ListenerResult postFromMod(Mod* sender);
template<class = void>
ListenerResult post() { template <class _ = void>
inline ListenerResult post() {
return postFromMod(getMod()); return postFromMod(getMod());
} }

View file

@ -26,6 +26,7 @@ namespace geode {
ModStateEvent(Mod* mod, ModEventType type); ModStateEvent(Mod* mod, ModEventType type);
ModEventType getType() const; ModEventType getType() const;
Mod* getMod() const; Mod* getMod() const;
EventListenerPool* getPool() const override;
}; };
/** /**
@ -40,6 +41,7 @@ namespace geode {
Mod* m_mod; Mod* m_mod;
public: public:
EventListenerPool* getPool() const override;
ListenerResult handle(std::function<Callback> fn, ModStateEvent* event); ListenerResult handle(std::function<Callback> fn, ModStateEvent* event);
/** /**

View file

@ -646,6 +646,7 @@ namespace geode {
SettingChangedEventV3(std::shared_ptr<SettingV3> setting); SettingChangedEventV3(std::shared_ptr<SettingV3> setting);
std::shared_ptr<SettingV3> getSetting() const; std::shared_ptr<SettingV3> getSetting() const;
EventListenerPool* getPool() const override;
}; };
class GEODE_DLL SettingChangedFilterV3 final : public EventFilter<SettingChangedEventV3> { class GEODE_DLL SettingChangedFilterV3 final : public EventFilter<SettingChangedEventV3> {
private: private:
@ -667,6 +668,7 @@ namespace geode {
); );
SettingChangedFilterV3(Mod* mod, std::optional<std::string> const& settingKey); SettingChangedFilterV3(Mod* mod, std::optional<std::string> const& settingKey);
SettingChangedFilterV3(SettingChangedFilterV3 const&); SettingChangedFilterV3(SettingChangedFilterV3 const&);
EventListenerPool* getPool() const override;
}; };
class GEODE_DLL SettingNodeSizeChangeEventV3 : public Event { class GEODE_DLL SettingNodeSizeChangeEventV3 : public Event {

View file

@ -49,6 +49,12 @@ namespace geode {
T* getLayer() const { T* getLayer() const {
return static_cast<T*>(this->layer); 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> template<class T, class N>
@ -64,7 +70,12 @@ namespace geode {
public: public:
ListenerResult handle(std::function<Callback> fn, EnterLayerEvent<N>* event) { 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)); fn(static_cast<T*>(event));
} }
return ListenerResult::Propagate; return ListenerResult::Propagate;
@ -74,5 +85,8 @@ namespace geode {
std::optional<std::string> const& id std::optional<std::string> const& id
) : m_targetID(id) {} ) : m_targetID(id) {}
EnterLayerFilter(EnterLayerFilter const&) = default; EnterLayerFilter(EnterLayerFilter const&) = default;
EventListenerPool* getPool() const override {
return DefaultEventListenerPool::getForEvent<EnterLayerEvent<N>>();
}
}; };
} }

View file

@ -31,6 +31,9 @@ namespace geode {
Popup* getPopup() const { Popup* getPopup() const {
return m_impl->popup; return m_impl->popup;
} }
EventListenerPool* getPool() const override {
return DefaultEventListenerPool::getForEvent<CloseEvent>();
}
}; };
class CloseEventFilter final : public ::geode::EventFilter<CloseEvent> { class CloseEventFilter final : public ::geode::EventFilter<CloseEvent> {
public: public:
@ -57,6 +60,9 @@ namespace geode {
} }
return ListenerResult::Propagate; return ListenerResult::Propagate;
} }
EventListenerPool* getPool() const override {
return DefaultEventListenerPool::getForEvent<CloseEvent>();
}
}; };
protected: protected:

View file

@ -11,6 +11,7 @@ namespace geode {
cocos2d::ccColor4B color; cocos2d::ccColor4B color;
ColorProvidedEvent(std::string const& id, cocos2d::ccColor4B const& color); ColorProvidedEvent(std::string const& id, cocos2d::ccColor4B const& color);
EventListenerPool* getPool() const override;
}; };
class GEODE_DLL ColorProvidedFilter final : public EventFilter<ColorProvidedEvent> { class GEODE_DLL ColorProvidedFilter final : public EventFilter<ColorProvidedEvent> {
@ -24,6 +25,7 @@ namespace geode {
ListenerResult handle(std::function<Callback> fn, ColorProvidedEvent* event); ListenerResult handle(std::function<Callback> fn, ColorProvidedEvent* event);
ColorProvidedFilter(std::string const& id); ColorProvidedFilter(std::string const& id);
EventListenerPool* getPool() const override;
}; };
/** /**

View file

@ -270,6 +270,7 @@ namespace geode::utils::file {
public: public:
FileWatchEvent(std::filesystem::path const& path); FileWatchEvent(std::filesystem::path const& path);
std::filesystem::path getPath() const; std::filesystem::path getPath() const;
EventListenerPool* getPool() const override;
}; };
class GEODE_DLL FileWatchFilter final : public EventFilter<FileWatchEvent> { class GEODE_DLL FileWatchFilter final : public EventFilter<FileWatchEvent> {
@ -281,6 +282,7 @@ namespace geode::utils::file {
ListenerResult handle(std::function<Callback> callback, FileWatchEvent* event); ListenerResult handle(std::function<Callback> callback, FileWatchEvent* event);
FileWatchFilter(std::filesystem::path const& path); FileWatchFilter(std::filesystem::path const& path);
EventListenerPool* getPool() const override;
}; };
/** /**

View file

@ -2,7 +2,10 @@
using namespace geode::prelude; using namespace geode::prelude;
std::unordered_map<std::string, EventListenerPool*>& geode::dispatchPools() { EventListenerPool* geode::getDispatchPool(std::string const& id) {
static std::unordered_map<std::string, EventListenerPool*> pools; static std::unordered_map<std::string, std::shared_ptr<DefaultEventListenerPool>> pools;
return pools; if (pools.count(id) == 0) {
pools[id] = DefaultEventListenerPool::create();
}
return pools[id].get();
} }

View file

@ -4,50 +4,59 @@
using namespace geode::prelude; 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) { 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); std::unique_lock lock(m_impl->m_mutex);
if (ranges::contains(m_data->m_listeners, listener) || ranges::contains(m_data->m_toAdd, listener)) { if (ranges::contains(m_impl->m_listeners, listener) || ranges::contains(m_impl->m_toAdd, listener)) {
return false; return false;
} }
if (m_data->m_locked) { if (m_impl->m_locked) {
m_data->m_toAdd.push_back(listener); m_impl->m_toAdd.push_back(listener);
} }
else { else {
// insert listeners at the start so new listeners get priority // 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; return true;
} }
void DefaultEventListenerPool::remove(EventListenerProtocol* listener) { 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); std::unique_lock lock(m_impl->m_mutex);
if (m_data->m_locked) { if (m_impl->m_locked) {
for (size_t i = 0 ; i < m_data->m_listeners.size(); i++) { for (size_t i = 0 ; i < m_impl->m_listeners.size(); i++) {
if (m_data->m_listeners[i] == listener) { if (m_impl->m_listeners[i] == listener) {
m_data->m_listeners[i] = nullptr; m_impl->m_listeners[i] = nullptr;
} }
} }
} }
else { 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) { 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; auto res = ListenerResult::Propagate;
m_data->m_locked += 1; m_impl->m_locked += 1;
std::unique_lock lock(m_data->m_mutex); std::unique_lock lock(m_impl->m_mutex);
for (auto h : m_data->m_listeners) { for (auto h : m_impl->m_listeners) {
lock.unlock(); lock.unlock();
if (h && h->handle(event) == ListenerResult::Stop) { if (h && h->handle(event) == ListenerResult::Stop) {
res = ListenerResult::Stop; res = ListenerResult::Stop;
@ -56,21 +65,21 @@ ListenerResult DefaultEventListenerPool::handle(Event* event) {
} }
lock.lock(); lock.lock();
} }
m_data->m_locked -= 1; m_impl->m_locked -= 1;
// only mutate listeners once nothing is iterating // only mutate listeners once nothing is iterating
// (if there are recursive handle calls) // (if there are recursive handle calls)
if (m_data->m_locked == 0) { if (m_impl->m_locked == 0) {
ranges::remove(m_data->m_listeners, nullptr); ranges::remove(m_impl->m_listeners, nullptr);
for (auto listener : m_data->m_toAdd) { for (auto listener : m_impl->m_toAdd) {
m_data->m_listeners.push_front(listener); m_impl->m_listeners.push_front(listener);
} }
m_data->m_toAdd.clear(); m_impl->m_toAdd.clear();
} }
return res; return res;
} }
DefaultEventListenerPool* DefaultEventListenerPool::create() { std::shared_ptr<DefaultEventListenerPool> DefaultEventListenerPool::create() {
return new DefaultEventListenerPool(); return std::shared_ptr<DefaultEventListenerPool>(new DefaultEventListenerPool(), [](DefaultEventListenerPool* p) { delete p; });
} }
DefaultEventListenerPool* DefaultEventListenerPool::get() { DefaultEventListenerPool* DefaultEventListenerPool::get() {

View file

@ -12,6 +12,21 @@ Mod* ModStateEvent::getMod() const {
return m_mod; 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) { 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())); // 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) { 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) {} ModStateFilter::ModStateFilter(Mod* mod, ModEventType type) : m_mod(mod), m_type(type) {}
EventListenerPool* ModStateFilter::getPool() const {
return getModEventPool(m_mod);
}

View file

@ -440,6 +440,20 @@ ListenerResult SettingChangedFilterV3::handle(std::function<Callback> fn, Settin
return ListenerResult::Propagate; 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( SettingChangedFilterV3::SettingChangedFilterV3(
std::string const& modID, std::string const& modID,
std::optional<std::string> const& settingKey std::optional<std::string> const& settingKey
@ -454,6 +468,10 @@ SettingChangedFilterV3::SettingChangedFilterV3(Mod* mod, std::optional<std::stri
SettingChangedFilterV3::SettingChangedFilterV3(SettingChangedFilterV3 const&) = default; SettingChangedFilterV3::SettingChangedFilterV3(SettingChangedFilterV3 const&) = default;
EventListenerPool* SettingChangedFilterV3::getPool() const {
return getSettingChangedPool(m_impl->modID);
}
EventListener<SettingChangedFilterV3>* geode::listenForAllSettingChangesV3( EventListener<SettingChangedFilterV3>* geode::listenForAllSettingChangesV3(
std::function<void(std::shared_ptr<SettingV3>)> const& callback, std::function<void(std::shared_ptr<SettingV3>)> const& callback,
Mod* mod Mod* mod

View file

@ -9,7 +9,12 @@ AEnterLayerEvent::AEnterLayerEvent(
layer(layer) {} layer(layer) {}
ListenerResult AEnterLayerFilter::handle(std::function<Callback> fn, AEnterLayerEvent* event) { 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); fn(event);
} }
return ListenerResult::Propagate; return ListenerResult::Propagate;

View file

@ -13,8 +13,26 @@ ListenerResult ColorProvidedFilter::handle(std::function<Callback> fn, ColorProv
return ListenerResult::Propagate; 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) {} ColorProvidedFilter::ColorProvidedFilter(std::string const& id) : m_id(id) {}
EventListenerPool* ColorProvidedFilter::getPool() const {
return getDispatchPool(m_id);
}
class ColorProvider::Impl { class ColorProvider::Impl {
public: public:
std::unordered_map<std::string, std::pair<ccColor4B, std::optional<ccColor4B>>> colors; std::unordered_map<std::string, std::pair<ccColor4B, std::optional<ccColor4B>>> colors;

View file

@ -697,6 +697,20 @@ std::filesystem::path FileWatchEvent::getPath() const {
return m_path; 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( ListenerResult FileWatchFilter::handle(
std::function<Callback> callback, std::function<Callback> callback,
FileWatchEvent* event FileWatchEvent* event
@ -711,6 +725,10 @@ ListenerResult FileWatchFilter::handle(
FileWatchFilter::FileWatchFilter(std::filesystem::path const& path) FileWatchFilter::FileWatchFilter(std::filesystem::path const& path)
: m_path(path) {} : m_path(path) {}
EventListenerPool* FileWatchFilter::getPool() const {
return getFileWatchPool(m_path);
}
// This is a vector because need to use std::filesystem::equivalent for // This is a vector because need to use std::filesystem::equivalent for
// comparisons and removal is not exactly performance-critical here // comparisons and removal is not exactly performance-critical here
// (who's going to add and remove 500 file watchers every frame) // (who's going to add and remove 500 file watchers every frame)

View file

@ -1,6 +1,7 @@
#include <Geode/Loader.hpp> #include <Geode/Loader.hpp>
#include <Geode/loader/ModEvent.hpp> #include <Geode/loader/ModEvent.hpp>
#include <Geode/utils/cocos.hpp> #include <Geode/utils/cocos.hpp>
#include <Geode/UI.hpp>
#include "../dependency/main.hpp" #include "../dependency/main.hpp"
using namespace geode::prelude; using namespace geode::prelude;
@ -23,6 +24,10 @@ $execute {
log::info("Received event: {}", event->getData()); log::info("Received event: {}", event->getData());
s_recievedEvent = 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> #include <Geode/modify/MenuLayer.hpp>