remove handler fixes by replacing dynamic_cast

This commit is contained in:
altalk23 2023-01-24 19:27:46 +03:00 committed by alk
parent 2626acba35
commit b00ab40ae2
3 changed files with 45 additions and 158 deletions

View file

@ -81,7 +81,7 @@ namespace geode::cast {
}
inline void* traverseTypeinfoFor(
void* ptr, ClassTypeinfoType* typeinfo, char const* afterIdent
void* ptr, ClassTypeinfoType const* typeinfo, char const* afterIdent
) {
DummySingleClass dummySingleClass;
DummyMultipleClass dummyMultipleClass;
@ -93,11 +93,11 @@ namespace geode::cast {
}
}
if (typeinfo->m_typeinfoVtable == typeinfoVtableOf(&dummySingleClass)) {
auto siTypeinfo = static_cast<SingleClassTypeinfoType*>(typeinfo);
auto siTypeinfo = static_cast<SingleClassTypeinfoType const*>(typeinfo);
return traverseTypeinfoFor(ptr, siTypeinfo->m_baseClassTypeinfo, afterIdent);
}
else if (typeinfo->m_typeinfoVtable == typeinfoVtableOf(&dummyMultipleClass)) {
auto vmiTypeinfo = static_cast<MultipleClassTypeinfoType*>(typeinfo);
auto vmiTypeinfo = static_cast<MultipleClassTypeinfoType const*>(typeinfo);
for (int i = 0; i < vmiTypeinfo->m_numBaseClass; ++i) {
auto& entry = vmiTypeinfo->m_baseClasses[i];
auto optionPtr = reinterpret_cast<std::byte*>(ptr) + entry.m_offset;
@ -109,20 +109,31 @@ namespace geode::cast {
return nullptr;
}
inline void* typeinfoCastInternal(void* ptr, ClassTypeinfoType const* beforeTypeinfo, ClassTypeinfoType const* afterTypeinfo, size_t hint) {
// we're not using either because uhhh idk
// hint is for diamond inheritance iirc which is never
// used in gd, so should be pretty safe to ignore
(void)beforeTypeinfo;
(void)hint;
auto vftable = *reinterpret_cast<VtableType**>(ptr);
auto dataPointer = static_cast<VtableTypeinfoType*>(static_cast<CompleteVtableType*>(vftable));
auto typeinfo = dataPointer->m_typeinfo;
auto basePtr = static_cast<std::byte*>(ptr) + dataPointer->m_offset;
auto afterIdent = afterTypeinfo->m_typeinfoName;
return traverseTypeinfoFor(basePtr, typeinfo, afterIdent);
}
template <class After, class Before>
inline After typeinfo_cast(Before ptr) {
static_assert(
std::is_polymorphic_v<std::remove_pointer_t<Before>>, "Input is not a polymorphic type"
std::is_polymorphic_v<std::remove_pointer_t<Before>> && std::is_polymorphic_v<std::remove_pointer_t<After>>,
"Input is not a polymorphic type"
);
auto basePtr = dynamic_cast<void*>(ptr);
auto vftable = *reinterpret_cast<VtableType**>(basePtr);
auto typeinfo =
static_cast<VtableTypeinfoType*>(static_cast<CompleteVtableType*>(vftable))->m_typeinfo;
auto afterTypeinfo =
reinterpret_cast<ClassTypeinfoType const*>(&typeid(std::remove_pointer_t<After>));
auto afterIdent = afterTypeinfo->m_typeinfoName;
return static_cast<After>(traverseTypeinfoFor(basePtr, typeinfo, afterIdent));
auto beforeTypeinfo = reinterpret_cast<ClassTypeinfoType const*>(&typeid(std::remove_pointer_t<Before>));
auto afterTypeinfo = reinterpret_cast<ClassTypeinfoType const*>(&typeid(std::remove_pointer_t<After>));
return static_cast<After>(typeinfoCastInternal(ptr, beforeTypeinfo, afterTypeinfo, 0));
}
}

View file

@ -0,0 +1,20 @@
#include <Geode/DefaultInclude.hpp>
#ifdef GEODE_IS_MACOS
USE_GEODE_NAMESPACE();
#include <Geode/modify/InternalMacros.hpp>
#include <Geode/loader/Mod.hpp>
$execute {
// this replaces the call to __dynamic_cast with a call to our own
// this is needed because the transitions in cocos uses dynamic cast to check
// layers, which fail on user layers due to typeinfo not matching
(void)Mod::get()->patch(
reinterpret_cast<void*>(base::get() + 0x603948),
toByteArray(&cast::typeinfoCastInternal)
);
}
#endif

View file

@ -1,144 +0,0 @@
// this is the fix for the dynamic_cast problems
// TODO: completely replace dynamic_cast on macos
#include <Geode/DefaultInclude.hpp>
#if defined(GEODE_IS_IOS) || defined(GEODE_IS_MACOS)
USE_GEODE_NAMESPACE();
#define HandlerFixFor(CCUtility) \
struct CCUtility##HandlerFix : Modify<CCUtility##HandlerFix, CCUtility##Handler> { \
void destructor() { \
if (m_pDelegate) { \
cocos2d::CCObject* pObject = base_cast<cocos2d::CCObject*>(m_pDelegate); \
if (pObject) { \
pObject->release(); \
} \
} \
} \
\
bool initWithDelegate(cocos2d::CCUtility##Delegate* pDelegate) { \
cocos2d::CCObject* pObject = base_cast<cocos2d::CCObject*>(pDelegate); \
if (pObject) { \
m_pDelegate = pDelegate; \
pObject->retain(); \
return true; \
} \
return false; \
} \
\
static cocos2d::CCUtility##Handler* handlerWithDelegate( \
cocos2d::CCUtility##Delegate* pDelegate \
) { \
cocos2d::CCUtility##Handler* pHandler = new cocos2d::CCUtility##Handler(); \
\
if (pHandler) { \
if (pHandler->initWithDelegate(pDelegate)) { \
pHandler->autorelease(); \
} \
else { \
CC_SAFE_RELEASE_NULL(pHandler); \
pHandler = CCUtility##Handler::handlerWithDelegate(pDelegate); \
} \
} \
\
return pHandler; \
} \
}
// clang-format off
#include <Geode/modify/CCKeypadHandler.hpp>
HandlerFixFor(CCKeypad);
#include <Geode/modify/CCKeyboardHandler.hpp>
HandlerFixFor(CCKeyboard);
#include <Geode/modify/CCMouseHandler.hpp>
HandlerFixFor(CCMouse);
#include <Geode/modify/CCTargetedTouchHandler.hpp>
struct CCTargetedTouchHandlerFix : Modify<CCTargetedTouchHandlerFix, CCTargetedTouchHandler> {
void destructor() {
if (m_pDelegate) {
cocos2d::CCObject* pObject = base_cast<cocos2d::CCObject*>(m_pDelegate);
if (pObject) {
// the entire destructor
pObject->release();
CC_SAFE_RELEASE(m_pClaimedTouches);
}
}
}
bool initWithDelegate(cocos2d::CCTouchDelegate *pDelegate, int nPriority, bool bSwallow) {
cocos2d::CCObject* pObject = base_cast<cocos2d::CCObject*>(pDelegate);
if (pObject) {
m_pDelegate = pDelegate;
pObject->retain();
m_nPriority = nPriority;
m_nEnabledSelectors = 0;
m_pClaimedTouches = new cocos2d::CCSet();
m_bSwallowsTouches = bSwallow;
return true;
}
return false;
}
static cocos2d::CCTargetedTouchHandler* handlerWithDelegate(cocos2d::CCTouchDelegate *pDelegate, int nPriority, bool bSwallow) {
cocos2d::CCTargetedTouchHandler* pHandler = new cocos2d::CCTargetedTouchHandler();
if (pHandler) {
if (pHandler->initWithDelegate(pDelegate, nPriority, bSwallow)) {
pHandler->autorelease();
}
else {
CC_SAFE_RELEASE_NULL(pHandler);
pHandler = CCTargetedTouchHandler::handlerWithDelegate(pDelegate, nPriority, bSwallow);
}
}
return pHandler;
}
};
#include <Geode/modify/CCStandardTouchHandler.hpp>
struct CCStandardTouchHandlerFix : Modify<CCStandardTouchHandlerFix, CCStandardTouchHandler> {
void destructor() {
if (m_pDelegate) {
cocos2d::CCObject* pObject = base_cast<cocos2d::CCObject*>(m_pDelegate);
if (pObject) {
// the entire destructor
pObject->release();
}
}
}
bool initWithDelegate(cocos2d::CCTouchDelegate *pDelegate, int nPriority) {
cocos2d::CCObject* pObject = base_cast<cocos2d::CCObject*>(pDelegate);
if (pObject) {
m_pDelegate = pDelegate;
pObject->retain();
m_nPriority = nPriority;
m_nEnabledSelectors = 0;
return true;
}
return false;
}
static cocos2d::CCStandardTouchHandler* handlerWithDelegate(cocos2d::CCTouchDelegate *pDelegate, int nPriority) {
cocos2d::CCStandardTouchHandler* pHandler = new cocos2d::CCStandardTouchHandler();
if (pHandler) {
if (pHandler->initWithDelegate(pDelegate, nPriority)) {
pHandler->autorelease();
}
else {
CC_SAFE_RELEASE_NULL(pHandler);
pHandler = CCStandardTouchHandler::handlerWithDelegate(pDelegate, nPriority);
}
}
return pHandler;
}
};
// clang-format on
#endif