gkms-local/app/src/main/cpp/deps/UnityResolve/UnityResolve.hpp

2672 lines
89 KiB
C++

/*
* Update: 2024-3-2 22:11
* Source: https://github.com/issuimo/UnityResolve.hpp
* Author: github@issuimo
*/
#ifndef UNITYRESOLVE_HPP
#define UNITYRESOLVE_HPP
#define WINDOWS_MODE 0 // 如果需要请改为 1 | 1 if you need
#define ANDROID_MODE 1
#define LINUX_MODE 0
/* Never
* #define MAC_MODE 0
* #define IOS_MODE 0
*/
#if WINDOWS_MODE || LINUX_MODE
#include <format>
#endif
#include <codecvt>
#include <fstream>
#include <iostream>
#include <mutex>
//#include <ranges>
#include <regex>
#include <string>
#include <unordered_map>
#include <vector>
#if WINDOWS_MODE
#include <windows.h>
#undef GetObject
#endif
#if WINDOWS_MODE
#ifdef _WIN64
#define UNITY_CALLING_CONVENTION __fastcall
#elif _WIN32
#define UNITY_CALLING_CONVENTION __cdecl
#endif
#elif ANDROID_MODE || LINUX_MODE
#include <locale>
// #include <dlfcn.h>
#define UNITY_CALLING_CONVENTION
#endif
#include "xdl.h"
#include "../../GakumasLocalify/Log.h"
#include "../../GakumasLocalify/Misc.hpp"
class UnityResolveProgress final {
public:
struct Progress {
long current = 0;
long total = 1;
};
static bool startInit;
static Progress assembliesProgress;
static Progress classProgress;
};
class UnityResolve final {
public:
struct Assembly;
struct Type;
struct Class;
struct Field;
struct Method;
class UnityType;
enum class Mode : char {
Il2Cpp,
Mono,
};
struct Assembly final {
void* address;
std::string name;
std::string file;
std::vector<Class*> classes;
[[nodiscard]] auto Get(const std::string& strClass, const std::string& strNamespace = "*", const std::string& strParent = "*") const -> Class* {
if (!this) return nullptr;
/*
if (lazyInit_ && classes.empty()) {
const auto image = Invoke<void*>("il2cpp_assembly_get_image", address);
ForeachClass(const_cast<Assembly *>(this), image);
}*/
for (const auto pClass : classes) if (strClass == pClass->name && (strNamespace == "*" || pClass->namespaze == strNamespace) && (strParent == "*" || pClass->parent == strParent)) return pClass;
if (lazyInit_) {
return FillClass_Il2ccpp(const_cast<Assembly *>(this), strNamespace.c_str(), strClass.c_str());
}
return nullptr;
}
};
struct Type final {
void* address;
std::string name;
int size;
// UnityType::CsType*
[[nodiscard]] auto GetCSType() const -> void* {
if (mode_ == Mode::Il2Cpp) return Invoke<void*>("il2cpp_type_get_object", address);
return Invoke<void*>("mono_type_get_object", pDomain, address);
}
};
struct Class final {
void* address;
std::string name;
std::string parent;
std::string namespaze;
std::vector<Field*> fields;
std::vector<Method*> methods;
void* objType;
template <typename RType>
auto Get(const std::string& name, const std::vector<std::string>& args = {}) -> RType* {
if (!this) return nullptr;
if constexpr (std::is_same_v<RType, Field>) for (auto pField : fields) if (pField->name == name) return static_cast<RType*>(pField);
if constexpr (std::is_same_v<RType, std::int32_t>) for (const auto pField : fields) if (pField->name == name) return reinterpret_cast<RType*>(pField->offset);
if constexpr (std::is_same_v<RType, Method>) {
for (auto pMethod : methods) {
if (pMethod->name == name) {
if (pMethod->args.empty() && args.empty()) return static_cast<RType*>(pMethod);
if (pMethod->args.size() == args.size()) {
size_t index{ 0 };
for (size_t i{ 0 }; const auto & typeName : args) if (typeName == "*" || typeName.empty() ? true : pMethod->args[i++]->pType->name == typeName) index++;
if (index == pMethod->args.size()) return static_cast<RType*>(pMethod);
}
}
}
for (auto pMethod : methods) if (pMethod->name == name) return static_cast<RType*>(pMethod);
}
return nullptr;
}
template <typename RType>
auto GetValue(void* obj, const std::string& name) -> RType { return *reinterpret_cast<RType*>(reinterpret_cast<uintptr_t>(obj) + Get<Field>(name)->offset); }
template <typename RType>
auto SetValue(void* obj, const std::string& name, RType value) -> void { return *reinterpret_cast<RType*>(reinterpret_cast<uintptr_t>(obj) + Get<Field>(name)->offset) = value; }
// UnityType::CsType*
[[nodiscard]] auto GetType() -> void* {
if (objType) return objType;
if (mode_ == Mode::Il2Cpp) {
const auto pUType = Invoke<void*, void*>("il2cpp_class_get_type", address);
objType = Invoke<void*>("il2cpp_type_get_object", pUType);
return objType;
}
const auto pUType = Invoke<void*, void*>("mono_class_get_type", address);
objType = Invoke<void*>("mono_type_get_object", pDomain, pUType);
return objType;
}
/**
* \brief 获取类所有实例
* \tparam T 返回数组类型
* \param type 类
* \return 返回实例指针数组
*/
template <typename T>
auto FindObjectsByType() -> std::vector<T> {
static Method* pMethod;
if (!pMethod) pMethod = UnityResolve::Get("UnityEngine.CoreModule.dll")->Get("Object")->Get<Method>(mode_ == Mode::Il2Cpp ? "FindObjectsOfType" : "FindObjectsOfTypeAll", { "System.Type" });
if (!objType) objType = this->GetType();
if (pMethod && objType) if (auto array = pMethod->Invoke<UnityType::Array<T>*>(objType)) return array->ToVector();
return std::vector<T>(0);
}
template <typename T>
auto New() -> T* {
if (mode_ == Mode::Il2Cpp) return Invoke<T*, void*>("il2cpp_object_new", address);
return Invoke<T*, void*, void*>("mono_object_new", pDomain, address);
}
};
struct Field final {
void* address;
std::string name;
Type* type;
Class* klass;
std::int32_t offset; // If offset is -1, then it's thread static
bool static_field;
void* vTable;
template <typename T>
auto SetValue(T* value) const -> void {
if (!static_field) return;
if (mode_ == Mode::Il2Cpp) return Invoke<void, void*, T*>("il2cpp_field_static_set_value", address, value);
}
template <typename T>
auto GetValue(T* value) const -> void {
if (!static_field) return;
if (mode_ == Mode::Il2Cpp) return Invoke<void, void*, T*>("il2cpp_field_static_get_value", address, value);
}
};
struct Method final {
void* address;
std::string name;
Class* klass;
Type* return_type;
std::int32_t flags;
bool static_function;
void* function;
struct Arg {
std::string name;
Type* pType;
};
std::vector<Arg*> args;
private:
bool badPtr{ false };
public:
template <typename Return, typename... Args>
auto Invoke(Args... args) -> Return {
if (!this) return Return();
Compile();
#if WINDOWS_MODE
try {
if (!badPtr) badPtr = !IsBadCodePtr(reinterpret_cast<FARPROC>(function));
if (function && badPtr) return reinterpret_cast<Return(UNITY_CALLING_CONVENTION*)(Args...)>(function)(args...);
} catch (...) { std::cout << name << " Invoke Error\n"; }
#else
try {
if (function) return reinterpret_cast<Return(UNITY_CALLING_CONVENTION*)(Args...)>(function)(args...);
} catch (...) { std::cout << name << " Invoke Error\n"; }
#endif
return Return();
}
auto Compile() -> void {
if (!this) return;
if (address && !function && mode_ == Mode::Mono) function = UnityResolve::Invoke<void*>("mono_compile_method", address);
}
template <typename Return, typename Obj, typename... Args>
auto RuntimeInvoke(Obj* obj, Args... args) -> Return {
if (!this) return Return();
void* exc{};
void* argArray[sizeof...(Args) + 1];
if (sizeof...(Args) > 0) {
size_t index = 0;
((argArray[index++] = static_cast<void*>(&args)), ...);
}
if (mode_ == Mode::Il2Cpp) {
if constexpr (std::is_void_v<Return>) {
UnityResolve::Invoke<void*>("il2cpp_runtime_invoke", address, obj, argArray, exc);
return;
}
else return *static_cast<Return*>(UnityResolve::Invoke<void*>("il2cpp_runtime_invoke", address, obj, argArray, exc));
}
if constexpr (std::is_void_v<Return>) {
UnityResolve::Invoke<void*>("mono_runtime_invoke", address, obj, argArray, exc);
return;
}
else return *static_cast<Return*>(UnityResolve::Invoke<void*>("mono_runtime_invoke", address, obj, argArray, exc));
return Return();
}
template <typename Return, typename... Args>
using MethodPointer = Return(UNITY_CALLING_CONVENTION*)(Args...);
template <typename Return, typename... Args>
auto Cast() -> MethodPointer<Return, Args...> {
if (!this) return nullptr;
Compile();
if (function) return reinterpret_cast<MethodPointer<Return, Args...>>(function);
return nullptr;
}
};
static auto ThreadAttach() -> void {
if (mode_ == Mode::Il2Cpp) Invoke<void*>("il2cpp_thread_attach", pDomain);
else {
Invoke<void*>("mono_thread_attach", pDomain);
Invoke<void*>("mono_jit_thread_attach", pDomain);
}
}
static auto ThreadDetach() -> void {
if (mode_ == Mode::Il2Cpp) Invoke<void*>("il2cpp_thread_detach", pDomain);
else {
Invoke<void*>("mono_thread_detach", pDomain);
Invoke<void*>("mono_jit_thread_detach", pDomain);
}
}
static auto Init(void* hmodule, const Mode mode = Mode::Mono, const bool lazyInit = false) -> void {
mode_ = mode;
hmodule_ = hmodule;
lazyInit_ = lazyInit;
if (mode_ == Mode::Il2Cpp) {
if (!lazyInit) UnityResolveProgress::startInit = true;
pDomain = Invoke<void*>("il2cpp_domain_get");
Invoke<void*>("il2cpp_thread_attach", pDomain);
ForeachAssembly();
if (!lazyInit) UnityResolveProgress::startInit = false;
}
else {
pDomain = Invoke<void*>("mono_get_root_domain");
Invoke<void*>("mono_thread_attach", pDomain);
Invoke<void*>("mono_jit_thread_attach", pDomain);
ForeachAssembly();
if (Get("UnityEngine.dll") && (!Get("UnityEngine.CoreModule.dll") || !Get("UnityEngine.PhysicsModule.dll"))) {
// 兼容某些游戏 (如生死狙击2)
for (const std::vector<std::string> names = { "UnityEngine.CoreModule.dll", "UnityEngine.PhysicsModule.dll" }; const auto name : names) {
const auto ass = Get("UnityEngine.dll");
const auto assembly = new Assembly{ .address = ass->address, .name = name, .file = ass->file, .classes = ass->classes };
UnityResolve::assembly.push_back(assembly);
}
}
}
}
#if WINDOWS_MODE || LINUX_MODE /*__cplusplus >= 202002L*/
static auto DumpToFile(const std::string& path) -> void {
std::ofstream io(path + "dump.cs", std::fstream::out);
if (!io) return;
for (const auto& pAssembly : assembly) {
for (const auto& pClass : pAssembly->classes) {
io << std::format("\tnamespace: {}", pClass->namespaze.empty() ? "" : pClass->namespaze);
io << "\n";
io << std::format("\tAssembly: {}\n", pAssembly->name.empty() ? "" : pAssembly->name);
io << std::format("\tAssemblyFile: {} \n", pAssembly->file.empty() ? "" : pAssembly->file);
io << std::format("\tclass {}{} ", pClass->name, pClass->parent.empty() ? "" : " : " + pClass->parent);
io << "{\n\n";
for (const auto& pField : pClass->fields) io << std::format("\t\t{:+#06X} | {}{} {};\n", pField->offset, pField->static_field ? "static " : "", pField->type->name, pField->name);
io << "\n";
for (const auto& pMethod : pClass->methods) {
io << std::format("\t\t[Flags: {:032b}] [ParamsCount: {:04d}] |RVA: {:+#010X}|\n", pMethod->flags, pMethod->args.size(), reinterpret_cast<std::uint64_t>(pMethod->function) - reinterpret_cast<std::uint64_t>(hmodule_));
io << std::format("\t\t{}{} {}(", pMethod->static_function ? "static " : "", pMethod->return_type->name, pMethod->name);
std::string params{};
for (const auto& pArg : pMethod->args) params += std::format("{} {}, ", pArg->pType->name, pArg->name);
if (!params.empty()) {
params.pop_back();
params.pop_back();
}
io << (params.empty() ? "" : params) << ");\n\n";
}
io << "\t}\n\n";
}
}
io << '\n';
io.close();
std::ofstream io2(path + "struct.hpp", std::fstream::out);
if (!io2) return;
for (const auto& pAssembly : assembly) {
for (const auto& pClass : pAssembly->classes) {
io2 << std::format("\tnamespace: {}", pClass->namespaze.empty() ? "" : pClass->namespaze);
io2 << "\n";
io2 << std::format("\tAssembly: {}\n", pAssembly->name.empty() ? "" : pAssembly->name);
io2 << std::format("\tAssemblyFile: {} \n", pAssembly->file.empty() ? "" : pAssembly->file);
io2 << std::format("\tstruct {}{} ", pClass->name, pClass->parent.empty() ? "" : " : " + pClass->parent);
io2 << "{\n\n";
for (size_t i = 0; i < pClass->fields.size(); i++) {
if (pClass->fields[i]->static_field) continue;
auto field = pClass->fields[i];
next: if ((i + 1) >= pClass->fields.size()) {
io2 << std::format("\t\tchar {}[0x{:06X}];\n", field->name, 0x4);
continue;
}
if (pClass->fields[i + 1]->static_field) {
i++;
goto next;
}
std::string name = field->name;
std::ranges::replace(name, '<', '_');
std::ranges::replace(name, '>', '_');
if (field->type->name == "System.Int64") {
io2 << std::format("\t\tstd::int64_t {};\n", name);
if (!pClass->fields[i + 1]->static_field && (pClass->fields[i + 1]->offset - field->offset) > 8) io2 << std::format("\t\tchar {}_[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset - 8);
continue;
}
if (field->type->name == "System.UInt64") {
io2 << std::format("\t\tstd::uint64_t {};\n", name);
if (!pClass->fields[i + 1]->static_field && (pClass->fields[i + 1]->offset - field->offset) > 8) io2 << std::format("\t\tchar {}_[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset - 8);
continue;
}
if (field->type->name == "System.Int32") {
io2 << std::format("\t\tint {};\n", name);
if (!pClass->fields[i + 1]->static_field && (pClass->fields[i + 1]->offset - field->offset) > 4) io2 << std::format("\t\tchar {}_[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset - 4);
continue;
}
if (field->type->name == "System.UInt32") {
io2 << std::format("\t\tstd::uint32_t {};\n", name);
if (!pClass->fields[i + 1]->static_field && (pClass->fields[i + 1]->offset - field->offset) > 4) io2 << std::format("\t\tchar {}_[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset - 4);
continue;
}
if (field->type->name == "System.Boolean") {
io2 << std::format("\t\tbool {};\n", name);
if (!pClass->fields[i + 1]->static_field && (pClass->fields[i + 1]->offset - field->offset) > 1) io2 << std::format("\t\tchar {}_[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset - 1);
continue;
}
if (field->type->name == "System.String") {
io2 << std::format("\t\tUnityResolve::UnityType::String* {};\n", name);
if (!pClass->fields[i + 1]->static_field && (pClass->fields[i + 1]->offset - field->offset) > sizeof(void*)) io2 << std::format("\t\tchar {}_[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset - sizeof(void*));
continue;
}
if (field->type->name == "System.Single") {
io2 << std::format("\t\tfloat {};\n", name);
if (!pClass->fields[i + 1]->static_field && (pClass->fields[i + 1]->offset - field->offset) > 4) io2 << std::format("\t\tchar {}_[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset - 4);
continue;
}
if (field->type->name == "System.Double") {
io2 << std::format("\t\tdouble {};\n", name);
if (!pClass->fields[i + 1]->static_field && (pClass->fields[i + 1]->offset - field->offset) > 8) io2 << std::format("\t\tchar {}_[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset - 8);
continue;
}
if (field->type->name == "UnityEngine.Vector3") {
io2 << std::format("\t\tUnityResolve::UnityType::Vector3 {};\n", name);
if (!pClass->fields[i + 1]->static_field && (pClass->fields[i + 1]->offset - field->offset) > sizeof(UnityType::Vector3)) io2 << std::format("\t\tchar {}_[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset - sizeof(UnityType::Vector3));
continue;
}
if (field->type->name == "UnityEngine.Vector2") {
io2 << std::format("\t\tUnityResolve::UnityType::Vector2 {};\n", name);
if (!pClass->fields[i + 1]->static_field && (pClass->fields[i + 1]->offset - field->offset) > sizeof(UnityType::Vector2)) io2 << std::format("\t\tchar {}_[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset - sizeof(UnityType::Vector2));
continue;
}
if (field->type->name == "UnityEngine.Vector4") {
io2 << std::format("\t\tUnityResolve::UnityType::Vector4 {};\n", name);
if (!pClass->fields[i + 1]->static_field && (pClass->fields[i + 1]->offset - field->offset) > sizeof(UnityType::Vector4)) io2 << std::format("\t\tchar {}_[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset - sizeof(UnityType::Vector4));
continue;
}
if (field->type->name == "UnityEngine.GameObject") {
io2 << std::format("\t\tUnityResolve::UnityType::GameObject* {};\n", name);
if (!pClass->fields[i + 1]->static_field && (pClass->fields[i + 1]->offset - field->offset) > sizeof(void*)) io2 << std::format("\t\tchar {}_[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset - sizeof(void*));
continue;
}
if (field->type->name == "UnityEngine.Transform") {
io2 << std::format("\t\tUnityResolve::UnityType::Transform* {};\n", name);
if (!pClass->fields[i + 1]->static_field && (pClass->fields[i + 1]->offset - field->offset) > sizeof(void*)) io2 << std::format("\t\tchar {}_[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset - sizeof(void*));
continue;
}
if (field->type->name == "UnityEngine.Animator") {
io2 << std::format("\t\tUnityResolve::UnityType::Animator* {};\n", name);
if (!pClass->fields[i + 1]->static_field && (pClass->fields[i + 1]->offset - field->offset) > sizeof(void*)) io2 << std::format("\t\tchar {}_[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset - sizeof(void*));
continue;
}
if (field->type->name == "UnityEngine.Physics") {
io2 << std::format("\t\tUnityResolve::UnityType::Physics* {};\n", name);
if (!pClass->fields[i + 1]->static_field && (pClass->fields[i + 1]->offset - field->offset) > sizeof(void*)) io2 << std::format("\t\tchar {}_[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset - sizeof(void*));
continue;
}
if (field->type->name == "UnityEngine.Component") {
io2 << std::format("\t\tUnityResolve::UnityType::Component* {};\n", name);
if (!pClass->fields[i + 1]->static_field && (pClass->fields[i + 1]->offset - field->offset) > sizeof(void*)) io2 << std::format("\t\tchar {}_[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset - sizeof(void*));
continue;
}
if (field->type->name == "UnityEngine.Rect") {
io2 << std::format("\t\tUnityResolve::UnityType::Rect {};\n", name);
if (!pClass->fields[i + 1]->static_field && (pClass->fields[i + 1]->offset - field->offset) > sizeof(UnityType::Rect)) io2 << std::format("\t\tchar {}_[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset - sizeof(UnityType::Rect));
continue;
}
if (field->type->name == "UnityEngine.Quaternion") {
io2 << std::format("\t\tUnityResolve::UnityType::Quaternion {};\n", name);
if (!pClass->fields[i + 1]->static_field && (pClass->fields[i + 1]->offset - field->offset) > sizeof(UnityType::Quaternion)) io2 << std::format("\t\tchar {}_[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset - sizeof(UnityType::Quaternion));
continue;
}
if (field->type->name == "UnityEngine.Color") {
io2 << std::format("\t\tUnityResolve::UnityType::Color {};\n", name);
if (!pClass->fields[i + 1]->static_field && (pClass->fields[i + 1]->offset - field->offset) > sizeof(UnityType::Color)) io2 << std::format("\t\tchar {}_[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset - sizeof(UnityType::Color));
continue;
}
if (field->type->name == "UnityEngine.Matrix4x4") {
io2 << std::format("\t\tUnityResolve::UnityType::Matrix4x4 {};\n", name);
if (!pClass->fields[i + 1]->static_field && (pClass->fields[i + 1]->offset - field->offset) > sizeof(UnityType::Matrix4x4)) io2 << std::format("\t\tchar {}_[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset - sizeof(UnityType::Matrix4x4));
continue;
}
if (field->type->name == "UnityEngine.Rigidbody") {
io2 << std::format("\t\tUnityResolve::UnityType::Rigidbody* {};\n", name);
if (!pClass->fields[i + 1]->static_field && (pClass->fields[i + 1]->offset - field->offset) > sizeof(void*)) io2 << std::format("\t\tchar {}_[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset - sizeof(void*));
continue;
}
io2 << std::format("\t\tchar {}[0x{:06X}];\n", name, pClass->fields[i + 1]->offset - field->offset);
}
io2 << "\n";
io2 << "\t};\n\n";
}
}
io2 << '\n';
io2.close();
}
#endif
/**
* \brief 调用dll函数
* \tparam Return 返回类型 (必须)
* \tparam Args 参数类型 (可以忽略)
* \param funcName dll导出函数名称
* \param args 参数
* \return 模板类型
*/
template <typename Return, typename... Args>
static auto Invoke(const std::string& funcName, Args... args) -> Return {
static std::mutex mutex{};
std::lock_guard lock(mutex);
// 检查函数是否已经获取地址, 没有则自动获取
#if WINDOWS_MODE
if (!address_.contains(funcName) || !address_[funcName]) address_[funcName] = static_cast<void*>(GetProcAddress(static_cast<HMODULE>(hmodule_), funcName.c_str()));
#elif ANDROID_MODE || LINUX_MODE
if (address_.find(funcName) == address_.end() || !address_[funcName]) {
auto xdlAddr = xdl_sym(hmodule_, funcName.c_str(), NULL);
if (!xdlAddr) {
address_[funcName] = dlsym(hmodule_, funcName.c_str());
}
else {
address_[funcName] = xdlAddr;
}
}
#endif
if (address_[funcName] != nullptr) {
try {
return reinterpret_cast<Return(UNITY_CALLING_CONVENTION*)(Args...)>(address_[funcName])(args...);
}
catch (...) {
std::cout << funcName << " Invoke Error\n";
Return();
}
}
Return();
}
inline static std::vector<Assembly*> assembly;
static auto Get(const std::string& strAssembly) -> Assembly* {
for (const auto pAssembly : assembly) if (pAssembly->name == strAssembly) return pAssembly;
return nullptr;
}
private:
static auto ForeachAssembly() -> void {
// 遍历程序集
if (mode_ == Mode::Il2Cpp) {
size_t nrofassemblies = 0;
const auto assemblies = Invoke<void**>("il2cpp_domain_get_assemblies", pDomain, &nrofassemblies);
if (!lazyInit_) UnityResolveProgress::assembliesProgress.total = nrofassemblies;
for (auto i = 0; i < nrofassemblies; i++) {
if (!lazyInit_) UnityResolveProgress::assembliesProgress.current = i + 1;
const auto ptr = assemblies[i];
if (ptr == nullptr) continue;
auto assembly = new Assembly{ .address = ptr };
const auto image = Invoke<void*>("il2cpp_assembly_get_image", ptr);
assembly->file = Invoke<const char*>("il2cpp_image_get_filename", image);
assembly->name = Invoke<const char*>("il2cpp_image_get_name", image);
UnityResolve::assembly.push_back(assembly);
if (!lazyInit_) {
ForeachClass(assembly, image);
}
}
}
else {
Invoke<void*, void(*)(void* ptr, std::vector<Assembly*>&), std::vector<Assembly*>&>("mono_assembly_foreach",
[](void* ptr, std::vector<Assembly*>& v) {
if (ptr == nullptr) return;
const auto assembly = new Assembly{ .address = ptr, };
const auto image = Invoke<void*>("mono_assembly_get_image", ptr);
assembly->file = Invoke<const char*>("mono_image_get_filename", image);
assembly->name = Invoke<const char*>("mono_image_get_name", image);
assembly->name += ".dll";
v.push_back(assembly);
ForeachClass(assembly, image);
},
assembly);
}
}
static auto GetPClassFromUnknownNamespace(void* image, const char* klassName) -> void* {
const auto count = Invoke<int>("il2cpp_image_get_class_count", image);
for (auto i = 0; i < count; i++) {
const auto pClass = Invoke<void*>("il2cpp_image_get_class", image, i);
const auto className = Invoke<const char*>("il2cpp_class_get_name", pClass);
if (strcmp(className, klassName) == 0) {
return pClass;
}
}
return nullptr;
}
static auto FillClass_Il2ccpp(Assembly* assembly, const char* namespaze, const char* klassName) -> Class* {
auto image = Invoke<void*>("il2cpp_assembly_get_image", assembly->address);
void* pClass;
if (strcmp(namespaze, "*") == 0) {
pClass = GetPClassFromUnknownNamespace(image, klassName);
}
else {
pClass = Invoke<void*>("il2cpp_class_from_name", image, namespaze, klassName);
}
if (!pClass && (strlen(namespaze) == 0)) {
pClass = GetPClassFromUnknownNamespace(image, klassName);
}
if (pClass == nullptr) return nullptr;
const auto pAClass = new Class();
pAClass->address = pClass;
pAClass->name = Invoke<const char*>("il2cpp_class_get_name", pClass);
if (const auto pPClass = Invoke<void*>("il2cpp_class_get_parent", pClass)) pAClass->parent = Invoke<const char*>("il2cpp_class_get_name", pPClass);
// pAClass->namespaze = Invoke<const char*>("il2cpp_class_get_namespace", pClass);
pAClass->namespaze = namespaze;
assembly->classes.push_back(pAClass);
ForeachFields(pAClass, pClass);
ForeachMethod(pAClass, pClass);
void* i_class{};
void* iter{};
do {
if ((i_class = Invoke<void*>("il2cpp_class_get_interfaces", pClass, &iter))) {
ForeachFields(pAClass, i_class);
ForeachMethod(pAClass, i_class);
}
} while (i_class);
return pAClass;
}
static auto ForeachClass(Assembly* assembly, void* image) -> void {
// 遍历类
if (mode_ == Mode::Il2Cpp) {
const auto count = Invoke<int>("il2cpp_image_get_class_count", image);
if (!lazyInit_) UnityResolveProgress::classProgress.total = count;
for (auto i = 0; i < count; i++) {
if (!lazyInit_) UnityResolveProgress::classProgress.current = i + 1;
const auto pClass = Invoke<void*>("il2cpp_image_get_class", image, i);
if (pClass == nullptr) continue;
const auto pAClass = new Class();
pAClass->address = pClass;
pAClass->name = Invoke<const char*>("il2cpp_class_get_name", pClass);
if (const auto pPClass = Invoke<void*>("il2cpp_class_get_parent", pClass)) pAClass->parent = Invoke<const char*>("il2cpp_class_get_name", pPClass);
pAClass->namespaze = Invoke<const char*>("il2cpp_class_get_namespace", pClass);
assembly->classes.push_back(pAClass);
ForeachFields(pAClass, pClass);
ForeachMethod(pAClass, pClass);
void* i_class{};
void* iter{};
do {
if ((i_class = Invoke<void*>("il2cpp_class_get_interfaces", pClass, &iter))) {
ForeachFields(pAClass, i_class);
ForeachMethod(pAClass, i_class);
}
} while (i_class);
}
}
else {
const void* table = Invoke<void*>("mono_image_get_table_info", image, 2);
const auto count = Invoke<int>("mono_table_info_get_rows", table);
for (auto i = 0; i < count; i++) {
const auto pClass = Invoke<void*>("mono_class_get", image, 0x02000000 | (i + 1));
if (pClass == nullptr) continue;
const auto pAClass = new Class();
pAClass->address = pClass;
pAClass->name = Invoke<const char*>("mono_class_get_name", pClass);
if (const auto pPClass = Invoke<void*>("mono_class_get_parent", pClass)) pAClass->parent = Invoke<const char*>("mono_class_get_name", pPClass);
pAClass->namespaze = Invoke<const char*>("mono_class_get_namespace", pClass);
assembly->classes.push_back(pAClass);
ForeachFields(pAClass, pClass);
ForeachMethod(pAClass, pClass);
void* iClass{};
void* iiter{};
do {
if ((iClass = Invoke<void*>("mono_class_get_interfaces", pClass, &iiter))) {
ForeachFields(pAClass, iClass);
ForeachMethod(pAClass, iClass);
}
} while (iClass);
}
}
}
static auto ForeachFields(Class* klass, void* pKlass) -> void {
// 遍历成员
if (mode_ == Mode::Il2Cpp) {
void* iter = nullptr;
void* field;
do {
if ((field = Invoke<void*>("il2cpp_class_get_fields", pKlass, &iter))) {
const auto pField = new Field{ .address = field, .name = Invoke<const char*>("il2cpp_field_get_name", field), .type = new Type{.address = Invoke<void*>("il2cpp_field_get_type", field)}, .klass = klass, .offset = Invoke<int>("il2cpp_field_get_offset", field), .static_field = false, .vTable = nullptr };
int tSize{};
pField->static_field = pField->offset <= 0;
pField->type->name = Invoke<const char*>("il2cpp_type_get_name", pField->type->address);
pField->type->size = -1;
klass->fields.push_back(pField);
}
} while (field);
}
else {
void* iter = nullptr;
void* field;
do {
if ((field = Invoke<void*>("mono_class_get_fields", pKlass, &iter))) {
const auto pField = new Field{ .address = field, .name = Invoke<const char*>("mono_field_get_name", field), .type = new Type{.address = Invoke<void*>("mono_field_get_type", field)}, .klass = klass, .offset = Invoke<int>("mono_field_get_offset", field), .static_field = false, .vTable = nullptr };
int tSize{};
pField->static_field = pField->offset <= 0;
pField->type->name = Invoke<const char*>("mono_type_get_name", pField->type->address);
pField->type->size = Invoke<int>("mono_type_size", pField->type->address, &tSize);
klass->fields.push_back(pField);
}
} while (field);
}
}
static auto ForeachMethod(Class* klass, void* pKlass) -> void {
// 遍历方法
if (mode_ == Mode::Il2Cpp) {
void* iter = nullptr;
void* method;
do {
if ((method = Invoke<void*>("il2cpp_class_get_methods", pKlass, &iter))) {
int fFlags{};
const auto pMethod = new Method{};
pMethod->address = method;
pMethod->name = Invoke<const char*>("il2cpp_method_get_name", method);
pMethod->klass = klass;
pMethod->return_type = new Type{ .address = Invoke<void*>("il2cpp_method_get_return_type", method), };
pMethod->flags = Invoke<int>("il2cpp_method_get_flags", method, &fFlags);
int tSize{};
pMethod->static_function = pMethod->flags & 0x10;
pMethod->return_type->name = Invoke<const char*>("il2cpp_type_get_name", pMethod->return_type->address);
pMethod->return_type->size = -1;
pMethod->function = *static_cast<void**>(method);
klass->methods.push_back(pMethod);
const auto argCount = Invoke<int>("il2cpp_method_get_param_count", method);
for (auto index = 0; index < argCount; index++) pMethod->args.push_back(new Method::Arg{ Invoke<const char*>("il2cpp_method_get_param_name", method, index), new Type{.address = Invoke<void*>("il2cpp_method_get_param", method, index), .name = Invoke<const char*>("il2cpp_type_get_name", Invoke<void*>("il2cpp_method_get_param", method, index)), .size = -1} });
}
} while (method);
}
else {
void* iter = nullptr;
void* method;
do {
if ((method = Invoke<void*>("mono_class_get_methods", pKlass, &iter))) {
const auto signature = Invoke<void*>("mono_method_signature", method);
int fFlags{};
const auto pMethod = new Method{};
pMethod->address = method;
pMethod->name = Invoke<const char*>("mono_method_get_name", method);
pMethod->klass = klass;
pMethod->return_type = new Type{ .address = Invoke<void*>("mono_signature_get_return_type", method), };
pMethod->flags = Invoke<int>("mono_method_get_flags", method, &fFlags);
int tSize{};
pMethod->static_function = pMethod->flags & 0x10;
pMethod->return_type->name = Invoke<const char*>("mono_type_get_name", pMethod->return_type->address);
pMethod->return_type->size = Invoke<int>("mono_type_size", pMethod->return_type->address, &tSize);
klass->methods.push_back(pMethod);
const auto names = new char* [Invoke<int>("mono_signature_get_param_count", signature)];
Invoke<void>("mono_method_get_param_names", method, names);
void* mIter = nullptr;
void* mType;
auto iname = 0;
do {
if ((mType = Invoke<void*>("mono_signature_get_params", signature, &mIter))) {
int t_size{};
try { pMethod->args.push_back(new Method::Arg{ names[iname], new Type{.address = mType, .name = Invoke<const char*>("mono_type_get_name", mType), .size = Invoke<int>("mono_type_size", mType, &t_size)} }); }
catch (...) {
// USE SEH!!!
}
iname++;
}
} while (mType);
}
} while (method);
}
}
public:
class UnityType final {
public:
using IntPtr = std::uintptr_t;
using Int32 = std::int32_t;
using Int64 = std::int64_t;
using Char = wchar_t;
using Int16 = std::int16_t;
using Byte = std::uint8_t;
struct Vector3;
struct Camera;
struct Transform;
struct Component;
struct UnityObject;
struct LayerMask;
struct Rigidbody;
struct Physics;
struct Time;
struct GameObject;
struct Collider;
struct Vector4;
struct Vector2;
struct Quaternion;
struct Bounds;
struct Plane;
struct Ray;
struct Rect;
struct Color;
struct Matrix4x4;
template <typename T>
struct Array;
struct String;
struct Object;
template <typename T>
struct List;
template <typename TKey, typename TValue>
struct Dictionary;
struct Behaviour;
struct MonoBehaviour;
struct CsType;
struct Mesh;
struct Renderer;
struct Animator;
struct CapsuleCollider;
struct BoxCollider;
struct Vector3 {
float x, y, z;
Vector3() { x = y = z = 0.f; }
Vector3(const float f1, const float f2, const float f3) {
x = f1;
y = f2;
z = f3;
}
[[nodiscard]] auto Length() const -> float { return x * x + y * y + z * z; }
[[nodiscard]] auto Dot(const Vector3 b) const -> float { return x * b.x + y * b.y + z * b.z; }
[[nodiscard]] auto Normalize() const -> Vector3 {
if (const auto len = Length(); len > 0) return Vector3(x / len, y / len, z / len);
return Vector3(x, y, z);
}
auto ToVectors(Vector3* m_pForward, Vector3* m_pRight, Vector3* m_pUp) const -> void {
constexpr auto m_fDeg2Rad = static_cast<float>(3.1415926) / 180.F;
const auto m_fSinX = sinf(x * m_fDeg2Rad);
const auto m_fCosX = cosf(x * m_fDeg2Rad);
const auto m_fSinY = sinf(y * m_fDeg2Rad);
const auto m_fCosY = cosf(y * m_fDeg2Rad);
const auto m_fSinZ = sinf(z * m_fDeg2Rad);
const auto m_fCosZ = cosf(z * m_fDeg2Rad);
if (m_pForward) {
m_pForward->x = m_fCosX * m_fCosY;
m_pForward->y = -m_fSinX;
m_pForward->z = m_fCosX * m_fSinY;
}
if (m_pRight) {
m_pRight->x = -1.f * m_fSinZ * m_fSinX * m_fCosY + -1.f * m_fCosZ * -m_fSinY;
m_pRight->y = -1.f * m_fSinZ * m_fCosX;
m_pRight->z = -1.f * m_fSinZ * m_fSinX * m_fSinY + -1.f * m_fCosZ * m_fCosY;
}
if (m_pUp) {
m_pUp->x = m_fCosZ * m_fSinX * m_fCosY + -m_fSinZ * -m_fSinY;
m_pUp->y = m_fCosZ * m_fCosX;
m_pUp->z = m_fCosZ * m_fSinX * m_fSinY + -m_fSinZ * m_fCosY;
}
}
[[nodiscard]] auto Distance(const Vector3& event) const -> float {
const auto dx = this->x - event.x;
const auto dy = this->y - event.y;
const auto dz = this->z - event.z;
return std::sqrt(dx * dx + dy * dy + dz * dz);
}
auto operator*(const float x) -> Vector3 {
this->x *= x;
this->y *= x;
this->z *= x;
return *this;
}
auto operator-(const float x) -> Vector3 {
this->x -= x;
this->y -= x;
this->z -= x;
return *this;
}
auto operator+(const float x) -> Vector3 {
this->x += x;
this->y += x;
this->z += x;
return *this;
}
auto operator/(const float x) -> Vector3 {
this->x /= x;
this->y /= x;
this->z /= x;
return *this;
}
auto operator*(const Vector3 x) -> Vector3 {
this->x *= x.x;
this->y *= x.y;
this->z *= x.z;
return *this;
}
auto operator-(const Vector3 x) -> Vector3 {
this->x -= x.x;
this->y -= x.y;
this->z -= x.z;
return *this;
}
auto operator+(const Vector3 x) -> Vector3 {
this->x += x.x;
this->y += x.y;
this->z += x.z;
return *this;
}
auto operator/(const Vector3 x) -> Vector3 {
this->x /= x.x;
this->y /= x.y;
this->z /= x.z;
return *this;
}
auto operator ==(const Vector3 x) const -> bool { return this->x == x.x && this->y == x.y && this->z == x.z; }
Vector3 cross(const Vector3& other) const {
return Vector3(
y * other.z - z * other.y,
z * other.x - x * other.z,
x * other.y - y * other.x
);
}
};
struct Vector2 {
float x, y;
Vector2() { x = y = 0.f; }
Vector2(const float f1, const float f2) {
x = f1;
y = f2;
}
[[nodiscard]] auto Distance(const Vector2& event) const -> float {
const auto dx = this->x - event.x;
const auto dy = this->y - event.y;
return std::sqrt(dx * dx + dy * dy);
}
auto operator*(const float x) -> Vector2 {
this->x *= x;
this->y *= x;
return *this;
}
auto operator/(const float x) -> Vector2 {
this->x /= x;
this->y /= x;
return *this;
}
auto operator+(const float x) -> Vector2 {
this->x += x;
this->y += x;
return *this;
}
auto operator-(const float x) -> Vector2 {
this->x -= x;
this->y -= x;
return *this;
}
auto operator*(const Vector2 x) -> Vector2 {
this->x *= x.x;
this->y *= x.y;
return *this;
}
auto operator-(const Vector2 x) -> Vector2 {
this->x -= x.x;
this->y -= x.y;
return *this;
}
auto operator+(const Vector2 x) -> Vector2 {
this->x += x.x;
this->y += x.y;
return *this;
}
auto operator/(const Vector2 x) -> Vector2 {
this->x /= x.x;
this->y /= x.y;
return *this;
}
auto operator ==(const Vector2 x) const -> bool { return this->x == x.x && this->y == x.y; }
};
struct Vector2Int {
int m_X, m_Y;
Vector2Int() { m_X = m_Y = 0; }
Vector2Int(const int f1, const int f2) {
m_X = f1;
m_Y = f2;
}
[[nodiscard]] auto Distance(const Vector2Int& event) const -> float {
const auto dx = this->m_X - event.m_X;
const auto dy = this->m_Y - event.m_Y;
return std::sqrt(dx * dx + dy * dy);
}
auto operator*(const int x) -> Vector2Int {
this->m_X *= x;
this->m_Y *= x;
return *this;
}
auto operator/(const int x) -> Vector2Int {
this->m_X /= x;
this->m_Y /= x;
return *this;
}
auto operator+(const int x) -> Vector2Int {
this->m_X += x;
this->m_Y += x;
return *this;
}
auto operator-(const int x) -> Vector2Int {
this->m_X -= x;
this->m_Y -= x;
return *this;
}
auto operator*(const Vector2Int x) -> Vector2Int {
this->m_X *= x.m_X;
this->m_Y *= x.m_Y;
return *this;
}
auto operator-(const Vector2Int x) -> Vector2Int {
this->m_X -= x.m_X;
this->m_Y -= x.m_Y;
return *this;
}
auto operator+(const Vector2Int x) -> Vector2Int {
this->m_X += x.m_X;
this->m_Y += x.m_Y;
return *this;
}
auto operator/(const Vector2Int x) -> Vector2Int {
this->m_X /= x.m_X;
this->m_Y /= x.m_Y;
return *this;
}
auto operator ==(const Vector2Int x) const -> bool { return this->m_X == x.m_X && this->m_Y == x.m_Y; }
};
struct Vector4 {
float x, y, z, w;
Vector4() { x = y = z = w = 0.F; }
Vector4(const float f1, const float f2, const float f3, const float f4) {
x = f1;
y = f2;
z = f3;
w = f4;
}
auto operator*(const float x) -> Vector4 {
this->x *= x;
this->y *= x;
this->z *= x;
this->w *= x;
return *this;
}
auto operator-(const float x) -> Vector4 {
this->x -= x;
this->y -= x;
this->z -= x;
this->w -= x;
return *this;
}
auto operator+(const float x) -> Vector4 {
this->x += x;
this->y += x;
this->z += x;
this->w += x;
return *this;
}
auto operator/(const float x) -> Vector4 {
this->x /= x;
this->y /= x;
this->z /= x;
this->w /= x;
return *this;
}
auto operator*(const Vector4 x) -> Vector4 {
this->x *= x.x;
this->y *= x.y;
this->z *= x.z;
this->w *= x.w;
return *this;
}
auto operator-(const Vector4 x) -> Vector4 {
this->x -= x.x;
this->y -= x.y;
this->z -= x.z;
this->w -= x.w;
return *this;
}
auto operator+(const Vector4 x) -> Vector4 {
this->x += x.x;
this->y += x.y;
this->z += x.z;
this->w += x.w;
return *this;
}
auto operator/(const Vector4 x) -> Vector4 {
this->x /= x.x;
this->y /= x.y;
this->z /= x.z;
this->w /= x.w;
return *this;
}
auto operator ==(const Vector4 x) const -> bool { return this->x == x.x && this->y == x.y && this->z == x.z && this->w == x.w; }
};
struct Quaternion {
float x, y, z, w;
Quaternion() { x = y = z = w = 0.F; }
Quaternion(const float f1, const float f2, const float f3, const float f4) {
x = f1;
y = f2;
z = f3;
w = f4;
}
auto Euler(float m_fX, float m_fY, float m_fZ) -> Quaternion {
constexpr auto m_fDeg2Rad = static_cast<float>(3.1415926) / 180.F;
m_fX = m_fX * m_fDeg2Rad * 0.5F;
m_fY = m_fY * m_fDeg2Rad * 0.5F;
m_fZ = m_fZ * m_fDeg2Rad * 0.5F;
const auto m_fSinX = sinf(m_fX);
const auto m_fCosX = cosf(m_fX);
const auto m_fSinY = sinf(m_fY);
const auto m_fCosY = cosf(m_fY);
const auto m_fSinZ = sinf(m_fZ);
const auto m_fCosZ = cosf(m_fZ);
x = m_fCosY * m_fSinX * m_fCosZ + m_fSinY * m_fCosX * m_fSinZ;
y = m_fSinY * m_fCosX * m_fCosZ - m_fCosY * m_fSinX * m_fSinZ;
z = m_fCosY * m_fCosX * m_fSinZ - m_fSinY * m_fSinX * m_fCosZ;
w = m_fCosY * m_fCosX * m_fCosZ + m_fSinY * m_fSinX * m_fSinZ;
return *this;
}
auto Euler(const Vector3& m_vRot) -> Quaternion { return Euler(m_vRot.x, m_vRot.y, m_vRot.z); }
[[nodiscard]] auto ToEuler() const -> Vector3 {
Vector3 m_vEuler;
const auto m_fDist = (x * x) + (y * y) + (z * z) + (w * w);
if (const auto m_fTest = x * w - y * z; m_fTest > 0.4995F * m_fDist) {
m_vEuler.x = static_cast<float>(3.1415926) * 0.5F;
m_vEuler.y = 2.F * atan2f(y, x);
m_vEuler.z = 0.F;
}
else if (m_fTest < -0.4995F * m_fDist) {
m_vEuler.x = static_cast<float>(3.1415926) * -0.5F;
m_vEuler.y = -2.F * atan2f(y, x);
m_vEuler.z = 0.F;
}
else {
m_vEuler.x = asinf(2.F * (w * x - y * z));
m_vEuler.y = atan2f(2.F * w * y + 2.F * z * x, 1.F - 2.F * (x * x + y * y));
m_vEuler.z = atan2f(2.F * w * z + 2.F * x * y, 1.F - 2.F * (z * z + x * x));
}
constexpr auto m_fRad2Deg = 180.F / static_cast<float>(3.1415926);
m_vEuler.x *= m_fRad2Deg;
m_vEuler.y *= m_fRad2Deg;
m_vEuler.z *= m_fRad2Deg;
return m_vEuler;
}
auto operator*(const float x) -> Quaternion {
this->x *= x;
this->y *= x;
this->z *= x;
this->w *= x;
return *this;
}
auto operator-(const float x) -> Quaternion {
this->x -= x;
this->y -= x;
this->z -= x;
this->w -= x;
return *this;
}
auto operator+(const float x) -> Quaternion {
this->x += x;
this->y += x;
this->z += x;
this->w += x;
return *this;
}
auto operator/(const float x) -> Quaternion {
this->x /= x;
this->y /= x;
this->z /= x;
this->w /= x;
return *this;
}
auto operator*(const Quaternion x) -> Quaternion {
this->x *= x.x;
this->y *= x.y;
this->z *= x.z;
this->w *= x.w;
return *this;
}
auto operator-(const Quaternion x) -> Quaternion {
this->x -= x.x;
this->y -= x.y;
this->z -= x.z;
this->w -= x.w;
return *this;
}
auto operator+(const Quaternion x) -> Quaternion {
this->x += x.x;
this->y += x.y;
this->z += x.z;
this->w += x.w;
return *this;
}
auto operator/(const Quaternion x) -> Quaternion {
this->x /= x.x;
this->y /= x.y;
this->z /= x.z;
this->w /= x.w;
return *this;
}
auto operator ==(const Quaternion x) const -> bool { return this->x == x.x && this->y == x.y && this->z == x.z && this->w == x.w; }
};
struct Bounds {
Vector3 m_vCenter;
Vector3 m_vExtents;
};
struct Plane {
Vector3 m_vNormal;
float fDistance;
};
struct Ray {
Vector3 m_vOrigin;
Vector3 m_vDirection;
};
struct Rect {
float fX, fY;
float fWidth, fHeight;
Rect() { fX = fY = fWidth = fHeight = 0.f; }
Rect(const float f1, const float f2, const float f3, const float f4) {
fX = f1;
fY = f2;
fWidth = f3;
fHeight = f4;
}
};
struct Color {
float r, g, b, a;
Color() { r = g = b = a = 0.f; }
explicit Color(const float fRed = 0.f, const float fGreen = 0.f, const float fBlue = 0.f, const float fAlpha = 1.f) {
r = fRed;
g = fGreen;
b = fBlue;
a = fAlpha;
}
};
struct Matrix4x4 {
float m[4][4] = { {0} };
Matrix4x4() = default;
auto operator[](const int i) -> float* { return m[i]; }
};
struct Object {
union {
void* klass{ nullptr };
void* vtable;
} Il2CppClass;
struct MonitorData* monitor{ nullptr };
auto GetType() -> CsType* {
if (!this) return nullptr;
static Method* method;
if (!method) method = Get("mscorlib.dll")->Get("Object", "System")->Get<Method>("GetType");
if (method) return method->Invoke<CsType*>(this);
return nullptr;
}
auto ToString() -> std::string {
if (!this) return {};
static Method* method;
if (!method) method = Get("mscorlib.dll")->Get("Object", "System")->Get<Method>("ToString");
if (method) return method->Invoke<String*>(this)->ToString();
return {};
}
};
struct CsType {
auto FormatTypeName() -> std::string {
if (!this) return {};
static Method* method;
if (!method) method = Get("mscorlib.dll")->Get("Type", "System", "MemberInfo")->Get<Method>("FormatTypeName");
if (method) return method->Invoke<String*>(this)->ToString();
return {};
}
auto GetFullName() -> std::string {
if (!this) return {};
static Method* method;
if (!method) method = Get("mscorlib.dll")->Get("Type", "System", "MemberInfo")->Get<Method>("get_FullName");
if (method) return method->Invoke<String*>(this)->ToString();
return {};
}
auto GetNamespace() -> std::string {
if (!this) return {};
static Method* method;
if (!method) method = Get("mscorlib.dll")->Get("Type", "System", "MemberInfo")->Get<Method>("get_Namespace");
if (method) return method->Invoke<String*>(this)->ToString();
return {};
}
};
struct String {
// int32_t m_stringLength{ 0 };
// wchar_t m_firstChar[32]{};
Object object;
int32_t length; ///< Length of string *excluding* the trailing null (which is included in
///< 'chars').
char16_t chars[1];
[[nodiscard]] auto ToString() const -> std::string {
#if WINDOWS_MODE
if (IsBadReadPtr(this, sizeof(String))) return {};
if (IsBadReadPtr(m_firstChar, m_stringLength)) return {};
#endif
if (!this) return {};
try {
// using convert_typeX = std::codecvt_utf8<wchar_t>;
// std::wstring_convert<convert_typeX> converterX;
// return converterX.to_bytes(m_firstChar);
return GakumasLocal::Misc::ToUTF8(chars);
}
catch (std::exception& e) {
std::cout << "String Invoke Error\n";
GakumasLocal::Log::ErrorFmt("String Invoke Error: %s", e.what());
return {};
}
}
auto operator=(const std::string& newString) const -> String* { return New(newString); }
auto operator==(const std::wstring& newString) const -> bool { return Equals(newString); }
auto Clear() -> void {
if (!this) return;
memset(chars, 0, length);
length = 0;
}
[[nodiscard]] auto Equals(const std::wstring& newString) const -> bool {
if (!this) return false;
if (newString.size() != length) return false;
if (std::memcmp(newString.data(), chars, length) != 0) return false;
return true;
}
static auto New(const std::string& str) -> String* {
if (mode_ == Mode::Il2Cpp) return UnityResolve::Invoke<String*, const char*>("il2cpp_string_new", str.c_str());
return UnityResolve::Invoke<String*, void*, const char*>("mono_string_new", UnityResolve::Invoke<void*>("mono_get_root_domain"), str.c_str());
}
};
template <typename T>
struct Array : Object {
struct {
std::uintptr_t length;
std::int32_t lower_bound;
}*bounds{ nullptr };
std::uintptr_t max_length{ 0 };
__declspec(align(8)) T** vector {};
auto GetData() -> uintptr_t { return reinterpret_cast<uintptr_t>(&vector); }
auto operator[](const unsigned int m_uIndex) -> T& { return *reinterpret_cast<T*>(GetData() + sizeof(T) * m_uIndex); }
auto At(const unsigned int m_uIndex) -> T& { return operator[](m_uIndex); }
auto Insert(T* m_pArray, uintptr_t m_uSize, const uintptr_t m_uIndex = 0) -> void {
if ((m_uSize + m_uIndex) >= max_length) {
if (m_uIndex >= max_length) return;
m_uSize = max_length - m_uIndex;
}
for (uintptr_t u = 0; m_uSize > u; ++u) operator[](u + m_uIndex) = m_pArray[u];
}
auto Fill(T m_tValue) -> void { for (uintptr_t u = 0; max_length > u; ++u) operator[](u) = m_tValue; }
auto RemoveAt(const unsigned int m_uIndex) -> void {
if (m_uIndex >= max_length) return;
if (max_length > (m_uIndex + 1)) for (auto u = m_uIndex; (max_length - m_uIndex) > u; ++u) operator[](u) = operator[](u + 1);
--max_length;
}
auto RemoveRange(const unsigned int m_uIndex, unsigned int m_uCount) -> void {
if (m_uCount == 0) m_uCount = 1;
const auto m_uTotal = m_uIndex + m_uCount;
if (m_uTotal >= max_length) return;
if (max_length > (m_uTotal + 1)) for (auto u = m_uIndex; (max_length - m_uTotal) >= u; ++u) operator[](u) = operator[](u + m_uCount);
max_length -= m_uCount;
}
auto RemoveAll() -> void {
if (max_length > 0) {
memset(GetData(), 0, sizeof(Type) * max_length);
max_length = 0;
}
}
auto ToVector() -> std::vector<T> {
#if WINDOWS_MODE
if (IsBadReadPtr(this, sizeof(Array))) return {};
#endif
if (!this) return {};
try {
std::vector<T> rs{};
rs.reserve(this->max_length);
for (auto i = 0; i < this->max_length; i++) rs.push_back(this->At(i));
return rs;
} catch (...) {
std::cout << "Array Invoke Error\n";
return {};
}
}
auto Resize(int newSize) -> void {
static Method* method;
if (!method) method = Get("mscorlib.dll")->Get("Array")->Get<Method>("Resize");
if (method) return method->Invoke<void>(this, newSize);
}
static auto New(const Class* kalss, const std::uintptr_t size) -> Array* {
if (mode_ == Mode::Il2Cpp) return UnityResolve::Invoke<Array*, void*, std::uintptr_t>("il2cpp_array_new", kalss->address, size);
return UnityResolve::Invoke<Array*, void*, void*, std::uintptr_t>("mono_array_new", pDomain, kalss->address, size);
}
};
template <typename Type>
struct List : Object {
Array<Type>* pList;
int size{};
int version{};
void* syncRoot{};
auto ToArray() -> Array<Type>* { return pList; }
static auto New(const Class* kalss, const std::uintptr_t size) -> List* {
auto pList = new List<Type>();
pList->pList = Array<Type>::New(kalss, size);
pList->size = size;
}
auto operator[](const unsigned int m_uIndex) -> Type& { return pList->At(m_uIndex); }
auto Add(Type pDate) -> void {
if (!this) return;
static Method* method;
if (!method) method = Get("mscorlib.dll")->Get("List`1")->Get<Method>("Add");
if (method) return method->Invoke<void>(this, pDate);
}
auto Remove(Type pDate) -> bool {
if (!this) return false;
static Method* method;
if (!method) method = Get("mscorlib.dll")->Get("List`1")->Get<Method>("Remove");
if (method) return method->Invoke<bool>(this, pDate);
return false;
}
auto RemoveAt(int index) -> void {
if (!this) return;
static Method* method;
if (!method) method = Get("mscorlib.dll")->Get("List`1")->Get<Method>("RemoveAt");
if (method) return method->Invoke<void>(this, index);
}
auto ForEach(void(*action)(Type pDate)) -> void {
if (!this) return;
static Method* method;
if (!method) method = Get("mscorlib.dll")->Get("List`1")->Get<Method>("ForEach");
if (method) return method->Invoke<void>(this, action);
}
auto GetRange(int index, int count) -> List* {
if (!this) return {};
static Method* method;
if (!method) method = Get("mscorlib.dll")->Get("List`1")->Get<Method>("GetRange");
if (method) return method->Invoke<List*>(this, index, count);
return nullptr;
}
auto Clear() -> void {
if (!this) return;
static Method* method;
if (!method) method = Get("mscorlib.dll")->Get("List`1")->Get<Method>("Clear");
if (method) return method->Invoke<void>(this);
}
auto Sort(int (*comparison)(Type* pX, Type* pY)) -> void {
if (!this) return;
static Method* method;
if (!method) method = Get("mscorlib.dll")->Get("List`1")->Get<Method>("Sort", { "*" });
if (method) return method->Invoke<void>(this, comparison);
}
};
template <typename TKey, typename TValue>
struct Dictionary : Object {
struct Entry {
int iHashCode;
int iNext;
TKey tKey;
TValue tValue;
};
Array<int>* pBuckets;
Array<Entry*>* pEntries;
int iCount;
int iVersion;
int iFreeList;
int iFreeCount;
void* pComparer;
void* pKeys;
void* pValues;
auto GetEntry() -> Entry* { return static_cast<Entry*>(pEntries->GetData()); }
auto GetKeyByIndex(const int iIndex) -> TKey {
TKey tKey = { 0 };
Entry* pEntry = GetEntry();
if (pEntry) tKey = pEntry[iIndex].m_tKey;
return tKey;
}
auto GetValueByIndex(const int iIndex) -> TValue {
TValue tValue = { 0 };
Entry* pEntry = GetEntry();
if (pEntry) tValue = pEntry[iIndex].m_tValue;
return tValue;
}
auto GetValueByKey(const TKey tKey) -> TValue {
TValue tValue = { 0 };
for (auto i = 0; i < iCount; i++) if (GetEntry()[i].m_tKey == tKey) tValue = GetEntry()[i].m_tValue;
return tValue;
}
auto operator[](const TKey tKey) const -> TValue { return GetValueByKey(tKey); }
};
struct UnityObject : Object {
void* m_CachedPtr;
auto GetName() -> std::string {
if (!this) return {};
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Object")->Get<Method>("get_name");
if (method) return method->Invoke<String*>(this)->ToString();
return {};
}
auto ToString() -> std::string {
if (!this) return {};
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Object")->Get<Method>("ToString");
if (method) return method->Invoke<String*>(this)->ToString();
return {};
}
static auto ToString(UnityObject* obj) -> std::string {
if (!obj) return {};
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Object")->Get<Method>("ToString", { "*" });
if (method) return method->Invoke<String*>(obj)->ToString();
return {};
}
static auto Instantiate(UnityObject* original) -> UnityObject* {
if (!original) return nullptr;
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Object")->Get<Method>("Instantiate", { "*" });
if (method) return method->Invoke<UnityObject*>(original);
return nullptr;
}
static auto Destroy(UnityObject* original) -> void {
if (!original) return;
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Object")->Get<Method>("Destroy", { "*" });
if (method) return method->Invoke<void>(original);
}
static auto op_Implicit(UnityObject* exists) -> bool {
if (!exists) return false;
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Object", "UnityEngine")->Get<Method>("op_Implicit");
if (method) return method->Invoke<bool>(exists);
return false;
}
};
struct Component : UnityObject {
auto GetTransform() -> Transform* {
if (!this) return nullptr;
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Component")->Get<Method>("get_transform");
if (method) return method->Invoke<Transform*>(this);
return nullptr;
}
auto GetGameObject() -> GameObject* {
if (!this) return nullptr;
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Component")->Get<Method>("get_gameObject");
if (method) return method->Invoke<GameObject*>(this);
return nullptr;
}
auto GetTag() -> std::string {
if (!this) return {};
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Component")->Get<Method>("get_tag");
if (method) return method->Invoke<String*>(this)->ToString();
return {};
}
template <typename T>
auto GetComponentsInChildren() -> std::vector<T> {
if (!this) return {};
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Component")->Get<Method>("GetComponentsInChildren");
if (method) return method->Invoke<Array<T>*>(this)->ToVector();
return {};
}
template <typename T>
auto GetComponentsInChildren(Class* pClass) -> std::vector<T> {
static Method* method;
if (!this) return {};
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Component")->Get<Method>("GetComponentsInChildren", { "System.Type" });
if (method) return method->Invoke<Array<T>*>(this, pClass->GetType())->ToVector();
return {};
}
template <typename T>
auto GetComponents() -> std::vector<T> {
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Component")->Get<Method>("GetComponents");
if (method) return method->Invoke<Array<T>*>(this)->ToVector();
return {};
}
template <typename T>
auto GetComponents(Class* pClass) -> std::vector<T> {
static Method* method;
static void* obj;
if (!this) return std::vector<T>();
if (!method || !obj) {
method = Get("UnityEngine.CoreModule.dll")->Get("Component")->Get<Method>("GetComponents", { "System.Type" });
obj = pClass->GetType();
}
if (method) return method->Invoke<Array<T>*>(this, obj)->ToVector();
return {};
}
template <typename T>
auto GetComponentsInParent() -> std::vector<T> {
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Component")->Get<Method>("GetComponentsInParent");
if (method) return method->Invoke<Array<T>*>(this)->ToVector();
return {};
}
template <typename T>
auto GetComponentsInParent(Class* pClass) -> std::vector<T> {
static Method* method;
static void* obj;
if (!this) return std::vector<T>();
if (!method || !obj) {
method = Get("UnityEngine.CoreModule.dll")->Get("Component")->Get<Method>("GetComponentsInParent", { "System.Type" });
obj = pClass->GetType();
}
if (method) return method->Invoke<Array<T>*>(this, obj)->ToVector();
return {};
}
template <typename T>
auto GetComponentInChildren(Class* pClass) -> T {
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Component")->Get<Method>("GetComponentInChildren", { "System.Type" });
if (method) return method->Invoke<T>(this, pClass->GetType());
return T();
}
template <typename T>
auto GetComponentInParent(Class* pClass) -> T {
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Component")->Get<Method>("GetComponentInParent", { "System.Type" });
if (method) return method->Invoke<T>(this, pClass->GetType());
return T();
}
};
struct Camera : Component {
enum class Eye : int {
Left,
Right,
Mono
};
static auto GetMain() -> Camera* {
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Camera")->Get<Method>("get_main");
if (method) return method->Invoke<Camera*>();
return nullptr;
}
static auto GetCurrent() -> Camera* {
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Camera")->Get<Method>("get_current");
if (method) return method->Invoke<Camera*>();
return nullptr;
}
static auto GetAllCount() -> int {
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Camera")->Get<Method>("get_allCamerasCount");
if (method) return method->Invoke<int>();
return 0;
}
static auto GetAllCamera() -> std::vector<Camera*> {
static Method* method;
static Class* klass;
if (!method || !klass) {
method = Get("UnityEngine.CoreModule.dll")->Get("Camera")->Get<Method>("GetAllCameras", { "*" });
klass = Get("UnityEngine.CoreModule.dll")->Get("Camera");
}
if (method && klass) {
if (const int count = GetAllCount(); count != 0) {
const auto array = Array<Camera*>::New(klass, count);
method->Invoke<int>(array);
return array->ToVector();
}
}
return {};
}
auto GetDepth() -> float {
if (!this) return 0.0f;
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Camera")->Get<Method>("get_depth");
if (method) return method->Invoke<float>(this);
return 0.0f;
}
auto SetDepth(const float depth) -> void {
if (!this) return;
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Camera")->Get<Method>("set_depth", { "*" });
if (method) return method->Invoke<void>(this, depth);
}
auto SetFoV(const float fov) -> void {
if (!this) return;
static Method* method_fieldOfView;
if (!method_fieldOfView) method_fieldOfView = Get("UnityEngine.CoreModule.dll")->Get("Camera")->Get<Method>("set_fieldOfView", { "*" });
if (method_fieldOfView) return method_fieldOfView->Invoke<void>(this, fov);
}
auto GetFoV() -> float {
if (!this) return 0.0f;
static Method* method_fieldOfView;
if (!method_fieldOfView) method_fieldOfView = Get("UnityEngine.CoreModule.dll")->Get("Camera")->Get<Method>("get_fieldOfView");
if (method_fieldOfView) return method_fieldOfView->Invoke<float>(this);
return 0.0f;
}
auto WorldToScreenPoint(const Vector3& position, const Eye eye = Eye::Mono) -> Vector3 {
if (!this) return { -100, -100, -100 };
static Method* method;
if (!method) {
if (mode_ == Mode::Mono) method = Get("UnityEngine.CoreModule.dll")->Get("Camera")->Get<Method>("WorldToScreenPoint_Injected");
else method = Get("UnityEngine.CoreModule.dll")->Get("Camera")->Get<Method>("WorldToScreenPoint", { "*", "*" });
}
if (mode_ == Mode::Mono && method) {
const Vector3 vec3{};
method->Invoke<void>(this, position, eye, &vec3);
return vec3;
}
if (method) return method->Invoke<Vector3>(this, position, eye);
return {};
}
auto ScreenToWorldPoint(const Vector3& position, const Eye eye = Eye::Mono) -> Vector3 {
if (!this) return {};
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Camera")->Get<Method>(mode_ == Mode::Mono ? "ScreenToWorldPoint_Injected" : "ScreenToWorldPoint");
if (mode_ == Mode::Mono && method) {
const Vector3 vec3{};
method->Invoke<void>(this, position, eye, &vec3);
return vec3;
}
if (method) return method->Invoke<Vector3>(this, position, eye);
return {};
}
auto CameraToWorldMatrix() -> Matrix4x4 {
if (!this) return {};
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Camera")->Get<Method>(mode_ == Mode::Mono ? "get_cameraToWorldMatrix_Injected" : "get_cameraToWorldMatrix");
if (mode_ == Mode::Mono && method) {
Matrix4x4 matrix4{};
method->Invoke<void>(this, &matrix4);
return matrix4;
}
if (method) return method->Invoke<Matrix4x4>(this);
return {};
}
auto GetPixelRect() -> Rect {
if (!this) return {};
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Camera")->Get<Method>("get_pixelRect");
return method->Invoke<Rect>(this);
}
auto GetOrthographicSize() -> float {
if (!this) return {};
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Camera")->Get<Method>("get_orthographicSize");
return method->Invoke<float>(this);
}
void SetNearClipPlane(float value) {
if (!this) return;
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Camera")->Get<Method>("set_nearClipPlane");
return method->Invoke<void>(this, value);
}
float GetNearClipPlane() {
if (!this) return -1;
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Camera")->Get<Method>("get_nearClipPlane");
return method->Invoke<float>(this);
}
};
struct Transform : Component {
auto GetPosition() -> Vector3 {
static Method* method;
if (!this) return {};
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>(mode_ == Mode::Mono ? "get_position_Injected" : "get_position");
if (mode_ == Mode::Mono && method) {
const Vector3 vec3{};
method->Invoke<void>(this, &vec3);
return vec3;
}
if (method) return method->Invoke<Vector3>(this);
return {};
}
auto SetPosition(const Vector3& position) -> void {
static Method* method;
if (!this) return;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>(mode_ == Mode::Mono ? "set_position_Injected" : "set_position");
if (mode_ == Mode::Mono && method) return method->Invoke<void>(this, &position);
if (method) return method->Invoke<void>(this, position);
}
auto GetRight() -> Vector3 {
static Method* method;
if (!this) return {};
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>("get_right");
if (method) return method->Invoke<Vector3>(this);
return {};
}
auto SetRight(const Vector3& value) -> void {
static Method* method;
if (!this) return;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>("set_right");
if (method) return method->Invoke<void>(this, value);
}
auto GetUp() -> Vector3 {
static Method* method;
if (!this) return {};
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>("get_up");
if (method) return method->Invoke<Vector3>(this);
return {};
}
auto SetUp(const Vector3& value) -> void {
static Method* method;
if (!this) return;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>("set_up");
if (method) return method->Invoke<void>(this, value);
}
auto GetForward() -> Vector3 {
static Method* method;
if (!this) return {};
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>("get_forward");
if (method) return method->Invoke<Vector3>(this);
return {};
}
auto SetForward(const Vector3& value) -> void {
static Method* method;
if (!this) return;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>("set_forward");
if (method) return method->Invoke<void>(this, value);
}
auto GetRotation() -> Quaternion {
static Method* method;
if (!this) return {};
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>(mode_ == Mode::Mono ? "get_rotation_Injected" : "get_rotation");
if (mode_ == Mode::Mono && method) {
const Quaternion vec3{};
method->Invoke<void>(this, &vec3);
return vec3;
}
if (method) return method->Invoke<Quaternion>(this);
return {};
}
auto SetRotation(const Quaternion& position) -> void {
static Method* method;
if (!this) return;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>(mode_ == Mode::Mono ? "set_rotation_Injected" : "set_rotation");
if (mode_ == Mode::Mono && method) return method->Invoke<void>(this, &position);
if (method) return method->Invoke<void>(this, position);
}
auto GetLocalPosition() -> Vector3 {
static Method* method;
if (!this) return {};
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>(mode_ == Mode::Mono ? "get_localPosition_Injected" : "get_localPosition");
if (mode_ == Mode::Mono && method) {
const Vector3 vec3{};
method->Invoke<void>(this, &vec3);
return vec3;
}
if (method) return method->Invoke<Vector3>(this);
return {};
}
auto SetLocalPosition(const Vector3& position) -> void {
static Method* method;
if (!this) return;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>(mode_ == Mode::Mono ? "set_localPosition_Injected" : "set_localPosition");
if (mode_ == Mode::Mono && method) return method->Invoke<void>(this, &position);
if (method) return method->Invoke<void>(this, position);
}
auto GetLocalRotation() -> Quaternion {
static Method* method;
if (!this) return {};
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>(mode_ == Mode::Mono ? "get_localRotation_Injected" : "get_localRotation");
if (mode_ == Mode::Mono && method) {
const Quaternion vec3{};
method->Invoke<void>(this, &vec3);
return vec3;
}
if (method) return method->Invoke<Quaternion>(this);
return {};
}
auto SetLocalRotation(const Quaternion& position) -> void {
static Method* method;
if (!this) return;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>(mode_ == Mode::Mono ? "set_localRotation_Injected" : "set_localRotation");
if (mode_ == Mode::Mono && method) return method->Invoke<void>(this, &position);
if (method) return method->Invoke<void>(this, position);
}
auto GetLocalScale() -> Vector3 {
static Method* method;
if (!this) return {};
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>(mode_ == Mode::Mono ? "get_localScale_Injected" : "get_localScale");
if (mode_ == Mode::Mono && method) {
const Vector3 vec3{};
method->Invoke<void>(this, &vec3);
return vec3;
}
if (method) return method->Invoke<Vector3>(this);
return {};
}
auto SetLocalScale(const Vector3& position) -> void {
static Method* method;
if (!this) return;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>(mode_ == Mode::Mono ? "set_localScale_Injected" : "set_localScale");
if (mode_ == Mode::Mono && method) return method->Invoke<void>(this, &position);
if (method) return method->Invoke<void>(this, position);
}
auto GetChildCount() -> int {
static Method* method;
if (!this) return 0;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>("get_childCount");
if (method) return method->Invoke<int>(this);
return 0;
}
auto GetChild(const int index) -> Transform* {
static Method* method;
if (!this) return nullptr;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>("GetChild");
if (method) return method->Invoke<Transform*>(this, index);
return nullptr;
}
auto GetRoot() -> Transform* {
static Method* method;
if (!this) return nullptr;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>("GetRoot");
if (method) return method->Invoke<Transform*>(this);
return nullptr;
}
auto GetParent() -> Transform* {
static Method* method;
if (!this) return nullptr;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>("GetParent");
if (method) return method->Invoke<Transform*>(this);
return nullptr;
}
auto GetLossyScale() -> Vector3 {
static Method* method;
if (!this) return {};
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>(mode_ == Mode::Mono ? "get_lossyScale_Injected" : "get_lossyScale");
if (mode_ == Mode::Mono && method) {
const Vector3 vec3{};
method->Invoke<void>(this, &vec3);
return vec3;
}
if (method) return method->Invoke<Vector3>(this);
return {};
}
auto TransformPoint(const Vector3& position) -> Vector3 {
static Method* method;
if (!this) return {};
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>(mode_ == Mode::Mono ? "TransformPoint_Injected" : "TransformPoint");
if (mode_ == Mode::Mono && method) {
const Vector3 vec3{};
method->Invoke<void>(this, position, &vec3);
return vec3;
}
if (method) return method->Invoke<Vector3>(this, position);
return {};
}
auto LookAt(const Vector3& worldPosition) -> void {
static Method* method;
if (!this) return;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>("LookAt", { "Vector3" });
if (method) return method->Invoke<void>(this, worldPosition);
}
auto Rotate(const Vector3& eulers) -> void {
static Method* method;
if (!this) return;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Transform")->Get<Method>("Rotate", { "Vector3" });
if (method) return method->Invoke<void>(this, eulers);
}
};
struct GameObject : UnityObject {
static auto Create(GameObject* obj, const std::string& name) -> void {
if (!obj) return;
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("GameObject")->Get<Method>("Internal_CreateGameObject");
if (method) method->Invoke<void, GameObject*, String*>(obj, String::New(name));
}
static auto FindGameObjectsWithTag(const std::string& name) -> std::vector<GameObject*> {
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("GameObject")->Get<Method>("FindGameObjectsWithTag");
if (method) {
const auto array = method->Invoke<Array<GameObject*>*>(String::New(name));
return array->ToVector();
}
return {};
}
static auto Find(const std::string& name) -> GameObject* {
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("GameObject")->Get<Method>("Find");
if (method) return method->Invoke<GameObject*>(String::New(name));
return nullptr;
}
auto GetActive() -> bool {
static Method* method;
if (!this) return false;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("GameObject")->Get<Method>("get_active");
if (method) return method->Invoke<bool>(this);
return false;
}
auto SetActive(bool value) -> void {
static Method* method;
if (!this) return;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("GameObject")->Get<Method>("set_active");
if (method) return method->Invoke<void>(this, value);
}
auto GetActiveSelf() -> bool {
static Method* method;
if (!this) return false;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("GameObject")->Get<Method>("get_activeSelf");
if (method) return method->Invoke<bool>(this);
return false;
}
auto GetActiveInHierarchy() -> bool {
static Method* method;
if (!this) return false;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("GameObject")->Get<Method>("get_activeInHierarchy");
if (method) return method->Invoke<bool>(this);
return false;
}
auto GetIsStatic() -> bool {
static Method* method;
if (!this) return false;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("GameObject")->Get<Method>("get_isStatic");
if (method) return method->Invoke<bool>(this);
return false;
}
auto GetTransform() -> Transform* {
static Method* method;
if (!this) return nullptr;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("GameObject")->Get<Method>("get_transform");
if (method) return method->Invoke<Transform*>(this);
return nullptr;
}
auto GetTag() -> std::string {
if (!this) return {};
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("GameObject")->Get<Method>("get_tag");
if (method) return method->Invoke<String*>(this)->ToString();
return {};
}
template <typename T>
auto GetComponent() -> T {
if (!this) return T();
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("GameObject")->Get<Method>("GetComponent");
if (method) return method->Invoke<T>(this);
return T();
}
template <typename T>
auto GetComponent(Class* type) -> T {
if (!this) return T();
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("GameObject")->Get<Method>("GetComponent", { "System.Type" });
if (method) return method->Invoke<T>(this, type->GetType());
return T();
}
template <typename T>
auto GetComponentInChildren(Class* type) -> T {
if (!this) return T();
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("GameObject")->Get<Method>("GetComponentInChildren", { "System.Type" });
if (method) return method->Invoke<T>(this, type->GetType());
return T();
}
template <typename T>
auto GetComponentInParent(Class* type) -> T {
if (!this) return T();
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("GameObject")->Get<Method>("GetComponentInParent", { "System.Type" });
if (method) return method->Invoke<T>(this, type->GetType());
return T();
}
template <typename T>
auto GetComponents(Class* type, bool useSearchTypeAsArrayReturnType = false, bool recursive = false, bool includeInactive = true, bool reverse = false, List<T>* resultList = nullptr) -> std::vector<T> {
if (!this) return {};
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("GameObject")->Get<Method>("GetComponentsInternal");
if (method) return method->Invoke<Array<T>*>(this, type->GetType(), useSearchTypeAsArrayReturnType, recursive, includeInactive, reverse, resultList)->ToVector();
return {};
}
template <typename T>
auto GetComponentsInChildren(Class* type, const bool includeInactive = false) -> std::vector<T> { return GetComponents<T>(type, false, true, includeInactive, false, nullptr); }
template <typename T>
auto GetComponentsInParent(Class* type, const bool includeInactive = false) -> std::vector<T> { return GetComponents<T>(type, false, true, includeInactive, true, nullptr); }
};
struct LayerMask : Object {
int m_Mask;
static auto NameToLayer(const std::string& layerName) -> int {
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("LayerMask")->Get<Method>("NameToLayer");
if (method) return method->Invoke<int>(String::New(layerName));
return 0;
}
static auto LayerToName(const int layer) -> std::string {
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("LayerMask")->Get<Method>("LayerToName");
if (method) return method->Invoke<String*>(layer)->ToString();
return {};
}
};
struct Rigidbody : Component {
auto GetDetectCollisions() -> bool {
static Method* method;
if (!method) method = Get("UnityEngine.PhysicsModule.dll")->Get("Rigidbody")->Get<Method>("get_detectCollisions");
if (method) return method->Invoke<bool>(this);
throw std::logic_error("nullptr");
}
auto SetDetectCollisions(const bool value) -> void {
static Method* method;
if (!method) method = Get("UnityEngine.PhysicsModule.dll")->Get("Rigidbody")->Get<Method>("set_detectCollisions");
if (method) return method->Invoke<void>(this, value);
throw std::logic_error("nullptr");
}
auto GetVelocity() -> Vector3 {
static Method* method;
if (!method) method = Get("UnityEngine.PhysicsModule.dll")->Get("Rigidbody")->Get<Method>(mode_ == Mode::Mono ? "get_velocity_Injected" : "get_velocity");
if (mode_ == Mode::Mono && method) {
Vector3 vector;
method->Invoke<void>(this, &vector);
return vector;
}
if (method) return method->Invoke<Vector3>(this);
throw std::logic_error("nullptr");
}
auto SetVelocity(Vector3 value) -> void {
static Method* method;
if (!method) method = Get("UnityEngine.PhysicsModule.dll")->Get("Rigidbody")->Get<Method>(mode_ == Mode::Mono ? "set_velocity_Injected" : "set_velocity");
if (mode_ == Mode::Mono && method) return method->Invoke<void>(this, &value);
if (method) return method->Invoke<void>(this, value);
throw std::logic_error("nullptr");
}
};
struct Collider : Component {
auto GetBounds() -> Bounds {
if (!this) return {};
static Method* method;
if (!method) method = Get("UnityEngine.PhysicsModule.dll")->Get("Collider")->Get<Method>("get_bounds_Injected");
if (method) {
Bounds bounds;
method->Invoke<void>(this, &bounds);
return bounds;
}
return {};
}
};
struct Mesh : UnityObject {
auto GetBounds() -> Bounds {
if (!this) return {};
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Mesh")->Get<Method>("get_bounds_Injected");
if (method) {
Bounds bounds;
method->Invoke<void>(this, &bounds);
return bounds;
}
return {};
}
};
struct CapsuleCollider : Collider {
auto GetCenter() -> Vector3 {
static Method* method;
if (!method) method = Get("UnityEngine.PhysicsModule.dll")->Get("CapsuleCollider")->Get<Method>("get_center");
if (method) return method->Invoke<Vector3>(this);
throw std::logic_error("nullptr");
}
auto GetDirection() -> Vector3 {
static Method* method;
if (!method) method = Get("UnityEngine.PhysicsModule.dll")->Get("CapsuleCollider")->Get<Method>("get_direction");
if (method) return method->Invoke<Vector3>(this);
throw std::logic_error("nullptr");
}
auto GetHeightn() -> Vector3 {
static Method* method;
if (!method) method = Get("UnityEngine.PhysicsModule.dll")->Get("CapsuleCollider")->Get<Method>("get_height");
if (method) return method->Invoke<Vector3>(this);
throw std::logic_error("nullptr");
}
auto GetRadius() -> Vector3 {
static Method* method;
if (!method) method = Get("UnityEngine.PhysicsModule.dll")->Get("CapsuleCollider")->Get<Method>("get_radius");
if (method) return method->Invoke<Vector3>(this);
throw std::logic_error("nullptr");
}
};
struct BoxCollider : Collider {
auto GetCenter() -> Vector3 {
static Method* method;
if (!method) method = Get("UnityEngine.PhysicsModule.dll")->Get("BoxCollider")->Get<Method>("get_center");
if (method) return method->Invoke<Vector3>(this);
throw std::logic_error("nullptr");
}
auto GetSize() -> Vector3 {
static Method* method;
if (!method) method = Get("UnityEngine.PhysicsModule.dll")->Get("BoxCollider")->Get<Method>("get_size");
if (method) return method->Invoke<Vector3>(this);
throw std::logic_error("nullptr");
}
};
struct Renderer : Component {
auto GetBounds() -> Bounds {
if (!this) return {};
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Renderer")->Get<Method>("get_bounds_Injected");
if (method) {
Bounds bounds;
method->Invoke<void>(this, &bounds);
return bounds;
}
return {};
}
};
struct Behaviour : Component {
auto GetEnabled() -> bool {
if (!this) return false;
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Behaviour")->Get<Method>("get_enabled");
if (method) return method->Invoke<bool>(this);
return false;
}
auto SetEnabled(const bool value) -> void {
if (!this) return;
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Behaviour")->Get<Method>("set_enabled");
if (method) return method->Invoke<void>(this, value);
}
};
struct MonoBehaviour : Behaviour {};
struct Physics : Object {
static auto Linecast(const Vector3& start, const Vector3& end) -> bool {
static Method* method;
if (!method) method = Get("UnityEngine.PhysicsModule.dll")->Get("Physics")->Get<Method>("Linecast", { "*", "*" });
if (method) return method->Invoke<bool>(start, end);
return false;
}
static auto Raycast(const Vector3& origin, const Vector3& direction, const float maxDistance) -> bool {
static Method* method;
if (!method) method = Get("UnityEngine.PhysicsModule.dll")->Get("Physics")->Get<Method>("Raycast", { "*", "*", "*" });
if (method) return method->Invoke<bool>(origin, direction, maxDistance);
return false;
}
static auto IgnoreCollision(Collider* collider1, Collider* collider2) -> void {
static Method* method;
if (!method) method = Get("UnityEngine.PhysicsModule.dll")->Get("Physics")->Get<Method>("IgnoreCollision1", { "*", "*" });
if (method) return method->Invoke<void>(collider1, collider2);
}
};
struct Time {
static auto GetTime() -> float {
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Time")->Get<Method>("get_time");
if (method) return method->Invoke<float>();
return 0.0f;
}
static auto GetDeltaTime() -> float {
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Time")->Get<Method>("get_deltaTime");
if (method) return method->Invoke<float>();
return 0.0f;
}
static auto GetFixedDeltaTime() -> float {
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Time")->Get<Method>("get_fixedDeltaTime");
if (method) return method->Invoke<float>();
return 0.0f;
}
static auto GetTimeScale() -> float {
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Time")->Get<Method>("get_timeScale");
if (method) return method->Invoke<float>();
return 0.0f;
}
static auto SetTimeScale(float value) -> void {
static Method* method;
if (!method) method = Get("UnityEngine.CoreModule.dll")->Get("Time")->Get<Method>("set_timeScale");
if (method) return method->Invoke<void>(value);
}
};
struct Animator : Behaviour {
enum class HumanBodyBones : int {
Hips,
LeftUpperLeg,
RightUpperLeg,
LeftLowerLeg,
RightLowerLeg,
LeftFoot,
RightFoot,
Spine,
Chest,
UpperChest = 54,
Neck = 9,
Head,
LeftShoulder,
RightShoulder,
LeftUpperArm,
RightUpperArm,
LeftLowerArm,
RightLowerArm,
LeftHand,
RightHand,
LeftToes,
RightToes,
LeftEye,
RightEye,
Jaw,
LeftThumbProximal,
LeftThumbIntermediate,
LeftThumbDistal,
LeftIndexProximal,
LeftIndexIntermediate,
LeftIndexDistal,
LeftMiddleProximal,
LeftMiddleIntermediate,
LeftMiddleDistal,
LeftRingProximal,
LeftRingIntermediate,
LeftRingDistal,
LeftLittleProximal,
LeftLittleIntermediate,
LeftLittleDistal,
RightThumbProximal,
RightThumbIntermediate,
RightThumbDistal,
RightIndexProximal,
RightIndexIntermediate,
RightIndexDistal,
RightMiddleProximal,
RightMiddleIntermediate,
RightMiddleDistal,
RightRingProximal,
RightRingIntermediate,
RightRingDistal,
RightLittleProximal,
RightLittleIntermediate,
RightLittleDistal,
LastBone = 55
};
auto GetBoneTransform(const HumanBodyBones humanBoneId) -> Transform* {
#if WINDOWS_MODE
if (IsBadReadPtr(this, sizeof(Animator))) return nullptr;
#endif
static Method* method;
if (!this) return nullptr;
if (!method) method = Get("UnityEngine.AnimationModule.dll")->Get("Animator")->Get<Method>("GetBoneTransform");
if (method) return method->Invoke<Transform*>(this, humanBoneId);
return nullptr;
}
};
template <typename Return, typename... Args>
static auto Invoke(const void* address, Args... args) -> Return {
#if WINDOWS_MODE
try {
bool badPtr;
if (!badPtr) badPtr = !IsBadCodePtr(FARPROC(address));
if (address != nullptr && badPtr) return reinterpret_cast<Return(*)(Args...)>(address)(args...);
}
catch (...) {}
#elif LINUX_MODE || ANDROID_MODE
try {
if (address != nullptr) return reinterpret_cast<Return(*)(Args...)>(address)(args...);
}
catch (...) {}
#endif
return Return();
}
};
private:
inline static Mode mode_{};
inline static void* hmodule_;
inline static bool lazyInit_;
inline static std::unordered_map<std::string, void*> address_{};
inline static void* pDomain{};
};
#endif // UNITYRESOLVE_HPP