#include #include #include USE_GEODE_NAMESPACE(); using namespace geode::modifier; #pragma warning(push) #pragma warning(disable : 4273) constexpr auto METADATA_TAG = 0xB324ABC; struct ProxyCCNode; class GeodeNodeMetadata final : public cocos2d::CCObject { private: FieldContainer* m_fieldContainer; Ref m_userObject; std::string m_id = ""; friend class ProxyCCNode; friend class cocos2d::CCNode; GeodeNodeMetadata() : m_fieldContainer(new FieldContainer()) {} virtual ~GeodeNodeMetadata() { delete m_fieldContainer; } public: static GeodeNodeMetadata* set(CCNode* target) { if (!target) return nullptr; auto old = target->m_pUserObject; // faster than dynamic_cast, technically can // but extremely unlikely to fail if (old && old->getTag() == METADATA_TAG) { return static_cast(old); } auto meta = new GeodeNodeMetadata(); meta->autorelease(); meta->setTag(METADATA_TAG); // set user object target->m_pUserObject = meta; meta->retain(); if (old) { meta->m_userObject = old; // the old user object has been retained by CCNode old->release(); } return meta; } FieldContainer* getFieldContainer() { return m_fieldContainer; } }; // proxy forwards // clang-format off #include #include class $modify(ProxyCCNode, CCNode) { virtual CCObject* getUserObject() { return GeodeNodeMetadata::set(this)->m_userObject; } virtual void setUserObject(CCObject* obj) { GeodeNodeMetadata::set(this)->m_userObject = obj; } }; // clang-format on // not const because might modify contents FieldContainer* CCNode::getFieldContainer() { return GeodeNodeMetadata::set(this)->getFieldContainer(); } std::string CCNode::getID() { return GeodeNodeMetadata::set(this)->m_id; } void CCNode::setID(std::string const& id) { GeodeNodeMetadata::set(this)->m_id = id; } CCNode* CCNode::getChildByID(std::string const& id) { for (auto child : CCArrayExt(m_pChildren)) { if (child->getID() == id) { return child; } } return nullptr; } CCNode* CCNode::getChildByIDRecursive(std::string const& id) { if (auto child = this->getChildByID(id)) { return child; } for (auto child : CCArrayExt(m_pChildren)) { if ((child = child->getChildByIDRecursive(id))) { return child; } } return nullptr; } #pragma warning(pop)