geode/loader/src/hooks/GeodeNodeMetadata.cpp

104 lines
2.7 KiB
C++
Raw Normal View History

#include <Geode/Bindings.hpp>
#include <Geode/utils/Ref.hpp>
#include <Geode/modify/Field.hpp>
#include <Geode/utils/WackyGeodeMacros.hpp>
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<cocos2d::CCObject> 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) {
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<GeodeNodeMetadata*>(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
class $modify(ProxyCCNode, CCNode) {
virtual CCObject* getUserObject() {
return GeodeNodeMetadata::set(this)->m_userObject;
}
virtual void setUserObject(CCObject* obj) {
GeodeNodeMetadata::set(this)->m_userObject = obj;
}
};
// 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) {
CCARRAY_FOREACH_B_TYPE(m_pChildren, child, CCNode) {
if (child->getID() == id) {
return child;
}
}
return nullptr;
}
CCNode* CCNode::getChildByIDRecursive(std::string const& id) {
if (auto child = this->getChildByID(id)) {
return child;
}
CCARRAY_FOREACH_B_TYPE(m_pChildren, child, CCNode) {
if (child = child->getChildByIDRecursive(id)) {
return child;
}
}
return nullptr;
}
#pragma warning(pop)