2022-10-30 15:07:49 -04:00
|
|
|
#include <Geode/modify/Field.hpp>
|
2022-10-13 05:56:23 -04:00
|
|
|
#include <Geode/utils/cocos.hpp>
|
2022-10-13 04:31:23 -04:00
|
|
|
#include <Geode/modify/Field.hpp>
|
2022-10-17 09:08:12 -04:00
|
|
|
#include <Geode/modify/CCNode.hpp>
|
2022-10-30 14:56:36 -04:00
|
|
|
#include <cocos2d.h>
|
2022-10-06 13:46:07 -04:00
|
|
|
|
2023-03-10 14:33:24 -05:00
|
|
|
using namespace geode::prelude;
|
2022-10-06 13:46:07 -04:00
|
|
|
using namespace geode::modifier;
|
|
|
|
|
|
|
|
#pragma warning(push)
|
2022-10-30 14:56:36 -04:00
|
|
|
#pragma warning(disable : 4273)
|
2022-10-06 13:46:07 -04:00
|
|
|
|
|
|
|
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 = "";
|
2023-03-19 09:02:49 -04:00
|
|
|
Ref<Layout> m_layout = nullptr;
|
2023-02-06 14:36:08 -05:00
|
|
|
std::unique_ptr<LayoutOptions> m_layoutOptions = nullptr;
|
2022-10-25 15:57:40 -04:00
|
|
|
std::unordered_map<std::string, std::any> m_attributes;
|
2022-10-06 13:46:07 -04:00
|
|
|
|
|
|
|
friend class ProxyCCNode;
|
|
|
|
friend class cocos2d::CCNode;
|
|
|
|
|
|
|
|
GeodeNodeMetadata() : m_fieldContainer(new FieldContainer()) {}
|
2022-10-30 14:56:36 -04:00
|
|
|
|
2022-10-06 13:46:07 -04:00
|
|
|
virtual ~GeodeNodeMetadata() {
|
|
|
|
delete m_fieldContainer;
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
static GeodeNodeMetadata* set(CCNode* target) {
|
2022-10-06 15:33:56 -04:00
|
|
|
if (!target) return nullptr;
|
2022-10-30 14:56:36 -04:00
|
|
|
|
2022-10-06 13:46:07 -04:00
|
|
|
auto old = target->m_pUserObject;
|
2022-10-30 14:56:36 -04:00
|
|
|
// faster than dynamic_cast, technically can
|
2022-10-06 13:46:07 -04:00
|
|
|
// 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
|
2022-10-30 14:56:36 -04:00
|
|
|
#include <Geode/modify/CCNode.hpp>
|
2022-11-09 13:03:53 -05:00
|
|
|
struct ProxyCCNode : Modify<ProxyCCNode, CCNode> {
|
2022-10-06 13:46:07 -04:00
|
|
|
virtual CCObject* getUserObject() {
|
2022-11-17 15:24:37 -05:00
|
|
|
if (static_cast<CCObject*>(this) == static_cast<CCObject*>(CCDirector::get())) {
|
|
|
|
// apparently this function is the same as
|
|
|
|
// CCDirector::getNextScene so yeah
|
2022-11-17 15:29:08 -05:00
|
|
|
return m_pUserObject;
|
2022-11-17 15:24:37 -05:00
|
|
|
}
|
2022-10-06 13:46:07 -04:00
|
|
|
return GeodeNodeMetadata::set(this)->m_userObject;
|
|
|
|
}
|
|
|
|
virtual void setUserObject(CCObject* obj) {
|
|
|
|
GeodeNodeMetadata::set(this)->m_userObject = obj;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-03-01 17:02:09 -05:00
|
|
|
static inline std::unordered_map<std::string, size_t> s_nextIndex;
|
|
|
|
size_t modifier::getFieldIndexForClass(char const* name) {
|
|
|
|
return s_nextIndex[name]++;
|
2022-12-03 08:51:46 -05:00
|
|
|
}
|
2022-10-30 14:56:36 -04:00
|
|
|
|
2023-03-01 17:08:25 -05:00
|
|
|
size_t modifier::getFieldIndexForClass(size_t hash) {
|
2023-03-01 17:09:07 -05:00
|
|
|
return s_nextIndex[std::to_string(hash)]++;
|
2023-03-01 17:08:25 -05:00
|
|
|
}
|
|
|
|
|
2022-10-06 13:46:07 -04:00
|
|
|
// 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) {
|
2022-10-13 05:56:23 -04:00
|
|
|
for (auto child : CCArrayExt<CCNode>(m_pChildren)) {
|
2022-10-06 13:46:07 -04:00
|
|
|
if (child->getID() == id) {
|
|
|
|
return child;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
CCNode* CCNode::getChildByIDRecursive(std::string const& id) {
|
|
|
|
if (auto child = this->getChildByID(id)) {
|
|
|
|
return child;
|
|
|
|
}
|
2022-10-13 05:56:23 -04:00
|
|
|
for (auto child : CCArrayExt<CCNode>(m_pChildren)) {
|
2022-10-08 05:41:36 -04:00
|
|
|
if ((child = child->getChildByIDRecursive(id))) {
|
2022-10-06 13:46:07 -04:00
|
|
|
return child;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2023-03-11 03:19:26 -05:00
|
|
|
void CCNode::removeChildByID(std::string const& id) {
|
|
|
|
if (auto child = this->getChildByID(id)) {
|
|
|
|
this->removeChild(child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-02 10:08:13 -05:00
|
|
|
void CCNode::setLayout(Layout* layout, bool apply, bool respectAnchor) {
|
|
|
|
if (respectAnchor && this->isIgnoreAnchorPointForPosition()) {
|
|
|
|
for (auto child : CCArrayExt<CCNode>(m_pChildren)) {
|
|
|
|
child->setPosition(child->getPosition() + this->getScaledContentSize());
|
|
|
|
}
|
|
|
|
this->ignoreAnchorPointForPosition(false);
|
|
|
|
}
|
2023-03-19 09:02:49 -04:00
|
|
|
GeodeNodeMetadata::set(this)->m_layout = layout;
|
2022-10-10 13:58:47 -04:00
|
|
|
if (apply) {
|
|
|
|
this->updateLayout();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Layout* CCNode::getLayout() {
|
2023-03-19 09:02:49 -04:00
|
|
|
return GeodeNodeMetadata::set(this)->m_layout.data();
|
2022-10-10 13:58:47 -04:00
|
|
|
}
|
|
|
|
|
2023-02-06 14:36:08 -05:00
|
|
|
void CCNode::setLayoutOptions(LayoutOptions* options, bool apply) {
|
|
|
|
GeodeNodeMetadata::set(this)->m_layoutOptions.reset(options);
|
|
|
|
if (apply && m_pParent) {
|
|
|
|
m_pParent->updateLayout();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LayoutOptions* CCNode::getLayoutOptions() {
|
|
|
|
return GeodeNodeMetadata::set(this)->m_layoutOptions.get();
|
|
|
|
}
|
|
|
|
|
2023-02-11 05:06:37 -05:00
|
|
|
void CCNode::updateLayout(bool updateChildOrder) {
|
|
|
|
if (updateChildOrder) {
|
|
|
|
this->sortAllChildren();
|
|
|
|
}
|
2023-03-19 09:02:49 -04:00
|
|
|
if (auto layout = GeodeNodeMetadata::set(this)->m_layout.data()) {
|
2023-02-02 10:08:13 -05:00
|
|
|
layout->apply(this);
|
2022-10-10 13:58:47 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-25 15:57:40 -04:00
|
|
|
void CCNode::setAttribute(std::string const& attr, std::any value) {
|
|
|
|
GeodeNodeMetadata::set(this)->m_attributes[attr] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::optional<std::any> CCNode::getAttributeInternal(std::string const& attr) {
|
|
|
|
auto meta = GeodeNodeMetadata::set(this);
|
|
|
|
if (meta->m_attributes.count(attr)) {
|
|
|
|
return meta->m_attributes.at(attr);
|
|
|
|
}
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
2022-10-06 13:46:07 -04:00
|
|
|
#pragma warning(pop)
|