From 77fc61d9da721ea0801cbcb5b2b79b3a086bbcbb Mon Sep 17 00:00:00 2001 From: chinosk <2248589280@qq.com> Date: Fri, 5 Jul 2024 20:34:46 +0800 Subject: [PATCH] add lazy initializing --- app/src/main/cpp/GakumasLocalify/Hook.cpp | 26 ++++++++- .../cpp/GakumasLocalify/config/Config.cpp | 2 + .../cpp/GakumasLocalify/config/Config.hpp | 1 + .../cpp/deps/UnityResolve/UnityResolve.hpp | 56 ++++++++++++++++--- .../gakumas/localify/ConfigUpdateListener.kt | 6 ++ .../gakumas/localify/models/GakumasConfig.kt | 1 + .../localify/ui/game_attach/InitProgressUI.kt | 2 +- .../localify/ui/pages/subPages/HomePage.kt | 5 ++ app/src/main/res/values-zh-rCN/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 10 files changed, 89 insertions(+), 12 deletions(-) diff --git a/app/src/main/cpp/GakumasLocalify/Hook.cpp b/app/src/main/cpp/GakumasLocalify/Hook.cpp index 5694fb6..688babc 100644 --- a/app/src/main/cpp/GakumasLocalify/Hook.cpp +++ b/app/src/main/cpp/GakumasLocalify/Hook.cpp @@ -39,7 +39,8 @@ std::unordered_set hookedStubs{}; GakumasLocal::Log::InfoFmt("ADD_HOOK: %s at %p", #name, addr); \ } \ } \ - else GakumasLocal::Log::ErrorFmt("Hook failed: %s is NULL", #name, addr) + else GakumasLocal::Log::ErrorFmt("Hook failed: %s is NULL", #name, addr); \ + if (Config::lazyInit) UnityResolveProgress::classProgress.current++ void UnHookAll() { for (const auto i: hookedStubs) { @@ -827,7 +828,8 @@ namespace GakumasLocal::HookMain { void StartInjectFunctions() { const auto hookInstaller = Plugin::GetInstance().GetHookInstaller(); - UnityResolve::Init(xdl_open(hookInstaller->m_il2cppLibraryPath.c_str(), RTLD_NOW), UnityResolve::Mode::Il2Cpp); + UnityResolve::Init(xdl_open(hookInstaller->m_il2cppLibraryPath.c_str(), RTLD_NOW), + UnityResolve::Mode::Il2Cpp, Config::lazyInit); ADD_HOOK(AssetBundle_LoadAssetAsync, Il2cppUtils::il2cpp_resolve_icall( "UnityEngine.AssetBundle::LoadAssetAsync_Internal(System.String,System.Type)")); @@ -959,10 +961,30 @@ namespace GakumasLocal::HookMain { Log::Info("Start init plugin..."); + if (Config::lazyInit) { + UnityResolveProgress::startInit = true; + UnityResolveProgress::assembliesProgress.total = 2; + UnityResolveProgress::assembliesProgress.current = 1; + UnityResolveProgress::classProgress.total = 36; + UnityResolveProgress::classProgress.current = 0; + } + StartInjectFunctions(); GKCamera::initCameraSettings(); + + if (Config::lazyInit) { + UnityResolveProgress::assembliesProgress.current = 2; + UnityResolveProgress::classProgress.total = 1; + UnityResolveProgress::classProgress.current = 0; + } + Local::LoadData(); + if (Config::lazyInit) { + UnityResolveProgress::classProgress.current = 1; + UnityResolveProgress::startInit = false; + } + Log::Info("Plugin init finished."); return ret; } diff --git a/app/src/main/cpp/GakumasLocalify/config/Config.cpp b/app/src/main/cpp/GakumasLocalify/config/Config.cpp index dae0fcd..2493565 100644 --- a/app/src/main/cpp/GakumasLocalify/config/Config.cpp +++ b/app/src/main/cpp/GakumasLocalify/config/Config.cpp @@ -7,6 +7,7 @@ namespace GakumasLocal::Config { bool dbgMode = false; bool enabled = true; + bool lazyInit = true; bool replaceFont = true; bool forceExportResource = true; bool textTest = false; @@ -55,6 +56,7 @@ namespace GakumasLocal::Config { GetConfigItem(dbgMode); GetConfigItem(enabled); + GetConfigItem(lazyInit); GetConfigItem(replaceFont); GetConfigItem(forceExportResource); GetConfigItem(gameOrientation); diff --git a/app/src/main/cpp/GakumasLocalify/config/Config.hpp b/app/src/main/cpp/GakumasLocalify/config/Config.hpp index 38aaa64..cba35b4 100644 --- a/app/src/main/cpp/GakumasLocalify/config/Config.hpp +++ b/app/src/main/cpp/GakumasLocalify/config/Config.hpp @@ -5,6 +5,7 @@ namespace GakumasLocal::Config { extern bool dbgMode; extern bool enabled; + extern bool lazyInit; extern bool replaceFont; extern bool forceExportResource; extern int gameOrientation; diff --git a/app/src/main/cpp/deps/UnityResolve/UnityResolve.hpp b/app/src/main/cpp/deps/UnityResolve/UnityResolve.hpp index 4ca2d48..c2f24ac 100644 --- a/app/src/main/cpp/deps/UnityResolve/UnityResolve.hpp +++ b/app/src/main/cpp/deps/UnityResolve/UnityResolve.hpp @@ -81,8 +81,16 @@ public: [[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("il2cpp_assembly_get_image", address); + ForeachClass(const_cast(this), image); + }*/ for (const auto pClass : classes) if (strClass == pClass->name && (strNamespace == "*" || pClass->namespaze == strNamespace) && (strParent == "*" || pClass->parent == strParent)) return pClass; - return nullptr; + if (lazyInit_) { + return FillClass_Il2ccpp(const_cast(this), strNamespace.c_str(), strClass.c_str()); + } + return nullptr; } }; @@ -291,16 +299,17 @@ public: } } - static auto Init(void* hmodule, const Mode mode = Mode::Mono) -> void { + 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) { - UnityResolveProgress::startInit = true; + if (!lazyInit) UnityResolveProgress::startInit = true; pDomain = Invoke("il2cpp_domain_get"); Invoke("il2cpp_thread_attach", pDomain); ForeachAssembly(); - UnityResolveProgress::startInit = false; + if (!lazyInit) UnityResolveProgress::startInit = false; } else { pDomain = Invoke("mono_get_root_domain"); @@ -576,10 +585,10 @@ private: size_t nrofassemblies = 0; const auto assemblies = Invoke("il2cpp_domain_get_assemblies", pDomain, &nrofassemblies); - UnityResolveProgress::assembliesProgress.total = nrofassemblies; + if (!lazyInit_) UnityResolveProgress::assembliesProgress.total = nrofassemblies; for (auto i = 0; i < nrofassemblies; i++) { - UnityResolveProgress::assembliesProgress.current = i + 1; + if (!lazyInit_) UnityResolveProgress::assembliesProgress.current = i + 1; const auto ptr = assemblies[i]; if (ptr == nullptr) continue; auto assembly = new Assembly{ .address = ptr }; @@ -587,7 +596,9 @@ private: assembly->file = Invoke("il2cpp_image_get_filename", image); assembly->name = Invoke("il2cpp_image_get_name", image); UnityResolve::assembly.push_back(assembly); - ForeachClass(assembly, image); + if (!lazyInit_) { + ForeachClass(assembly, image); + } } } else { @@ -608,13 +619,39 @@ private: } } + static auto FillClass_Il2ccpp(Assembly* assembly, const char* namespaze, const char* klassName) -> Class* { + auto image = Invoke("il2cpp_assembly_get_image", assembly->address); + const auto pClass = Invoke("il2cpp_class_from_name", image, namespaze, klassName); + if (pClass == nullptr) return nullptr; + const auto pAClass = new Class(); + pAClass->address = pClass; + pAClass->name = Invoke("il2cpp_class_get_name", pClass); + if (const auto pPClass = Invoke("il2cpp_class_get_parent", pClass)) pAClass->parent = Invoke("il2cpp_class_get_name", pPClass); + // pAClass->namespaze = Invoke("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("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("il2cpp_image_get_class_count", image); - UnityResolveProgress::classProgress.total = count; + if (!lazyInit_) UnityResolveProgress::classProgress.total = count; for (auto i = 0; i < count; i++) { - UnityResolveProgress::classProgress.current = i + 1; + if (!lazyInit_) UnityResolveProgress::classProgress.current = i + 1; const auto pClass = Invoke("il2cpp_image_get_class", image, i); if (pClass == nullptr) continue; const auto pAClass = new Class(); @@ -2606,6 +2643,7 @@ public: private: inline static Mode mode_{}; inline static void* hmodule_; + inline static bool lazyInit_; inline static std::unordered_map address_{}; inline static void* pDomain{}; }; diff --git a/app/src/main/java/io/github/chinosk/gakumas/localify/ConfigUpdateListener.kt b/app/src/main/java/io/github/chinosk/gakumas/localify/ConfigUpdateListener.kt index b7117b4..1281bfe 100644 --- a/app/src/main/java/io/github/chinosk/gakumas/localify/ConfigUpdateListener.kt +++ b/app/src/main/java/io/github/chinosk/gakumas/localify/ConfigUpdateListener.kt @@ -17,6 +17,7 @@ interface ConfigListener { fun onForceExportResourceChanged(value: Boolean) fun onTextTestChanged(value: Boolean) fun onReplaceFontChanged(value: Boolean) + fun onLazyInitChanged(value: Boolean) fun onEnableFreeCameraChanged(value: Boolean) fun onTargetFpsChanged(s: CharSequence, start: Int, before: Int, count: Int) fun onUnlockAllLiveChanged(value: Boolean) @@ -111,6 +112,11 @@ interface ConfigUpdateListener: ConfigListener, IHasConfigItems { pushKeyEvent(KeyEvent(1145, 30)) } + override fun onLazyInitChanged(value: Boolean) { + config.lazyInit = value + saveConfig() + } + override fun onTextTestChanged(value: Boolean) { config.textTest = value saveConfig() diff --git a/app/src/main/java/io/github/chinosk/gakumas/localify/models/GakumasConfig.kt b/app/src/main/java/io/github/chinosk/gakumas/localify/models/GakumasConfig.kt index cff65cf..3f206bc 100644 --- a/app/src/main/java/io/github/chinosk/gakumas/localify/models/GakumasConfig.kt +++ b/app/src/main/java/io/github/chinosk/gakumas/localify/models/GakumasConfig.kt @@ -6,6 +6,7 @@ import kotlinx.serialization.Serializable data class GakumasConfig ( var dbgMode: Boolean = false, var enabled: Boolean = true, + var lazyInit: Boolean = true, var replaceFont: Boolean = true, var textTest: Boolean = false, var dumpText: Boolean = false, diff --git a/app/src/main/java/io/github/chinosk/gakumas/localify/ui/game_attach/InitProgressUI.kt b/app/src/main/java/io/github/chinosk/gakumas/localify/ui/game_attach/InitProgressUI.kt index 8ba00d4..e96d328 100644 --- a/app/src/main/java/io/github/chinosk/gakumas/localify/ui/game_attach/InitProgressUI.kt +++ b/app/src/main/java/io/github/chinosk/gakumas/localify/ui/game_attach/InitProgressUI.kt @@ -96,7 +96,7 @@ class InitProgressUI { gravity = Gravity.CENTER_HORIZONTAL } setTextColor(Color.BLACK) - text = "Initializing Plugins" + text = "Initializing" textSize = 20f setTypeface(typeface, Typeface.BOLD) } diff --git a/app/src/main/java/io/github/chinosk/gakumas/localify/ui/pages/subPages/HomePage.kt b/app/src/main/java/io/github/chinosk/gakumas/localify/ui/pages/subPages/HomePage.kt index 8abde41..aa978d9 100644 --- a/app/src/main/java/io/github/chinosk/gakumas/localify/ui/pages/subPages/HomePage.kt +++ b/app/src/main/java/io/github/chinosk/gakumas/localify/ui/pages/subPages/HomePage.kt @@ -141,9 +141,14 @@ fun HomePage(modifier: Modifier = Modifier, v -> context?.onEnabledChanged(v) } + GakuSwitch(modifier, stringResource(R.string.lazy_init), checked = config.value.lazyInit) { + v -> context?.onLazyInitChanged(v) + } + GakuSwitch(modifier, stringResource(R.string.replace_font), checked = config.value.replaceFont) { v -> context?.onReplaceFontChanged(v) } + } } Spacer(Modifier.height(6.dp)) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index f53086c..7976009 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -3,6 +3,7 @@ Gakumas Localify 启用插件 (不可热重载) 替换字体 + 快速初始化(懒加载配置) 启用自由视角(可热重载; 需使用实体键盘) 以上述配置启动游戏/重载配置 最大 FPS (0 为保持游戏原设置) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 49e079e..c79f892 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3,6 +3,7 @@ Gakumas Localify Enable Plugin (Not Hot Reloadable) Replace Font + Fast Initialization (Lazy loading) Enable Free Camera Start Game / Hot Reload Config Max FPS (0 is Use Original Settings)