From 8dd2e15c383f7829a4e5db0a3c5a54b32dc2076f Mon Sep 17 00:00:00 2001
From: altalk23 <45172705+altalk23@users.noreply.github.com>
Date: Mon, 2 Oct 2023 16:50:10 +0300
Subject: [PATCH] fix dynamic cast

---
 loader/include/Geode/platform/ItaniumCast.hpp | 42 +++++++------------
 loader/include/Geode/platform/android.hpp     |  8 +---
 loader/src/hooks/DynamicCastFix.cpp           | 21 +++++-----
 3 files changed, 28 insertions(+), 43 deletions(-)

diff --git a/loader/include/Geode/platform/ItaniumCast.hpp b/loader/include/Geode/platform/ItaniumCast.hpp
index 93cd024e..8f90d179 100644
--- a/loader/include/Geode/platform/ItaniumCast.hpp
+++ b/loader/include/Geode/platform/ItaniumCast.hpp
@@ -1,8 +1,6 @@
 #pragma once
 
 namespace geode::cast {
-    using uinthalf_t = uint32_t;
-    using inthalf_t = int32_t;
 
     struct DummyClass {
         virtual ~DummyClass() {}
@@ -14,8 +12,10 @@ namespace geode::cast {
 
     struct DummyMultipleClass : DummySingleClass, DummyClass2 {};
 
+    struct VtableType;
+
     struct ClassTypeinfoType {
-        void** m_typeinfoVtable;
+        VtableType* m_typeinfoVtable;
         char const* m_typeinfoName;
     };
 
@@ -23,16 +23,17 @@ namespace geode::cast {
         ClassTypeinfoType* m_baseClassTypeinfo;
     };
 
-#pragma pack(push, 1)
-
     struct MultipleClassSingleEntryType {
         ClassTypeinfoType* m_baseClassTypeinfo;
-        uint8_t m_visibilityFlag;
-        inthalf_t m_offset;
-        uint8_t m_padding[sizeof(inthalf_t) - 1];
-    };
+        intptr_t m_metadata;
 
-#pragma pack(pop)
+        uint8_t visibilityFlag() const {
+            return m_metadata & 0xFF;
+        }
+        intptr_t offset() const {
+            return m_metadata >> 8;
+        }
+    };
 
     struct MultipleClassTypeinfoType : ClassTypeinfoType {
         uint32_t m_flags;
@@ -41,7 +42,7 @@ namespace geode::cast {
     };
 
     struct VtableTypeinfoType {
-        inthalf_t m_offset;
+        intptr_t m_offset;
         ClassTypeinfoType* m_typeinfo;
     };
 
@@ -51,36 +52,25 @@ namespace geode::cast {
 
     struct CompleteVtableType : VtableTypeinfoType, VtableType {};
 
-    inline void** typeinfoVtableOf(void* ptr) {
-        auto vftable = *reinterpret_cast<VtableType**>(ptr);
-
-        auto typeinfoPtr =
-            static_cast<VtableTypeinfoType*>(static_cast<CompleteVtableType*>(vftable));
-
-        return typeinfoPtr->m_typeinfo->m_typeinfoVtable;
-    }
-
     inline void* traverseTypeinfoFor(
         void* ptr, ClassTypeinfoType const* typeinfo, char const* afterIdent
     ) {
-        DummySingleClass dummySingleClass;
-        DummyMultipleClass dummyMultipleClass;
-
         {
             auto optionIdent = typeinfo->m_typeinfoName;
             if (std::strcmp(optionIdent, afterIdent) == 0) {
                 return ptr;
             }
         }
-        if (typeinfo->m_typeinfoVtable == typeinfoVtableOf(&dummySingleClass)) {
+        auto typeinfoVtableName = static_cast<CompleteVtableType*>(typeinfo->m_typeinfoVtable)->m_typeinfo->m_typeinfoName;
+        if (std::strcmp(typeinfoVtableName, "N10__cxxabiv120__si_class_type_infoE") == 0) {
             auto siTypeinfo = static_cast<SingleClassTypeinfoType const*>(typeinfo);
             return traverseTypeinfoFor(ptr, siTypeinfo->m_baseClassTypeinfo, afterIdent);
         }
-        else if (typeinfo->m_typeinfoVtable == typeinfoVtableOf(&dummyMultipleClass)) {
+        else if (std::strcmp(typeinfoVtableName, "N10__cxxabiv121__vmi_class_type_infoE") == 0) {
             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;
+                auto optionPtr = reinterpret_cast<std::byte*>(ptr) + entry.offset();
                 auto ret = traverseTypeinfoFor(optionPtr, entry.m_baseClassTypeinfo, afterIdent);
                 if (ret != nullptr) return ret;
             }
diff --git a/loader/include/Geode/platform/android.hpp b/loader/include/Geode/platform/android.hpp
index e19402bc..31c7edeb 100644
--- a/loader/include/Geode/platform/android.hpp
+++ b/loader/include/Geode/platform/android.hpp
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <dlfcn.h>
+#include "ItaniumCast.hpp"
 
 namespace geode {
     struct PlatformInfo {
@@ -12,10 +13,3 @@ namespace geode::base {
     /*GEODE_NOINLINE inline*/ uintptr_t get();
 }
 
-namespace geode::cast {
-    template <class After, class Before>
-    After typeinfo_cast(Before ptr) {
-        // yall have symbols smh
-        return dynamic_cast<After>(ptr);
-    }
-}
diff --git a/loader/src/hooks/DynamicCastFix.cpp b/loader/src/hooks/DynamicCastFix.cpp
index 3986eeae..5a17e56f 100644
--- a/loader/src/hooks/DynamicCastFix.cpp
+++ b/loader/src/hooks/DynamicCastFix.cpp
@@ -1,19 +1,20 @@
 #include <Geode/DefaultInclude.hpp>
-
-#ifdef GEODE_IS_MACOS
+#include <Geode/loader/Mod.hpp>
 
 using namespace geode::prelude;
 
-    #include <Geode/loader/Mod.hpp>
-    #include <Geode/modify/Modify.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
\ No newline at end of file
+    #if defined(GEODE_IS_MACOS)
+        (void)Mod::get()->patch(
+            reinterpret_cast<void*>(base::get() + 0x603948), toByteArray(&cast::typeinfoCastInternal)
+        );
+    #elif defined(GEODE_IS_ANDROID)
+        (void)Mod::get()->addHook(reinterpret_cast<void*>(base::get() + 0x519a8c), &cast::typeinfoCastInternal, "__dynamic_cast");
+    #endif
+
+
+}
\ No newline at end of file