diff --git a/loader/include/Geode/cocos/base_nodes/CCNode.h b/loader/include/Geode/cocos/base_nodes/CCNode.h index 30f5c46b..fc69fee3 100644 --- a/loader/include/Geode/cocos/base_nodes/CCNode.h +++ b/loader/include/Geode/cocos/base_nodes/CCNode.h @@ -852,7 +852,10 @@ private: GEODE_DLL geode::modifier::FieldContainer* getFieldContainer(); GEODE_DLL std::optional getAttributeInternal(std::string const& attribute); - GEODE_DLL void addEventListenerInternal(geode::EventListenerProtocol* protocol); + GEODE_DLL void addEventListenerInternal( + std::string const& id, + geode::EventListenerProtocol* protocol + ); public: /** @@ -1003,24 +1006,28 @@ public: template geode::EventListenerProtocol* addEventListener( - geode::utils::MiniFunction callback, Args&&... args + std::string const& id, + geode::utils::MiniFunction callback, + Args&&... args ) { auto listener = new geode::EventListener( callback, Filter(this, std::forward(args)...) ); - this->addEventListenerInternal(listener); + this->addEventListenerInternal(id, listener); return listener; } - template + template geode::EventListenerProtocol* addEventListener( - geode::utils::MiniFunction callback, + geode::utils::MiniFunction callback, Args&&... args ) { - return this->template addEventListener( - callback, std::forward(args)... + return this->template addEventListener( + "", callback, std::forward(args)... ); } GEODE_DLL void removeEventListener(geode::EventListenerProtocol* listener); + GEODE_DLL void removeEventListener(std::string const& id); + GEODE_DLL geode::EventListenerProtocol* getEventListener(std::string const& id); /// @{ /// @name Shader Program diff --git a/loader/src/hooks/GeodeNodeMetadata.cpp b/loader/src/hooks/GeodeNodeMetadata.cpp index beef927b..0e97ef2d 100644 --- a/loader/src/hooks/GeodeNodeMetadata.cpp +++ b/loader/src/hooks/GeodeNodeMetadata.cpp @@ -22,7 +22,8 @@ private: Ref m_layout = nullptr; std::unique_ptr m_layoutOptions = nullptr; std::unordered_map m_attributes; - std::vector m_eventListeners; + std::unordered_set> m_eventListeners; + std::unordered_map> m_idEventListeners; friend class ProxyCCNode; friend class cocos2d::CCNode; @@ -31,9 +32,6 @@ private: virtual ~GeodeNodeMetadata() { delete m_fieldContainer; - for (auto& listener : m_eventListeners) { - delete listener; - } } public: @@ -195,12 +193,44 @@ std::optional CCNode::getAttributeInternal(std::string const& attr) return std::nullopt; } -void CCNode::addEventListenerInternal(EventListenerProtocol* listener) { - GeodeNodeMetadata::set(this)->m_eventListeners.push_back(listener); +void CCNode::addEventListenerInternal(std::string const& id, EventListenerProtocol* listener) { + auto meta = GeodeNodeMetadata::set(this); + if (id.size()) { + if (meta->m_idEventListeners.contains(id)) { + meta->m_idEventListeners.at(id).reset(listener); + } + else { + meta->m_idEventListeners.emplace(id, listener); + } + } + else { + std::erase_if(meta->m_eventListeners, [=](auto& l) { + return l.get() == listener; + }); + meta->m_eventListeners.emplace(listener); + } } void CCNode::removeEventListener(EventListenerProtocol* listener) { - ranges::remove(GeodeNodeMetadata::set(this)->m_eventListeners, listener); + auto meta = GeodeNodeMetadata::set(this); + std::erase_if(meta->m_eventListeners, [=](auto& l) { + return l.get() == listener; + }); + std::erase_if(meta->m_idEventListeners, [=](auto& l) { + return l.second.get() == listener; + }); +} + +void CCNode::removeEventListener(std::string const& id) { + GeodeNodeMetadata::set(this)->m_idEventListeners.erase(id); +} + +EventListenerProtocol* CCNode::getEventListener(std::string const& id) { + auto meta = GeodeNodeMetadata::set(this); + if (meta->m_idEventListeners.contains(id)) { + return meta->m_idEventListeners.at(id).get(); + } + return nullptr; } #pragma warning(pop)