├── Config.h ├── API ├── ResolveCall.hpp ├── Domain.hpp ├── String.hpp ├── Image.hpp ├── Thread.hpp ├── Callback.hpp └── Class.hpp ├── Utils ├── MemoryInfo.hpp ├── Hash.hpp ├── VTable.hpp ├── CacheInstance.hpp └── Helper.hpp ├── Unity ├── API │ ├── LayerMask.hpp │ ├── Component.hpp │ ├── Rigidbody.hpp │ ├── Object.hpp │ ├── Camera.hpp │ ├── Transform.hpp │ └── GameObject.hpp ├── Obfuscators.hpp ├── Structures │ ├── System_String.hpp │ ├── il2cppDictionary.hpp │ ├── Engine.hpp │ ├── il2cppArray.hpp │ └── il2cpp.hpp └── Defines.hpp ├── SystemTypeCache.hpp ├── Data.hpp ├── README.md ├── Defines.hpp ├── IL2CPP_Resolver.hpp ├── Vector2.hpp ├── Vector3.hpp └── Quaternion.hpp /Config.h: -------------------------------------------------------------------------------- 1 | #define BINARY_NAME "UnityFramework" 2 | 3 | #define WAIT_TIME_SEC 60 4 | -------------------------------------------------------------------------------- /API/ResolveCall.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace IL2CPP 4 | { 5 | // Without this function, you're pretty much fucked up. 6 | void* ResolveCall(const char* m_Name) 7 | { 8 | return reinterpret_cast(Functions.m_ResolveFunction)(m_Name); 9 | } 10 | } -------------------------------------------------------------------------------- /API/Domain.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace IL2CPP 4 | { 5 | namespace Domain 6 | { 7 | void* Get() 8 | { 9 | return reinterpret_cast(Functions.m_DomainGet)(); 10 | } 11 | 12 | Unity::il2cppAssembly** GetAssemblies(size_t* m_Size) 13 | { 14 | return reinterpret_cast(Functions.m_DomainGetAssemblies)(Get(), m_Size); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /API/String.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace IL2CPP 4 | { 5 | namespace String 6 | { 7 | Unity::System_String* New(const char* m_String) 8 | { 9 | return reinterpret_cast(Functions.m_StringNew)(m_String); 10 | } 11 | 12 | Unity::System_String* New(std::string m_String) 13 | { 14 | return New(&m_String[0]); 15 | } 16 | 17 | namespace NoGC 18 | { 19 | Unity::System_String* New(const char* m_String) 20 | { 21 | Unity::System_String* m_NewString = new Unity::System_String; 22 | m_NewString->m_pClass = IL2CPP::Class::Find(IL2CPP_RStr("System.String")); 23 | m_NewString->m_iLength = swprintf(m_NewString->m_wString, (sizeof(Unity::System_String::m_wString) / 4), L"%hs", m_String); 24 | 25 | return m_NewString; 26 | } 27 | 28 | Unity::System_String* New(std::string m_String) 29 | { 30 | return New(&m_String[0]); 31 | } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Utils/MemoryInfo.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class MemoryInfo 4 | { 5 | public: 6 | uint32_t index; 7 | const mach_header *header; 8 | const char *name; 9 | intptr_t address; 10 | }; 11 | 12 | // Credit KittyMemory 13 | MemoryInfo getBaseAddress(const std::string &fileName) 14 | { 15 | MemoryInfo _info; 16 | 17 | const uint32_t imageCount = _dyld_image_count(); 18 | 19 | for (uint32_t i = 0; i < imageCount; i++) 20 | { 21 | const char *name = _dyld_get_image_name(i); 22 | if (!name) 23 | continue; 24 | 25 | std::string fullpath(name); 26 | 27 | if (fullpath.length() < fileName.length() || fullpath.compare(fullpath.length() - fileName.length(), fileName.length(), fileName) != 0) 28 | continue; 29 | 30 | _info.index = i; 31 | _info.header = _dyld_get_image_header(i); 32 | _info.name = _dyld_get_image_name(i); 33 | _info.address = _dyld_get_image_vmaddr_slide(i); 34 | 35 | break; 36 | } 37 | return _info; 38 | } 39 | -------------------------------------------------------------------------------- /API/Image.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace IL2CPP 4 | { 5 | namespace Image 6 | { 7 | Unity::il2cppImage* GetByName(const char *image) 8 | { 9 | // Retrieve the assemblies in the current domain 10 | size_t assemblyCount = 0; 11 | Unity::il2cppAssembly **assemblies = Domain::GetAssemblies(&assemblyCount); 12 | 13 | // Iterate over each assembly 14 | for (size_t i = 0; i < assemblyCount; ++i) 15 | { 16 | // Get the image from the current assembly 17 | void *img = reinterpret_cast(Functions.m_AssembliesGetImage)(assemblies[i]); 18 | 19 | // Get the image name 20 | const char *imgName = reinterpret_cast(Functions.m_ImageGetName)(img); 21 | 22 | // Compare the image name with the one we are looking for 23 | if (strcmp(imgName, image) == 0) 24 | { 25 | return reinterpret_cast(img); // Return the image cast to il2cppImage* 26 | } 27 | } 28 | 29 | // If no match is found, return nullptr 30 | return nullptr; 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /Unity/API/LayerMask.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Unity 4 | { 5 | struct LayerMaskFunctions_t 6 | { 7 | void* m_LayerToName = nullptr; 8 | void* m_NameToLayer = nullptr; 9 | }; 10 | LayerMaskFunctions_t m_LayerMaskFunctions; 11 | 12 | namespace LayerMask 13 | { 14 | void Initialize() 15 | { 16 | IL2CPP::SystemTypeCache::Initializer::Add(UNITY_LAYERMASK_CLASS); 17 | 18 | m_LayerMaskFunctions.m_LayerToName = IL2CPP::ResolveCall(UNITY_LAYERMASK_LAYERTONAME); 19 | m_LayerMaskFunctions.m_NameToLayer = IL2CPP::ResolveCall(UNITY_LAYERMASK_NAMETOLAYER); 20 | } 21 | 22 | System_String* LayerToName(unsigned int m_uLayer) 23 | { 24 | return reinterpret_cast(m_LayerMaskFunctions.m_LayerToName)(m_uLayer); 25 | } 26 | 27 | uint32_t NameToLayer(const char* m_pName) 28 | { 29 | return reinterpret_cast(m_LayerMaskFunctions.m_NameToLayer)(IL2CPP::String::New(m_pName)); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /Unity/API/Component.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Unity 4 | { 5 | struct ComponentFunctions_t 6 | { 7 | void* m_GetGameObject = nullptr; 8 | void* m_GetTransform = nullptr; 9 | }; 10 | ComponentFunctions_t m_ComponentFunctions; 11 | 12 | class CComponent : public CObject 13 | { 14 | public: 15 | CGameObject* GetGameObject() 16 | { 17 | return reinterpret_cast(m_ComponentFunctions.m_GetGameObject)(this); 18 | } 19 | 20 | CTransform* GetTransform() 21 | { 22 | return reinterpret_cast(m_ComponentFunctions.m_GetTransform)(this); 23 | } 24 | }; 25 | 26 | namespace Component 27 | { 28 | void Initialize() 29 | { 30 | IL2CPP::SystemTypeCache::Initializer::Add(UNITY_COMPONENT_CLASS); 31 | 32 | m_ComponentFunctions.m_GetGameObject = IL2CPP::ResolveCall(UNITY_COMPONENT_GETGAMEOBJECT); 33 | m_ComponentFunctions.m_GetTransform = IL2CPP::ResolveCall(UNITY_COMPONENT_GETTRANSFORM); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /SystemTypeCache.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace IL2CPP 4 | { 5 | namespace SystemTypeCache 6 | { 7 | std::unordered_map m_Map; 8 | 9 | void Add(uint32_t m_Hash, Unity::il2cppObject* m_SystemType) 10 | { 11 | m_Map[m_Hash] = m_SystemType; 12 | } 13 | 14 | void Add(const char* m_Name, Unity::il2cppObject* m_SystemType) 15 | { 16 | Add(Utils::Hash::Get(m_Name), m_SystemType); 17 | } 18 | 19 | Unity::il2cppObject* Get(uint32_t m_Hash) 20 | { 21 | return m_Map[m_Hash]; 22 | } 23 | 24 | Unity::il2cppObject* Get(const char* m_Name) 25 | { 26 | return Get(Utils::Hash::Get(m_Name)); 27 | } 28 | 29 | // Legacy Naming 30 | Unity::il2cppObject* Find(uint32_t m_Hash) 31 | { 32 | return Get(m_Hash); 33 | } 34 | 35 | Unity::il2cppObject* Find(const char* m_Name) 36 | { 37 | return Get(m_Name); 38 | } 39 | 40 | namespace Initializer 41 | { 42 | std::vector m_List; 43 | 44 | void Add(const char* m_Name) 45 | { 46 | m_List.emplace_back(m_Name); 47 | } 48 | 49 | void PreCache() 50 | { 51 | for (const char* m_Name : m_List) 52 | SystemTypeCache::Add(m_Name, IL2CPP::Class::GetSystemType(m_Name)); 53 | 54 | m_List.clear(); 55 | } 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /Data.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace IL2CPP 4 | { 5 | struct Globals_t 6 | { 7 | void* m_GameFramework = nullptr; 8 | }; 9 | Globals_t Globals; 10 | 11 | struct Functions_t 12 | { 13 | void* m_ClassFromName = nullptr; 14 | void* m_ClassGetFields = nullptr; 15 | void* m_ClassGetFieldFromName = nullptr; 16 | void* m_ClassGetMethods = nullptr; 17 | void* m_ClassGetMethodFromName = nullptr; 18 | void* m_ClassGetPropertyFromName = nullptr; 19 | void* m_ClassGetType = nullptr; 20 | 21 | void* m_DomainGet = nullptr; 22 | void* m_DomainGetAssemblies = nullptr; 23 | 24 | void* m_AssembliesGetImage = nullptr; 25 | void* m_ImageGetName = nullptr; 26 | 27 | void* m_Free = nullptr; 28 | 29 | void* m_ImageGetClass = nullptr; 30 | void* m_ImageGetClassCount = nullptr; 31 | 32 | void* m_ResolveFunction = nullptr; 33 | 34 | void* m_StringNew = nullptr; 35 | 36 | void* m_ThreadAttach = nullptr; 37 | void* m_ThreadDetach = nullptr; 38 | 39 | void* m_TypeGetObject = nullptr; 40 | 41 | void* m_pObjectNew = nullptr; 42 | void* m_MethodGetParamName = nullptr; 43 | void* m_MethodGetParam = nullptr; 44 | void* m_ClassFromIl2cppType = nullptr; 45 | 46 | void* m_FieldStaticGetValue = nullptr; 47 | void* m_FieldStaticSetValue = nullptr; 48 | }; 49 | Functions_t Functions; 50 | } 51 | -------------------------------------------------------------------------------- /Utils/Hash.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace IL2CPP 4 | { 5 | namespace Utils 6 | { 7 | namespace Hash 8 | { 9 | uint32_t Get(const char* m_String) 10 | { 11 | uint32_t m_Hash = 0; 12 | 13 | for (; *m_String; ++m_String) 14 | { 15 | m_Hash += *m_String; 16 | m_Hash += m_Hash << 10; 17 | m_Hash ^= m_Hash >> 6; 18 | } 19 | 20 | m_Hash += m_Hash << 3; 21 | m_Hash ^= m_Hash >> 11; 22 | m_Hash += m_Hash << 15; 23 | 24 | return m_Hash; 25 | } 26 | 27 | constexpr uint32_t GetCompileTime(const char* m_String) 28 | { 29 | uint32_t m_Hash = 0; 30 | 31 | for (; *m_String; ++m_String) 32 | { 33 | m_Hash += *m_String; 34 | m_Hash += m_Hash << 10; 35 | m_Hash ^= m_Hash >> 6; 36 | } 37 | 38 | m_Hash += m_Hash << 3; 39 | m_Hash ^= m_Hash >> 11; 40 | m_Hash += m_Hash << 15; 41 | 42 | return m_Hash; 43 | } 44 | } 45 | } 46 | } 47 | 48 | #define IL2CPP_HASH(m_String) \ 49 | [](){ \ 50 | static constexpr uint32_t m_Hash = IL2CPP::Utils::Hash::GetCompileTime(m_String); \ 51 | return m_Hash; \ 52 | }() 53 | -------------------------------------------------------------------------------- /Unity/Obfuscators.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Unity 4 | { 5 | namespace Obfuscators 6 | { 7 | // Should do the basic work 8 | std::string ROT_String(const char* pString, int iValue) 9 | { 10 | std::string sRet; 11 | size_t sSize = strlen(pString); 12 | for (size_t i = 0; sSize > i; ++i) 13 | { 14 | bool bIsUppercase = pString[i] >= 'A' && 'Z' >= pString[i]; 15 | bool bIsLowercase = !bIsUppercase && pString[i] >= 'a' && 'z' >= pString[i]; 16 | if (!bIsUppercase && !bIsLowercase) 17 | { 18 | sRet += pString[i]; 19 | continue; 20 | } 21 | 22 | int iNewValue = static_cast(pString[i]) + iValue; 23 | if (bIsUppercase) 24 | { 25 | int iMaxValue = static_cast('Z'); 26 | while (iNewValue > iMaxValue) iNewValue = static_cast('A') + (iNewValue - iMaxValue); 27 | } 28 | else 29 | { 30 | int iMaxValue = static_cast('z'); 31 | while (iNewValue > iMaxValue) iNewValue = static_cast('a') + (iNewValue - iMaxValue); 32 | } 33 | 34 | sRet += static_cast(iNewValue); 35 | } 36 | 37 | sRet += '\0'; 38 | return sRet; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Utils/VTable.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace IL2CPP 4 | { 5 | namespace Utils 6 | { 7 | namespace VTable 8 | { 9 | void ReplaceFunction(void** m_VTableFunc, void* m_NewFunc, void** m_Original = nullptr) 10 | { // Researched code, I don't know if it works properly as VirtualProtect from WIN API 11 | if (!m_VTableFunc) 12 | return; 13 | 14 | long pageSize = sysconf(_SC_PAGESIZE); 15 | 16 | uintptr_t pageStart = ((uintptr_t)m_VTableFunc) & ~(pageSize - 1); 17 | 18 | if (mprotect((void*)pageStart, pageSize, PROT_READ | PROT_WRITE) == 0) 19 | { 20 | if (m_Original) 21 | *m_Original = *m_VTableFunc; 22 | *m_VTableFunc = m_NewFunc; 23 | 24 | mprotect((void*)pageStart, pageSize, PROT_READ | PROT_EXEC); 25 | } 26 | } 27 | 28 | void** FindFunction(void** m_VTable, int m_Count, std::initializer_list m_Opcodes) 29 | { 30 | size_t m_OpcodeSize = m_Opcodes.size(); 31 | const void* m_OpcodesPtr = m_Opcodes.begin(); 32 | 33 | for (int i = 0; m_Count > i; ++i) 34 | { 35 | if (memcmp(m_VTable[i], m_OpcodesPtr, m_OpcodeSize) == 0) 36 | return &m_VTable[i]; 37 | } 38 | 39 | return 0; 40 | } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IOS-IL2CPP Resolver 2 | A run-time API resolver for IL2CPP Unity. 3 | 4 | 5 | ## Environment Variables 6 | 7 | Change in Config.h 8 | 9 | `BINARY_NAME` to target the right file! Default is "UnityFramework" 10 | 11 | `WAIT_TIME_SEC` 12 | 13 | ## Example usage 14 | #### This need to be added in your tweak.xm! 15 | ```c 16 | static inline const char* IL2CPP_FRAMEWORK(const char* NAME) { 17 | NSString *appPath = [[NSBundle mainBundle] bundlePath]; 18 | NSString *binaryPath = [NSString stringWithFormat:@"%s", NAME]; 19 | if ([binaryPath isEqualToString:@"UnityFramework"]) 20 | { 21 | binaryPath = [appPath stringByAppendingPathComponent:@"Frameworks/UnityFramework.framework/UnityFramework"]; 22 | } 23 | else 24 | { 25 | binaryPath = [appPath stringByAppendingPathComponent:binaryPath]; 26 | } 27 | return [binaryPath UTF8String]; 28 | } 29 | ``` 30 | ### INIT (IMPORTANT) 31 | ```c 32 | #include "IL2CPP_Resolver.hpp" 33 | 34 | IL2CPP::Initialize(true, WAIT_TIME_SEC, IL2CPP_FRAMEWORK(BINARY_NAME) // This needs to be called once! 35 | 36 | IL2CPP::Initialize(false, WAIT_TIME_SEC, IL2CPP_FRAMEWORK(BINARY_NAME) // This will not wait for the module. 37 | ``` 38 | 39 | For more usage check the [wiki](https://github.com/Batchhh/IOS-Il2cppResolver/wiki/Start-here!) 40 | 41 | ## Authors 42 | 43 | - [@sneakyevil](https://www.github.com/sneakyevil) Base source 44 | - [@Batchh](https://www.github.com/Batchhh) Modified and adapted for IOS usage 45 | 46 | 47 | ## License 48 | 49 | [MIT](https://choosealicense.com/licenses/mit/) 50 | -------------------------------------------------------------------------------- /Unity/Structures/System_String.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(__clang__) 4 | #pragma clang diagnostic push 5 | #pragma clang diagnostic ignored "-Wtautological-undefined-compare" 6 | #pragma clang diagnostic ignored "-Wtautological-pointer-compare" 7 | #endif 8 | 9 | namespace Unity 10 | { 11 | struct System_String : il2cppObject 12 | { 13 | int32_t m_iLength; // 0x8 14 | wchar_t m_wString[1024]; // 0xC 15 | 16 | void Clear() 17 | { 18 | if (this == nullptr) return; 19 | 20 | memset(m_wString, 0, static_cast(m_iLength) * 2); 21 | m_iLength = 0; 22 | } 23 | 24 | wchar_t* ToWideString() 25 | { 26 | return m_wString; 27 | } 28 | 29 | int32_t ToLength() 30 | { 31 | return m_iLength; 32 | } 33 | 34 | std::string ToString() 35 | { 36 | if ((this == nullptr) || (m_wString == nullptr) || (m_iLength == 0)) 37 | return ""; 38 | 39 | std::string retStr; 40 | mbstate_t state = mbstate_t(); 41 | char buf[MB_CUR_MAX]; 42 | 43 | for (int32_t i = 0; i < m_iLength; ++i) 44 | { 45 | size_t ret = wcrtomb(buf, m_wString[i], &state); 46 | if (ret == (size_t)-1) 47 | { 48 | return ""; 49 | } 50 | retStr.append(buf, ret); 51 | } 52 | return retStr; 53 | } 54 | }; 55 | } 56 | 57 | #if defined(__clang__) 58 | #pragma clang diagnostic pop 59 | #endif 60 | -------------------------------------------------------------------------------- /Unity/Structures/il2cppDictionary.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Unity 4 | { 5 | template 6 | struct il2cppDictionary : il2cppObject 7 | { 8 | struct Entry 9 | { 10 | int m_iHashCode; 11 | int m_iNext; 12 | TKey m_tKey; 13 | TValue m_tValue; 14 | }; 15 | il2cppArray* m_pBuckets; 16 | il2cppArray* m_pEntries; 17 | int m_iCount; 18 | int m_iVersion; 19 | int m_iFreeList; 20 | int m_iFreeCount; 21 | void* m_pComparer; 22 | void* m_pKeys; 23 | void* m_pValues; 24 | 25 | Entry* GetEntry() 26 | { 27 | return (Entry*)m_pEntries->GetData(); 28 | } 29 | 30 | TKey GetKeyByIndex(int iIndex) 31 | { 32 | TKey tKey = { 0 }; 33 | 34 | Entry* pEntry = GetEntry(); 35 | if (pEntry) 36 | tKey = pEntry[iIndex].m_tKey; 37 | 38 | return tKey; 39 | } 40 | 41 | TValue GetValueByIndex(int iIndex) 42 | { 43 | TValue tValue = { 0 }; 44 | 45 | Entry* pEntry = GetEntry(); 46 | if (pEntry) 47 | tValue = pEntry[iIndex].m_tValue; 48 | 49 | return tValue; 50 | } 51 | 52 | TValue GetValueByKey(TKey tKey) 53 | { 54 | TValue tValue = { 0 }; 55 | for (int i = 0; i < m_iCount; i++) { 56 | if (GetEntry()[i].m_tKey == tKey) 57 | tValue = GetEntry()[i].m_tValue; 58 | } 59 | return tValue; 60 | } 61 | }; 62 | } 63 | -------------------------------------------------------------------------------- /Unity/Structures/Engine.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #pragma clang diagnostic ignored "-Wmissing-braces" 3 | 4 | namespace Unity 5 | { 6 | struct Vector4 7 | { 8 | float x, y, z, w; 9 | 10 | Vector4() { x = y = z = w = 0.f; } 11 | Vector4(float f1, float f2, float f3, float f4) { x = f1; y = f2; z = f3; w = f4; } 12 | }; 13 | 14 | struct Bounds 15 | { 16 | Vector3 m_vCenter; 17 | Vector3 m_vExtents; 18 | }; 19 | 20 | struct Plane 21 | { 22 | Vector3 m_vNormal; 23 | float fDistance; 24 | }; 25 | 26 | struct Ray 27 | { 28 | Vector3 m_vOrigin; 29 | Vector3 m_vDirection; 30 | }; 31 | 32 | struct Rect 33 | { 34 | float fX, fY; 35 | float fWidth, fHeight; 36 | 37 | Rect() { fX = fY = fWidth = fHeight = 0.f; } 38 | Rect(float f1, float f2, float f3, float f4) { fX = f1; fY = f2; fWidth = f3; fHeight = f4; } 39 | }; 40 | 41 | struct Color 42 | { 43 | float r, g, b, a; 44 | 45 | Color() { r = g = b = a = 0.f; } 46 | Color(float fRed = 0.f, float fGreen = 0.f, float fBlue = 0.f, float fAlpha = 1.f) { r = fRed; g = fGreen; b = fBlue; a = fAlpha; } 47 | }; 48 | 49 | struct Matrix4x4 50 | { 51 | float m[4][4] = { 0 }; 52 | 53 | Matrix4x4() { } 54 | 55 | float* operator[](int i) { return m[i]; } 56 | }; 57 | 58 | struct CSMatrix4x4 59 | { 60 | float 61 | m11 = 0, m12 = 0, m13 = 0, m14 = 0, 62 | m21 = 0, m22 = 0, m23 = 0, m24 = 0, 63 | m31 = 0, m32 = 0, m33 = 0, m34 = 0, 64 | m41 = 0, m42 = 0, m43 = 0, m44 = 0; 65 | 66 | CSMatrix4x4() { } 67 | }; 68 | } 69 | -------------------------------------------------------------------------------- /Unity/API/Rigidbody.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Unity 4 | { 5 | struct RigidbodyFunctions_t 6 | { 7 | void* m_GetDetectCollisions = nullptr; 8 | void* m_GetVelocity = nullptr; 9 | void* m_SetDetectCollisions = nullptr; 10 | void* m_SetVelocity = nullptr; 11 | }; 12 | RigidbodyFunctions_t m_RigidbodyFunctions; 13 | 14 | class CRigidbody : public IL2CPP::CClass 15 | { 16 | public: 17 | bool GetDetectCollisions() 18 | { 19 | return reinterpret_cast(m_RigidbodyFunctions.m_GetDetectCollisions)(this); 20 | } 21 | 22 | void SetDetectCollisions(bool m_bDetect) 23 | { 24 | reinterpret_cast(m_RigidbodyFunctions.m_SetDetectCollisions)(this, m_bDetect); 25 | } 26 | 27 | Vector3 GetVelocity() 28 | { 29 | Vector3 vRet; 30 | reinterpret_cast(m_RigidbodyFunctions.m_GetVelocity)(this, vRet); 31 | return vRet; 32 | } 33 | 34 | void SetVelocity(Vector3 m_vVector) 35 | { 36 | reinterpret_cast(m_RigidbodyFunctions.m_SetVelocity)(this, m_vVector); 37 | } 38 | }; 39 | 40 | namespace RigidBody 41 | { 42 | void Initialize() 43 | { 44 | IL2CPP::SystemTypeCache::Initializer::Add(UNITY_RIGIDBODY_CLASS); 45 | 46 | m_RigidbodyFunctions.m_GetDetectCollisions = IL2CPP::ResolveCall(UNITY_RIGIDBODY_GETDETECTCOLLISIONS); 47 | m_RigidbodyFunctions.m_GetVelocity = IL2CPP::ResolveCall(UNITY_RIGIDBODY_GETVELOCITY); 48 | m_RigidbodyFunctions.m_SetDetectCollisions = IL2CPP::ResolveCall(UNITY_RIGIDBODY_SETDETECTCOLLISIONS); 49 | m_RigidbodyFunctions.m_SetVelocity = IL2CPP::ResolveCall(UNITY_RIGIDBODY_SETVELOCITY); 50 | 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /API/Thread.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace IL2CPP 4 | { 5 | namespace Thread 6 | { 7 | void* Attach(void* m_Domain) 8 | { 9 | return reinterpret_cast(Functions.m_ThreadAttach)(m_Domain); 10 | } 11 | 12 | void Detach(void* m_Thread) 13 | { 14 | reinterpret_cast(Functions.m_ThreadDetach)(m_Thread); 15 | } 16 | } 17 | 18 | // Our Stuff 19 | class CThread 20 | { 21 | public: 22 | void* m_OnStart = nullptr; 23 | void* m_OnEnd = nullptr; 24 | 25 | static void Handler(void* m_Reserved) 26 | { 27 | void* m_IL2CPPThread = Thread::Attach(Domain::Get()); 28 | 29 | CThread* m_Thread = reinterpret_cast(m_Reserved); 30 | void* m_ThreadStart = m_Thread->m_OnStart; 31 | void* m_ThreadEnd = m_Thread->m_OnEnd; 32 | delete m_Thread; 33 | 34 | reinterpret_cast(m_ThreadStart)(); 35 | if (m_ThreadEnd) 36 | reinterpret_cast(m_ThreadEnd)(); 37 | 38 | Thread::Detach(m_IL2CPPThread); 39 | } 40 | 41 | CThread() { /* Why would you even do this? */ } 42 | CThread(void* m_OnStartFunc, void* m_OnEndFunc) 43 | { 44 | m_OnStart = m_OnStartFunc; 45 | m_OnEnd = m_OnEndFunc; 46 | 47 | if (!m_OnStart) 48 | { 49 | IL2CPP_ASSERT("IL2CPP::CThread - m_OnStart is nullptr"); 50 | return; 51 | } 52 | 53 | std::thread (Handler, this).detach(); 54 | } 55 | }; 56 | 57 | namespace Thread 58 | { 59 | void Create(void* m_OnStartFunc, void* m_OnEndFunc = nullptr) 60 | { 61 | CThread* m_Thread = new CThread(m_OnStartFunc, m_OnEndFunc); 62 | IL2CPP_ASSERT(m_Thread && "IL2CPP::Thread::Create - Failed!"); 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /Defines.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define IL2CPP_INIT_EXPORT IL2CPP_RStr("il2cpp_init") 4 | #define IL2CPP_CLASS_FROM_NAME_EXPORT IL2CPP_RStr("il2cpp_class_from_name") 5 | #define IL2CPP_CLASS_GET_FIELDS IL2CPP_RStr("il2cpp_class_get_fields") 6 | #define IL2CPP_CLASS_GET_FIELD_FROM_NAME_EXPORT IL2CPP_RStr("il2cpp_class_get_field_from_name") 7 | #define IL2CPP_CLASS_GET_METHODS IL2CPP_RStr("il2cpp_class_get_methods") 8 | #define IL2CPP_CLASS_GET_METHOD_FROM_NAME_EXPORT IL2CPP_RStr("il2cpp_class_get_method_from_name") 9 | #define IL2CPP_CLASS_GET_PROPERTY_FROM_NAME_EXPORT IL2CPP_RStr("il2cpp_class_get_property_from_name") 10 | #define IL2CPP_CLASS_GET_TYPE_EXPORT IL2CPP_RStr("il2cpp_class_get_type") 11 | #define IL2CPP_DOMAIN_GET_EXPORT IL2CPP_RStr("il2cpp_domain_get") 12 | #define IL2CPP_DOMAIN_GET_ASSEMBLIES_EXPORT IL2CPP_RStr("il2cpp_domain_get_assemblies") 13 | #define IL2CPP_FREE_EXPORT IL2CPP_RStr("il2cpp_free") 14 | #define IL2CPP_IMAGE_GET_CLASS_EXPORT IL2CPP_RStr("il2cpp_image_get_class") 15 | #define IL2CPP_IMAGE_GET_CLASS_COUNT_EXPORT IL2CPP_RStr("il2cpp_image_get_class_count") 16 | #define IL2CPP_RESOLVE_FUNC_EXPORT IL2CPP_RStr("il2cpp_resolve_icall") 17 | #define IL2CPP_STRING_NEW_EXPORT IL2CPP_RStr("il2cpp_string_new") 18 | #define IL2CPP_THREAD_ATTACH_EXPORT IL2CPP_RStr("il2cpp_thread_attach") 19 | #define IL2CPP_THREAD_DETACH_EXPORT IL2CPP_RStr("il2cpp_thread_detach") 20 | #define IL2CPP_TYPE_GET_OBJECT_EXPORT IL2CPP_RStr("il2cpp_type_get_object") 21 | #define IL2CPP_OBJECT_NEW IL2CPP_RStr("il2cpp_object_new") 22 | #define IL2CPP_METHOD_GET_PARAM_NAME IL2CPP_RStr("il2cpp_method_get_param_name") 23 | #define IL2CPP_METHOD_GET_PARAM IL2CPP_RStr("il2cpp_method_get_param") 24 | #define IL2CPP_CLASS_FROM_IL2CPP_TYPE IL2CPP_RStr("il2cpp_class_from_il2cpp_type") 25 | #define IL2CPP_FIELD_STATIC_GET_VALUE IL2CPP_RStr("il2cpp_field_static_get_value") 26 | #define IL2CPP_FIELD_STATIC_SET_VALUE IL2CPP_RStr("il2cpp_field_static_set_value") 27 | 28 | #define IL2CPP_ASSEMBLY_GET_IMAGE IL2CPP_RStr("il2cpp_assembly_get_image") 29 | #define IL2CPP_IMAGE_GET_NAME IL2CPP_RStr("il2cpp_image_get_name") 30 | 31 | // Calling Convention 32 | #define IL2CPP_CALLING_CONVENTION * 33 | -------------------------------------------------------------------------------- /Utils/CacheInstance.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | struct CacheConfig { 12 | std::string typeName; 13 | std::vector* storage; 14 | std::function process; 15 | }; 16 | 17 | class CacheManager { 18 | public: 19 | CacheManager() : running(false) {} 20 | 21 | void AddCacheConfig(const std::string& typeName, std::vector& storage, std::function process = nullptr) { 22 | std::lock_guard lock(configMutex); 23 | configs[typeName] = { typeName, &storage, process }; 24 | } 25 | 26 | void StartCaching() { 27 | running.store(true); 28 | while (running.load()) { 29 | { 30 | std::lock_guard lock(configMutex); 31 | for (auto& [typeName, config] : configs) { 32 | config.storage->clear(); 33 | auto objects = Unity::Object::FindObjectsOfType(typeName.c_str()); 34 | 35 | if (objects) { 36 | for (int i = 0; i < objects->m_uMaxLength; i++) { 37 | if (auto component = objects->operator[](i)) { 38 | if (auto gameObject = component->GetGameObject()) { 39 | config.storage->push_back(gameObject); 40 | if (config.process) { 41 | config.process(gameObject); 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | } 49 | std::this_thread::sleep_for(std::chrono::milliseconds(1000)); 50 | } 51 | } 52 | 53 | void StopCaching() { 54 | running.store(false); 55 | } 56 | 57 | private: 58 | std::unordered_map configs; 59 | std::mutex configMutex; 60 | std::atomic running; 61 | }; 62 | 63 | extern CacheManager cacheManager; 64 | -------------------------------------------------------------------------------- /API/Callback.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace IL2CPP 4 | { 5 | struct CallbackHook_t 6 | { 7 | std::vector m_Funcs; 8 | 9 | void** m_VFunc = nullptr; 10 | void* m_Original = nullptr; 11 | }; 12 | 13 | namespace Callback 14 | { 15 | namespace OnUpdate 16 | { 17 | CallbackHook_t m_CallbackHook; 18 | 19 | void Add(void* m_pFunction) 20 | { 21 | m_CallbackHook.m_Funcs.emplace_back(m_pFunction); 22 | } 23 | 24 | void Hook(void* rcx) 25 | { 26 | for (void* m_Func : m_CallbackHook.m_Funcs) 27 | reinterpret_cast(m_Func)(); 28 | 29 | reinterpret_cast(m_CallbackHook.m_Original)(rcx); 30 | } 31 | } 32 | 33 | namespace OnLateUpdate 34 | { 35 | CallbackHook_t m_CallbackHook; 36 | 37 | void Add(void* m_pFunction) 38 | { 39 | m_CallbackHook.m_Funcs.emplace_back(m_pFunction); 40 | } 41 | 42 | void Hook(void* rcx) 43 | { 44 | for (void* m_Func : m_CallbackHook.m_Funcs) 45 | reinterpret_cast(m_Func)(); 46 | 47 | reinterpret_cast(m_CallbackHook.m_Original)(rcx); 48 | } 49 | } 50 | 51 | void Initialize() 52 | { 53 | void* m_IL2CPPThread = Thread::Attach(IL2CPP::Domain::Get()); 54 | 55 | // Find 56 | void** m_MonoBehaviourVTable = *reinterpret_cast(IL2CPP::Helper::GetMonoBehaviour()->m_CachedPtr); 57 | if (m_MonoBehaviourVTable) 58 | { 59 | #ifdef __aarch64__ 60 | OnUpdate::m_CallbackHook.m_VFunc = Utils::VTable::FindFunction(m_MonoBehaviourVTable, 99, { 0x02, 0x00, 0x80, 0xD2, 0x00, 0x00, 0x00, 0x14 }); // mov x2, #0 | b 61 | OnLateUpdate::m_CallbackHook.m_VFunc = Utils::VTable::FindFunction(m_MonoBehaviourVTable, 99, { 0x22, 0x00, 0x80, 0xD2, 0x00, 0x00, 0x00, 0x14 }); // mov x2, #1 | b 62 | #elif __arm__ 63 | OnUpdate::m_CallbackHook.m_VFunc = Utils::VTable::FindFunction(m_MonoBehaviourVTable, 99, { 0x00, 0x20, 0xA0, 0xE3, 0x00, 0x00, 0x00, 0xEA }); // mov r2, #0 | b 64 | OnLateUpdate::m_CallbackHook.m_VFunc = Utils::VTable::FindFunction(m_MonoBehaviourVTable, 99, { 0x01, 0x20, 0xA0, 0xE3, 0x00, 0x00, 0x00, 0xEA }); // mov r2, #1 | b 65 | #endif 66 | } 67 | 68 | IL2CPP::Thread::Detach(m_IL2CPPThread); 69 | 70 | // Replace (Hook) 71 | Utils::VTable::ReplaceFunction(OnUpdate::m_CallbackHook.m_VFunc, (void*)OnUpdate::Hook, &OnUpdate::m_CallbackHook.m_Original); 72 | Utils::VTable::ReplaceFunction(OnLateUpdate::m_CallbackHook.m_VFunc, (void*)OnLateUpdate::Hook, &OnLateUpdate::m_CallbackHook.m_Original); 73 | } 74 | 75 | void Uninitialize() 76 | { 77 | Utils::VTable::ReplaceFunction(OnUpdate::m_CallbackHook.m_VFunc, OnUpdate::m_CallbackHook.m_Original); 78 | Utils::VTable::ReplaceFunction(OnLateUpdate::m_CallbackHook.m_VFunc, OnLateUpdate::m_CallbackHook.m_Original); 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /Unity/Structures/il2cppArray.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Unity 4 | { 5 | template 6 | struct il2cppArray : il2cppObject 7 | { 8 | il2cppArrayBounds* m_pBounds = nullptr; 9 | uintptr_t m_uMaxLength = 0; 10 | T* m_pValues = nullptr; 11 | 12 | uintptr_t GetData() 13 | { 14 | return reinterpret_cast(&m_pValues); 15 | } 16 | 17 | T& operator[](unsigned int m_uIndex) 18 | { 19 | return *reinterpret_cast(GetData() + sizeof(T) * m_uIndex); 20 | } 21 | 22 | T& At(unsigned int m_uIndex) 23 | { 24 | return operator[](m_uIndex); 25 | } 26 | 27 | void Insert(T* m_pArray, uintptr_t m_uSize, uintptr_t m_uIndex = 0) 28 | { 29 | if ((m_uSize + m_uIndex) >= m_uMaxLength) 30 | { 31 | if (m_uIndex >= m_uMaxLength) 32 | return; 33 | 34 | m_uSize = m_uMaxLength - m_uIndex; 35 | } 36 | 37 | for (uintptr_t u = 0; m_uSize > u; ++u) 38 | operator[](u + m_uIndex) = m_pArray[u]; 39 | } 40 | 41 | void Fill(T m_tValue) 42 | { 43 | for (uintptr_t u = 0; m_uMaxLength > u; ++u) 44 | operator[](u) = m_tValue; 45 | } 46 | 47 | void RemoveAt(unsigned int m_uIndex) 48 | { 49 | if (m_uIndex >= m_uMaxLength) 50 | return; 51 | 52 | if (m_uMaxLength > (m_uIndex + 1)) 53 | { 54 | for (unsigned int u = m_uIndex; (static_cast(m_uMaxLength) - m_uIndex) > u; ++u) 55 | operator[](u) = operator[](u + 1); 56 | } 57 | 58 | --m_uMaxLength; 59 | } 60 | 61 | void RemoveRange(unsigned int m_uIndex, unsigned int m_uCount) 62 | { 63 | if (m_uCount == 0) 64 | m_uCount = 1; 65 | 66 | unsigned int m_uTotal = m_uIndex + m_uCount; 67 | if (m_uTotal >= m_uMaxLength) 68 | return; 69 | 70 | if (m_uMaxLength > (m_uTotal + 1)) 71 | { 72 | for (unsigned int u = m_uIndex; (static_cast(m_uMaxLength) - m_uTotal) >= u; ++u) 73 | operator[](u) = operator[](u + m_uCount); 74 | } 75 | 76 | m_uMaxLength -= m_uCount; 77 | } 78 | 79 | void RemoveAll() 80 | { 81 | if (m_uMaxLength > 0) 82 | { 83 | memset(GetData(), 0, sizeof(T) * m_uMaxLength); 84 | m_uMaxLength = 0; 85 | } 86 | } 87 | }; 88 | 89 | // Defined here because its basically same shit 90 | template 91 | struct il2cppList : il2cppObject 92 | { 93 | il2cppArray* m_pListArray; 94 | 95 | il2cppArray* ToArray() { return m_pListArray; } 96 | }; 97 | } -------------------------------------------------------------------------------- /Unity/API/Object.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #pragma clang diagnostic ignored "-Wunused-function" 4 | 5 | namespace Unity 6 | { 7 | struct ObjectFunctions_t 8 | { 9 | void* m_Destroy = nullptr; 10 | void* m_FindObjectsOfType = nullptr; 11 | void* m_GetName = nullptr; 12 | }; 13 | ObjectFunctions_t m_ObjectFunctions; 14 | 15 | class CObject : public IL2CPP::CClass 16 | { 17 | public: 18 | void Destroy(float fTimeDelay = 0.f) 19 | { 20 | reinterpret_cast(m_ObjectFunctions.m_Destroy)(this, fTimeDelay); 21 | } 22 | 23 | System_String* GetName() 24 | { 25 | return reinterpret_cast(m_ObjectFunctions.m_GetName)(this); 26 | } 27 | }; 28 | 29 | namespace Object 30 | { 31 | void Initialize() 32 | { 33 | IL2CPP::SystemTypeCache::Initializer::Add(UNITY_OBJECT_CLASS); 34 | 35 | m_ObjectFunctions.m_Destroy = IL2CPP::ResolveCall(UNITY_OBJECT_DESTROY); 36 | m_ObjectFunctions.m_FindObjectsOfType = IL2CPP::ResolveCall(UNITY_OBJECT_FINDOBJECTSOFTYPE); 37 | m_ObjectFunctions.m_GetName = IL2CPP::ResolveCall(UNITY_OBJECT_GETNAME); 38 | } 39 | 40 | static il2cppObject* New(il2cppClass* m_pClass) 41 | { 42 | return reinterpret_cast(IL2CPP::Functions.m_pObjectNew)(m_pClass); 43 | } 44 | 45 | template 46 | static il2cppArray* FindObjectsOfType(il2cppObject* m_pSystemType, bool m_bIncludeInactive = false) 47 | { 48 | return reinterpret_cast*(UNITY_CALLING_CONVENTION)(void*, bool)>(m_ObjectFunctions.m_FindObjectsOfType)(m_pSystemType, m_bIncludeInactive); 49 | } 50 | 51 | template 52 | static il2cppArray* FindObjectsOfType(const char* m_pSystemTypeName, bool m_bIncludeInactive = false) 53 | { 54 | il2cppClass* m_pClass = IL2CPP::Class::Find(m_pSystemTypeName); 55 | if (!m_pClass) return nullptr; 56 | 57 | return FindObjectsOfType(IL2CPP::Class::GetSystemType(m_pClass), m_bIncludeInactive); 58 | } 59 | 60 | template 61 | static T* FindObjectOfType(il2cppObject* m_pSystemType, bool m_bIncludeInactive = false) 62 | { 63 | il2cppArray* m_pArray = FindObjectsOfType(m_pSystemType, m_bIncludeInactive); 64 | if (!m_pArray || m_pArray->m_uMaxLength == 0U) return nullptr; 65 | 66 | return m_pArray->m_pValues[0]; 67 | } 68 | 69 | template 70 | static T* FindObjectOfType(const char* m_pSystemTypeName, bool m_bIncludeInactive = false) 71 | { 72 | il2cppClass* m_pClass = IL2CPP::Class::Find(m_pSystemTypeName); 73 | if (!m_pClass) return nullptr; 74 | 75 | return FindObjectOfType(IL2CPP::Class::GetSystemType(m_pClass), m_bIncludeInactive); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Unity/API/Camera.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Unity 4 | { 5 | struct CameraFunctions_t 6 | { 7 | void* m_GetCurrent = nullptr; 8 | void* m_GetMain = nullptr; 9 | void* m_GetDepth = nullptr; 10 | void* m_SetDepth = nullptr; 11 | void* m_GetFieldOfView = nullptr; 12 | void* m_SetFieldOfView = nullptr; 13 | void* m_WorldToScreen = nullptr; 14 | }; 15 | CameraFunctions_t m_CameraFunctions; 16 | 17 | class CCamera : public CGameObject 18 | { 19 | public: 20 | float GetDepth() 21 | { 22 | return reinterpret_cast(m_CameraFunctions.m_GetDepth)(this); 23 | } 24 | 25 | void SetDepth(float m_fValue) 26 | { 27 | reinterpret_cast(m_CameraFunctions.m_SetDepth)(this, m_fValue); 28 | } 29 | 30 | float GetFieldOfView() 31 | { 32 | return reinterpret_cast(m_CameraFunctions.m_GetFieldOfView)(this); 33 | } 34 | 35 | void SetFieldOfView(float m_fValue) 36 | { 37 | reinterpret_cast(m_CameraFunctions.m_SetFieldOfView)(this, m_fValue); 38 | } 39 | 40 | void WorldToScreen(Vector3& m_vWorld, Vector3& m_vScreen, int m_iEye = 2) 41 | { 42 | reinterpret_cast(m_CameraFunctions.m_WorldToScreen)(this, m_vWorld, m_iEye, m_vScreen); 43 | } 44 | }; 45 | 46 | namespace Camera 47 | { 48 | void Initialize() 49 | { 50 | IL2CPP::SystemTypeCache::Initializer::Add(UNITY_CAMERA_CLASS); 51 | 52 | m_CameraFunctions.m_GetCurrent = IL2CPP::ResolveCall(UNITY_CAMERA_GETCURRENT); 53 | m_CameraFunctions.m_GetMain = IL2CPP::ResolveCall(UNITY_CAMERA_GETMAIN); 54 | m_CameraFunctions.m_GetDepth = IL2CPP::ResolveCall(UNITY_CAMERA_GETDEPTH); 55 | m_CameraFunctions.m_SetDepth = IL2CPP::ResolveCall(UNITY_CAMERA_SETDEPTH); 56 | m_CameraFunctions.m_GetFieldOfView = IL2CPP::ResolveCall(UNITY_CAMERA_GETFIELDOFVIEW); 57 | m_CameraFunctions.m_SetFieldOfView = IL2CPP::ResolveCall(UNITY_CAMERA_SETFIELDOFVIEW); 58 | m_CameraFunctions.m_WorldToScreen = IL2CPP::ResolveCall(UNITY_CAMERA_WORLDTOSCREEN); 59 | } 60 | 61 | CCamera* GetCurrent() 62 | { 63 | return reinterpret_cast(m_CameraFunctions.m_GetCurrent)(); 64 | } 65 | 66 | CCamera* GetMain() 67 | { 68 | return reinterpret_cast(m_CameraFunctions.m_GetMain)(); 69 | } 70 | } 71 | 72 | enum m_eCameraType : int 73 | { 74 | m_eCameraType_Game = 1, 75 | m_eCameraType_SceneView = 2, 76 | m_eCameraType_Preview = 4, 77 | m_eCameraType_VR = 8, 78 | m_eCameraType_Reflection = 16, 79 | }; 80 | 81 | enum m_eCameraEye : int 82 | { 83 | m_eCameraEye_Left = 0, 84 | m_eCameraEye_Right = 1, 85 | m_eCameraEye_Center = 2, 86 | }; 87 | } -------------------------------------------------------------------------------- /Unity/Structures/il2cpp.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Unity 4 | { 5 | struct il2cppImage 6 | { 7 | const char* m_pName; 8 | const char* m_pNameNoExt; 9 | }; 10 | 11 | struct il2cppAssemblyName 12 | { 13 | const char* m_pName; 14 | const char* m_pCulture; 15 | const char* m_pHash; 16 | const char* m_pPublicKey; 17 | unsigned int m_uHash; 18 | int m_iHashLength; 19 | unsigned int m_uFlags; 20 | int m_iMajor; 21 | int m_iMinor; 22 | int m_iBuild; 23 | int m_bRevision; 24 | unsigned char m_uPublicKeyToken[8]; 25 | }; 26 | 27 | struct il2cppAssembly 28 | { 29 | il2cppImage* m_pImage; 30 | unsigned int m_uToken; 31 | int m_ReferencedAssemblyStart; 32 | int m_ReferencedAssemblyCount; 33 | il2cppAssemblyName m_aName; 34 | }; 35 | 36 | struct il2cppClass 37 | { 38 | void* m_pImage; 39 | void* m_pGC; 40 | const char* m_pName; 41 | const char* m_pNamespace; 42 | void* m_pValue; 43 | void* m_pArgs; 44 | il2cppClass* m_pElementClass; 45 | il2cppClass* m_pCastClass; 46 | il2cppClass* m_pDeclareClass; 47 | il2cppClass* m_pParentClass; 48 | void* m_pGenericClass; 49 | void* m_pTypeDefinition; 50 | void* m_pInteropData; 51 | void* m_pFields; 52 | void* m_pEvents; 53 | void* m_pProperties; 54 | void** m_pMethods; 55 | il2cppClass** m_pNestedTypes; 56 | il2cppClass** m_ImplementedInterfaces; 57 | void* m_pInterfaceOffsets; 58 | void* m_pStaticFields; 59 | void* m_pRGCTX; 60 | }; 61 | 62 | struct il2cppObject 63 | { 64 | il2cppClass* m_pClass = nullptr; 65 | void* m_pMonitor = nullptr; 66 | }; 67 | 68 | #ifdef UNITY_VERSION_2022_3_8F1 69 | struct il2cppType 70 | { 71 | void* data; 72 | unsigned int bits; 73 | }; 74 | #else 75 | struct il2cppType 76 | { 77 | union 78 | { 79 | void* m_pDummy; 80 | unsigned int m_uClassIndex; 81 | il2cppType* m_pType; 82 | void* m_pArray; 83 | unsigned int m_uGenericParameterIndex; 84 | void* m_pGenericClass; 85 | }; 86 | unsigned int m_uAttributes : 16; 87 | unsigned int m_uType : 8; 88 | unsigned int m_uMods : 6; 89 | unsigned int m_uByref : 1; 90 | unsigned int m_uPinned : 1; 91 | }; 92 | #endif 93 | 94 | struct il2cppFieldInfo 95 | { 96 | const char* m_pName; 97 | il2cppType* m_pType; 98 | il2cppClass* m_pParentClass; 99 | int m_iOffset; 100 | int m_iAttributeIndex; 101 | unsigned int m_uToken; 102 | }; 103 | 104 | struct il2cppParameterInfo 105 | { 106 | const char* m_pName; 107 | int m_iPosition; 108 | unsigned int m_uToken; 109 | il2cppType* m_pParameterType; 110 | }; 111 | 112 | struct il2cppMethodInfo 113 | { 114 | void* m_pMethodPointer; 115 | #ifdef UNITY_VERSION_2022_3_8F1 116 | void* m_pVirtualMethodPointer; 117 | #endif 118 | void* m_pInvokerMethod; 119 | const char* m_pName; 120 | il2cppClass* m_pClass; 121 | il2cppType* m_pReturnType; 122 | #ifdef UNITY_VERSION_2022_3_8F1 123 | il2cppType** m_pParameters; 124 | #else 125 | il2cppParameterInfo* m_pParameters; 126 | #endif 127 | 128 | union 129 | { 130 | void* m_pRGCTX; 131 | void* m_pMethodDefinition; 132 | }; 133 | 134 | union 135 | { 136 | void* m_pGenericMethod; 137 | void* m_pGenericContainer; 138 | }; 139 | 140 | unsigned int m_uToken; 141 | unsigned short m_uFlags; 142 | unsigned short m_uFlags2; 143 | unsigned short m_uSlot; 144 | unsigned char m_uArgsCount; 145 | unsigned char m_uGeneric : 1; 146 | unsigned char m_uInflated : 1; 147 | unsigned char m_uWrapperType : 1; 148 | unsigned char m_uMarshaledFromNative : 1; 149 | }; 150 | 151 | struct il2cppPropertyInfo 152 | { 153 | il2cppClass* m_pParentClass; 154 | const char* m_pName; 155 | il2cppMethodInfo* m_pGet; 156 | il2cppMethodInfo* m_pSet; 157 | unsigned int m_uAttributes; 158 | unsigned int m_uToken; 159 | }; 160 | 161 | struct il2cppArrayBounds 162 | { 163 | uintptr_t m_uLength; 164 | int m_iLowerBound; 165 | }; 166 | } 167 | -------------------------------------------------------------------------------- /Unity/API/Transform.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Unity 4 | { 5 | struct TransformFunctions_t 6 | { 7 | void* m_GetParent = nullptr; 8 | void* m_GetRoot = nullptr; 9 | void* m_GetChild = nullptr; 10 | void* m_GetChildCount = nullptr; 11 | void* m_FindChild = nullptr; 12 | void* m_GetPosition = nullptr; 13 | void* m_GetForward = nullptr; 14 | void* m_GetRotation = nullptr; 15 | void* m_GetLocalPosition = nullptr; 16 | void* m_GetLocalScale = nullptr; 17 | void* m_SetPosition = nullptr; 18 | void* m_SetForward = nullptr; 19 | void* m_SetRotation = nullptr; 20 | void* m_SetLocalPosition = nullptr; 21 | void* m_SetLocalScale = nullptr; 22 | }; 23 | TransformFunctions_t m_TransformFunctions; 24 | 25 | class CTransform : public IL2CPP::CClass 26 | { 27 | public: 28 | CTransform* GetParent() 29 | { 30 | return reinterpret_cast(m_TransformFunctions.m_GetParent)(this); 31 | } 32 | 33 | CTransform* GetRoot() 34 | { 35 | return reinterpret_cast(m_TransformFunctions.m_GetRoot)(this); 36 | } 37 | 38 | CTransform* GetChild(int m_iIndex) 39 | { 40 | return reinterpret_cast(m_TransformFunctions.m_GetChild)(this, m_iIndex); 41 | } 42 | 43 | int GetChildCount() 44 | { 45 | return reinterpret_cast(m_TransformFunctions.m_GetChildCount)(this); 46 | } 47 | 48 | CTransform* FindChild(const char* path, bool isActiveOnly) 49 | { 50 | return reinterpret_cast(m_TransformFunctions.m_FindChild)(this, IL2CPP::String::New(path), isActiveOnly); 51 | } 52 | 53 | // e.g CGameObject->GetTransform()->FindChild("child1/child2/child3"); 54 | CTransform* FindChild(const char* path) 55 | { 56 | if (path == NULL) { 57 | return nullptr; 58 | } 59 | return FindChild(path, false); 60 | } 61 | 62 | Vector3 GetPosition() 63 | { 64 | Vector3 vRet; 65 | reinterpret_cast(m_TransformFunctions.m_GetPosition)(this, vRet); 66 | return vRet; 67 | } 68 | 69 | Vector3 GetForward() 70 | { 71 | Vector3 vRet; 72 | vRet = reinterpret_cast(m_TransformFunctions.m_GetForward)(this); 73 | return vRet; 74 | } 75 | 76 | Quaternion GetRotation() 77 | { 78 | Quaternion m_qRet; 79 | reinterpret_cast(m_TransformFunctions.m_GetRotation)(this, m_qRet); 80 | return m_qRet; 81 | } 82 | 83 | Vector3 GetLocalPosition() 84 | { 85 | Vector3 vRet; 86 | reinterpret_cast(m_TransformFunctions.m_GetLocalPosition)(this, vRet); 87 | return vRet; 88 | } 89 | 90 | Vector3 GetLocalScale() 91 | { 92 | Vector3 vRet; 93 | reinterpret_cast(m_TransformFunctions.m_GetLocalScale)(this, vRet); 94 | return vRet; 95 | } 96 | 97 | void SetPosition(Vector3 m_vVector) 98 | { 99 | reinterpret_cast(m_TransformFunctions.m_SetPosition)(this, m_vVector); 100 | } 101 | 102 | void SetForward(Vector3 m_vVector) 103 | { 104 | reinterpret_cast(m_TransformFunctions.m_SetForward)(this, m_vVector); 105 | } 106 | 107 | void SetRotation(Quaternion m_qQuat) 108 | { 109 | reinterpret_cast(m_TransformFunctions.m_SetRotation)(this, m_qQuat); 110 | } 111 | 112 | void SetLocalPosition(Vector3 m_vVector) 113 | { 114 | reinterpret_cast(m_TransformFunctions.m_SetLocalPosition)(this, m_vVector); 115 | } 116 | 117 | void SetLocalScale(Vector3 m_vVector) 118 | { 119 | reinterpret_cast(m_TransformFunctions.m_SetLocalScale)(this, m_vVector); 120 | } 121 | }; 122 | 123 | namespace Transform 124 | { 125 | void Initialize() 126 | { 127 | IL2CPP::SystemTypeCache::Initializer::Add(UNITY_TRANSFORM_CLASS); 128 | 129 | m_TransformFunctions.m_GetParent = IL2CPP::ResolveCall(UNITY_TRANSFORM_GETPARENT); 130 | m_TransformFunctions.m_GetRoot = IL2CPP::ResolveCall(UNITY_TRANSFORM_GETROOT); 131 | m_TransformFunctions.m_GetChild = IL2CPP::ResolveCall(UNITY_TRANSFORM_GETCHILD); 132 | m_TransformFunctions.m_GetChildCount = IL2CPP::ResolveCall(UNITY_TRANSFORM_GETCHILDCOUNT); 133 | m_TransformFunctions.m_FindChild = IL2CPP::ResolveCall(UNITY_TRANSFORM_FINDCHILD); 134 | m_TransformFunctions.m_GetPosition = IL2CPP::ResolveCall(UNITY_TRANSFORM_GETPOSITION); 135 | m_TransformFunctions.m_GetForward = IL2CPP::ResolveCall(UNITY_TRANSFORM_GETFORWARD); 136 | m_TransformFunctions.m_GetRotation = IL2CPP::ResolveCall(UNITY_TRANSFORM_GETROTATION); 137 | m_TransformFunctions.m_GetLocalPosition = IL2CPP::ResolveCall(UNITY_TRANSFORM_GETLOCALPOSITION); 138 | m_TransformFunctions.m_GetLocalScale = IL2CPP::ResolveCall(UNITY_TRANSFORM_GETLOCALSCALE); 139 | m_TransformFunctions.m_SetPosition = IL2CPP::ResolveCall(UNITY_TRANSFORM_SETPOSITION); 140 | m_TransformFunctions.m_SetForward = IL2CPP::ResolveCall(UNITY_TRANSFORM_SETFORWARD); 141 | m_TransformFunctions.m_SetRotation = IL2CPP::ResolveCall(UNITY_TRANSFORM_SETROTATION); 142 | m_TransformFunctions.m_SetLocalPosition = IL2CPP::ResolveCall(UNITY_TRANSFORM_SETLOCALPOSITION); 143 | m_TransformFunctions.m_SetLocalScale = IL2CPP::ResolveCall(UNITY_TRANSFORM_SETLOCALSCALE); 144 | } 145 | } 146 | } -------------------------------------------------------------------------------- /Unity/API/GameObject.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Unity 4 | { 5 | struct GameObjectFunctions_t 6 | { 7 | void* m_AddComponent = nullptr; 8 | void* m_CreatePrimitive = nullptr; 9 | void* m_Find = nullptr; 10 | void* m_FindGameObjectsWithTag = nullptr; 11 | void* m_GetComponent = nullptr; 12 | void* m_GetComponents = nullptr; 13 | void* m_GetComponentInChildren = nullptr; 14 | void* m_GetActive = nullptr; 15 | void* m_GetLayer = nullptr; 16 | void* m_GetTransform = nullptr; 17 | void* m_SetActive = nullptr; 18 | void* m_SetLayer = nullptr; 19 | }; 20 | GameObjectFunctions_t m_GameObjectFunctions; 21 | 22 | class CGameObject : public CObject 23 | { 24 | public: 25 | void AddComponent(il2cppObject* m_pSystemType) 26 | { 27 | reinterpret_cast(m_GameObjectFunctions.m_AddComponent)(this, m_pSystemType); 28 | } 29 | 30 | CComponent* GetComponent(const char* m_pName) 31 | { 32 | return reinterpret_cast(m_GameObjectFunctions.m_GetComponent)(this, IL2CPP::String::New(m_pName)); 33 | } 34 | 35 | CComponent* GetComponentInChildren(il2cppObject* m_pSystemType, bool includeInactive) 36 | { 37 | return reinterpret_cast(m_GameObjectFunctions.m_GetComponentInChildren)(this, m_pSystemType, includeInactive); 38 | } 39 | 40 | // e.g CGameObject->GetComponentInChildren("Namespace.Component"); 41 | CComponent* GetComponentInChildren(const char* type) 42 | { 43 | il2cppClass* m_pClass = IL2CPP::Class::Find(type); 44 | if (!m_pClass) return nullptr; 45 | 46 | return GetComponentInChildren(IL2CPP::Class::GetSystemType(m_pClass), true); 47 | } 48 | 49 | il2cppArray* GetComponents(il2cppObject* m_pSystemType) 50 | { 51 | /* 52 | 0 - Object 53 | 1 - Type 54 | 2 - Use search type as array return type 55 | 3 - Recursive 56 | 4 - Include inactive 57 | 5 - Reverse 58 | 6 - Result list 59 | */ 60 | return reinterpret_cast*(UNITY_CALLING_CONVENTION)(void*, void*, bool, bool, bool, bool, void*)>(m_GameObjectFunctions.m_GetComponents)(this, m_pSystemType, false, false, true, false, nullptr); 61 | } 62 | 63 | il2cppArray* GetComponents(const char* m_pSystemTypeName) 64 | { 65 | il2cppClass* m_pClass = IL2CPP::Class::Find(m_pSystemTypeName); 66 | if (!m_pClass) return nullptr; 67 | 68 | return GetComponents(IL2CPP::Class::GetSystemType(m_pClass)); 69 | } 70 | 71 | CComponent* GetComponentByIndex(il2cppObject* m_pSystemType, unsigned int m_uIndex = 0U) 72 | { 73 | il2cppArray* m_pComponents = GetComponents(m_pSystemType); 74 | if (!m_pComponents || m_uIndex >= m_pComponents->m_uMaxLength) return nullptr; 75 | 76 | return m_pComponents->operator[](m_uIndex); 77 | } 78 | 79 | CComponent* GetComponentByIndex(const char* m_pSystemTypeName, unsigned int m_uIndex = 0U) 80 | { 81 | il2cppClass* m_pClass = IL2CPP::Class::Find(m_pSystemTypeName); 82 | if (!m_pClass) return nullptr; 83 | 84 | return GetComponentByIndex(IL2CPP::Class::GetSystemType(m_pClass), m_uIndex); 85 | } 86 | 87 | CTransform* GetTransform() 88 | { 89 | return reinterpret_cast(m_GameObjectFunctions.m_GetTransform)(this); 90 | } 91 | 92 | bool GetActive() 93 | { 94 | return reinterpret_cast(m_GameObjectFunctions.m_GetActive)(this); 95 | } 96 | 97 | unsigned int GetLayer() 98 | { 99 | return reinterpret_cast(m_GameObjectFunctions.m_GetLayer)(this); 100 | } 101 | 102 | /* 103 | * (WARNING) when you use GameObject::Find and you set the object to unactive, you won't find it anymore with that slow function. 104 | */ 105 | void SetActive(bool m_bActive) 106 | { 107 | reinterpret_cast(m_GameObjectFunctions.m_SetActive)(this, m_bActive); 108 | } 109 | 110 | void SetLayer(unsigned int m_uLayer) 111 | { 112 | reinterpret_cast(m_GameObjectFunctions.m_SetLayer)(this, m_uLayer); 113 | } 114 | }; 115 | 116 | namespace GameObject 117 | { 118 | enum class m_ePrimitiveType : int 119 | { 120 | Default = 0, 121 | Sphere = 0, 122 | Capsule, 123 | Cylinder, 124 | Cube, 125 | Plane, 126 | Quad, 127 | }; 128 | 129 | void Initialize() 130 | { 131 | IL2CPP::SystemTypeCache::Initializer::Add(UNITY_GAMEOBJECT_CLASS); 132 | 133 | m_GameObjectFunctions.m_AddComponent = IL2CPP::ResolveCall(UNITY_GAMEOBJECT_ADDCOMPONENT); 134 | m_GameObjectFunctions.m_CreatePrimitive = IL2CPP::ResolveCall(UNITY_GAMEOBJECT_CREATEPRIMITIVE); 135 | m_GameObjectFunctions.m_Find = IL2CPP::ResolveCall(UNITY_GAMEOBJECT_FIND); 136 | m_GameObjectFunctions.m_FindGameObjectsWithTag = IL2CPP::ResolveCall(UNITY_GAMEOBJECT_FINDGAMEOBJECTWITHTAG); 137 | m_GameObjectFunctions.m_GetComponent = IL2CPP::ResolveCall(UNITY_GAMEOBJECT_GETCOMPONENT); 138 | m_GameObjectFunctions.m_GetComponents = IL2CPP::ResolveCall(UNITY_GAMEOBJECT_GETCOMPONENTS); 139 | m_GameObjectFunctions.m_GetComponentInChildren = IL2CPP::ResolveCall(UNITY_GAMEOBJECT_GETCOMPONENTINCHILDREN); 140 | m_GameObjectFunctions.m_GetActive = IL2CPP::ResolveCall(UNITY_GAMEOBJECT_GETACTIVE); 141 | m_GameObjectFunctions.m_GetLayer = IL2CPP::ResolveCall(UNITY_GAMEOBJECT_GETLAYER); 142 | m_GameObjectFunctions.m_GetTransform = IL2CPP::ResolveCall(UNITY_GAMEOBJECT_GETTRANSFORM); 143 | m_GameObjectFunctions.m_SetActive = IL2CPP::ResolveCall(UNITY_GAMEOBJECT_SETACTIVE); 144 | m_GameObjectFunctions.m_SetLayer = IL2CPP::ResolveCall(UNITY_GAMEOBJECT_SETLAYER); 145 | } 146 | 147 | CGameObject* CreatePrimitive(m_ePrimitiveType m_Type) 148 | { 149 | return reinterpret_cast(m_GameObjectFunctions.m_CreatePrimitive)(m_Type); 150 | } 151 | 152 | CGameObject* Find(const char* m_Name) 153 | { 154 | return reinterpret_cast(m_GameObjectFunctions.m_Find)(IL2CPP::String::New(m_Name)); 155 | } 156 | 157 | il2cppArray* FindWithTag(const char* m_Tag) 158 | { 159 | return reinterpret_cast*(UNITY_CALLING_CONVENTION)(void*)>(m_GameObjectFunctions.m_FindGameObjectsWithTag)(IL2CPP::String::New(m_Tag)); 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /Unity/Defines.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Calling Convention 4 | #define UNITY_CALLING_CONVENTION * 5 | 6 | 7 | // Camera 8 | #define UNITY_CAMERA_CLASS "UnityEngine.Camera" 9 | #define UNITY_CAMERA_GETCURRENT IL2CPP_RStr(UNITY_CAMERA_CLASS"::get_current") 10 | #define UNITY_CAMERA_GETMAIN IL2CPP_RStr(UNITY_CAMERA_CLASS"::get_main") 11 | #define UNITY_CAMERA_GETDEPTH IL2CPP_RStr(UNITY_CAMERA_CLASS"::get_depth") 12 | #define UNITY_CAMERA_SETDEPTH IL2CPP_RStr(UNITY_CAMERA_CLASS"::set_depth") 13 | #define UNITY_CAMERA_GETFIELDOFVIEW IL2CPP_RStr(UNITY_CAMERA_CLASS"::get_fieldOfView") 14 | #define UNITY_CAMERA_SETFIELDOFVIEW IL2CPP_RStr(UNITY_CAMERA_CLASS"::set_fieldOfView") 15 | #define UNITY_CAMERA_WORLDTOSCREEN IL2CPP_RStr(UNITY_CAMERA_CLASS"::WorldToScreenPoint_Injected") 16 | 17 | // Component 18 | #define UNITY_COMPONENT_CLASS "UnityEngine.Component" 19 | #define UNITY_COMPONENT_GETGAMEOBJECT IL2CPP_RStr(UNITY_COMPONENT_CLASS"::get_gameObject") 20 | #define UNITY_COMPONENT_GETTRANSFORM IL2CPP_RStr(UNITY_COMPONENT_CLASS"::get_transform") 21 | 22 | // GameObject 23 | #define UNITY_GAMEOBJECT_CLASS "UnityEngine.GameObject" 24 | #define UNITY_GAMEOBJECT_ADDCOMPONENT IL2CPP_RStr(UNITY_GAMEOBJECT_CLASS"::Internal_AddComponentWithType") 25 | #define UNITY_GAMEOBJECT_CREATEPRIMITIVE IL2CPP_RStr(UNITY_GAMEOBJECT_CLASS"::CreatePrimitive") 26 | #define UNITY_GAMEOBJECT_FIND IL2CPP_RStr(UNITY_GAMEOBJECT_CLASS"::Find") 27 | #define UNITY_GAMEOBJECT_GETCOMPONENT IL2CPP_RStr(UNITY_GAMEOBJECT_CLASS"::GetComponentByName") 28 | #define UNITY_GAMEOBJECT_GETCOMPONENTS IL2CPP_RStr(UNITY_GAMEOBJECT_CLASS"::GetComponentsInternal") 29 | #define UNITY_GAMEOBJECT_GETCOMPONENTINCHILDREN IL2CPP_RStr(UNITY_GAMEOBJECT_CLASS"::GetComponentInChildren") 30 | #define UNITY_GAMEOBJECT_GETACTIVE IL2CPP_RStr(UNITY_GAMEOBJECT_CLASS"::get_active") 31 | #define UNITY_GAMEOBJECT_GETLAYER IL2CPP_RStr(UNITY_GAMEOBJECT_CLASS"::get_layer") 32 | #define UNITY_GAMEOBJECT_GETTRANSFORM IL2CPP_RStr(UNITY_GAMEOBJECT_CLASS"::get_transform") 33 | #define UNITY_GAMEOBJECT_SETACTIVE IL2CPP_RStr(UNITY_GAMEOBJECT_CLASS"::set_active") 34 | #define UNITY_GAMEOBJECT_SETLAYER IL2CPP_RStr(UNITY_GAMEOBJECT_CLASS"::set_layer") 35 | #define UNITY_GAMEOBJECT_FINDGAMEOBJECTWITHTAG IL2CPP_RStr(UNITY_GAMEOBJECT_CLASS"::FindGameObjectsWithTag") 36 | 37 | // LayerMask 38 | #define UNITY_LAYERMASK_CLASS "UnityEngine.LayerMask" 39 | #define UNITY_LAYERMASK_LAYERTONAME IL2CPP_RStr(UNITY_LAYERMASK_CLASS"::LayerToName") 40 | #define UNITY_LAYERMASK_NAMETOLAYER IL2CPP_RStr(UNITY_LAYERMASK_CLASS"::NameToLayer") 41 | 42 | // MonoBehaviour 43 | #define UNITY_MONOBEHAVIOUR_CLASS "UnityEngine.MonoBehaviour" 44 | 45 | // Object 46 | #define UNITY_OBJECT_CLASS "UnityEngine.Object" 47 | #define UNITY_OBJECT_DESTROY IL2CPP_RStr(UNITY_OBJECT_CLASS"::Destroy") 48 | #define UNITY_OBJECT_FINDOBJECTSOFTYPE IL2CPP_RStr(UNITY_OBJECT_CLASS"::FindObjectsOfType(System.Type,System.Boolean)") 49 | #define UNITY_OBJECT_GETNAME IL2CPP_RStr(UNITY_OBJECT_CLASS"::GetName") 50 | 51 | // Rigidbody 52 | #define UNITY_RIGIDBODY_CLASS "UnityEngine.Rigidbody" 53 | #define UNITY_RIGIDBODY_GETDETECTCOLLISIONS IL2CPP_RStr(UNITY_RIGIDBODY_CLASS"::get_detectCollisions") 54 | #define UNITY_RIGIDBODY_GETVELOCITY IL2CPP_RStr(UNITY_RIGIDBODY_CLASS"::get_velocity_Injected") 55 | #define UNITY_RIGIDBODY_SETDETECTCOLLISIONS IL2CPP_RStr(UNITY_RIGIDBODY_CLASS"::set_detectCollisions") 56 | #define UNITY_RIGIDBODY_SETVELOCITY IL2CPP_RStr(UNITY_RIGIDBODY_CLASS"::set_velocity_Injected") 57 | 58 | // Transform 59 | #define UNITY_TRANSFORM_CLASS "UnityEngine.Transform" 60 | #define UNITY_TRANSFORM_GETPARENT IL2CPP_RStr(UNITY_TRANSFORM_CLASS"::GetParent") 61 | #define UNITY_TRANSFORM_GETROOT IL2CPP_RStr(UNITY_TRANSFORM_CLASS"::GetRoot") 62 | #define UNITY_TRANSFORM_GETCHILD IL2CPP_RStr(UNITY_TRANSFORM_CLASS"::GetChild") 63 | #define UNITY_TRANSFORM_GETCHILDCOUNT IL2CPP_RStr(UNITY_TRANSFORM_CLASS"::get_childCount") 64 | #define UNITY_TRANSFORM_FINDCHILD IL2CPP_RStr(UNITY_TRANSFORM_CLASS"::FindRelativeTransformWithPath") 65 | #define UNITY_TRANSFORM_GETPOSITION IL2CPP_RStr(UNITY_TRANSFORM_CLASS"::get_position_Injected") 66 | #define UNITY_TRANSFORM_GETROTATION IL2CPP_RStr(UNITY_TRANSFORM_CLASS"::get_rotation_Injected") 67 | #define UNITY_TRANSFORM_GETLOCALPOSITION IL2CPP_RStr(UNITY_TRANSFORM_CLASS"::get_localPosition_Injected") 68 | #define UNITY_TRANSFORM_GETLOCALSCALE IL2CPP_RStr(UNITY_TRANSFORM_CLASS"::get_localScale_Injected") 69 | #define UNITY_TRANSFORM_SETPOSITION IL2CPP_RStr(UNITY_TRANSFORM_CLASS"::set_position_Injected") 70 | #define UNITY_TRANSFORM_SETROTATION IL2CPP_RStr(UNITY_TRANSFORM_CLASS"::set_rotation_Injected") 71 | #define UNITY_TRANSFORM_GETFORWARD IL2CPP_RStr(UNITY_TRANSFORM_CLASS"::get_forward") 72 | #define UNITY_TRANSFORM_SETFORWARD IL2CPP_RStr(UNITY_TRANSFORM_CLASS"::set_forward") 73 | #define UNITY_TRANSFORM_SETLOCALPOSITION IL2CPP_RStr(UNITY_TRANSFORM_CLASS"::set_localPosition_Injected") 74 | #define UNITY_TRANSFORM_SETLOCALSCALE IL2CPP_RStr(UNITY_TRANSFORM_CLASS"::set_localScale_Injected") 75 | 76 | namespace Unity 77 | { 78 | enum m_eTypeEnum 79 | { 80 | Type_Void = 1, 81 | Type_Boolean = 2, 82 | Type_Character = 3, 83 | Type_Integer = 8, 84 | Type_Float = 12, 85 | Type_String = 14, 86 | Type_Pointer = 15, 87 | Type_ValueType = 17, 88 | Type_Class = 18, 89 | Type_Variable = 19, 90 | Type_Array = 20, 91 | Type_Enum = 85, 92 | }; 93 | 94 | enum m_eFieldAttribute 95 | { 96 | FieldAttribute_Compiler, 97 | FieldAttribute_Private, 98 | FieldAttribute_FamilyAndAssembly, 99 | FieldAttribute_Assembly, 100 | FieldAttribute_Family, 101 | FieldAttribute_FamilyOrAssembly, 102 | FieldAttribute_Public, 103 | FieldAttribute_AccessMask, 104 | FieldAttribute_Static = 16, 105 | FieldAttribute_InitOnly = 32, 106 | FieldAttribute_Literal = 64, 107 | FieldAttribute_NotSerialized = 128, 108 | FieldAttribute_HasRVA = 256, 109 | FieldAttribute_SpecialName = 512, 110 | FieldAttribute_RTSpecialName = 1024, 111 | FieldAttribute_HasMarshal = 4096, 112 | FieldAttribute_InvokeImpl = 8192, 113 | FieldAttribute_Default = 32768, 114 | FieldAttribute_Reserved = 38144, 115 | }; 116 | } 117 | -------------------------------------------------------------------------------- /IL2CPP_Resolver.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // C Headers 4 | #include 5 | #include 6 | #include 7 | 8 | // C++ Headers 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | //#include 17 | #include 18 | 19 | // Application Defines 20 | #ifndef UNITY_VERSION_2022_3_8F1 21 | // If Unity version is equal or greater than 2022.3.8f1 uncomment this define. 22 | // #define UNITY_VERSION_2022_3_8F1 23 | #endif 24 | 25 | // IL2CPP Defines 26 | 27 | // Disable Asserts 28 | //#define IL2CPP_ASSERT(x) assert(0) 29 | #ifndef IL2CPP_ASSERT 30 | #include 31 | #define IL2CPP_ASSERT(x) assert(x) 32 | #endif 33 | 34 | 35 | #ifndef IL2CPP_RStr 36 | // If you wanna forward to some string encryption just define before including this file. 37 | #define IL2CPP_RStr(x) x 38 | #endif 39 | 40 | 41 | #ifndef IL2CPP_FRAMEWORK_NAME 42 | #define IL2CPP_FRAMEWORK_NAME "UnityFramework" 43 | #endif 44 | 45 | #include "Config.h" 46 | #include "Defines.hpp" 47 | 48 | #include "Utils/MemoryInfo.hpp" 49 | 50 | 51 | // Vector2, Vector3 && Quaternion 52 | #include "Vector2.hpp" 53 | #include "Vector3.hpp" 54 | #include "Quaternion.hpp" 55 | 56 | // IL2CPP Headers 57 | #include "Data.hpp" 58 | 59 | // Unity Headers 60 | #include "Unity/Obfuscators.hpp" 61 | #include "Unity/Defines.hpp" 62 | #include "Unity/Structures/il2cpp.hpp" 63 | #include "Unity/Structures/il2cppArray.hpp" 64 | #include "Unity/Structures/il2cppDictionary.hpp" 65 | #include "Unity/Structures/Engine.hpp" 66 | #include "Unity/Structures/System_String.hpp" 67 | 68 | // IL2CPP Utils 69 | #include "Utils/Hash.hpp" 70 | #include "Utils/VTable.hpp" 71 | 72 | // IL2CPP API Headers 73 | #include "API/Domain.hpp" 74 | #include "API/Image.hpp" 75 | #include "API/Class.hpp" 76 | #include "API/ResolveCall.hpp" 77 | #include "API/String.hpp" 78 | #include "API/Thread.hpp" 79 | 80 | // IL2CPP Headers before Unity API 81 | #include "SystemTypeCache.hpp" 82 | 83 | // Unity Class APIs - So they're accessible everywhere 84 | namespace Unity 85 | { 86 | class CCamera; 87 | class CComponent; 88 | class CGameObject; 89 | class CLayerMask; 90 | class CObject; 91 | class CRigidbody; 92 | class CTransform; 93 | } 94 | 95 | // Unity API 96 | #include "Unity/API/Object.hpp" 97 | #include "Unity/API/GameObject.hpp" 98 | #include "Unity/API/Camera.hpp" 99 | #include "Unity/API/Component.hpp" 100 | #include "Unity/API/LayerMask.hpp" 101 | #include "Unity/API/Rigidbody.hpp" 102 | #include "Unity/API/Transform.hpp" 103 | 104 | // IL2CPP Headers after Unity API 105 | #include "Utils/Helper.hpp" 106 | #include "Utils/CacheInstance.hpp" 107 | #include "API/Callback.hpp" 108 | 109 | namespace IL2CPP 110 | { 111 | namespace UnityAPI 112 | { 113 | enum m_eExportObfuscationType 114 | { 115 | None = 0, 116 | ROT = 1, 117 | MAX = 2, 118 | }; 119 | 120 | m_eExportObfuscationType m_ExportObfuscation = m_eExportObfuscationType::None; 121 | 122 | int m_ROTObfuscationValue = -1; 123 | 124 | void* ResolveExport(const char* m_Name) 125 | { 126 | switch (m_ExportObfuscation) 127 | { 128 | case m_eExportObfuscationType::ROT: 129 | { 130 | if (m_ROTObfuscationValue == -1) // Bruteforce 131 | { 132 | for (int i = 1; 26 > i; ++i) 133 | { 134 | void* m_Return = dlsym(Globals.m_GameFramework, &Unity::Obfuscators::ROT_String(m_Name, i)[0]); 135 | if (m_Return) 136 | { 137 | m_ROTObfuscationValue = i; 138 | return m_Return; 139 | } 140 | } 141 | 142 | return nullptr; 143 | } 144 | 145 | return dlsym(Globals.m_GameFramework, &Unity::Obfuscators::ROT_String(m_Name, m_ROTObfuscationValue)[0]); 146 | } 147 | default: 148 | return dlsym(Globals.m_GameFramework, m_Name); 149 | } 150 | 151 | return nullptr; 152 | } 153 | 154 | bool ResolveExport_Boolean(void** m_Address, const char* m_Name) 155 | { 156 | *m_Address = ResolveExport(m_Name); 157 | IL2CPP_ASSERT(*m_Address != nullptr && "Couldn't resolve export!"); 158 | return (*m_Address); 159 | } 160 | 161 | bool Initialize() 162 | { 163 | bool m_InitExportResolved = false; 164 | for (int i = 0; m_eExportObfuscationType::MAX > i; ++i) 165 | { 166 | m_ExportObfuscation = static_cast(i); 167 | if (ResolveExport(IL2CPP_INIT_EXPORT)) 168 | { 169 | m_InitExportResolved = true; 170 | break; 171 | } 172 | } 173 | 174 | IL2CPP_ASSERT(m_InitExportResolved && "Couldn't resolve il2cpp_init!"); 175 | if (!m_InitExportResolved) 176 | return false; 177 | 178 | std::unordered_map m_ExportMap = 179 | { 180 | { IL2CPP_CLASS_FROM_NAME_EXPORT, &Functions.m_ClassFromName }, 181 | { IL2CPP_CLASS_GET_FIELDS, &Functions.m_ClassGetFields }, 182 | { IL2CPP_CLASS_GET_FIELD_FROM_NAME_EXPORT, &Functions.m_ClassGetFieldFromName }, 183 | { IL2CPP_CLASS_GET_METHODS, &Functions.m_ClassGetMethods }, 184 | { IL2CPP_CLASS_GET_METHOD_FROM_NAME_EXPORT, &Functions.m_ClassGetMethodFromName }, 185 | { IL2CPP_CLASS_GET_PROPERTY_FROM_NAME_EXPORT, &Functions.m_ClassGetPropertyFromName }, 186 | { IL2CPP_CLASS_GET_TYPE_EXPORT, &Functions.m_ClassGetType }, 187 | { IL2CPP_DOMAIN_GET_EXPORT, &Functions.m_DomainGet }, 188 | { IL2CPP_DOMAIN_GET_ASSEMBLIES_EXPORT, &Functions.m_DomainGetAssemblies }, 189 | { IL2CPP_FREE_EXPORT, &Functions.m_Free }, 190 | { IL2CPP_IMAGE_GET_CLASS_EXPORT, &Functions.m_ImageGetClass }, 191 | { IL2CPP_IMAGE_GET_CLASS_COUNT_EXPORT, &Functions.m_ImageGetClassCount }, 192 | { IL2CPP_RESOLVE_FUNC_EXPORT, &Functions.m_ResolveFunction }, 193 | { IL2CPP_STRING_NEW_EXPORT, &Functions.m_StringNew }, 194 | { IL2CPP_THREAD_ATTACH_EXPORT, &Functions.m_ThreadAttach }, 195 | { IL2CPP_THREAD_DETACH_EXPORT, &Functions.m_ThreadDetach }, 196 | { IL2CPP_TYPE_GET_OBJECT_EXPORT, &Functions.m_TypeGetObject }, 197 | { IL2CPP_OBJECT_NEW, &Functions.m_pObjectNew }, 198 | { IL2CPP_METHOD_GET_PARAM_NAME, &Functions.m_MethodGetParamName }, 199 | { IL2CPP_METHOD_GET_PARAM, &Functions.m_MethodGetParam }, 200 | { IL2CPP_CLASS_FROM_IL2CPP_TYPE, &Functions.m_ClassFromIl2cppType }, 201 | { IL2CPP_FIELD_STATIC_GET_VALUE, &Functions.m_FieldStaticGetValue }, 202 | { IL2CPP_FIELD_STATIC_SET_VALUE, &Functions.m_FieldStaticSetValue }, 203 | { IL2CPP_ASSEMBLY_GET_IMAGE, &Functions.m_AssembliesGetImage }, 204 | { IL2CPP_IMAGE_GET_NAME, &Functions.m_ImageGetName }, 205 | }; 206 | 207 | for (auto& m_ExportPair : m_ExportMap) 208 | { 209 | if (!ResolveExport_Boolean(m_ExportPair.second, &m_ExportPair.first[0])) 210 | return false; 211 | } 212 | 213 | // Unity APIs 214 | Unity::Camera::Initialize(); 215 | Unity::Component::Initialize(); 216 | Unity::GameObject::Initialize(); 217 | Unity::LayerMask::Initialize(); 218 | Unity::Object::Initialize(); 219 | Unity::RigidBody::Initialize(); 220 | Unity::Transform::Initialize(); 221 | 222 | // Caches 223 | IL2CPP::SystemTypeCache::Initializer::PreCache(); 224 | 225 | return true; 226 | } 227 | } 228 | 229 | /* 230 | * You need to call this, before using any IL2CPP/Unity Functions! 231 | * Args: 232 | * m_WaitForModule - Will wait for main module if you're loading your dll earlier than the main module. 233 | * m_MaxSecondsWait - Max seconds it will wait for main module to load otherwise will return false to prevent infinite loop. 234 | */ 235 | bool Initialize(bool m_WaitForModule = false, int m_MaxSecondsWait = 60, const char *dir = "UnityFramework") 236 | { 237 | 238 | if (m_WaitForModule) 239 | { 240 | int m_SecondsWaited = 0; 241 | while (!Globals.m_GameFramework) 242 | { 243 | if (m_SecondsWaited >= m_MaxSecondsWait) 244 | return false; 245 | 246 | Globals.m_GameFramework = dlopen(dir, RTLD_LAZY); 247 | ++m_SecondsWaited; 248 | std::this_thread::sleep_for(std::chrono::seconds(1)); 249 | } 250 | } 251 | else 252 | Globals.m_GameFramework = dlopen(dir, RTLD_LAZY); 253 | 254 | if (Globals.m_GameFramework == nullptr) 255 | return false; 256 | 257 | if (!UnityAPI::Initialize()) 258 | return false; 259 | 260 | return true; 261 | } 262 | 263 | bool Initialize(void* GameAssemblyHandle) 264 | { 265 | if (GameAssemblyHandle != nullptr) 266 | Globals.m_GameFramework = GameAssemblyHandle; 267 | else 268 | return false; 269 | 270 | if (!UnityAPI::Initialize()) 271 | return false; 272 | 273 | return true; 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /Vector2.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define _USE_MATH_DEFINES 4 | #include 5 | 6 | namespace Unity 7 | { 8 | struct Vector2 9 | { 10 | union 11 | { 12 | struct 13 | { 14 | float X; 15 | float Y; 16 | }; 17 | float data[2]; 18 | }; 19 | 20 | 21 | /** 22 | * Constructors. 23 | */ 24 | inline Vector2(); 25 | inline Vector2(float data[]); 26 | inline Vector2(float value); 27 | inline Vector2(float x, float y); 28 | 29 | 30 | /** 31 | * Constants for common vectors. 32 | */ 33 | static inline Vector2 Zero(); 34 | static inline Vector2 One(); 35 | static inline Vector2 Right(); 36 | static inline Vector2 Left(); 37 | static inline Vector2 Up(); 38 | static inline Vector2 Down(); 39 | 40 | 41 | /** 42 | * Returns the angle between two vectors in radians. 43 | * @param a: The first vector. 44 | * @param b: The second vector. 45 | * @return: A scalar value. 46 | */ 47 | static inline float Angle(Vector2 a, Vector2 b); 48 | 49 | /** 50 | * Returns a vector with its magnitude clamped to maxLength. 51 | * @param vector: The target vector. 52 | * @param maxLength: The maximum length of the return vector. 53 | * @return: A new vector. 54 | */ 55 | static inline Vector2 ClampMagnitude(Vector2 vector, float maxLength); 56 | 57 | /** 58 | * Returns the component of a in the direction of b (scalar projection). 59 | * @param a: The target vector. 60 | * @param b: The vector being compared against. 61 | * @return: A scalar value. 62 | */ 63 | static inline float Component(Vector2 a, Vector2 b); 64 | 65 | /** 66 | * Returns the distance between a and b. 67 | * @param a: The first point. 68 | * @param b: The second point. 69 | * @return: A scalar value. 70 | */ 71 | static inline float Distance(Vector2 a, Vector2 b); 72 | 73 | /** 74 | * Returns the dot product of two vectors. 75 | * @param lhs: The left side of the multiplication. 76 | * @param rhs: The right side of the multiplication. 77 | * @return: A scalar value. 78 | */ 79 | static inline float Dot(Vector2 lhs, Vector2 rhs); 80 | 81 | /** 82 | * Converts a polar representation of a vector into cartesian 83 | * coordinates. 84 | * @param rad: The magnitude of the vector. 85 | * @param theta: The angle from the X axis. 86 | * @return: A new vector. 87 | */ 88 | static inline Vector2 FromPolar(float rad, float theta); 89 | 90 | /** 91 | * Returns a vector linearly interpolated between a and b, moving along 92 | * a straight line. The vector is clamped to never go beyond the end points. 93 | * @param a: The starting point. 94 | * @param b: The ending point. 95 | * @param t: The interpolation value [0-1]. 96 | * @return: A new vector. 97 | */ 98 | static inline Vector2 Lerp(Vector2 a, Vector2 b, float t); 99 | 100 | /** 101 | * Returns a vector linearly interpolated between a and b, moving along 102 | * a straight line. 103 | * @param a: The starting point. 104 | * @param b: The ending point. 105 | * @param t: The interpolation value [0-1] (no actual bounds). 106 | * @return: A new vector. 107 | */ 108 | static inline Vector2 LerpUnclamped(Vector2 a, Vector2 b, float t); 109 | 110 | /** 111 | * Returns the magnitude of a vector. 112 | * @param v: The vector in question. 113 | * @return: A scalar value. 114 | */ 115 | static inline float Magnitude(Vector2 v); 116 | 117 | /** 118 | * Returns a vector made from the largest components of two other vectors. 119 | * @param a: The first vector. 120 | * @param b: The second vector. 121 | * @return: A new vector. 122 | */ 123 | static inline Vector2 Max(Vector2 a, Vector2 b); 124 | 125 | /** 126 | * Returns a vector made from the smallest components of two other vectors. 127 | * @param a: The first vector. 128 | * @param b: The second vector. 129 | * @return: A new vector. 130 | */ 131 | static inline Vector2 Min(Vector2 a, Vector2 b); 132 | 133 | /** 134 | * Returns a vector "maxDistanceDelta" units closer to the target. This 135 | * interpolation is in a straight line, and will not overshoot. 136 | * @param current: The current position. 137 | * @param target: The destination position. 138 | * @param maxDistanceDelta: The maximum distance to move. 139 | * @return: A new vector. 140 | */ 141 | static inline Vector2 MoveTowards(Vector2 current, Vector2 target, 142 | float maxDistanceDelta); 143 | 144 | /** 145 | * Returns a new vector with magnitude of one. 146 | * @param v: The vector in question. 147 | * @return: A new vector. 148 | */ 149 | static inline Vector2 Normalized(Vector2 v); 150 | 151 | /** 152 | * Creates a new coordinate system out of the two vectors. 153 | * Normalizes "normal" and normalizes "tangent" and makes it orthogonal to 154 | * "normal".. 155 | * @param normal: A reference to the first axis vector. 156 | * @param tangent: A reference to the second axis vector. 157 | */ 158 | static inline void OrthoNormalize(Vector2 &normal, Vector2 &tangent); 159 | 160 | /** 161 | * Returns the vector projection of a onto b. 162 | * @param a: The target vector. 163 | * @param b: The vector being projected onto. 164 | * @return: A new vector. 165 | */ 166 | static inline Vector2 Project(Vector2 a, Vector2 b); 167 | 168 | /** 169 | * Returns a vector reflected about the provided line. 170 | * This behaves as if there is a plane with the line as its normal, and the 171 | * vector comes in and bounces off this plane. 172 | * @param vector: The vector traveling inward at the imaginary plane. 173 | * @param line: The line about which to reflect. 174 | * @return: A new vector pointing outward from the imaginary plane. 175 | */ 176 | static inline Vector2 Reflect(Vector2 vector, Vector2 line); 177 | 178 | /** 179 | * Returns the vector rejection of a on b. 180 | * @param a: The target vector. 181 | * @param b: The vector being projected onto. 182 | * @return: A new vector. 183 | */ 184 | static inline Vector2 Reject(Vector2 a, Vector2 b); 185 | 186 | /** 187 | * Rotates vector "current" towards vector "target" by "maxRadiansDelta". 188 | * This treats the vectors as directions and will linearly interpolate 189 | * between their magnitudes by "maxMagnitudeDelta". This function does not 190 | * overshoot. If a negative delta is supplied, it will rotate away from 191 | * "target" until it is pointing the opposite direction, but will not 192 | * overshoot that either. 193 | * @param current: The starting direction. 194 | * @param target: The destination direction. 195 | * @param maxRadiansDelta: The maximum number of radians to rotate. 196 | * @param maxMagnitudeDelta: The maximum delta for magnitude interpolation. 197 | * @return: A new vector. 198 | */ 199 | static inline Vector2 RotateTowards(Vector2 current, Vector2 target, 200 | float maxRadiansDelta, 201 | float maxMagnitudeDelta); 202 | 203 | /** 204 | * Multiplies two vectors component-wise. 205 | * @param a: The lhs of the multiplication. 206 | * @param b: The rhs of the multiplication. 207 | * @return: A new vector. 208 | */ 209 | static inline Vector2 Scale(Vector2 a, Vector2 b); 210 | 211 | /** 212 | * Returns a vector rotated towards b from a by the percent t. 213 | * Since interpolation is done spherically, the vector moves at a constant 214 | * angular velocity. This rotation is clamped to 0 <= t <= 1. 215 | * @param a: The starting direction. 216 | * @param b: The ending direction. 217 | * @param t: The interpolation value [0-1]. 218 | */ 219 | static inline Vector2 Slerp(Vector2 a, Vector2 b, float t); 220 | 221 | /** 222 | * Returns a vector rotated towards b from a by the percent t. 223 | * Since interpolation is done spherically, the vector moves at a constant 224 | * angular velocity. This rotation is unclamped. 225 | * @param a: The starting direction. 226 | * @param b: The ending direction. 227 | * @param t: The interpolation value [0-1]. 228 | */ 229 | static inline Vector2 SlerpUnclamped(Vector2 a, Vector2 b, float t); 230 | 231 | /** 232 | * Returns the squared magnitude of a vector. 233 | * This is useful when comparing relative lengths, where the exact length 234 | * is not important, and much time can be saved by not calculating the 235 | * square root. 236 | * @param v: The vector in question. 237 | * @return: A scalar value. 238 | */ 239 | static inline float SqrMagnitude(Vector2 v); 240 | 241 | /** 242 | * Calculates the polar coordinate space representation of a vector. 243 | * @param vector: The vector to convert. 244 | * @param rad: The magnitude of the vector. 245 | * @param theta: The angle from the X axis. 246 | */ 247 | static inline void ToPolar(Vector2 vector, float &rad, float &theta); 248 | 249 | 250 | /** 251 | * Operator overloading. 252 | */ 253 | inline struct Vector2& operator+=(const float rhs); 254 | inline struct Vector2& operator-=(const float rhs); 255 | inline struct Vector2& operator*=(const float rhs); 256 | inline struct Vector2& operator/=(const float rhs); 257 | inline struct Vector2& operator+=(const Vector2 rhs); 258 | inline struct Vector2& operator-=(const Vector2 rhs); 259 | }; 260 | 261 | inline Vector2 operator-(Vector2 rhs); 262 | inline Vector2 operator+(Vector2 lhs, const float rhs); 263 | inline Vector2 operator-(Vector2 lhs, const float rhs); 264 | inline Vector2 operator*(Vector2 lhs, const float rhs); 265 | inline Vector2 operator/(Vector2 lhs, const float rhs); 266 | inline Vector2 operator+(const float lhs, Vector2 rhs); 267 | inline Vector2 operator-(const float lhs, Vector2 rhs); 268 | inline Vector2 operator*(const float lhs, Vector2 rhs); 269 | inline Vector2 operator/(const float lhs, Vector2 rhs); 270 | inline Vector2 operator+(Vector2 lhs, const Vector2 rhs); 271 | inline Vector2 operator-(Vector2 lhs, const Vector2 rhs); 272 | inline bool operator==(const Vector2 lhs, const Vector2 rhs); 273 | inline bool operator!=(const Vector2 lhs, const Vector2 rhs); 274 | 275 | 276 | 277 | /******************************************************************************* 278 | * Implementation 279 | */ 280 | 281 | Vector2::Vector2() : X(0), Y(0) {} 282 | Vector2::Vector2(float data[]) : X(data[0]), Y(data[1]) {} 283 | Vector2::Vector2(float value) : X(value), Y(value) {} 284 | Vector2::Vector2(float x, float y) : X(x), Y(y) {} 285 | 286 | 287 | Vector2 Vector2::Zero() { return Vector2(0, 0); } 288 | Vector2 Vector2::One() { return Vector2(1, 1); } 289 | Vector2 Vector2::Right() { return Vector2(1, 0); } 290 | Vector2 Vector2::Left() { return Vector2(-1, 0); } 291 | Vector2 Vector2::Up() { return Vector2(0, 1); } 292 | Vector2 Vector2::Down() { return Vector2(0, -1); } 293 | 294 | 295 | float Vector2::Angle(Vector2 a, Vector2 b) 296 | { 297 | float v = Dot(a, b) / (Magnitude(a) * Magnitude(b)); 298 | v = fmax(v, -1.0); 299 | v = fmin(v, 1.0); 300 | return acos(v); 301 | } 302 | 303 | Vector2 Vector2::ClampMagnitude(Vector2 vector, float maxLength) 304 | { 305 | float length = Magnitude(vector); 306 | if (length > maxLength) 307 | vector *= maxLength / length; 308 | return vector; 309 | } 310 | 311 | float Vector2::Component(Vector2 a, Vector2 b) 312 | { 313 | return Dot(a, b) / Magnitude(b); 314 | } 315 | 316 | float Vector2::Distance(Vector2 a, Vector2 b) 317 | { 318 | return Vector2::Magnitude(a - b); 319 | } 320 | 321 | float Vector2::Dot(Vector2 lhs, Vector2 rhs) 322 | { 323 | return lhs.X * rhs.X + lhs.Y * rhs.Y; 324 | } 325 | 326 | Vector2 Vector2::FromPolar(float rad, float theta) 327 | { 328 | Vector2 v; 329 | v.X = rad * cos(theta); 330 | v.Y = rad * sin(theta); 331 | return v; 332 | } 333 | 334 | Vector2 Vector2::Lerp(Vector2 a, Vector2 b, float t) 335 | { 336 | if (t < 0) return a; 337 | else if (t > 1) return b; 338 | return LerpUnclamped(a, b, t); 339 | } 340 | 341 | Vector2 Vector2::LerpUnclamped(Vector2 a, Vector2 b, float t) 342 | { 343 | return (b - a) * t + a; 344 | } 345 | 346 | float Vector2::Magnitude(Vector2 v) 347 | { 348 | return sqrt(SqrMagnitude(v)); 349 | } 350 | 351 | Vector2 Vector2::Max(Vector2 a, Vector2 b) 352 | { 353 | float x = a.X > b.X ? a.X : b.X; 354 | float y = a.Y > b.Y ? a.Y : b.Y; 355 | return Vector2(x, y); 356 | } 357 | 358 | Vector2 Vector2::Min(Vector2 a, Vector2 b) 359 | { 360 | float x = a.X > b.X ? b.X : a.X; 361 | float y = a.Y > b.Y ? b.Y : a.Y; 362 | return Vector2(x, y); 363 | } 364 | 365 | Vector2 Vector2::MoveTowards(Vector2 current, Vector2 target, 366 | float maxDistanceDelta) 367 | { 368 | Vector2 d = target - current; 369 | float m = Magnitude(d); 370 | if (m < maxDistanceDelta || m == 0) 371 | return target; 372 | return current + (d * maxDistanceDelta / m); 373 | } 374 | 375 | Vector2 Vector2::Normalized(Vector2 v) 376 | { 377 | float mag = Magnitude(v); 378 | if (mag == 0) 379 | return Vector2::Zero(); 380 | return v / mag; 381 | } 382 | 383 | void Vector2::OrthoNormalize(Vector2 &normal, Vector2 &tangent) 384 | { 385 | normal = Normalized(normal); 386 | tangent = Reject(tangent, normal); 387 | tangent = Normalized(tangent); 388 | } 389 | 390 | Vector2 Vector2::Project(Vector2 a, Vector2 b) 391 | { 392 | float m = Magnitude(b); 393 | return Dot(a, b) / (m * m) * b; 394 | } 395 | 396 | Vector2 Vector2::Reflect(Vector2 vector, Vector2 planeNormal) 397 | { 398 | return vector - 2 * Project(vector, planeNormal); 399 | } 400 | 401 | Vector2 Vector2::Reject(Vector2 a, Vector2 b) 402 | { 403 | return a - Project(a, b); 404 | } 405 | 406 | Vector2 Vector2::RotateTowards(Vector2 current, Vector2 target, 407 | float maxRadiansDelta, 408 | float maxMagnitudeDelta) 409 | { 410 | float magCur = Magnitude(current); 411 | float magTar = Magnitude(target); 412 | float newMag = magCur + maxMagnitudeDelta * 413 | ((magTar > magCur) - (magCur > magTar)); 414 | newMag = fmin(newMag, fmax(magCur, magTar)); 415 | newMag = fmax(newMag, fmin(magCur, magTar)); 416 | 417 | float totalAngle = Angle(current, target) - maxRadiansDelta; 418 | if (totalAngle <= 0) 419 | return Normalized(target) * newMag; 420 | else if (totalAngle >= M_PI) 421 | return Normalized(-target) * newMag; 422 | 423 | float axis = current.X * target.Y - current.Y * target.X; 424 | axis = axis / fabs(axis); 425 | if (!(1 - fabs(axis) < 0.00001)) 426 | axis = 1; 427 | current = Normalized(current); 428 | Vector2 newVector = current * cos(maxRadiansDelta) + 429 | Vector2(-current.Y, current.X) * sin(maxRadiansDelta) * axis; 430 | return newVector * newMag; 431 | } 432 | 433 | Vector2 Vector2::Scale(Vector2 a, Vector2 b) 434 | { 435 | return Vector2(a.X * b.X, a.Y * b.Y); 436 | } 437 | 438 | Vector2 Vector2::Slerp(Vector2 a, Vector2 b, float t) 439 | { 440 | if (t < 0) return a; 441 | else if (t > 1) return b; 442 | return SlerpUnclamped(a, b, t); 443 | } 444 | 445 | Vector2 Vector2::SlerpUnclamped(Vector2 a, Vector2 b, float t) 446 | { 447 | float magA = Magnitude(a); 448 | float magB = Magnitude(b); 449 | a /= magA; 450 | b /= magB; 451 | float dot = Dot(a, b); 452 | dot = fmax(dot, -1.0); 453 | dot = fmin(dot, 1.0); 454 | float theta = acos(dot) * t; 455 | Vector2 relativeVec = Normalized(b - a * dot); 456 | Vector2 newVec = a * cos(theta) + relativeVec * sin(theta); 457 | return newVec * (magA + (magB - magA) * t); 458 | } 459 | 460 | float Vector2::SqrMagnitude(Vector2 v) 461 | { 462 | return v.X * v.X + v.Y * v.Y; 463 | } 464 | 465 | void Vector2::ToPolar(Vector2 vector, float &rad, float &theta) 466 | { 467 | rad = Magnitude(vector); 468 | theta = atan2(vector.Y, vector.X); 469 | } 470 | 471 | 472 | struct Vector2& Vector2::operator+=(const float rhs) 473 | { 474 | X += rhs; 475 | Y += rhs; 476 | return *this; 477 | } 478 | 479 | struct Vector2& Vector2::operator-=(const float rhs) 480 | { 481 | X -= rhs; 482 | Y -= rhs; 483 | return *this; 484 | } 485 | 486 | struct Vector2& Vector2::operator*=(const float rhs) 487 | { 488 | X *= rhs; 489 | Y *= rhs; 490 | return *this; 491 | } 492 | 493 | struct Vector2& Vector2::operator/=(const float rhs) 494 | { 495 | X /= rhs; 496 | Y /= rhs; 497 | return *this; 498 | } 499 | 500 | struct Vector2& Vector2::operator+=(const Vector2 rhs) 501 | { 502 | X += rhs.X; 503 | Y += rhs.Y; 504 | return *this; 505 | } 506 | 507 | struct Vector2& Vector2::operator-=(const Vector2 rhs) 508 | { 509 | X -= rhs.X; 510 | Y -= rhs.Y; 511 | return *this; 512 | } 513 | 514 | Vector2 operator-(Vector2 rhs) { return rhs * -1; } 515 | Vector2 operator+(Vector2 lhs, const float rhs) { return lhs += rhs; } 516 | Vector2 operator-(Vector2 lhs, const float rhs) { return lhs -= rhs; } 517 | Vector2 operator*(Vector2 lhs, const float rhs) { return lhs *= rhs; } 518 | Vector2 operator/(Vector2 lhs, const float rhs) { return lhs /= rhs; } 519 | Vector2 operator+(const float lhs, Vector2 rhs) { return rhs += lhs; } 520 | Vector2 operator-(const float lhs, Vector2 rhs) { return rhs -= lhs; } 521 | Vector2 operator*(const float lhs, Vector2 rhs) { return rhs *= lhs; } 522 | Vector2 operator/(const float lhs, Vector2 rhs) { return rhs /= lhs; } 523 | Vector2 operator+(Vector2 lhs, const Vector2 rhs) { return lhs += rhs; } 524 | Vector2 operator-(Vector2 lhs, const Vector2 rhs) { return lhs -= rhs; } 525 | 526 | bool operator==(const Vector2 lhs, const Vector2 rhs) 527 | { 528 | return lhs.X == rhs.X && lhs.Y == rhs.Y; 529 | } 530 | 531 | bool operator!=(const Vector2 lhs, const Vector2 rhs) 532 | { 533 | return !(lhs == rhs); 534 | } 535 | } -------------------------------------------------------------------------------- /Utils/Helper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace IL2CPP 7 | { 8 | namespace Helper 9 | { 10 | Unity::CComponent *GetMonoBehaviour() 11 | { 12 | Unity::il2cppArray *m_Objects = Unity::Object::FindObjectsOfType(UNITY_GAMEOBJECT_CLASS); 13 | for (uintptr_t u = 0U; m_Objects->m_uMaxLength > u; ++u) 14 | { 15 | Unity::CGameObject *m_Object = m_Objects->operator[](static_cast(u)); 16 | if (!m_Object) 17 | continue; 18 | 19 | Unity::CComponent *m_MonoBehaviour = m_Object->GetComponentByIndex(UNITY_MONOBEHAVIOUR_CLASS); 20 | if (m_MonoBehaviour) 21 | return m_MonoBehaviour; 22 | } 23 | 24 | return nullptr; 25 | } 26 | 27 | template 28 | Ret InvokeStaticMethod(const std::string &className, const std::string &methodName, Args... args) 29 | { 30 | auto il2cppClass = IL2CPP::Class::Find(className.c_str()); 31 | if (!il2cppClass) 32 | { 33 | std::cerr << "Class " << className << " not found.\n"; 34 | return Ret(); 35 | } 36 | 37 | uint64_t methodPointer = IL2CPP::Class::Utils::GetMethodPointerRVA(il2cppClass, methodName.c_str(), sizeof...(args)); 38 | if (!methodPointer) 39 | { 40 | std::cerr << "Method " << methodName << " not found in class " << className << ".\n"; 41 | return Ret(); 42 | } 43 | 44 | return reinterpret_cast(methodPointer)(args...); 45 | } 46 | 47 | template 48 | T GetStaticFieldValue(const std::string &className, const std::string &fieldName) 49 | { 50 | auto il2cppClass = IL2CPP::Class::Find(className.c_str()); 51 | if (!il2cppClass) 52 | { 53 | std::cerr << "Class " << className << " not found.\n"; 54 | return T(); 55 | } 56 | 57 | void *value = IL2CPP::Class::Utils::GetStaticField(il2cppClass, fieldName.c_str()); 58 | if (!value) 59 | { 60 | std::cerr << "Field " << fieldName << " not found in class " << className << ".\n"; 61 | return T(); 62 | } 63 | 64 | return *reinterpret_cast(value); 65 | } 66 | 67 | template 68 | void SetStaticFieldValue(const std::string &className, const std::string &fieldName, const T &value) 69 | { 70 | auto il2cppClass = IL2CPP::Class::Find(className.c_str()); 71 | if (!il2cppClass) 72 | { 73 | std::cerr << "Class " << className << " not found.\n"; 74 | return; 75 | } 76 | 77 | IL2CPP::Class::Utils::SetStaticField(il2cppClass, fieldName.c_str(), (void *)&value); 78 | } 79 | 80 | template 81 | T GetPropertyValue(Unity::CGameObject *obj, const std::string &className, const std::string &propertyName) 82 | { 83 | auto il2cppClass = IL2CPP::Class::Find(className.c_str()); 84 | if (!il2cppClass) 85 | { 86 | std::cerr << "Class " << className << " not found.\n"; 87 | return T(); 88 | } 89 | 90 | auto instance = obj->GetComponent(className.c_str()); 91 | if (!instance) 92 | { 93 | std::cerr << "Failed to get instance of class " << className << ".\n"; 94 | return T(); 95 | } 96 | 97 | return reinterpret_cast(IL2CPP::Class::Utils::GetMethodPointer(il2cppClass, ("get_" + propertyName).c_str()))(instance); 98 | } 99 | 100 | template 101 | void SetPropertyValue(Unity::CGameObject *obj, const std::string &className, const std::string &propertyName, const T &value) 102 | { 103 | auto il2cppClass = IL2CPP::Class::Find(className.c_str()); 104 | if (!il2cppClass) 105 | { 106 | std::cerr << "Class " << className << " not found.\n"; 107 | return; 108 | } 109 | 110 | auto instance = obj->GetComponent(className.c_str()); 111 | if (!instance) 112 | { 113 | std::cerr << "Failed to get instance of class " << className << ".\n"; 114 | return; 115 | } 116 | 117 | reinterpret_cast(IL2CPP::Class::Utils::GetMethodPointer(il2cppClass, ("set_" + propertyName).c_str()))(instance, value); 118 | } 119 | 120 | Unity::CGameObject *CloneGameObject(Unity::CGameObject *obj, const Unity::Vector3 &position) 121 | { 122 | auto il2cppClass = IL2CPP::Class::Find("UnityEngine.Object"); 123 | if (!il2cppClass) 124 | { 125 | std::cerr << "Class UnityEngine.Object not found.\n"; 126 | return nullptr; 127 | } 128 | 129 | void *instantiateMethod = IL2CPP::Class::Utils::GetMethodPointer(il2cppClass, "Instantiate", 1); 130 | if (!instantiateMethod) 131 | { 132 | std::cerr << "Method Instantiate not found in class UnityEngine.Object.\n"; 133 | return nullptr; 134 | } 135 | 136 | auto clonedObj = reinterpret_cast(instantiateMethod)(obj); 137 | if (!clonedObj) 138 | { 139 | std::cerr << "Failed to clone object.\n"; 140 | return nullptr; 141 | } 142 | 143 | auto transform = clonedObj->GetTransform(); 144 | transform->SetPosition(position); 145 | 146 | return clonedObj; 147 | } 148 | 149 | Unity::CGameObject *FindGameObjectByName(const std::string &name) 150 | { 151 | auto gameObject = Unity::GameObject::Find(name.c_str()); 152 | if (!gameObject) 153 | { 154 | std::cerr << "GameObject " << name << " not found.\n"; 155 | } 156 | return gameObject; 157 | } 158 | 159 | std::vector FindGameObjectsWithTag(const std::string &tag) 160 | { 161 | auto gameObjectsArray = Unity::GameObject::FindWithTag(tag.c_str()); 162 | std::vector gameObjects; 163 | if (!gameObjectsArray) 164 | { 165 | std::cerr << "No GameObjects found with tag " << tag << ".\n"; 166 | return gameObjects; 167 | } 168 | for (size_t i = 0; i < gameObjectsArray->m_uMaxLength; ++i) 169 | { 170 | gameObjects.push_back(gameObjectsArray->operator[](i)); 171 | } 172 | return gameObjects; 173 | } 174 | 175 | template 176 | T *GetComponent(Unity::CGameObject *obj, const std::string &componentName) 177 | { 178 | auto component = obj->GetComponent(componentName.c_str()); 179 | if (!component) 180 | { 181 | std::cerr << "Component " << componentName << " not found in GameObject.\n"; 182 | return nullptr; 183 | } 184 | return reinterpret_cast(component); 185 | } 186 | 187 | template 188 | std::vector GetComponents(Unity::CGameObject *obj, const std::string &componentName) 189 | { 190 | auto componentsArray = obj->GetComponents(componentName.c_str()); 191 | std::vector components; 192 | if (!componentsArray) 193 | { 194 | std::cerr << "No components found with name " << componentName << " in GameObject.\n"; 195 | return components; 196 | } 197 | for (size_t i = 0; i < componentsArray->m_uMaxLength; ++i) 198 | { 199 | components.push_back(reinterpret_cast(componentsArray->operator[](i))); 200 | } 201 | return components; 202 | } 203 | 204 | void SetGameObjectPosition(Unity::CGameObject *obj, const Unity::Vector3 &position) 205 | { 206 | auto transform = obj->GetTransform(); 207 | transform->SetPosition(position); 208 | } 209 | 210 | Unity::Vector3 GetGameObjectPosition(Unity::CGameObject *obj) 211 | { 212 | auto transform = obj->GetTransform(); 213 | return transform->GetPosition(); 214 | } 215 | 216 | void SetGameObjectRotation(Unity::CGameObject *obj, const Unity::Quaternion &rotation) 217 | { 218 | auto transform = obj->GetTransform(); 219 | transform->SetRotation(rotation); 220 | } 221 | 222 | Unity::Quaternion GetGameObjectRotation(Unity::CGameObject *obj) 223 | { 224 | auto transform = obj->GetTransform(); 225 | return transform->GetRotation(); 226 | } 227 | 228 | template 229 | Ret CreateInstanceAndInvoke(const std::string &className, const std::string &ctorName, const std::string &methodName, Args... ctorArgs) 230 | { 231 | auto il2cppClass = IL2CPP::Class::Find(className.c_str()); 232 | if (!il2cppClass) 233 | { 234 | std::cerr << "Class " << className << " not found.\n"; 235 | return Ret(); 236 | } 237 | 238 | void *ctorPointer = IL2CPP::Class::Utils::GetMethodPointer(il2cppClass, ctorName.c_str(), sizeof...(ctorArgs)); 239 | if (!ctorPointer) 240 | { 241 | std::cerr << "Constructor " << ctorName << " not found in class " << className << ".\n"; 242 | return Ret(); 243 | } 244 | 245 | auto instance = reinterpret_cast(ctorPointer)(ctorArgs...); 246 | if (!instance) 247 | { 248 | std::cerr << "Failed to create instance of class " << className << ".\n"; 249 | return Ret(); 250 | } 251 | 252 | void *methodPointer = IL2CPP::Class::Utils::GetMethodPointer(il2cppClass, methodName.c_str(), 0); 253 | if (!methodPointer) 254 | { 255 | std::cerr << "Method " << methodName << " not found in class " << className << ".\n"; 256 | return Ret(); 257 | } 258 | 259 | return reinterpret_cast(methodPointer)(instance); 260 | } 261 | 262 | void PrintInstanceFields(Unity::il2cppObject *instance, const std::string &className) 263 | { 264 | auto il2cppClass = IL2CPP::Class::Find(className.c_str()); 265 | if (!il2cppClass) 266 | { 267 | std::cerr << "Class " << className << " not found.\n"; 268 | return; 269 | } 270 | 271 | std::vector fields; 272 | IL2CPP::Class::FetchFields(il2cppClass, &fields); 273 | for (const auto &field : fields) 274 | { 275 | std::cout << field->m_pName << ": " << reinterpret_cast(reinterpret_cast(instance) + field->m_iOffset) << std::endl; 276 | } 277 | } 278 | 279 | std::vector FindAllInstancesByClass(const std::string &className) 280 | { 281 | std::vector instances; 282 | auto il2cppClass = IL2CPP::Class::Find(className.c_str()); 283 | if (!il2cppClass) 284 | { 285 | std::cerr << "Class " << className << " not found.\n"; 286 | return instances; 287 | } 288 | 289 | auto allObjects = Unity::Object::FindObjectsOfType("UnityEngine.GameObject"); 290 | if (!allObjects) 291 | { 292 | std::cerr << "No GameObjects found.\n"; 293 | return instances; 294 | } 295 | 296 | for (size_t i = 0; i < allObjects->m_uMaxLength; ++i) 297 | { 298 | auto gameObject = allObjects->operator[](i); 299 | if (gameObject->GetComponent(className.c_str())) 300 | { 301 | instances.push_back(gameObject); 302 | } 303 | } 304 | return instances; 305 | } 306 | 307 | template 308 | Ret InvokeMethodByRVA(uintptr_t rva, void *instance, Args... args) 309 | { 310 | auto methodPointer = reinterpret_cast(rva); 311 | return methodPointer(instance, args...); 312 | } 313 | 314 | template 315 | void InvokeMethodOnAllInstancesByRVA(const std::string &className, uintptr_t rva, Args... args) 316 | { 317 | auto il2cppClass = IL2CPP::Class::Find(className.c_str()); 318 | if (!il2cppClass) 319 | { 320 | std::cerr << "Class " << className << " not found.\n"; 321 | return; 322 | } 323 | 324 | auto allObjects = Unity::Object::FindObjectsOfType("UnityEngine.GameObject"); 325 | if (!allObjects) 326 | { 327 | std::cerr << "No GameObjects found.\n"; 328 | return; 329 | } 330 | 331 | for (size_t i = 0; i < allObjects->m_uMaxLength; ++i) 332 | { 333 | auto gameObject = allObjects->operator[](i); 334 | auto component = gameObject->GetComponent(className.c_str()); 335 | if (component) 336 | { 337 | std::cout << "Invoking method on instance: " << gameObject->GetName()->ToString() << "\n"; 338 | InvokeMethodByRVA(rva, component, args...); 339 | } 340 | } 341 | } 342 | 343 | template 344 | using MethodDelegate = Ret (*)(void *, Args...); 345 | 346 | template 347 | Ret InvokeMethodByDelegate(Unity::CGameObject *obj, const std::string &className, const std::string &methodName, Args... args) 348 | { 349 | auto il2cppClass = IL2CPP::Class::Find(className.c_str()); 350 | if (!il2cppClass) 351 | { 352 | std::cerr << "Class " << className << " not found.\n"; 353 | return Ret(); 354 | } 355 | 356 | void *methodPointer = IL2CPP::Class::Utils::GetMethodPointer(il2cppClass, methodName.c_str(), sizeof...(args)); 357 | if (!methodPointer) 358 | { 359 | std::cerr << "Method " << methodName << " not found in class " << className << ".\n"; 360 | return Ret(); 361 | } 362 | 363 | auto instance = obj->GetComponent(className.c_str()); 364 | if (!instance) 365 | { 366 | std::cerr << "Failed to get instance of class " << className << ".\n"; 367 | return Ret(); 368 | } 369 | 370 | MethodDelegate method = reinterpret_cast>(methodPointer); 371 | return method(instance, args...); 372 | } 373 | 374 | template 375 | Ret InvokeMethodOnComponent(Unity::CGameObject *obj, const std::string &componentName, const std::string &methodName, Args... args) 376 | { 377 | auto component = obj->GetComponent(componentName.c_str()); 378 | if (!component) 379 | { 380 | std::cerr << "Component " << componentName << " not found in GameObject.\n"; 381 | return Ret(); 382 | } 383 | 384 | auto il2cppClass = IL2CPP::Class::Find(componentName.c_str()); 385 | if (!il2cppClass) 386 | { 387 | std::cerr << "Class " << componentName << " not found.\n"; 388 | return Ret(); 389 | } 390 | 391 | void *methodPointer = IL2CPP::Class::Utils::GetMethodPointer(il2cppClass, methodName.c_str(), sizeof...(args)); 392 | if (!methodPointer) 393 | { 394 | std::cerr << "Method " << methodName << " not found in class " << componentName << ".\n"; 395 | return Ret(); 396 | } 397 | 398 | return reinterpret_cast(methodPointer)(component, args...); 399 | } 400 | 401 | void CountAndPrintInstances(const std::string &className) 402 | { 403 | auto il2cppClass = IL2CPP::Class::Find(className.c_str()); 404 | if (!il2cppClass) 405 | { 406 | std::cerr << "Class " << className << " not found.\n"; 407 | return; 408 | } 409 | 410 | auto allObjects = Unity::Object::FindObjectsOfType(className.c_str()); 411 | if (!allObjects) 412 | { 413 | std::cout << "No instances of class " << className << " found.\n"; 414 | return; 415 | } 416 | 417 | size_t count = allObjects->m_uMaxLength; 418 | std::cout << "Number of instances of class " << className << ": " << count << "\n"; 419 | 420 | for (size_t i = 0; i < count; ++i) 421 | { 422 | auto gameObject = allObjects->operator[](i); 423 | std::cout << "Instance " << i + 1 << ": " << gameObject->GetName()->ToString() << "\n"; 424 | } 425 | } 426 | 427 | Unity::CGameObject *CreateInstance(const std::string &className) 428 | { 429 | auto il2cppClass = IL2CPP::Class::Find(className.c_str()); 430 | if (!il2cppClass) 431 | { 432 | std::cerr << "Class " << className << " not found.\n"; 433 | return nullptr; 434 | } 435 | 436 | void *createInstanceMethod = IL2CPP::Class::Utils::GetMethodPointer(il2cppClass, "Instantiate", 1); 437 | if (!createInstanceMethod) 438 | { 439 | std::cerr << "Instantiate method not found in class " << className << ".\n"; 440 | return nullptr; 441 | } 442 | 443 | auto instance = reinterpret_cast(createInstanceMethod)(nullptr); 444 | if (!instance) 445 | { 446 | std::cerr << "Failed to create instance of class " << className << ".\n"; 447 | return nullptr; 448 | } 449 | 450 | std::cout << "Instance of class " << className << " created.\n"; 451 | return instance; 452 | } 453 | 454 | template 455 | void InvokeMethodOnTaggedGameObjects(const std::string &tag, const std::string &className, const std::string &methodName, Args... args) 456 | { 457 | auto gameObjectsArray = Unity::GameObject::FindWithTag(tag.c_str()); 458 | if (!gameObjectsArray) 459 | { 460 | std::cerr << "No GameObjects found with tag " << tag << ".\n"; 461 | return; 462 | } 463 | 464 | auto il2cppClass = IL2CPP::Class::Find(className.c_str()); 465 | if (!il2cppClass) 466 | { 467 | std::cerr << "Class " << className << " not found.\n"; 468 | return; 469 | } 470 | 471 | void *methodPointer = IL2CPP::Class::Utils::GetMethodPointer(il2cppClass, methodName.c_str()); 472 | if (!methodPointer) 473 | { 474 | std::cerr << "Method " << methodName << " not found in class " << className << ".\n"; 475 | return; 476 | } 477 | 478 | for (size_t i = 0; i < gameObjectsArray->m_uMaxLength; ++i) 479 | { 480 | auto gameObject = gameObjectsArray->operator[](i); 481 | if (gameObject) 482 | { 483 | auto component = gameObject->GetComponent(className.c_str()); 484 | if (component) 485 | { 486 | reinterpret_cast(methodPointer)(component, args...); 487 | } 488 | } 489 | } 490 | } 491 | 492 | void DestroyGameObjectsByTag(const std::string &tag) 493 | { 494 | auto gameObjectsArray = Unity::GameObject::FindWithTag(tag.c_str()); 495 | if (!gameObjectsArray) 496 | { 497 | std::cerr << "No GameObjects found with tag " << tag << ".\n"; 498 | return; 499 | } 500 | 501 | for (size_t i = 0; i < gameObjectsArray->m_uMaxLength; ++i) 502 | { 503 | auto gameObject = gameObjectsArray->operator[](i); 504 | gameObject->Destroy(); 505 | std::cout << "Destroyed GameObject with tag " << tag << ": " << gameObject->GetName()->ToString() << "\n"; 506 | } 507 | } 508 | } 509 | } 510 | -------------------------------------------------------------------------------- /Vector3.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define _USE_MATH_DEFINES 4 | #include 5 | #include 6 | #pragma clang diagnostic ignored "-Wint-to-pointer-cast" 7 | 8 | namespace Unity 9 | { 10 | struct Vector3 11 | { 12 | union 13 | { 14 | struct 15 | { 16 | float X; 17 | float Y; 18 | float Z; 19 | }; 20 | float data[3]; 21 | }; 22 | 23 | 24 | /** 25 | * Constructors. 26 | */ 27 | inline Vector3(); 28 | inline Vector3(float data[]); 29 | inline Vector3(float value); 30 | inline Vector3(float x, float y); 31 | inline Vector3(float x, float y, float z); 32 | 33 | /** 34 | * Constants for common vectors. 35 | */ 36 | static inline Vector3 Zero(); 37 | static inline Vector3 One(); 38 | static inline Vector3 Right(); 39 | static inline Vector3 Left(); 40 | static inline Vector3 Up(); 41 | static inline Vector3 Down(); 42 | static inline Vector3 Forward(); 43 | static inline Vector3 Backward(); 44 | 45 | 46 | /** 47 | * Returns the angle between two vectors in radians. 48 | * @param a: The first vector. 49 | * @param b: The second vector. 50 | * @return: A scalar value. 51 | */ 52 | static inline float Angle(Vector3 a, Vector3 b); 53 | 54 | /** 55 | * Returns a vector with its magnitude clamped to maxLength. 56 | * @param vector: The target vector. 57 | * @param maxLength: The maximum length of the return vector. 58 | * @return: A new vector. 59 | */ 60 | static inline Vector3 ClampMagnitude(Vector3 vector, float maxLength); 61 | 62 | /** 63 | * Retorna o componente de a na direção de b (projeção escalar). 64 | * @param a: O vetor de destino. 65 | * @param b: O vetor que está sendo comparado. 66 | * @return: Um valor escalar. 67 | */ 68 | static inline float Component(Vector3 a, Vector3 b); 69 | 70 | /** 71 | * Retorna o produto vetorial de dois vetores. 72 | * @param lhs: O lado esquerdo da multiplicação. 73 | * @param rhs: O lado direito da multiplicação. 74 | * @return: Um novo vetor. 75 | */ 76 | static inline Vector3 Cross(Vector3 lhs, Vector3 rhs); 77 | 78 | /** 79 | * Returns the distance between a and b. 80 | * @param a: The first point. 81 | * @param b: The second point. 82 | * @return: A scalar value. 83 | */ 84 | static inline float Distance(Vector3 a, Vector3 b); 85 | 86 | static inline char ToChar(Vector3 a); 87 | 88 | /** 89 | * Returns the dot product of two vectors. 90 | * @param lhs: The left side of the multiplication. 91 | * @param rhs: The right side of the multiplication. 92 | * @return: A scalar value. 93 | */ 94 | static inline float Dot(Vector3 lhs, Vector3 rhs); 95 | 96 | /** 97 | * Converte uma representação esférica de um vetor em cartesiano 98 | * coordenadas. 99 | * Isso usa a convenção ISO (raio r, inclinação theta, azimute phi). 100 | * @param rad: A magnitude do vetor. 101 | * @param theta: O ângulo no plano XY do eixo X. 102 | * @param phi: O ângulo do eixo Z positivo para o vetor. 103 | * @return: Um novo vetor. 104 | */ 105 | static inline Vector3 FromSpherical(float rad, float theta, float phi); 106 | 107 | /** 108 | * Returns a vector linearly interpolated between a and b, moving along 109 | * a straight line. The vector is clamped to never go beyond the end points. 110 | * @param a: The starting point. 111 | * @param b: The ending point. 112 | * @param t: The interpolation value [0-1]. 113 | * @return: A new vector. 114 | */ 115 | static inline Vector3 Lerp(Vector3 a, Vector3 b, float t); 116 | 117 | /** 118 | * Returns a vector linearly interpolated between a and b, moving along 119 | * a straight line. 120 | * @param a: The starting point. 121 | * @param b: The ending point. 122 | * @param t: The interpolation value [0-1] (no actual bounds). 123 | * @return: A new vector. 124 | */ 125 | static inline Vector3 LerpUnclamped(Vector3 a, Vector3 b, float t); 126 | 127 | /** 128 | * Returns the magnitude of a vector. 129 | * @param v: The vector in question. 130 | * @return: A scalar value. 131 | */ 132 | static inline float Magnitude(Vector3 v); 133 | 134 | /** 135 | * Returns a vector made from the largest components of two other vectors. 136 | * @param a: The first vector. 137 | * @param b: The second vector. 138 | * @return: A new vector. 139 | */ 140 | static inline Vector3 Max(Vector3 a, Vector3 b); 141 | 142 | /** 143 | * Returns a vector made from the smallest components of two other vectors. 144 | * @param a: The first vector. 145 | * @param b: The second vector. 146 | * @return: A new vector. 147 | */ 148 | static inline Vector3 Min(Vector3 a, Vector3 b); 149 | 150 | /** 151 | * Returns a vector "maxDistanceDelta" units closer to the target. This 152 | * interpolation is in a straight line, and will not overshoot. 153 | * @param current: The current position. 154 | * @param target: The destination position. 155 | * @param maxDistanceDelta: The maximum distance to move. 156 | * @return: A new vector. 157 | */ 158 | static inline Vector3 MoveTowards(Vector3 current, Vector3 target, 159 | float maxDistanceDelta); 160 | 161 | /** 162 | * Returns a new vector with magnitude of one. 163 | * @param v: The vector in question. 164 | * @return: A new vector. 165 | */ 166 | static inline Vector3 Normalized(Vector3 v); 167 | 168 | /** 169 | * Returns an arbitrary vector orthogonal to the input. 170 | * This vector is not normalized. 171 | * @param v: The input vector. 172 | * @return: A new vector. 173 | */ 174 | static inline Vector3 Orthogonal(Vector3 v); 175 | 176 | /** 177 | * Creates a new coordinate system out of the three vectors. 178 | * Normalizes "normal", normalizes "tangent" and makes it orthogonal to 179 | * "normal" and normalizes "binormal" and makes it orthogonal to both 180 | * "normal" and "tangent". 181 | * @param normal: A reference to the first axis vector. 182 | * @param tangent: A reference to the second axis vector. 183 | * @param binormal: A reference to the third axis vector. 184 | */ 185 | static inline void OrthoNormalize(Vector3 &normal, Vector3 &tangent, 186 | Vector3 &binormal); 187 | 188 | /** 189 | * Returns the vector projection of a onto b. 190 | * @param a: The target vector. 191 | * @param b: The vector being projected onto. 192 | * @return: A new vector. 193 | */ 194 | static inline Vector3 Project(Vector3 a, Vector3 b); 195 | 196 | /** 197 | * Returns a vector projected onto a plane orthogonal to "planeNormal". 198 | * This can be visualized as the shadow of the vector onto the plane, if 199 | * the light source were in the direction of the plane normal. 200 | * @param vector: The vector to project. 201 | * @param planeNormal: The normal of the plane onto which to project. 202 | * @param: A new vector. 203 | */ 204 | static inline Vector3 ProjectOnPlane(Vector3 vector, Vector3 planeNormal); 205 | 206 | /** 207 | * Returns a vector reflected off the plane orthogonal to the normal. 208 | * The input vector is pointed inward, at the plane, and the return vector 209 | * is pointed outward from the plane, like a beam of light hitting and then 210 | * reflecting off a mirror. 211 | * @param vector: The vector traveling inward at the plane. 212 | * @param planeNormal: The normal of the plane off of which to reflect. 213 | * @return: A new vector pointing outward from the plane. 214 | */ 215 | static inline Vector3 Reflect(Vector3 vector, Vector3 planeNormal); 216 | 217 | /** 218 | * Returns the vector rejection of a on b. 219 | * @param a: The target vector. 220 | * @param b: The vector being projected onto. 221 | * @return: A new vector. 222 | */ 223 | static inline Vector3 Reject(Vector3 a, Vector3 b); 224 | 225 | /** 226 | * Rotates vector "current" towards vector "target" by "maxRadiansDelta". 227 | * This treats the vectors as directions and will linearly interpolate 228 | * between their magnitudes by "maxMagnitudeDelta". This function does not 229 | * overshoot. If a negative delta is supplied, it will rotate away from 230 | * "target" until it is pointing the opposite direction, but will not 231 | * overshoot that either. 232 | * @param current: The starting direction. 233 | * @param target: The destination direction. 234 | * @param maxRadiansDelta: The maximum number of radians to rotate. 235 | * @param maxMagnitudeDelta: The maximum delta for magnitude interpolation. 236 | * @return: A new vector. 237 | */ 238 | static inline Vector3 RotateTowards(Vector3 current, Vector3 target, 239 | float maxRadiansDelta, 240 | float maxMagnitudeDelta); 241 | 242 | /** 243 | * Multiplies two vectors element-wise. 244 | * @param a: The lhs of the multiplication. 245 | * @param b: The rhs of the multiplication. 246 | * @return: A new vector. 247 | */ 248 | static inline Vector3 Scale(Vector3 a, Vector3 b); 249 | 250 | /** 251 | * Returns a vector rotated towards b from a by the percent t. 252 | * Since interpolation is done spherically, the vector moves at a constant 253 | * angular velocity. This rotation is clamped to 0 <= t <= 1. 254 | * @param a: The starting direction. 255 | * @param b: The ending direction. 256 | * @param t: The interpolation value [0-1]. 257 | */ 258 | static inline Vector3 Slerp(Vector3 a, Vector3 b, float t); 259 | 260 | /** 261 | * Returns a vector rotated towards b from a by the percent t. 262 | * Since interpolation is done spherically, the vector moves at a constant 263 | * angular velocity. This rotation is unclamped. 264 | * @param a: The starting direction. 265 | * @param b: The ending direction. 266 | * @param t: The interpolation value [0-1]. 267 | */ 268 | static inline Vector3 SlerpUnclamped(Vector3 a, Vector3 b, float t); 269 | 270 | /** 271 | * Returns the squared magnitude of a vector. 272 | * This is useful when comparing relative lengths, where the exact length 273 | * is not important, and much time can be saved by not calculating the 274 | * square root. 275 | * @param v: The vector in question. 276 | * @return: A scalar value. 277 | */ 278 | static inline float SqrMagnitude(Vector3 v); 279 | 280 | /** 281 | * Calculates the spherical coordinate space representation of a vector. 282 | * This uses the ISO convention (radius r, inclination theta, azimuth phi). 283 | * @param vector: The vector to convert. 284 | * @param rad: The magnitude of the vector. 285 | * @param theta: The angle in the XY plane from the X axis. 286 | * @param phi: The angle from the positive Z axis to the vector. 287 | */ 288 | static inline void ToSpherical(Vector3 vector, float &rad, float &theta, 289 | float &phi); 290 | 291 | 292 | /** 293 | * Operator overloading. 294 | */ 295 | inline struct Vector3& operator+=(const float rhs); 296 | inline struct Vector3& operator-=(const float rhs); 297 | inline struct Vector3& operator*=(const float rhs); 298 | inline struct Vector3& operator/=(const float rhs); 299 | inline struct Vector3& operator+=(const Vector3 rhs); 300 | inline struct Vector3& operator-=(const Vector3 rhs); 301 | }; 302 | 303 | inline Vector3 operator-(Vector3 rhs); 304 | inline Vector3 operator+(Vector3 lhs, const float rhs); 305 | inline Vector3 operator-(Vector3 lhs, const float rhs); 306 | inline Vector3 operator*(Vector3 lhs, const float rhs); 307 | inline Vector3 operator/(Vector3 lhs, const float rhs); 308 | inline Vector3 operator+(const float lhs, Vector3 rhs); 309 | inline Vector3 operator-(const float lhs, Vector3 rhs); 310 | inline Vector3 operator*(const float lhs, Vector3 rhs); 311 | inline Vector3 operator/(const float lhs, Vector3 rhs); 312 | inline Vector3 operator+(Vector3 lhs, const Vector3 rhs); 313 | inline Vector3 operator-(Vector3 lhs, const Vector3 rhs); 314 | inline bool operator==(const Vector3 lhs, const Vector3 rhs); 315 | inline bool operator!=(const Vector3 lhs, const Vector3 rhs); 316 | 317 | 318 | 319 | /******************************************************************************* 320 | * Implementation 321 | */ 322 | 323 | Vector3::Vector3() : X(0), Y(0), Z(0) {} 324 | Vector3::Vector3(float data[]) : X(data[0]), Y(data[1]), Z(data[2]) {} 325 | Vector3::Vector3(float value) : X(value), Y(value), Z(value) {} 326 | Vector3::Vector3(float x, float y) : X(x), Y(y), Z(0) {} 327 | Vector3::Vector3(float x, float y, float z) : X(x), Y(y), Z(z) {} 328 | 329 | 330 | Vector3 Vector3::Zero() { return Vector3(0, 0, 0); } 331 | Vector3 Vector3::One() { return Vector3(1, 1, 1); } 332 | Vector3 Vector3::Right() { return Vector3(1, 0, 0); } 333 | Vector3 Vector3::Left() { return Vector3(-1, 0, 0); } 334 | Vector3 Vector3::Up() { return Vector3(0, 1, 0); } 335 | Vector3 Vector3::Down() { return Vector3(0, -1, 0); } 336 | Vector3 Vector3::Forward() { return Vector3(0, 0, 1); } 337 | Vector3 Vector3::Backward() { return Vector3(0, 0, -1); } 338 | 339 | 340 | float Vector3::Angle(Vector3 a, Vector3 b) 341 | { 342 | float v = Dot(a, b) / (Magnitude(a) * Magnitude(b)); 343 | v = fmax(v, -1.0); 344 | v = fmin(v, 1.0); 345 | return acos(v); 346 | } 347 | 348 | Vector3 Vector3::ClampMagnitude(Vector3 vector, float maxLength) 349 | { 350 | float length = Magnitude(vector); 351 | if (length > maxLength) 352 | vector *= maxLength / length; 353 | return vector; 354 | } 355 | 356 | float Vector3::Component(Vector3 a, Vector3 b) 357 | { 358 | return Dot(a, b) / Magnitude(b); 359 | } 360 | 361 | Vector3 Vector3::Cross(Vector3 lhs, Vector3 rhs) 362 | { 363 | float x = lhs.Y * rhs.Z - lhs.Z * rhs.Y; 364 | float y = lhs.Z * rhs.X - lhs.X * rhs.Z; 365 | float z = lhs.X * rhs.Y - lhs.Y * rhs.X; 366 | return Vector3(x, y, z); 367 | } 368 | 369 | float Vector3::Distance(Vector3 a, Vector3 b) 370 | { 371 | return Vector3::Magnitude(a - b); 372 | } 373 | 374 | float Vector3::Dot(Vector3 lhs, Vector3 rhs) 375 | { 376 | return lhs.X * rhs.X + lhs.Y * rhs.Y + lhs.Z * rhs.Z; 377 | } 378 | 379 | Vector3 Vector3::FromSpherical(float rad, float theta, float phi) 380 | { 381 | Vector3 v; 382 | v.X = rad * sin(theta) * cos(phi); 383 | v.Y = rad * sin(theta) * sin(phi); 384 | v.Z = rad * cos(theta); 385 | return v; 386 | } 387 | 388 | Vector3 Vector3::Lerp(Vector3 a, Vector3 b, float t) 389 | { 390 | if (t < 0) return a; 391 | else if (t > 1) return b; 392 | return LerpUnclamped(a, b, t); 393 | } 394 | 395 | Vector3 Vector3::LerpUnclamped(Vector3 a, Vector3 b, float t) 396 | { 397 | return (b - a) * t + a; 398 | } 399 | 400 | float Vector3::Magnitude(Vector3 v) 401 | { 402 | return sqrt(SqrMagnitude(v)); 403 | } 404 | 405 | Vector3 Vector3::Max(Vector3 a, Vector3 b) 406 | { 407 | float x = a.X > b.X ? a.X : b.X; 408 | float y = a.Y > b.Y ? a.Y : b.Y; 409 | float z = a.Z > b.Z ? a.Z : b.Z; 410 | return Vector3(x, y, z); 411 | } 412 | 413 | Vector3 Vector3::Min(Vector3 a, Vector3 b) 414 | { 415 | float x = a.X > b.X ? b.X : a.X; 416 | float y = a.Y > b.Y ? b.Y : a.Y; 417 | float z = a.Z > b.Z ? b.Z : a.Z; 418 | return Vector3(x, y, z); 419 | } 420 | 421 | Vector3 Vector3::MoveTowards(Vector3 current, Vector3 target, 422 | float maxDistanceDelta) 423 | { 424 | Vector3 d = target - current; 425 | float m = Magnitude(d); 426 | if (m < maxDistanceDelta || m == 0) 427 | return target; 428 | return current + (d * maxDistanceDelta / m); 429 | } 430 | 431 | Vector3 Vector3::Normalized(Vector3 v) 432 | { 433 | float mag = Magnitude(v); 434 | if (mag == 0) 435 | return Vector3::Zero(); 436 | return v / mag; 437 | } 438 | 439 | Vector3 Vector3::Orthogonal(Vector3 v) 440 | { 441 | return v.Z < v.X ? Vector3(v.Y, -v.X, 0) : Vector3(0, -v.Z, v.Y); 442 | } 443 | 444 | void Vector3::OrthoNormalize(Vector3 &normal, Vector3 &tangent, 445 | Vector3 &binormal) 446 | { 447 | normal = Normalized(normal); 448 | tangent = ProjectOnPlane(tangent, normal); 449 | tangent = Normalized(tangent); 450 | binormal = ProjectOnPlane(binormal, tangent); 451 | binormal = ProjectOnPlane(binormal, normal); 452 | binormal = Normalized(binormal); 453 | } 454 | 455 | Vector3 Vector3::Project(Vector3 a, Vector3 b) 456 | { 457 | float m = Magnitude(b); 458 | return Dot(a, b) / (m * m) * b; 459 | } 460 | 461 | Vector3 Vector3::ProjectOnPlane(Vector3 vector, Vector3 planeNormal) 462 | { 463 | return Reject(vector, planeNormal); 464 | } 465 | 466 | Vector3 Vector3::Reflect(Vector3 vector, Vector3 planeNormal) 467 | { 468 | return vector - 2 * Project(vector, planeNormal); 469 | } 470 | 471 | Vector3 Vector3::Reject(Vector3 a, Vector3 b) 472 | { 473 | return a - Project(a, b); 474 | } 475 | 476 | Vector3 Vector3::RotateTowards(Vector3 current, Vector3 target, 477 | float maxRadiansDelta, 478 | float maxMagnitudeDelta) 479 | { 480 | float magCur = Magnitude(current); 481 | float magTar = Magnitude(target); 482 | float newMag = magCur + maxMagnitudeDelta * 483 | ((magTar > magCur) - (magCur > magTar)); 484 | newMag = fmin(newMag, fmax(magCur, magTar)); 485 | newMag = fmax(newMag, fmin(magCur, magTar)); 486 | 487 | float totalAngle = Angle(current, target) - maxRadiansDelta; 488 | if (totalAngle <= 0) 489 | return Normalized(target) * newMag; 490 | else if (totalAngle >= M_PI) 491 | return Normalized(-target) * newMag; 492 | 493 | Vector3 axis = Cross(current, target); 494 | float magAxis = Magnitude(axis); 495 | if (magAxis == 0) 496 | axis = Normalized(Cross(current, current + Vector3(3.95, 5.32, -4.24))); 497 | else 498 | axis /= magAxis; 499 | current = Normalized(current); 500 | Vector3 newVector = current * cos(maxRadiansDelta) + 501 | Cross(axis, current) * sin(maxRadiansDelta); 502 | return newVector * newMag; 503 | } 504 | 505 | Vector3 Vector3::Scale(Vector3 a, Vector3 b) 506 | { 507 | return Vector3(a.X * b.X, a.Y * b.Y, a.Z * b.Z); 508 | } 509 | 510 | Vector3 Vector3::Slerp(Vector3 a, Vector3 b, float t) 511 | { 512 | if (t < 0) return a; 513 | else if (t > 1) return b; 514 | return SlerpUnclamped(a, b, t); 515 | } 516 | 517 | Vector3 Vector3::SlerpUnclamped(Vector3 a, Vector3 b, float t) 518 | { 519 | float magA = Magnitude(a); 520 | float magB = Magnitude(b); 521 | a /= magA; 522 | b /= magB; 523 | float dot = Dot(a, b); 524 | dot = fmax(dot, -1.0); 525 | dot = fmin(dot, 1.0); 526 | float theta = acos(dot) * t; 527 | Vector3 relativeVec = Normalized(b - a * dot); 528 | Vector3 newVec = a * cos(theta) + relativeVec * sin(theta); 529 | return newVec * (magA + (magB - magA) * t); 530 | } 531 | 532 | float Vector3::SqrMagnitude(Vector3 v) 533 | { 534 | return v.X * v.X + v.Y * v.Y + v.Z * v.Z; 535 | } 536 | 537 | void Vector3::ToSpherical(Vector3 vector, float &rad, float &theta, 538 | float &phi) 539 | { 540 | rad = Magnitude(vector); 541 | float v = vector.Z / rad; 542 | v = fmax(v, -1.0); 543 | v = fmin(v, 1.0); 544 | theta = acos(v); 545 | phi = atan2(vector.Y, vector.X); 546 | } 547 | 548 | 549 | struct Vector3& Vector3::operator+=(const float rhs) 550 | { 551 | X += rhs; 552 | Y += rhs; 553 | Z += rhs; 554 | return *this; 555 | } 556 | 557 | struct Vector3& Vector3::operator-=(const float rhs) 558 | { 559 | X -= rhs; 560 | Y -= rhs; 561 | Z -= rhs; 562 | return *this; 563 | } 564 | 565 | struct Vector3& Vector3::operator*=(const float rhs) 566 | { 567 | X *= rhs; 568 | Y *= rhs; 569 | Z *= rhs; 570 | return *this; 571 | } 572 | 573 | struct Vector3& Vector3::operator/=(const float rhs) 574 | { 575 | X /= rhs; 576 | Y /= rhs; 577 | Z /= rhs; 578 | return *this; 579 | } 580 | 581 | struct Vector3& Vector3::operator+=(const Vector3 rhs) 582 | { 583 | X += rhs.X; 584 | Y += rhs.Y; 585 | Z += rhs.Z; 586 | return *this; 587 | } 588 | 589 | struct Vector3& Vector3::operator-=(const Vector3 rhs) 590 | { 591 | X -= rhs.X; 592 | Y -= rhs.Y; 593 | Z -= rhs.Z; 594 | return *this; 595 | } 596 | 597 | char Vector3::ToChar(Vector3 a) { 598 | const char* x = (const char*)(int)a.X; 599 | const char* y = (const char*)(int)a.Y; 600 | const char* z = (const char*)(int)a.Z; 601 | char buffer[25]; 602 | strncpy(buffer, x, sizeof(buffer)); 603 | strncpy(buffer, ", ", sizeof(buffer)); 604 | strncpy(buffer, y, sizeof(buffer)); 605 | strncpy(buffer, ", ", sizeof(buffer)); 606 | strncpy(buffer, z, sizeof(buffer)); 607 | strncpy(buffer, ", ", sizeof(buffer)); 608 | return buffer[24]; 609 | } 610 | 611 | Vector3 operator-(Vector3 rhs) { return rhs * -1; } 612 | Vector3 operator+(Vector3 lhs, const float rhs) { return lhs += rhs; } 613 | Vector3 operator-(Vector3 lhs, const float rhs) { return lhs -= rhs; } 614 | Vector3 operator*(Vector3 lhs, const float rhs) { return lhs *= rhs; } 615 | Vector3 operator/(Vector3 lhs, const float rhs) { return lhs /= rhs; } 616 | Vector3 operator+(const float lhs, Vector3 rhs) { return rhs += lhs; } 617 | Vector3 operator-(const float lhs, Vector3 rhs) { return rhs -= lhs; } 618 | Vector3 operator*(const float lhs, Vector3 rhs) { return rhs *= lhs; } 619 | Vector3 operator/(const float lhs, Vector3 rhs) { return rhs /= lhs; } 620 | Vector3 operator+(Vector3 lhs, const Vector3 rhs) { return lhs += rhs; } 621 | Vector3 operator-(Vector3 lhs, const Vector3 rhs) { return lhs -= rhs; } 622 | 623 | bool operator==(const Vector3 lhs, const Vector3 rhs) 624 | { 625 | return lhs.X == rhs.X && lhs.Y == rhs.Y && lhs.Z == rhs.Z; 626 | } 627 | 628 | bool operator!=(const Vector3 lhs, const Vector3 rhs) 629 | { 630 | return !(lhs == rhs); 631 | } 632 | } -------------------------------------------------------------------------------- /Quaternion.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define _USE_MATH_DEFINES 4 | #include 5 | 6 | #define SMALL_float 0.0000000001 7 | 8 | namespace Unity 9 | { 10 | struct Quaternion 11 | { 12 | union 13 | { 14 | struct 15 | { 16 | float X; 17 | float Y; 18 | float Z; 19 | float W; 20 | }; 21 | float data[4]; 22 | }; 23 | 24 | 25 | /** 26 | * Constructors. 27 | */ 28 | inline Quaternion(); 29 | inline Quaternion(float data[]); 30 | inline Quaternion(Vector3 vector, float scalar); 31 | inline Quaternion(float x, float y, float z, float w); 32 | 33 | 34 | /** 35 | * Constants for common quaternions. 36 | */ 37 | static inline Quaternion Identity(); 38 | 39 | 40 | /** 41 | * Returns the angle between two quaternions. 42 | * The quaternions must be normalized. 43 | * @param a: The first quaternion. 44 | * @param b: The second quaternion. 45 | * @return: A scalar value. 46 | */ 47 | static inline float Angle(Quaternion a, Quaternion b); 48 | 49 | /** 50 | * Returns the conjugate of a quaternion. 51 | * @param rotation: The quaternion in question. 52 | * @return: A new quaternion. 53 | */ 54 | static inline Quaternion Conjugate(Quaternion rotation); 55 | 56 | /** 57 | * Returns the dot product of two quaternions. 58 | * @param lhs: The left side of the multiplication. 59 | * @param rhs: The right side of the multiplication. 60 | * @return: A scalar value. 61 | */ 62 | static inline float Dot(Quaternion lhs, Quaternion rhs); 63 | 64 | /** 65 | * Creates a new quaternion from the angle-axis representation of 66 | * a rotation. 67 | * @param angle: The rotation angle in radians. 68 | * @param axis: The vector about which the rotation occurs. 69 | * @return: A new quaternion. 70 | */ 71 | static inline Quaternion FromAngleAxis(float angle, Vector3 axis); 72 | 73 | /** 74 | * Create a new quaternion from the euler angle representation of 75 | * a rotation. The z, x and y values represent rotations about those 76 | * axis in that respective order. 77 | * @param rotation: The x, y and z rotations. 78 | * @return: A new quaternion. 79 | */ 80 | static inline Quaternion FromEuler(Vector3 rotation); 81 | 82 | /** 83 | * Create a new quaternion from the euler angle representation of 84 | * a rotation. The z, x and y values represent rotations about those 85 | * axis in that respective order. 86 | * @param x: The rotation about the x-axis in radians. 87 | * @param y: The rotation about the y-axis in radians. 88 | * @param z: The rotation about the z-axis in radians. 89 | * @return: A new quaternion. 90 | */ 91 | static inline Quaternion FromEuler(float x, float y, float z); 92 | 93 | /** 94 | * Create a quaternion rotation which rotates "fromVector" to "toVector". 95 | * @param fromVector: The vector from which to start the rotation. 96 | * @param toVector: The vector at which to end the rotation. 97 | * @return: A new quaternion. 98 | */ 99 | static inline Quaternion FromToRotation(Vector3 fromVector, 100 | Vector3 toVector); 101 | 102 | /** 103 | * Returns the inverse of a rotation. 104 | * @param rotation: The quaternion in question. 105 | * @return: A new quaternion. 106 | */ 107 | static inline Quaternion Inverse(Quaternion rotation); 108 | 109 | /** 110 | * Interpolates between a and b by t, which is clamped to the range [0-1]. 111 | * The result is normalized before being returned. 112 | * @param a: The starting rotation. 113 | * @param b: The ending rotation. 114 | * @return: A new quaternion. 115 | */ 116 | static inline Quaternion Lerp(Quaternion a, Quaternion b, float t); 117 | 118 | /** 119 | * Interpolates between a and b by t. This normalizes the result when 120 | * complete. 121 | * @param a: The starting rotation. 122 | * @param b: The ending rotation. 123 | * @param t: The interpolation value. 124 | * @return: A new quaternion. 125 | */ 126 | static inline Quaternion LerpUnclamped(Quaternion a, Quaternion b, 127 | float t); 128 | 129 | /** 130 | * Creates a rotation with the specified forward direction. This is the 131 | * same as calling LookRotation with (0, 1, 0) as the upwards vector. 132 | * The output is undefined for parallel vectors. 133 | * @param forward: The forward direction to look toward. 134 | * @return: A new quaternion. 135 | */ 136 | static inline Quaternion LookRotation(Vector3 forward); 137 | 138 | /** 139 | * Creates a rotation with the specified forward and upwards directions. 140 | * The output is undefined for parallel vectors. 141 | * @param forward: The forward direction to look toward. 142 | * @param upwards: The direction to treat as up. 143 | * @return: A new quaternion. 144 | */ 145 | static inline Quaternion LookRotation(Vector3 forward, Vector3 upwards); 146 | 147 | /** 148 | * Returns the norm of a quaternion. 149 | * @param rotation: The quaternion in question. 150 | * @return: A scalar value. 151 | */ 152 | static inline float Norm(Quaternion rotation); 153 | 154 | /** 155 | * Returns a quaternion with identical rotation and a norm of one. 156 | * @param rotation: The quaternion in question. 157 | * @return: A new quaternion. 158 | */ 159 | static inline Quaternion Normalized(Quaternion rotation); 160 | 161 | /** 162 | * Returns a new Quaternion created by rotating "from" towards "to" by 163 | * "maxRadiansDelta". This will not overshoot, and if a negative delta is 164 | * applied, it will rotate till completely opposite "to" and then stop. 165 | * @param from: The rotation at which to start. 166 | * @param to: The rotation at which to end. 167 | # @param maxRadiansDelta: The maximum number of radians to rotate. 168 | * @return: A new Quaternion. 169 | */ 170 | static inline Quaternion RotateTowards(Quaternion from, Quaternion to, 171 | float maxRadiansDelta); 172 | 173 | /** 174 | * Returns a new quaternion interpolated between a and b, using spherical 175 | * linear interpolation. The variable t is clamped to the range [0-1]. The 176 | * resulting quaternion will be normalized. 177 | * @param a: The starting rotation. 178 | * @param b: The ending rotation. 179 | * @param t: The interpolation value. 180 | * @return: A new quaternion. 181 | */ 182 | static inline Quaternion Slerp(Quaternion a, Quaternion b, float t); 183 | 184 | /** 185 | * Returns a new quaternion interpolated between a and b, using spherical 186 | * linear interpolation. The resulting quaternion will be normalized. 187 | * @param a: The starting rotation. 188 | * @param b: The ending rotation. 189 | * @param t: The interpolation value. 190 | * @return: A new quaternion. 191 | */ 192 | static inline Quaternion SlerpUnclamped(Quaternion a, Quaternion b, 193 | float t); 194 | 195 | /** 196 | * Outputs the angle axis representation of the provided quaternion. 197 | * @param rotation: The input quaternion. 198 | * @param angle: The output angle. 199 | * @param axis: The output axis. 200 | */ 201 | static inline void ToAngleAxis(Quaternion rotation, float &angle, 202 | Vector3 &axis); 203 | 204 | /** 205 | * Returns the Euler angle representation of a rotation. The resulting 206 | * vector contains the rotations about the z, x and y axis, in that order. 207 | * @param rotation: The quaternion to convert. 208 | * @return: A new vector. 209 | */ 210 | static inline Vector3 ToEuler(Quaternion rotation); 211 | 212 | /** 213 | * Operator overloading. 214 | */ 215 | inline struct Quaternion& operator+=(const float rhs); 216 | inline struct Quaternion& operator-=(const float rhs); 217 | inline struct Quaternion& operator*=(const float rhs); 218 | inline struct Quaternion& operator/=(const float rhs); 219 | inline struct Quaternion& operator+=(const Quaternion rhs); 220 | inline struct Quaternion& operator-=(const Quaternion rhs); 221 | inline struct Quaternion& operator*=(const Quaternion rhs); 222 | }; 223 | 224 | inline Quaternion operator-(Quaternion rhs); 225 | inline Quaternion operator+(Quaternion lhs, const float rhs); 226 | inline Quaternion operator-(Quaternion lhs, const float rhs); 227 | inline Quaternion operator*(Quaternion lhs, const float rhs); 228 | inline Quaternion operator/(Quaternion lhs, const float rhs); 229 | inline Quaternion operator+(const float lhs, Quaternion rhs); 230 | inline Quaternion operator-(const float lhs, Quaternion rhs); 231 | inline Quaternion operator*(const float lhs, Quaternion rhs); 232 | inline Quaternion operator/(const float lhs, Quaternion rhs); 233 | inline Quaternion operator+(Quaternion lhs, const Quaternion rhs); 234 | inline Quaternion operator-(Quaternion lhs, const Quaternion rhs); 235 | inline Quaternion operator*(Quaternion lhs, const Quaternion rhs); 236 | inline Vector3 operator*(Quaternion lhs, const Vector3 rhs); 237 | inline bool operator==(const Quaternion lhs, const Quaternion rhs); 238 | inline bool operator!=(const Quaternion lhs, const Quaternion rhs); 239 | 240 | 241 | 242 | /******************************************************************************* 243 | * Implementation 244 | */ 245 | 246 | Quaternion::Quaternion() : X(0), Y(0), Z(0), W(1) {} 247 | Quaternion::Quaternion(float data[]) : X(data[0]), Y(data[1]), Z(data[2]), 248 | W(data[3]) {} 249 | Quaternion::Quaternion(Vector3 vector, float scalar) : X(vector.X), 250 | Y(vector.Y), Z(vector.Z), W(scalar) {} 251 | Quaternion::Quaternion(float x, float y, float z, float w) : X(x), Y(y), 252 | Z(z), W(w) {} 253 | 254 | 255 | Quaternion Quaternion::Identity() { return Quaternion(0, 0, 0, 1); } 256 | 257 | 258 | float Quaternion::Angle(Quaternion a, Quaternion b) 259 | { 260 | float dot = Dot(a, b); 261 | return acos(fmin(fabs(dot), 1)) * 2; 262 | } 263 | 264 | Quaternion Quaternion::Conjugate(Quaternion rotation) 265 | { 266 | return Quaternion(-rotation.X, -rotation.Y, -rotation.Z, rotation.W); 267 | } 268 | 269 | float Quaternion::Dot(Quaternion lhs, Quaternion rhs) 270 | { 271 | return lhs.X * rhs.X + lhs.Y * rhs.Y + lhs.Z * rhs.Z + lhs.W * rhs.W; 272 | } 273 | 274 | Quaternion Quaternion::FromAngleAxis(float angle, Vector3 axis) 275 | { 276 | Quaternion q; 277 | float m = sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); 278 | float s = sin(angle / 2) / m; 279 | q.X = axis.X * s; 280 | q.Y = axis.Y * s; 281 | q.Z = axis.Z * s; 282 | q.W = cos(angle / 2); 283 | return q; 284 | } 285 | 286 | Quaternion Quaternion::FromEuler(Vector3 rotation) 287 | { 288 | return FromEuler(rotation.X, rotation.Y, rotation.Z); 289 | } 290 | 291 | Quaternion Quaternion::FromEuler(float x, float y, float z) 292 | { 293 | float cx = cos(x * 0.5); 294 | float cy = cos(y * 0.5); 295 | float cz = cos(z * 0.5); 296 | float sx = sin(x * 0.5); 297 | float sy = sin(y * 0.5); 298 | float sz = sin(z * 0.5); 299 | Quaternion q; 300 | q.X = cx * sy * sz + cy * cz * sx; 301 | q.Y = cx * cz * sy - cy * sx * sz; 302 | q.Z = cx * cy * sz - cz * sx * sy; 303 | q.W = sx * sy * sz + cx * cy * cz; 304 | return q; 305 | } 306 | 307 | Quaternion Quaternion::FromToRotation(Vector3 fromVector, Vector3 toVector) 308 | { 309 | float dot = Vector3::Dot(fromVector, toVector); 310 | float k = sqrt(Vector3::SqrMagnitude(fromVector) * 311 | Vector3::SqrMagnitude(toVector)); 312 | if (fabs(dot / k + 1) < 0.00001) 313 | { 314 | Vector3 ortho = Vector3::Orthogonal(fromVector); 315 | return Quaternion(Vector3::Normalized(ortho), 0); 316 | } 317 | Vector3 cross = Vector3::Cross(fromVector, toVector); 318 | return Normalized(Quaternion(cross, dot + k)); 319 | } 320 | 321 | Quaternion Quaternion::Inverse(Quaternion rotation) 322 | { 323 | float n = Norm(rotation); 324 | return Conjugate(rotation) / (n * n); 325 | } 326 | 327 | Quaternion Quaternion::Lerp(Quaternion a, Quaternion b, float t) 328 | { 329 | if (t < 0) return Normalized(a); 330 | else if (t > 1) return Normalized(b); 331 | return LerpUnclamped(a, b, t); 332 | } 333 | 334 | Quaternion Quaternion::LerpUnclamped(Quaternion a, Quaternion b, float t) 335 | { 336 | Quaternion quaternion; 337 | if (Dot(a, b) >= 0) 338 | quaternion = a * (1 - t) + b * t; 339 | else 340 | quaternion = a * (1 - t) - b * t; 341 | return Normalized(quaternion); 342 | } 343 | 344 | Quaternion Quaternion::LookRotation(Vector3 forward) 345 | { 346 | return LookRotation(forward, Vector3(0, 1, 0)); 347 | } 348 | 349 | Quaternion Quaternion::LookRotation(Vector3 forward, Vector3 upwards) 350 | { 351 | // Normalize inputs 352 | forward = Vector3::Normalized(forward); 353 | upwards = Vector3::Normalized(upwards); 354 | // Don't allow zero vectors 355 | if (Vector3::SqrMagnitude(forward) < SMALL_float || Vector3::SqrMagnitude(upwards) < SMALL_float) 356 | return Quaternion::Identity(); 357 | // Handle alignment with up direction 358 | if (1 - fabs(Vector3::Dot(forward, upwards)) < SMALL_float) 359 | return FromToRotation(Vector3::Forward(), forward); 360 | // Get orthogonal vectors 361 | Vector3 right = Vector3::Normalized(Vector3::Cross(upwards, forward)); 362 | upwards = Vector3::Cross(forward, right); 363 | // Calculate rotation 364 | Quaternion quaternion; 365 | float radicand = right.X + upwards.Y + forward.Z; 366 | if (radicand > 0) 367 | { 368 | quaternion.W = sqrt(1.0 + radicand) * 0.5; 369 | float recip = 1.0 / (4.0 * quaternion.W); 370 | quaternion.X = (upwards.Z - forward.Y) * recip; 371 | quaternion.Y = (forward.X - right.Z) * recip; 372 | quaternion.Z = (right.Y - upwards.X) * recip; 373 | } 374 | else if (right.X >= upwards.Y && right.X >= forward.Z) 375 | { 376 | quaternion.X = sqrt(1.0 + right.X - upwards.Y - forward.Z) * 0.5; 377 | float recip = 1.0 / (4.0 * quaternion.X); 378 | quaternion.W = (upwards.Z - forward.Y) * recip; 379 | quaternion.Z = (forward.X + right.Z) * recip; 380 | quaternion.Y = (right.Y + upwards.X) * recip; 381 | } 382 | else if (upwards.Y > forward.Z) 383 | { 384 | quaternion.Y = sqrt(1.0 - right.X + upwards.Y - forward.Z) * 0.5; 385 | float recip = 1.0 / (4.0 * quaternion.Y); 386 | quaternion.Z = (upwards.Z + forward.Y) * recip; 387 | quaternion.W = (forward.X - right.Z) * recip; 388 | quaternion.X = (right.Y + upwards.X) * recip; 389 | } 390 | else 391 | { 392 | quaternion.Z = sqrt(1.0 - right.X - upwards.Y + forward.Z) * 0.5; 393 | float recip = 1.0 / (4.0 * quaternion.Z); 394 | quaternion.Y = (upwards.Z + forward.Y) * recip; 395 | quaternion.X = (forward.X + right.Z) * recip; 396 | quaternion.W = (right.Y - upwards.X) * recip; 397 | } 398 | return quaternion; 399 | } 400 | 401 | float Quaternion::Norm(Quaternion rotation) 402 | { 403 | return sqrt(rotation.X * rotation.X + 404 | rotation.Y * rotation.Y + 405 | rotation.Z * rotation.Z + 406 | rotation.W * rotation.W); 407 | } 408 | 409 | Quaternion Quaternion::Normalized(Quaternion rotation) 410 | { 411 | return rotation / Norm(rotation); 412 | } 413 | 414 | Quaternion Quaternion::RotateTowards(Quaternion from, Quaternion to, 415 | float maxRadiansDelta) 416 | { 417 | float angle = Quaternion::Angle(from, to); 418 | if (angle == 0) 419 | return to; 420 | maxRadiansDelta = fmax(maxRadiansDelta, angle - M_PI); 421 | float t = fmin(1, maxRadiansDelta / angle); 422 | return Quaternion::SlerpUnclamped(from, to, t); 423 | } 424 | 425 | Quaternion Quaternion::Slerp(Quaternion a, Quaternion b, float t) 426 | { 427 | if (t < 0) return Normalized(a); 428 | else if (t > 1) return Normalized(b); 429 | return SlerpUnclamped(a, b, t); 430 | } 431 | 432 | Quaternion Quaternion::SlerpUnclamped(Quaternion a, Quaternion b, float t) 433 | { 434 | float n1; 435 | float n2; 436 | float n3 = Dot(a, b); 437 | bool flag = false; 438 | if (n3 < 0) 439 | { 440 | flag = true; 441 | n3 = -n3; 442 | } 443 | if (n3 > 0.999999) 444 | { 445 | n2 = 1 - t; 446 | n1 = flag ? -t : t; 447 | } 448 | else 449 | { 450 | float n4 = acos(n3); 451 | float n5 = 1 / sin(n4); 452 | n2 = sin((1 - t) * n4) * n5; 453 | n1 = flag ? -sin(t * n4) * n5 : sin(t * n4) * n5; 454 | } 455 | Quaternion quaternion; 456 | quaternion.X = (n2 * a.X) + (n1 * b.X); 457 | quaternion.Y = (n2 * a.Y) + (n1 * b.Y); 458 | quaternion.Z = (n2 * a.Z) + (n1 * b.Z); 459 | quaternion.W = (n2 * a.W) + (n1 * b.W); 460 | return Normalized(quaternion); 461 | } 462 | 463 | void Quaternion::ToAngleAxis(Quaternion rotation, float &angle, Vector3 &axis) 464 | { 465 | if (rotation.W > 1) 466 | rotation = Normalized(rotation); 467 | angle = 2 * acos(rotation.W); 468 | float s = sqrt(1 - rotation.W * rotation.W); 469 | if (s < 0.00001) { 470 | axis.X = 1; 471 | axis.Y = 0; 472 | axis.Z = 0; 473 | } else { 474 | axis.X = rotation.X / s; 475 | axis.Y = rotation.Y / s; 476 | axis.Z = rotation.Z / s; 477 | } 478 | } 479 | 480 | Vector3 Quaternion::ToEuler(Quaternion rotation) 481 | { 482 | float sqw = rotation.W * rotation.W; 483 | float sqx = rotation.X * rotation.X; 484 | float sqy = rotation.Y * rotation.Y; 485 | float sqz = rotation.Z * rotation.Z; 486 | // If normalized is one, otherwise is correction factor 487 | float unit = sqx + sqy + sqz + sqw; 488 | float test = rotation.X * rotation.W - rotation.Y * rotation.Z; 489 | Vector3 v; 490 | // Singularity at north pole 491 | if (test > 0.4995f * unit) 492 | { 493 | v.Y = 2 * atan2(rotation.Y, rotation.X); 494 | v.X = M_PI_2; 495 | v.Z = 0; 496 | return v; 497 | } 498 | // Singularity at south pole 499 | if (test < -0.4995f * unit) 500 | { 501 | v.Y = -2 * atan2(rotation.Y, rotation.X); 502 | v.X = -M_PI_2; 503 | v.Z = 0; 504 | return v; 505 | } 506 | // Yaw 507 | v.Y = atan2(2 * rotation.W * rotation.Y + 2 * rotation.Z * rotation.X, 508 | 1 - 2 * (rotation.X * rotation.X + rotation.Y * rotation.Y)); 509 | // Pitch 510 | v.X = asin(2 * (rotation.W * rotation.X - rotation.Y * rotation.Z)); 511 | // Roll 512 | v.Z = atan2(2 * rotation.W * rotation.Z + 2 * rotation.X * rotation.Y, 513 | 1 - 2 * (rotation.Z * rotation.Z + rotation.X * rotation.X)); 514 | return v; 515 | } 516 | 517 | struct Quaternion& Quaternion::operator+=(const float rhs) 518 | { 519 | X += rhs; 520 | Y += rhs; 521 | Z += rhs; 522 | W += rhs; 523 | return *this; 524 | } 525 | 526 | struct Quaternion& Quaternion::operator-=(const float rhs) 527 | { 528 | X -= rhs; 529 | Y -= rhs; 530 | Z -= rhs; 531 | W -= rhs; 532 | return *this; 533 | } 534 | 535 | struct Quaternion& Quaternion::operator*=(const float rhs) 536 | { 537 | X *= rhs; 538 | Y *= rhs; 539 | Z *= rhs; 540 | W *= rhs; 541 | return *this; 542 | } 543 | 544 | struct Quaternion& Quaternion::operator/=(const float rhs) 545 | { 546 | X /= rhs; 547 | Y /= rhs; 548 | Z /= rhs; 549 | W /= rhs; 550 | return *this; 551 | } 552 | 553 | struct Quaternion& Quaternion::operator+=(const Quaternion rhs) 554 | { 555 | X += rhs.X; 556 | Y += rhs.Y; 557 | Z += rhs.Z; 558 | W += rhs.W; 559 | return *this; 560 | } 561 | 562 | struct Quaternion& Quaternion::operator-=(const Quaternion rhs) 563 | { 564 | X -= rhs.X; 565 | Y -= rhs.Y; 566 | Z -= rhs.Z; 567 | W -= rhs.W; 568 | return *this; 569 | } 570 | 571 | struct Quaternion& Quaternion::operator*=(const Quaternion rhs) 572 | { 573 | Quaternion q; 574 | q.W = W * rhs.W - X * rhs.X - Y * rhs.Y - Z * rhs.Z; 575 | q.X = X * rhs.W + W * rhs.X + Y * rhs.Z - Z * rhs.Y; 576 | q.Y = W * rhs.Y - X * rhs.Z + Y * rhs.W + Z * rhs.X; 577 | q.Z = W * rhs.Z + X * rhs.Y - Y * rhs.X + Z * rhs.W; 578 | *this = q; 579 | return *this; 580 | } 581 | 582 | Quaternion operator-(Quaternion rhs) { return rhs * -1; } 583 | Quaternion operator+(Quaternion lhs, const float rhs) { return lhs += rhs; } 584 | Quaternion operator-(Quaternion lhs, const float rhs) { return lhs -= rhs; } 585 | Quaternion operator*(Quaternion lhs, const float rhs) { return lhs *= rhs; } 586 | Quaternion operator/(Quaternion lhs, const float rhs) { return lhs /= rhs; } 587 | Quaternion operator+(const float lhs, Quaternion rhs) { return rhs += lhs; } 588 | Quaternion operator-(const float lhs, Quaternion rhs) { return rhs -= lhs; } 589 | Quaternion operator*(const float lhs, Quaternion rhs) { return rhs *= lhs; } 590 | Quaternion operator/(const float lhs, Quaternion rhs) { return rhs /= lhs; } 591 | Quaternion operator+(Quaternion lhs, const Quaternion rhs) 592 | { 593 | return lhs += rhs; 594 | } 595 | Quaternion operator-(Quaternion lhs, const Quaternion rhs) 596 | { 597 | return lhs -= rhs; 598 | } 599 | Quaternion operator*(Quaternion lhs, const Quaternion rhs) 600 | { 601 | return lhs *= rhs; 602 | } 603 | 604 | Vector3 operator*(Quaternion lhs, const Vector3 rhs) 605 | { 606 | Vector3 u = Vector3(lhs.X, lhs.Y, lhs.Z); 607 | float s = lhs.W; 608 | return u * (Vector3::Dot(u, rhs) * 2) 609 | + rhs * (s * s - Vector3::Dot(u, u)) 610 | + Vector3::Cross(u, rhs) * (2.0 * s); 611 | } 612 | 613 | bool operator==(const Quaternion lhs, const Quaternion rhs) 614 | { 615 | return lhs.X == rhs.X && 616 | lhs.Y == rhs.Y && 617 | lhs.Z == rhs.Z && 618 | lhs.W == rhs.W; 619 | } 620 | 621 | bool operator!=(const Quaternion lhs, const Quaternion rhs) 622 | { 623 | return !(lhs == rhs); 624 | } 625 | } 626 | -------------------------------------------------------------------------------- /API/Class.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace IL2CPP 4 | { 5 | namespace Class 6 | { 7 | Unity::il2cppFieldInfo* GetFields(Unity::il2cppClass* m_pClass, void** m_pIterator) 8 | { 9 | return reinterpret_cast(Functions.m_ClassGetFields)(m_pClass, m_pIterator); 10 | } 11 | 12 | void FetchFields(Unity::il2cppClass* m_pClass, std::vector* m_pVector, void* m_pFieldIterator = nullptr) 13 | { 14 | m_pVector->clear(); 15 | 16 | while (1) 17 | { 18 | Unity::il2cppFieldInfo* m_pField = GetFields(m_pClass, &m_pFieldIterator); 19 | if (!m_pField) 20 | break; 21 | 22 | m_pVector->emplace_back(m_pField); 23 | } 24 | } 25 | 26 | Unity::il2cppMethodInfo* GetMethods(Unity::il2cppClass* m_pClass, void** m_pIterator) 27 | { 28 | return reinterpret_cast(Functions.m_ClassGetMethods)(m_pClass, m_pIterator); 29 | } 30 | 31 | void FetchMethods(Unity::il2cppClass* m_pClass, std::vector* m_pVector, void* m_pMethodIterator = nullptr) 32 | { 33 | m_pVector->clear(); 34 | 35 | while (1) 36 | { 37 | Unity::il2cppMethodInfo* m_pMethod = GetMethods(m_pClass, &m_pMethodIterator); 38 | if (!m_pMethod) 39 | break; 40 | 41 | m_pVector->emplace_back(m_pMethod); 42 | } 43 | } 44 | 45 | Unity::il2cppType* GetType(Unity::il2cppClass* m_pClass) 46 | { 47 | return reinterpret_cast(Functions.m_ClassGetType)(m_pClass); 48 | } 49 | 50 | Unity::il2cppObject* GetSystemType(Unity::il2cppClass* m_pClass) 51 | { 52 | return reinterpret_cast(Functions.m_TypeGetObject)(GetType(m_pClass)); 53 | } 54 | 55 | Unity::il2cppClass* GetFromName(Unity::il2cppImage* m_pImage, const char* m_pNamespace, const char* m_pName) 56 | { 57 | return reinterpret_cast(Functions.m_ClassFromName)(m_pImage, m_pNamespace, m_pName); 58 | } 59 | 60 | Unity::il2cppClass* Find(const char* m_pName) 61 | { 62 | size_t m_sAssembliesCount = 0U; 63 | Unity::il2cppAssembly** m_pAssemblies = Domain::GetAssemblies(&m_sAssembliesCount); 64 | if (!m_pAssemblies || 0U >= m_sAssembliesCount) return nullptr; 65 | 66 | const char* m_pNameSpaceEnd = strrchr(m_pName, '.'); 67 | char* m_pNameSpace = nullptr; 68 | if (m_pNameSpaceEnd) 69 | { 70 | uintptr_t m_uNamespaceSize = static_cast(m_pNameSpaceEnd - m_pName); 71 | m_pNameSpace = new char[m_uNamespaceSize + 1]; 72 | memcpy(m_pNameSpace, m_pName, m_uNamespaceSize); 73 | m_pNameSpace[m_uNamespaceSize] = '\0'; 74 | 75 | m_pName = m_pNameSpaceEnd + 1; 76 | } 77 | else 78 | { 79 | m_pNameSpace = new char[2]; 80 | memset(m_pNameSpace, 0, 2); 81 | } 82 | 83 | 84 | Unity::il2cppClass* m_pClassReturn = nullptr; 85 | for (size_t i = 0U; m_sAssembliesCount > i; ++i) 86 | { 87 | Unity::il2cppAssembly* m_pAssembly = m_pAssemblies[i]; 88 | if (!m_pAssembly || !m_pAssembly->m_pImage) continue; 89 | 90 | m_pClassReturn = GetFromName(m_pAssembly->m_pImage, m_pNameSpace, m_pName); 91 | if (m_pClassReturn) break; 92 | } 93 | 94 | delete[] m_pNameSpace; 95 | return m_pClassReturn; 96 | } 97 | 98 | Unity::il2cppObject* GetSystemType(const char* m_pClassName) 99 | { 100 | Unity::il2cppClass* m_pClass = Find(m_pClassName); 101 | if (!m_pClass) 102 | return nullptr; 103 | 104 | return GetSystemType(m_pClass); 105 | } 106 | 107 | void FetchClasses(std::vector* m_pVector, const char* m_pModuleName, const char* m_pNamespace) 108 | { 109 | m_pVector->clear(); 110 | 111 | size_t m_sAssembliesCount = 0U; 112 | Unity::il2cppAssembly** m_pAssemblies = Domain::GetAssemblies(&m_sAssembliesCount); 113 | if (!m_pAssemblies || 0U >= m_sAssembliesCount) return; 114 | 115 | Unity::il2cppImage* m_pImage = nullptr; 116 | for (size_t i = 0U; m_sAssembliesCount > i; ++i) 117 | { 118 | Unity::il2cppAssembly* m_pAssembly = m_pAssemblies[i]; 119 | if (!m_pAssembly || !m_pAssembly->m_pImage || strcmp(m_pAssembly->m_pImage->m_pNameNoExt, m_pModuleName) != 0) 120 | continue; 121 | 122 | m_pImage = m_pAssembly->m_pImage; 123 | break; 124 | } 125 | 126 | if (m_pImage) 127 | { 128 | size_t m_sClassesCount = reinterpret_cast(Functions.m_ImageGetClassCount)(m_pImage); 129 | for (size_t i = 0U; m_sClassesCount > i; ++i) 130 | { 131 | Unity::il2cppClass* m_pClass = reinterpret_cast(Functions.m_ImageGetClass)(m_pImage, i); 132 | if (m_pNamespace) 133 | { 134 | if (m_pNamespace[0] == '\0') 135 | { 136 | if (m_pClass->m_pNamespace[0] != '\0') 137 | continue; 138 | } 139 | else if (strcmp(m_pClass->m_pNamespace, m_pNamespace) != 0) 140 | continue; 141 | } 142 | 143 | m_pVector->emplace_back(m_pClass); 144 | } 145 | } 146 | } 147 | 148 | namespace Utils 149 | { 150 | int GetFieldOffset(Unity::il2cppClass* m_pClass, const char* m_pName) 151 | { 152 | void* m_pFieldIterator = nullptr; 153 | while (1) 154 | { 155 | Unity::il2cppFieldInfo* m_pField = GetFields(m_pClass, &m_pFieldIterator); 156 | if (!m_pField) 157 | break; 158 | 159 | if (strcmp(m_pField->m_pName, m_pName) == 0) 160 | return m_pField->m_iOffset; 161 | } 162 | 163 | return -1; 164 | } 165 | 166 | int GetFieldOffset(const char* m_pClassName, const char* m_pName) 167 | { 168 | Unity::il2cppClass* m_pClass = Find(m_pClassName); 169 | if (m_pClass) 170 | return GetFieldOffset(m_pClass, m_pName); 171 | 172 | return -1; 173 | } 174 | 175 | void SetStaticField(Unity::il2cppClass* m_pClass, const char* m_pMemberName, void* m_pValue) { 176 | Unity::il2cppFieldInfo* m_pField = reinterpret_cast(Functions.m_ClassGetFieldFromName)(m_pClass, m_pMemberName); 177 | if (m_pField) 178 | reinterpret_cast(Functions.m_FieldStaticSetValue)(m_pField, m_pValue); 179 | } 180 | 181 | void SetStaticField(const char* m_pClassName, const char* m_pMemberName, void* m_pValue) { 182 | Unity::il2cppClass* m_pClass = Find(m_pClassName); 183 | if (m_pClass) 184 | SetStaticField(m_pClass, m_pMemberName, m_pValue); 185 | } 186 | 187 | void* GetStaticField(Unity::il2cppClass* m_pClass, const char* m_pMemberName) { 188 | Unity::il2cppFieldInfo* m_pField = reinterpret_cast(Functions.m_ClassGetFieldFromName)(m_pClass, m_pMemberName); 189 | void* m_pValue = nullptr; 190 | if (m_pField) 191 | reinterpret_cast(Functions.m_FieldStaticGetValue)(m_pField, &m_pValue); 192 | 193 | return m_pValue; 194 | } 195 | 196 | void* GetStaticField(const char* m_pClassName, const char* m_pMemberName) 197 | { 198 | Unity::il2cppClass* m_pClass = Find(m_pClassName); 199 | if (m_pClass) 200 | return GetStaticField(m_pClass, m_pMemberName); 201 | 202 | return nullptr; 203 | } 204 | 205 | void* GetMethodPointer(Unity::il2cppClass* m_pClass, const char* m_pMethodName, int m_iArgs = -1) 206 | { 207 | Unity::il2cppMethodInfo* pMethod = reinterpret_cast(Functions.m_ClassGetMethodFromName)(m_pClass, m_pMethodName, m_iArgs); 208 | if (!pMethod) return nullptr; 209 | 210 | return pMethod->m_pMethodPointer; 211 | } 212 | 213 | 214 | void* GetMethodPointer(const char* m_pClassName, const char* m_pMethodName, int m_iArgs = -1) 215 | { 216 | Unity::il2cppClass* m_pClass = Find(m_pClassName); 217 | if (m_pClass) 218 | return GetMethodPointer(m_pClass, m_pMethodName, m_iArgs); 219 | 220 | return nullptr; 221 | } 222 | 223 | uint64_t GetMethodPointerRVA(Unity::il2cppClass* m_pClass, const char* m_pMethodName, int m_iArgs = -1) { 224 | void* methodPointer = GetMethodPointer(m_pClass, m_pMethodName, m_iArgs); 225 | if (!methodPointer) 226 | return 0; 227 | 228 | MemoryInfo info = getBaseAddress(BINARY_NAME); 229 | uint64_t rvaOffset = reinterpret_cast(methodPointer) - info.address; 230 | return rvaOffset; 231 | } 232 | 233 | uint64_t GetMethodPointerRVA(const char* m_pClassName, const char* m_pMethodName, int m_iArgs = -1) { 234 | Unity::il2cppClass* m_pClass = Find(m_pClassName); 235 | if (m_pClass) 236 | return GetMethodPointerRVA(m_pClass, m_pMethodName, m_iArgs); 237 | 238 | return 0; 239 | } 240 | 241 | 242 | const char* MethodGetParamName(Unity::il2cppMethodInfo* m_pMethodInfo, uint32_t index) 243 | { 244 | if (index >= m_pMethodInfo->m_uArgsCount) 245 | return nullptr; 246 | 247 | return reinterpret_cast(Functions.m_MethodGetParamName)(m_pMethodInfo, index); 248 | } 249 | 250 | Unity::il2cppType* GetMethodParamType(Unity::il2cppMethodInfo* m_pMethodInfo, uint32_t index) { 251 | if (index >= m_pMethodInfo->m_uArgsCount) 252 | return nullptr; 253 | 254 | return reinterpret_cast(Functions.m_MethodGetParam)(m_pMethodInfo, index); 255 | } 256 | 257 | Unity::il2cppClass* ClassFromType(Unity::il2cppType * type) 258 | { 259 | return reinterpret_cast(Functions.m_ClassFromIl2cppType)(type); 260 | } 261 | 262 | void* GetMethodPointer(const char* m_pClassName, const char* m_pMethodName, std::initializer_list m_vNames) 263 | { 264 | Unity::il2cppClass* m_pClass = Find(m_pClassName); 265 | if (!m_pClass) 266 | return nullptr; 267 | 268 | int m_iNamesCount = static_cast(m_vNames.size()); 269 | const char** m_pNames = const_cast(m_vNames.begin()); 270 | 271 | void* m_pMethodIterator = nullptr; 272 | while (1) 273 | { 274 | Unity::il2cppMethodInfo* m_pMethod = GetMethods(m_pClass, &m_pMethodIterator); 275 | if (!m_pMethod) 276 | break; 277 | 278 | if (strcmp(m_pMethod->m_pName, m_pMethodName) != 0) 279 | continue; 280 | 281 | #ifdef UNITY_VERSION_2022_3_8F1 282 | Unity::il2cppType** m_pCurrentParameterTypes = m_pMethod->m_pParameters; 283 | 284 | for (size_t i = 0; i < m_pMethod->m_uArgsCount; ++i) 285 | { 286 | Unity::il2cppType* m_pCurrentParameterType = m_pCurrentParameterTypes[i]; 287 | Unity::il2cppClass* m_pClass = ClassFromType(m_pCurrentParameterType); 288 | 289 | if (strcmp(m_pClass->m_pName, m_pNames[i]) != 0) 290 | break; 291 | 292 | if ((i + 1) == m_iNamesCount) 293 | return m_pMethod->m_pMethodPointer; 294 | } 295 | #else 296 | Unity::il2cppParameterInfo* m_pCurrentParameters = m_pMethod->m_pParameters; 297 | for (int i = 0; m_iNamesCount > i; ++i) 298 | { 299 | if (strcmp(m_pCurrentParameters->m_pName, m_pNames[i]) != 0) 300 | break; 301 | 302 | m_pCurrentParameters++; // m_pCurrentParameters += sizeof(Unity::il2cppParameterInfo); 303 | if ((i + 1) == m_iNamesCount) 304 | return m_pMethod->m_pMethodPointer; 305 | } 306 | #endif 307 | } 308 | return nullptr; 309 | } 310 | 311 | Unity::il2cppClass* FilterClass(std::vector* m_pClasses, std::initializer_list m_vNames, int m_iFoundCount = -1) 312 | { 313 | int m_iNamesCount = static_cast(m_vNames.size()); 314 | const char** m_pNames = const_cast(m_vNames.begin()); 315 | 316 | if (0 >= m_iFoundCount || m_iFoundCount > m_iNamesCount) 317 | m_iFoundCount = m_iNamesCount; 318 | 319 | Unity::il2cppClass* m_pReturn = nullptr; 320 | for (size_t c = 0; m_pClasses->size() > c; ++c) 321 | { 322 | int m_iFoundCountNow = 0; 323 | 324 | Unity::il2cppClass* m_pClass = m_pClasses->operator[](c); 325 | if (!m_pClass) 326 | continue; 327 | 328 | for (int i = 0; m_iNamesCount > i; ++i) 329 | { 330 | const char* m_pNameToFind = m_pNames[i]; 331 | 332 | bool m_bFoundInClass = false; 333 | if (m_pNameToFind[0] == '~') // Field 334 | m_bFoundInClass = GetFieldOffset(m_pClass, &m_pNameToFind[1]) >= 0; 335 | else if (m_pNameToFind[0] == '-') // Method 336 | m_bFoundInClass = GetMethodPointer(m_pClass, &m_pNameToFind[1]) != nullptr; 337 | else // Both 338 | { 339 | m_bFoundInClass = GetFieldOffset(m_pClass, m_pNameToFind) >= 0; 340 | if (!m_bFoundInClass) 341 | m_bFoundInClass = GetMethodPointer(m_pClass, m_pNameToFind) != nullptr; 342 | } 343 | 344 | if (m_bFoundInClass) 345 | ++m_iFoundCountNow; 346 | } 347 | 348 | if (m_iFoundCount == m_iFoundCountNow) 349 | { 350 | m_pReturn = m_pClass; 351 | break; 352 | } 353 | } 354 | 355 | return m_pReturn; 356 | } 357 | 358 | void* FilterClassToMethodPointer(std::vector* m_pClasses, const char* m_pMethodName, int m_iArgs = -1) 359 | { 360 | void* m_pMethodPointer = nullptr; 361 | for (size_t c = 0; m_pClasses->size() > c; ++c) 362 | { 363 | Unity::il2cppClass* m_pClass = m_pClasses->operator[](c); 364 | if (!m_pClass) 365 | continue; 366 | 367 | m_pMethodPointer = GetMethodPointer(m_pClass, m_pMethodName, m_iArgs); 368 | if (m_pMethodPointer) 369 | break; 370 | } 371 | 372 | return m_pMethodPointer; 373 | } 374 | } 375 | } 376 | 377 | enum class m_eClassPropType : int 378 | { 379 | Unknown = 0, 380 | Field, // Member of class that can be accessed directly by RVA 381 | Property, // Member of class that can be accessed by calling function 382 | Method, // Function of class 383 | }; 384 | 385 | // Main Class 386 | class CClass 387 | { 388 | public: 389 | Unity::il2cppObject m_Object; 390 | void* m_CachedPtr = nullptr; 391 | 392 | // Wrappers for namespace, ah... 393 | Unity::il2cppFieldInfo* GetFields(void** m_pIterator) 394 | { 395 | return Class::GetFields(m_Object.m_pClass, m_pIterator); 396 | } 397 | 398 | void FetchFields(std::vector* m_pVector, void* m_pFieldIterator = nullptr) 399 | { 400 | Class::FetchFields(m_Object.m_pClass, m_pVector, m_pFieldIterator); 401 | } 402 | 403 | Unity::il2cppMethodInfo* GetMethods(void** m_pIterator) 404 | { 405 | return Class::GetMethods(m_Object.m_pClass, m_pIterator); 406 | } 407 | 408 | void FetchMethods(std::vector* m_pVector, void* m_pMethodIterator = nullptr) 409 | { 410 | Class::FetchMethods(m_Object.m_pClass, m_pVector, m_pMethodIterator); 411 | } 412 | 413 | void* GetMethodPointer(const char* m_pMethodName, int m_iArgs = -1) 414 | { 415 | return Class::Utils::GetMethodPointer(m_Object.m_pClass, m_pMethodName, m_iArgs); 416 | } 417 | 418 | m_eClassPropType GetPropType(const char* m_pPropType) 419 | { 420 | Unity::il2cppFieldInfo* pField = reinterpret_cast(Functions.m_ClassGetFieldFromName)(m_Object.m_pClass, m_pPropType); 421 | if (pField) 422 | return m_eClassPropType::Field; 423 | 424 | Unity::il2cppPropertyInfo* pProperty = reinterpret_cast(Functions.m_ClassGetPropertyFromName)(m_Object.m_pClass, m_pPropType); 425 | if (pProperty) 426 | return m_eClassPropType::Property; 427 | 428 | Unity::il2cppMethodInfo* pMethod = reinterpret_cast(Functions.m_ClassGetMethodFromName)(m_Object.m_pClass, m_pPropType, -1); 429 | if (pMethod) 430 | return m_eClassPropType::Method; 431 | 432 | return m_eClassPropType::Unknown; 433 | } 434 | 435 | // Call Method 436 | template 437 | TReturn CallMethod(void* m_pMethod, TArgs... tArgs) { return reinterpret_cast(m_pMethod)(this, tArgs...); } 438 | 439 | template 440 | TReturn CallMethod(const char* m_pMethodName, TArgs... tArgs) { return CallMethod(GetMethodPointer(m_pMethodName), tArgs...); } 441 | 442 | template 443 | TReturn CallMethodSafe(void* m_pMethod, TArgs... tArgs) 444 | { 445 | if (!m_pMethod) 446 | { 447 | 448 | TReturn m_tDefault = {}; // void goes like illegal use of type. (use void* and fuck them) 449 | return m_tDefault; 450 | } 451 | 452 | return CallMethod(m_pMethod, tArgs...); 453 | } 454 | 455 | template 456 | TReturn CallMethodSafe(const char* m_pMethodName, TArgs... tArgs) { return CallMethodSafe(GetMethodPointer(m_pMethodName), tArgs...); } 457 | 458 | // Properties/Fields 459 | 460 | template 461 | T GetPropertyValue(const char* m_pPropertyName) 462 | { 463 | Unity::il2cppPropertyInfo* pProperty = reinterpret_cast(Functions.m_ClassGetPropertyFromName)(m_Object.m_pClass, m_pPropertyName); 464 | if (pProperty && pProperty->m_pGet) 465 | return reinterpret_cast(pProperty->m_pGet->m_pMethodPointer)(this); 466 | 467 | T tDefault = {}; 468 | return tDefault; 469 | } 470 | 471 | template 472 | void SetPropertyValue(const char* m_pPropertyName, T m_tValue) 473 | { 474 | Unity::il2cppPropertyInfo* pProperty = reinterpret_cast(Functions.m_ClassGetPropertyFromName)(m_Object.m_pClass, m_pPropertyName); 475 | if (pProperty && pProperty->m_pSet) 476 | return reinterpret_cast(pProperty->m_pSet->m_pMethodPointer)(this, m_tValue); 477 | } 478 | 479 | template 480 | __inline T GetMemberValue(int m_iOffset) 481 | { 482 | return *reinterpret_cast(reinterpret_cast(this) + m_iOffset); 483 | } 484 | 485 | template 486 | __inline void SetMemberValue(int m_iOffset, T m_tValue) 487 | { 488 | *reinterpret_cast(reinterpret_cast(this) + m_iOffset) = m_tValue; 489 | } 490 | 491 | template 492 | __inline T GetMemberValue(Unity::il2cppFieldInfo* m_pField) 493 | { 494 | if (!m_pField || 0 > m_pField->m_iOffset) 495 | { 496 | T m_tDefault = {}; 497 | return m_tDefault; 498 | } 499 | 500 | return GetMemberValue(m_pField->m_iOffset); 501 | } 502 | 503 | template 504 | __inline void SetMemberValue(Unity::il2cppFieldInfo* m_pField, T m_tValue) 505 | { 506 | if (!m_pField || 0 > m_pField->m_iOffset) 507 | return; 508 | 509 | SetMemberValue(m_pField->m_iOffset, m_tValue); 510 | } 511 | 512 | template 513 | T GetMemberValue(const char* m_pMemberName) 514 | { 515 | Unity::il2cppFieldInfo* pField = reinterpret_cast(Functions.m_ClassGetFieldFromName)(m_Object.m_pClass, m_pMemberName); 516 | if (pField) 517 | { 518 | if (pField->m_iOffset >= 0) return *reinterpret_cast(reinterpret_cast(this) + pField->m_iOffset); 519 | } 520 | else 521 | return GetPropertyValue(m_pMemberName); 522 | 523 | T tDefault = {}; 524 | return tDefault; 525 | } 526 | 527 | template 528 | void SetMemberValue(const char* m_pMemberName, T m_tValue) 529 | { 530 | Unity::il2cppFieldInfo* pField = reinterpret_cast(Functions.m_ClassGetFieldFromName)(m_Object.m_pClass, m_pMemberName); 531 | if (pField) 532 | { 533 | if (pField->m_iOffset >= 0) *reinterpret_cast(reinterpret_cast(this) + pField->m_iOffset) = m_tValue; 534 | return; 535 | } 536 | 537 | SetPropertyValue(m_pMemberName, m_tValue); 538 | } 539 | 540 | template 541 | __inline T GetObscuredViaOffset(int m_iOffset) 542 | { 543 | if (m_iOffset >= 0) 544 | { 545 | switch (sizeof(T)) 546 | { 547 | case sizeof(double) : 548 | { 549 | long long m_lKey = *reinterpret_cast(reinterpret_cast(this) + m_iOffset); 550 | long long m_lValue = *reinterpret_cast(reinterpret_cast(this) + m_iOffset + sizeof(m_lKey)); 551 | 552 | m_lValue ^= m_lKey; 553 | return *reinterpret_cast(&m_lValue); 554 | } 555 | break; 556 | case sizeof(int) : 557 | { 558 | int m_iKey = *reinterpret_cast(reinterpret_cast(this) + m_iOffset); 559 | int m_iValue = *reinterpret_cast(reinterpret_cast(this) + m_iOffset + sizeof(m_iKey)); 560 | 561 | m_iValue ^= m_iKey; 562 | return *reinterpret_cast(&m_iValue); 563 | } 564 | break; 565 | case sizeof(bool) : 566 | { 567 | unsigned char m_uKey = *reinterpret_cast(reinterpret_cast(this) + m_iOffset); 568 | int m_iValue = *reinterpret_cast(reinterpret_cast(this) + m_iOffset + sizeof(m_uKey)); 569 | 570 | m_iValue ^= m_uKey; 571 | return *reinterpret_cast(&m_iValue); 572 | } 573 | break; 574 | } 575 | } 576 | 577 | T m_tDefault = { 0 }; 578 | return m_tDefault; 579 | } 580 | 581 | template 582 | T GetObscuredValue(const char* m_pMemberName) 583 | { 584 | Unity::il2cppFieldInfo* m_pField = reinterpret_cast(Functions.m_ClassGetFieldFromName)(m_Object.m_pClass, m_pMemberName); 585 | return GetObscuredViaOffset(m_pField ? m_pField->m_iOffset : -1); 586 | } 587 | 588 | template 589 | __inline void SetObscuredViaOffset(int m_iOffset, T m_tValue) 590 | { 591 | if (0 > m_iOffset) 592 | return; 593 | 594 | switch (sizeof(T)) 595 | { 596 | case sizeof(double) : 597 | { 598 | long long m_lKey = *reinterpret_cast(reinterpret_cast(this) + m_iOffset); 599 | long long* m_pValue = reinterpret_cast(reinterpret_cast(this) + m_iOffset + sizeof(m_lKey)); 600 | 601 | *m_pValue = *reinterpret_cast(&m_tValue) ^ m_lKey; 602 | } 603 | break; 604 | case sizeof(int) : 605 | { 606 | int m_iKey = *reinterpret_cast(reinterpret_cast(this) + m_iOffset); 607 | int* m_pValue = reinterpret_cast(reinterpret_cast(this) + m_iOffset + sizeof(m_iKey)); 608 | 609 | *m_pValue = *reinterpret_cast(&m_tValue) ^ m_iKey; 610 | } 611 | break; 612 | case sizeof(bool) : 613 | { 614 | unsigned char m_uKey = *reinterpret_cast(reinterpret_cast(this) + m_iOffset); 615 | int* m_pValue = reinterpret_cast(reinterpret_cast(this) + m_iOffset + sizeof(m_uKey)); 616 | 617 | *m_pValue = *reinterpret_cast(&m_tValue) ^ m_uKey; 618 | } 619 | break; 620 | } 621 | } 622 | 623 | template 624 | void SetObscuredValue(const char* m_pMemberName, T m_tValue) 625 | { 626 | Unity::il2cppFieldInfo* m_pField = reinterpret_cast(Functions.m_ClassGetFieldFromName)(m_Object.m_pClass, m_pMemberName); 627 | if (!m_pField) 628 | return; 629 | 630 | SetObscuredViaOffset(m_pField->m_iOffset, m_tValue); 631 | } 632 | }; 633 | } --------------------------------------------------------------------------------