2022-07-30 12:24:03 -04:00
|
|
|
#pragma once
|
2022-10-06 13:46:07 -04:00
|
|
|
|
2022-07-30 12:24:03 -04:00
|
|
|
#include "Traits.hpp"
|
2022-11-29 17:48:06 -05:00
|
|
|
#include <cocos2d.h>
|
2022-10-08 05:59:06 -04:00
|
|
|
#include <Geode/loader/Loader.hpp>
|
2022-07-30 12:24:03 -04:00
|
|
|
#include <vector>
|
|
|
|
|
2022-10-13 05:56:23 -04:00
|
|
|
namespace cocos2d {
|
2022-10-30 14:59:20 -04:00
|
|
|
class CCNode;
|
2022-10-13 05:56:23 -04:00
|
|
|
}
|
|
|
|
|
2022-07-30 12:24:03 -04:00
|
|
|
namespace geode::modifier {
|
2022-10-30 14:59:20 -04:00
|
|
|
class FieldContainer {
|
|
|
|
private:
|
|
|
|
std::vector<void*> m_containedFields;
|
|
|
|
std::vector<std::function<void(void*)>> m_destructorFunctions;
|
|
|
|
|
|
|
|
public:
|
|
|
|
~FieldContainer() {
|
|
|
|
for (auto i = 0u; i < m_containedFields.size(); i++) {
|
|
|
|
m_destructorFunctions[i](m_containedFields[i]);
|
|
|
|
operator delete(m_containedFields[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void* getField(size_t index) {
|
|
|
|
if (m_containedFields.size() <= index) {
|
|
|
|
m_containedFields.resize(index + 1);
|
|
|
|
m_destructorFunctions.resize(index + 1);
|
|
|
|
}
|
|
|
|
return m_containedFields.at(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
void* setField(size_t index, size_t size, std::function<void(void*)> destructor) {
|
|
|
|
m_containedFields.at(index) = operator new(size);
|
|
|
|
m_destructorFunctions.at(index) = destructor;
|
|
|
|
return m_containedFields.at(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
static FieldContainer* from(cocos2d::CCNode* node) {
|
|
|
|
return node->getFieldContainer();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-11-09 12:11:50 -05:00
|
|
|
template <class Parent, class Base>
|
2022-10-30 14:59:20 -04:00
|
|
|
class FieldIntermediate {
|
|
|
|
// Padding used for guaranteeing any member of parents
|
|
|
|
// will be in between sizeof(Intermediate) and sizeof(Parent)
|
|
|
|
uintptr_t m_padding;
|
2022-11-29 17:48:06 -05:00
|
|
|
static inline std::unordered_map<size_t, size_t> nextIndex;
|
|
|
|
|
|
|
|
static size_t getFieldIndexForClass(size_t hash) {
|
|
|
|
return nextIndex[hash]++;
|
|
|
|
}
|
2022-10-30 14:59:20 -04:00
|
|
|
|
|
|
|
public:
|
|
|
|
static void fieldConstructor(void* offsetField) {
|
|
|
|
std::array<std::byte, sizeof(Parent)> parentContainer;
|
|
|
|
|
|
|
|
auto parent = new (parentContainer.data()) Parent();
|
|
|
|
|
2022-11-09 12:11:50 -05:00
|
|
|
parent->Base::~Base();
|
2022-10-30 14:59:20 -04:00
|
|
|
|
|
|
|
std::memcpy(
|
2022-11-09 12:11:50 -05:00
|
|
|
offsetField, std::launder(&parentContainer[sizeof(Base)]),
|
|
|
|
sizeof(Parent) - sizeof(Base)
|
2022-10-30 14:59:20 -04:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fieldDestructor(void* offsetField) {
|
|
|
|
std::array<std::byte, sizeof(Parent)> parentContainer;
|
|
|
|
|
2022-11-09 12:11:50 -05:00
|
|
|
auto parent = new (parentContainer.data()) Base();
|
2022-10-30 14:59:20 -04:00
|
|
|
|
|
|
|
std::memcpy(
|
2022-11-09 12:11:50 -05:00
|
|
|
std::launder(&parentContainer[sizeof(Base)]), offsetField,
|
|
|
|
sizeof(Parent) - sizeof(Base)
|
2022-10-30 14:59:20 -04:00
|
|
|
);
|
|
|
|
|
|
|
|
static_cast<Parent*>(parent)->Parent::~Parent();
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class = std::enable_if_t<true>>
|
|
|
|
Parent* operator->() {
|
|
|
|
// get the this pointer of the base
|
|
|
|
auto node =
|
|
|
|
reinterpret_cast<Parent*>(reinterpret_cast<std::byte*>(this) - sizeof(Base));
|
|
|
|
static_assert(sizeof(Base) == offsetof(Parent, m_fields), "offsetof not correct");
|
|
|
|
auto container = FieldContainer::from(node);
|
2022-11-29 17:48:06 -05:00
|
|
|
static size_t index = getFieldIndexForClass(typeid(Base).hash_code());
|
2022-10-30 14:59:20 -04:00
|
|
|
// this pointer is offset
|
|
|
|
auto offsetField = container->getField(index);
|
|
|
|
if (!offsetField) {
|
|
|
|
offsetField = container->setField(
|
2022-11-09 12:11:50 -05:00
|
|
|
index, sizeof(Parent) - sizeof(Base), &FieldIntermediate::fieldDestructor
|
2022-10-30 14:59:20 -04:00
|
|
|
);
|
|
|
|
|
|
|
|
FieldIntermediate::fieldConstructor(offsetField);
|
|
|
|
}
|
|
|
|
|
|
|
|
return reinterpret_cast<Parent*>(
|
2022-11-09 12:11:50 -05:00
|
|
|
reinterpret_cast<std::byte*>(offsetField) - sizeof(Base)
|
2022-10-30 14:59:20 -04:00
|
|
|
);
|
|
|
|
}
|
|
|
|
};
|
2022-07-30 12:24:03 -04:00
|
|
|
|
|
|
|
}
|