1717
1818namespace AlphaUtils {
1919
20+ static uint64_t fnv1aHash (char const * str) {
21+ uint64_t hash = 0xcbf29ce484222325 ;
22+ while (*str) {
23+ hash ^= *str++;
24+ hash *= 0x100000001b3 ;
25+ }
26+ return hash;
27+ }
28+
29+ template <typename T>
30+ class NoHashHasher ;
31+
32+ template <>
33+ class NoHashHasher <uint64_t > {
34+ public:
35+ size_t operator ()(uint64_t key) const {
36+ return key;
37+ }
38+ };
39+
40+ class ObjectFieldContainer {
41+ private:
42+ std::vector<void *> m_containedFields;
43+ std::vector<std::function<void (void *)>> m_destructorFunctions;
44+
45+ public:
46+ ~ObjectFieldContainer () {
47+ for (auto i = 0u ; i < m_containedFields.size (); i++) {
48+ if (m_destructorFunctions[i] && m_containedFields[i]) {
49+ m_destructorFunctions[i](m_containedFields[i]);
50+ operator delete (m_containedFields[i]);
51+ }
52+ }
53+ }
54+
55+ void * getField (size_t index) {
56+ while (m_containedFields.size () <= index) {
57+ m_containedFields.push_back (nullptr );
58+ m_destructorFunctions.push_back (nullptr );
59+ }
60+ return m_containedFields.at (index);
61+ }
62+
63+ void * setField (size_t index, size_t size, std::function<void (void *)> destructor) {
64+ m_containedFields.at (index) = operator new (size);
65+ m_destructorFunctions.at (index) = std::move (destructor);
66+ return m_containedFields.at (index);
67+ }
68+
69+ static ObjectFieldContainer* from (cocos2d::CCObject* node, char const * forClass) {
70+ // return node->getFieldContainer(forClass);
71+ }
72+ };
73+
74+ class ObjectMetadata final : public cocos2d::CCNode {
75+ private:
76+ std::unordered_map<uint64_t , ObjectFieldContainer*, NoHashHasher<uint64_t >> m_classFieldContainers;
77+
78+ friend class cocos2d ::CCObject;
79+
80+ ObjectMetadata () {}
81+
82+ virtual ~ObjectMetadata () {
83+ for (auto & [_, container] : m_classFieldContainers) {
84+ delete container;
85+ }
86+ }
87+
88+ public:
89+ static ObjectMetadata* set (CCObject* target) {
90+ if (!target) return nullptr ;
91+
92+ auto meta = new ObjectMetadata ();
93+ meta->autorelease ();
94+
95+ target->m_pUserObject = meta;
96+ meta->retain ();
97+
98+ return meta;
99+ }
100+
101+ ObjectFieldContainer* getFieldContainer (char const * forClass) {
102+ auto hash = fnv1aHash (forClass);
103+
104+ auto & container = m_classFieldContainers[hash];
105+ if (!container) {
106+ container = new ObjectFieldContainer ();
107+ }
108+
109+ return container;
110+ }
111+ };
112+
113+ GEODE_DLL size_t getFieldIndexForClass (char const * name);
114+
115+ template <class Parent , class Base >
116+ class ObjectFieldIntermediate {
117+ using Intermediate = Modify<Parent, Base>;
118+ std::aligned_storage_t <std::alignment_of_v<Base>, std::alignment_of_v<Base>> m_padding;
119+
120+ public:
121+ static void fieldConstructor (void * offsetField) {
122+ (void ) new (offsetField) typename Parent::Fields ();
123+ }
124+
125+ static void fieldDestructor (void * offsetField) {
126+ static_cast <typename Parent::Fields*>(offsetField)->~Fields ();
127+ }
128+
129+ auto self () {
130+
131+ auto node = reinterpret_cast <Parent*>(reinterpret_cast <std::byte*>(this ) - sizeof (Base));
132+ auto container = ObjectFieldContainer::from (node, typeid (Base).name ());
133+ static size_t index = getFieldIndexForClass (typeid (Base).name ());
134+ auto offsetField = container->getField (index);
135+ if (!offsetField) {
136+ offsetField = container->setField (
137+ index, sizeof (typename Parent::Fields), &ObjectFieldIntermediate::fieldDestructor
138+ );
139+ ObjectFieldIntermediate::fieldConstructor (offsetField);
140+ }
141+
142+ return reinterpret_cast <typename Parent::Fields*>(offsetField);
143+ }
144+ auto operator ->() {
145+ return this ->self ();
146+ }
147+ };
148+
20149 struct ModifyInfo {
21150 int priority;
22151 std::function<void (cocos2d::CCNode*)> method;
@@ -39,6 +168,12 @@ namespace AlphaUtils {
39168 static int modifyPrio () { return 0 ; }
40169 };
41170
171+ template <class Derived >
172+ struct ObjectWrapper : public cocos2d ::CCObject {
173+ ObjectFieldIntermediate<Derived, cocos2d::CCObject> m_fields;
174+ static int modifyPrio () { return 0 ; }
175+ };
176+
42177 template <class T >
43178 class ModifyLoad {
44179 public:
@@ -65,3 +200,5 @@ struct derived : AlphaUtils::NodeWrapper<derived>
65200
66201#define $nodeModify(...) \
67202 GEODE_INVOKE (GEODE_CONCAT(MODIFY, GEODE_NUMBER_OF_ARGS(__VA_ARGS__)), __VA_ARGS__)
203+
204+ #define $objectModify(...) $nodeModify(__VA_ARGS__)
0 commit comments