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 {
// 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) {

View file

@ -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());
}

View file

@ -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);
/**

View file

@ -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 {

View file

@ -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>>();
}
};
}

View file

@ -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:

View file

@ -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;
};
/**

View file

@ -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;
};
/**

View file

@ -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();
}

View file

@ -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() {

View file

@ -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);
}

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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)

View file

@ -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>