mirror of
https://github.com/geode-sdk/geode.git
synced 2025-02-17 00:30:26 -05:00
Merge branch 'main' of https://github.com/geode-sdk/geode into main
This commit is contained in:
commit
b25740dc98
16 changed files with 122 additions and 180 deletions
|
@ -71,6 +71,15 @@ namespace geode::modifier {
|
|||
return Ok(m_hooks[name]);
|
||||
}
|
||||
|
||||
Result<> setHookPriority(std::string const& name, int32_t priority) {
|
||||
auto res = this->getHook(name);
|
||||
if (!res) {
|
||||
return Err(res.unwrapErr());
|
||||
}
|
||||
res.unwrap()->setPriority(priority);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
// unordered_map<handles> idea
|
||||
ModifyBase() {
|
||||
// i really dont want to recompile codegen
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
20
loader/src/hooks/DynamicCastFix.cpp
Normal file
20
loader/src/hooks/DynamicCastFix.cpp
Normal 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
|
|
@ -43,6 +43,12 @@ $execute {
|
|||
};
|
||||
|
||||
struct CustomMenuLayer : Modify<CustomMenuLayer, MenuLayer> {
|
||||
static void onModify(auto& self) {
|
||||
if (!self.setHookPriority("MenuLayer::init", GEODE_ID_PRIORITY)) {
|
||||
log::warn("Failed to set MenuLayer::init hook priority, node IDs may not work properly");
|
||||
}
|
||||
}
|
||||
|
||||
CCSprite* m_geodeButton;
|
||||
|
||||
bool init() {
|
||||
|
|
|
@ -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
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
static constexpr int32_t GEODE_ID_PRIORITY = 0x100000;
|
||||
|
||||
template<class T = CCNode>
|
||||
requires std::is_base_of_v<CCNode, T>
|
||||
T* setIDSafe(CCNode* node, int index, const char* id) {
|
||||
|
|
|
@ -52,6 +52,12 @@ $register_ids(CreatorLayer) {
|
|||
}
|
||||
|
||||
struct CreatorLayerIDs : Modify<CreatorLayerIDs, CreatorLayer> {
|
||||
static void onModify(auto& self) {
|
||||
if (!self.setHookPriority("CreatorLayer::init", GEODE_ID_PRIORITY)) {
|
||||
log::warn("Failed to set CreatorLayer::init hook priority, node IDs may not work properly");
|
||||
}
|
||||
}
|
||||
|
||||
bool init() {
|
||||
if (!CreatorLayer::init()) return false;
|
||||
|
||||
|
|
|
@ -55,6 +55,12 @@ $register_ids(EditLevelLayer) {
|
|||
}
|
||||
|
||||
struct EditLevelLayerIDs : Modify<EditLevelLayerIDs, EditLevelLayer> {
|
||||
static void onModify(auto& self) {
|
||||
if (!self.setHookPriority("EditLevelLayer::init", GEODE_ID_PRIORITY)) {
|
||||
log::warn("Failed to set EditLevelLayer::init hook priority, node IDs may not work properly");
|
||||
}
|
||||
}
|
||||
|
||||
bool init(GJGameLevel* l) {
|
||||
if (!EditLevelLayer::init(l)) return false;
|
||||
|
||||
|
|
|
@ -213,6 +213,12 @@ $register_ids(EditorUI) {
|
|||
}
|
||||
|
||||
struct EditorUIIDs : Modify<EditorUIIDs, EditorUI> {
|
||||
static void onModify(auto& self) {
|
||||
if (!self.setHookPriority("EditorUI::init", GEODE_ID_PRIORITY)) {
|
||||
log::warn("Failed to set EditorUI::init hook priority, node IDs may not work properly");
|
||||
}
|
||||
}
|
||||
|
||||
bool init(LevelEditorLayer* lel) {
|
||||
if (!EditorUI::init(lel)) return false;
|
||||
|
||||
|
|
|
@ -59,6 +59,12 @@ $register_ids(GJGarageLayer) {
|
|||
}
|
||||
|
||||
struct GJGarageLayerIDs : Modify<GJGarageLayerIDs, GJGarageLayer> {
|
||||
static void onModify(auto& self) {
|
||||
if (!self.setHookPriority("GJGarageLayer::init", GEODE_ID_PRIORITY)) {
|
||||
log::warn("Failed to set GJGarageLayer::init hook priority, node IDs may not work properly");
|
||||
}
|
||||
}
|
||||
|
||||
bool init() {
|
||||
if (!GJGarageLayer::init()) return false;
|
||||
|
||||
|
|
|
@ -32,6 +32,12 @@ $register_ids(LevelBrowserLayer) {
|
|||
}
|
||||
|
||||
struct LevelBrowserLayerIDs : Modify<LevelBrowserLayerIDs, LevelBrowserLayer> {
|
||||
static void onModify(auto& self) {
|
||||
if (!self.setHookPriority("LevelBrowserLayer::init", GEODE_ID_PRIORITY)) {
|
||||
log::warn("Failed to set LevelBrowserLayer::init hook priority, node IDs may not work properly");
|
||||
}
|
||||
}
|
||||
|
||||
bool init(GJSearchObject* obj) {
|
||||
if (!LevelBrowserLayer::init(obj)) return false;
|
||||
|
||||
|
|
|
@ -81,6 +81,12 @@ $register_ids(LevelInfoLayer) {
|
|||
}
|
||||
|
||||
struct LevelInfoLayerIDs : Modify<LevelInfoLayerIDs, LevelInfoLayer> {
|
||||
static void onModify(auto& self) {
|
||||
if (!self.setHookPriority("LevelInfoLayer::init", GEODE_ID_PRIORITY)) {
|
||||
log::warn("Failed to set LevelInfoLayer::init hook priority, node IDs may not work properly");
|
||||
}
|
||||
}
|
||||
|
||||
bool init(GJGameLevel* level) {
|
||||
if (!LevelInfoLayer::init(level)) return false;
|
||||
|
||||
|
|
|
@ -66,6 +66,12 @@ $register_ids(LevelSearchLayer) {
|
|||
}
|
||||
|
||||
struct LevelSearchLayerIDs : Modify<LevelSearchLayerIDs, LevelSearchLayer> {
|
||||
static void onModify(auto& self) {
|
||||
if (!self.setHookPriority("LevelSearchLayer::init", GEODE_ID_PRIORITY)) {
|
||||
log::warn("Failed to set LevelSearchLayer::init hook priority, node IDs may not work properly");
|
||||
}
|
||||
}
|
||||
|
||||
bool init() {
|
||||
if (!LevelSearchLayer::init()) return false;
|
||||
|
||||
|
|
|
@ -197,6 +197,12 @@ $register_ids(LevelSettingsLayer) {
|
|||
}
|
||||
|
||||
struct LevelSettingsLayerIDs : Modify<LevelSettingsLayerIDs, LevelSettingsLayer> {
|
||||
static void onModify(auto& self) {
|
||||
if (!self.setHookPriority("LevelSettingsLayer::init", GEODE_ID_PRIORITY)) {
|
||||
log::warn("Failed to set LevelSettingsLayer::init hook priority, node IDs may not work properly");
|
||||
}
|
||||
}
|
||||
|
||||
bool init(LevelSettingsObject* levelSettings, LevelEditorLayer* editor) {
|
||||
if (!LevelSettingsLayer::init(levelSettings, editor)) return false;
|
||||
|
||||
|
@ -205,25 +211,3 @@ struct LevelSettingsLayerIDs : Modify<LevelSettingsLayerIDs, LevelSettingsLayer>
|
|||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <class... Params>
|
||||
struct Resolve2 {
|
||||
template <class Return>
|
||||
static constexpr auto func(Return(*ptr)(float)) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <class Return, class Class>
|
||||
static constexpr auto func(Return(Class::*ptr)(float)) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <class Return, class Class>
|
||||
static constexpr auto func(Return(Class::*ptr)(float) const) {
|
||||
return ptr;
|
||||
}
|
||||
};
|
||||
|
||||
#include <Geode/modify/PlayerObject.hpp>
|
||||
constexpr auto b = Resolve2<float>::func(&PlayerObject::runBallRotation);
|
|
@ -59,6 +59,12 @@ $register_ids(PauseLayer) {
|
|||
}
|
||||
|
||||
struct PauseLayerIDs : Modify<PauseLayerIDs, PauseLayer> {
|
||||
static void onModify(auto& self) {
|
||||
if (!self.setHookPriority("PauseLayer::customSetup", GEODE_ID_PRIORITY)) {
|
||||
log::warn("Failed to set PauseLayer::customSetup hook priority, node IDs may not work properly");
|
||||
}
|
||||
}
|
||||
|
||||
void customSetup() {
|
||||
PauseLayer::customSetup();
|
||||
|
||||
|
|
|
@ -21,6 +21,12 @@ $register_ids(UILayer) {
|
|||
}
|
||||
|
||||
struct UILayerIDs : Modify<UILayerIDs, UILayer> {
|
||||
static void onModify(auto& self) {
|
||||
if (!self.setHookPriority("UILayer::init", GEODE_ID_PRIORITY)) {
|
||||
log::warn("Failed to set UILayer::init hook priority, node IDs may not work properly");
|
||||
}
|
||||
}
|
||||
|
||||
bool init() {
|
||||
if (!UILayer::init()) return false;
|
||||
|
||||
|
|
Loading…
Reference in a new issue