Compare commits
	
		
			12 Commits
		
	
	
		
			main
			...
			feature-in
		
	
	| Author | SHA1 | Date | 
|---|---|---|
| 
							
							
								
								 | 
						af7a9ad0ec | |
| 
							
							
								
								 | 
						b5e4de0f65 | |
| 
							
							
								
								 | 
						ebeb51b8f8 | |
| 
							
							
								
								 | 
						1a77936237 | |
| 
							
							
								
								 | 
						76730b68ab | |
| 
							
							
								
								 | 
						1e28dee5e2 | |
| 
							
							
								
								 | 
						b55074d840 | |
| 
							
							
								
								 | 
						1905a75b0e | |
| 
							
							
								
								 | 
						2c5a10262a | |
| 
							
							
								
								 | 
						573bfb870a | |
| 
							
							
								
								 | 
						77fc61d9da | |
| 
							
							
								
								 | 
						c810a27ba2 | 
| 
						 | 
					@ -12,21 +12,22 @@ jobs:
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        submodules: recursive
 | 
					        submodules: recursive
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: set up android development environment
 | 
					 | 
				
			||||||
      uses: android-actions/setup-android@v2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    - name: install dependencies
 | 
					 | 
				
			||||||
      run: |
 | 
					 | 
				
			||||||
        sdkmanager --install "cmake;3.22.1"
 | 
					 | 
				
			||||||
        echo "cmake.dir=/usr/local/lib/android/sdk/cmake/3.22.1" > local.properties
 | 
					 | 
				
			||||||
        npm install -g pnpm
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    - name: Setup Java JDK
 | 
					    - name: Setup Java JDK
 | 
				
			||||||
      uses: actions/setup-java@v4.2.1
 | 
					      uses: actions/setup-java@v4.2.1
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        distribution: 'temurin'
 | 
					        distribution: 'temurin'
 | 
				
			||||||
        java-version: '21'
 | 
					        java-version: '21'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: Setup Android Development Environment
 | 
				
			||||||
 | 
					      uses: android-actions/setup-android@v3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: install dependencies
 | 
				
			||||||
 | 
					      run: |
 | 
				
			||||||
 | 
					        sdkmanager --install "cmake;3.22.1"
 | 
				
			||||||
 | 
					        echo "cmake.dir=$ANDROID_HOME/cmake/3.22.1" > local.properties
 | 
				
			||||||
 | 
					        echo "$ANDROID_HOME/build-tools/34.0.0" >> $GITHUB_PATH
 | 
				
			||||||
 | 
					        npm install -g pnpm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: Update Submodules
 | 
					    - name: Update Submodules
 | 
				
			||||||
      run: |
 | 
					      run: |
 | 
				
			||||||
        git submodule foreach --recursive 'git pull --rebase origin main --allow-unrelated-histories'
 | 
					        git submodule foreach --recursive 'git pull --rebase origin main --allow-unrelated-histories'
 | 
				
			||||||
| 
						 | 
					@ -58,24 +59,44 @@ jobs:
 | 
				
			||||||
      run: ./gradlew build
 | 
					      run: ./gradlew build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - uses: actions/upload-artifact@v4
 | 
					    - uses: actions/upload-artifact@v4
 | 
				
			||||||
 | 
					      id: upload_unsigned_v4
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        name: GakumasLocalify-Unsigned-apk
 | 
					        name: GakumasLocalify-Unsigned-apk
 | 
				
			||||||
        path: app/build/outputs/apk/debug/app-debug.apk
 | 
					        path: app/build/outputs/apk/debug/app-debug.apk
 | 
				
			||||||
 | 
					      continue-on-error: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - uses: ilharp/sign-android-release@v1
 | 
					    - name: Upload Unsigned APK with v3 if v4 failed
 | 
				
			||||||
 | 
					      if: steps.upload_unsigned_v4.outcome == 'failure'
 | 
				
			||||||
 | 
					      uses: actions/upload-artifact@v3
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        name: GakumasLocalify-Unsigned-apk
 | 
				
			||||||
 | 
					        path: app/build/outputs/apk/debug/app-debug.apk
 | 
				
			||||||
 | 
					      continue-on-error: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - uses: r0adkll/sign-android-release@v1
 | 
				
			||||||
      name: Sign app APK
 | 
					      name: Sign app APK
 | 
				
			||||||
      id: sign_app
 | 
					      id: sign_app
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        releaseDir: app/build/outputs/apk/debug
 | 
					        releaseDirectory: app/build/outputs/apk/debug
 | 
				
			||||||
        signingKey: ${{ secrets.KEYSTOREB64 }}
 | 
					        signingKeyBase64: ${{ secrets.KEYSTOREB64 }}
 | 
				
			||||||
        keyAlias: ${{ secrets.ANDROID_KEY_ALIAS }}
 | 
					        alias: ${{ secrets.ANDROID_KEY_ALIAS }}
 | 
				
			||||||
        keyStorePassword: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
 | 
					        keyStorePassword: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
 | 
				
			||||||
        keyPassword: ${{ secrets.ANDROID_KEY_PASSWORD }}
 | 
					        keyPassword: ${{ secrets.ANDROID_KEY_PASSWORD }}
 | 
				
			||||||
        buildToolsVersion: 33.0.0
 | 
					      env:
 | 
				
			||||||
 | 
					        BUILD_TOOLS_VERSION: "34.0.0"
 | 
				
			||||||
      continue-on-error: true
 | 
					      continue-on-error: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - uses: actions/upload-artifact@v4
 | 
					    - uses: actions/upload-artifact@v4
 | 
				
			||||||
 | 
					      id: upload_signed_v4
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        name: GakumasLocalify-Signed-apk
 | 
					        name: GakumasLocalify-Signed-apk
 | 
				
			||||||
        path: ${{steps.sign_app.outputs.signedFile}}
 | 
					        path: ${{steps.sign_app.outputs.signedReleaseFile}}
 | 
				
			||||||
 | 
					      continue-on-error: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: Upload Signed APK with v3 if v4 failed
 | 
				
			||||||
 | 
					      if: steps.upload_signed_v4.outcome == 'failure'
 | 
				
			||||||
 | 
					      uses: actions/upload-artifact@v3
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        name: GakumasLocalify-Signed-apk
 | 
				
			||||||
 | 
					        path: ${{steps.sign_app.outputs.signedReleaseFile}}
 | 
				
			||||||
      continue-on-error: true
 | 
					      continue-on-error: true
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,7 +39,8 @@ std::unordered_set<void*> hookedStubs{};
 | 
				
			||||||
            GakumasLocal::Log::InfoFmt("ADD_HOOK: %s at %p", #name, addr);                         \
 | 
					            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() {
 | 
					void UnHookAll() {
 | 
				
			||||||
    for (const auto i: hookedStubs) {
 | 
					    for (const auto i: hookedStubs) {
 | 
				
			||||||
| 
						 | 
					@ -97,7 +98,7 @@ namespace GakumasLocal::HookMain {
 | 
				
			||||||
    UnityResolve::UnityType::Transform* cameraTransformCache = nullptr;
 | 
					    UnityResolve::UnityType::Transform* cameraTransformCache = nullptr;
 | 
				
			||||||
    void CheckAndUpdateMainCamera() {
 | 
					    void CheckAndUpdateMainCamera() {
 | 
				
			||||||
        if (!Config::enableFreeCamera) return;
 | 
					        if (!Config::enableFreeCamera) return;
 | 
				
			||||||
        if (IsNativeObjectAlive(mainCameraCache)) return;
 | 
					        if (IsNativeObjectAlive(mainCameraCache) && IsNativeObjectAlive(cameraTransformCache)) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        mainCameraCache = UnityResolve::UnityType::Camera::GetMain();
 | 
					        mainCameraCache = UnityResolve::UnityType::Camera::GetMain();
 | 
				
			||||||
        cameraTransformCache = mainCameraCache->GetTransform();
 | 
					        cameraTransformCache = mainCameraCache->GetTransform();
 | 
				
			||||||
| 
						 | 
					@ -827,7 +828,8 @@ namespace GakumasLocal::HookMain {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void StartInjectFunctions() {
 | 
					    void StartInjectFunctions() {
 | 
				
			||||||
        const auto hookInstaller = Plugin::GetInstance().GetHookInstaller();
 | 
					        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(
 | 
					        ADD_HOOK(AssetBundle_LoadAssetAsync, Il2cppUtils::il2cpp_resolve_icall(
 | 
				
			||||||
                "UnityEngine.AssetBundle::LoadAssetAsync_Internal(System.String,System.Type)"));
 | 
					                "UnityEngine.AssetBundle::LoadAssetAsync_Internal(System.String,System.Type)"));
 | 
				
			||||||
| 
						 | 
					@ -959,10 +961,30 @@ namespace GakumasLocal::HookMain {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Log::Info("Start init plugin...");
 | 
					        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();
 | 
					        StartInjectFunctions();
 | 
				
			||||||
        GKCamera::initCameraSettings();
 | 
					        GKCamera::initCameraSettings();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (Config::lazyInit) {
 | 
				
			||||||
 | 
					            UnityResolveProgress::assembliesProgress.current = 2;
 | 
				
			||||||
 | 
					            UnityResolveProgress::classProgress.total = 1;
 | 
				
			||||||
 | 
					            UnityResolveProgress::classProgress.current = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Local::LoadData();
 | 
					        Local::LoadData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (Config::lazyInit) {
 | 
				
			||||||
 | 
					            UnityResolveProgress::classProgress.current = 1;
 | 
				
			||||||
 | 
					            UnityResolveProgress::startInit = false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Log::Info("Plugin init finished.");
 | 
					        Log::Info("Plugin init finished.");
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,7 @@ namespace GakumasLocal::Config {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool dbgMode = false;
 | 
					    bool dbgMode = false;
 | 
				
			||||||
    bool enabled = true;
 | 
					    bool enabled = true;
 | 
				
			||||||
 | 
					    bool lazyInit = true;
 | 
				
			||||||
    bool replaceFont = true;
 | 
					    bool replaceFont = true;
 | 
				
			||||||
    bool forceExportResource = true;
 | 
					    bool forceExportResource = true;
 | 
				
			||||||
    bool textTest = false;
 | 
					    bool textTest = false;
 | 
				
			||||||
| 
						 | 
					@ -55,6 +56,7 @@ namespace GakumasLocal::Config {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            GetConfigItem(dbgMode);
 | 
					            GetConfigItem(dbgMode);
 | 
				
			||||||
            GetConfigItem(enabled);
 | 
					            GetConfigItem(enabled);
 | 
				
			||||||
 | 
					            GetConfigItem(lazyInit);
 | 
				
			||||||
            GetConfigItem(replaceFont);
 | 
					            GetConfigItem(replaceFont);
 | 
				
			||||||
            GetConfigItem(forceExportResource);
 | 
					            GetConfigItem(forceExportResource);
 | 
				
			||||||
            GetConfigItem(gameOrientation);
 | 
					            GetConfigItem(gameOrientation);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@ namespace GakumasLocal::Config {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    extern bool dbgMode;
 | 
					    extern bool dbgMode;
 | 
				
			||||||
    extern bool enabled;
 | 
					    extern bool enabled;
 | 
				
			||||||
 | 
					    extern bool lazyInit;
 | 
				
			||||||
    extern bool replaceFont;
 | 
					    extern bool replaceFont;
 | 
				
			||||||
    extern bool forceExportResource;
 | 
					    extern bool forceExportResource;
 | 
				
			||||||
    extern int gameOrientation;
 | 
					    extern int gameOrientation;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,6 +47,18 @@
 | 
				
			||||||
#include "../../GakumasLocalify/Log.h"
 | 
					#include "../../GakumasLocalify/Log.h"
 | 
				
			||||||
#include "../../GakumasLocalify/Misc.hpp"
 | 
					#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 {
 | 
					class UnityResolve final {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	struct Assembly;
 | 
						struct Assembly;
 | 
				
			||||||
| 
						 | 
					@ -69,7 +81,15 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		[[nodiscard]] auto Get(const std::string& strClass, const std::string& strNamespace = "*", const std::string& strParent = "*") const -> Class* {
 | 
							[[nodiscard]] auto Get(const std::string& strClass, const std::string& strNamespace = "*", const std::string& strParent = "*") const -> Class* {
 | 
				
			||||||
			if (!this) return nullptr;
 | 
								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;
 | 
								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;
 | 
					            return nullptr;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
| 
						 | 
					@ -279,14 +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;
 | 
							mode_ = mode;
 | 
				
			||||||
		hmodule_ = hmodule;
 | 
							hmodule_ = hmodule;
 | 
				
			||||||
 | 
					        lazyInit_ = lazyInit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (mode_ == Mode::Il2Cpp) {
 | 
							if (mode_ == Mode::Il2Cpp) {
 | 
				
			||||||
 | 
					            if (!lazyInit) UnityResolveProgress::startInit = true;
 | 
				
			||||||
			pDomain = Invoke<void*>("il2cpp_domain_get");
 | 
								pDomain = Invoke<void*>("il2cpp_domain_get");
 | 
				
			||||||
			Invoke<void*>("il2cpp_thread_attach", pDomain);
 | 
								Invoke<void*>("il2cpp_thread_attach", pDomain);
 | 
				
			||||||
			ForeachAssembly();
 | 
								ForeachAssembly();
 | 
				
			||||||
 | 
					            if (!lazyInit) UnityResolveProgress::startInit = false;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else {
 | 
							else {
 | 
				
			||||||
			pDomain = Invoke<void*>("mono_get_root_domain");
 | 
								pDomain = Invoke<void*>("mono_get_root_domain");
 | 
				
			||||||
| 
						 | 
					@ -561,7 +584,11 @@ private:
 | 
				
			||||||
		if (mode_ == Mode::Il2Cpp) {
 | 
							if (mode_ == Mode::Il2Cpp) {
 | 
				
			||||||
			size_t     nrofassemblies = 0;
 | 
								size_t     nrofassemblies = 0;
 | 
				
			||||||
			const auto assemblies = Invoke<void**>("il2cpp_domain_get_assemblies", pDomain, &nrofassemblies);
 | 
								const auto assemblies = Invoke<void**>("il2cpp_domain_get_assemblies", pDomain, &nrofassemblies);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!lazyInit_) UnityResolveProgress::assembliesProgress.total = nrofassemblies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for (auto i = 0; i < nrofassemblies; i++) {
 | 
								for (auto i = 0; i < nrofassemblies; i++) {
 | 
				
			||||||
 | 
					                if (!lazyInit_) UnityResolveProgress::assembliesProgress.current = i + 1;
 | 
				
			||||||
				const auto ptr = assemblies[i];
 | 
									const auto ptr = assemblies[i];
 | 
				
			||||||
				if (ptr == nullptr) continue;
 | 
									if (ptr == nullptr) continue;
 | 
				
			||||||
				auto       assembly = new Assembly{ .address = ptr };
 | 
									auto       assembly = new Assembly{ .address = ptr };
 | 
				
			||||||
| 
						 | 
					@ -569,9 +596,11 @@ private:
 | 
				
			||||||
				assembly->file = Invoke<const char*>("il2cpp_image_get_filename", image);
 | 
									assembly->file = Invoke<const char*>("il2cpp_image_get_filename", image);
 | 
				
			||||||
				assembly->name = Invoke<const char*>("il2cpp_image_get_name", image);
 | 
									assembly->name = Invoke<const char*>("il2cpp_image_get_name", image);
 | 
				
			||||||
				UnityResolve::assembly.push_back(assembly);
 | 
									UnityResolve::assembly.push_back(assembly);
 | 
				
			||||||
 | 
					                if (!lazyInit_) {
 | 
				
			||||||
                    ForeachClass(assembly, image);
 | 
					                    ForeachClass(assembly, image);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		else {
 | 
							else {
 | 
				
			||||||
			Invoke<void*, void(*)(void* ptr, std::vector<Assembly*>&), std::vector<Assembly*>&>("mono_assembly_foreach",
 | 
								Invoke<void*, void(*)(void* ptr, std::vector<Assembly*>&), std::vector<Assembly*>&>("mono_assembly_foreach",
 | 
				
			||||||
				[](void* ptr, std::vector<Assembly*>& v) {
 | 
									[](void* ptr, std::vector<Assembly*>& v) {
 | 
				
			||||||
| 
						 | 
					@ -590,11 +619,60 @@ private:
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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 {
 | 
						static auto ForeachClass(Assembly* assembly, void* image) -> void {
 | 
				
			||||||
		// 遍历类
 | 
							// 遍历类
 | 
				
			||||||
		if (mode_ == Mode::Il2Cpp) {
 | 
							if (mode_ == Mode::Il2Cpp) {
 | 
				
			||||||
			const auto count = Invoke<int>("il2cpp_image_get_class_count", image);
 | 
								const auto count = Invoke<int>("il2cpp_image_get_class_count", image);
 | 
				
			||||||
 | 
					            if (!lazyInit_) UnityResolveProgress::classProgress.total = count;
 | 
				
			||||||
			for (auto i = 0; i < count; i++) {
 | 
								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);
 | 
									const auto pClass = Invoke<void*>("il2cpp_image_get_class", image, i);
 | 
				
			||||||
				if (pClass == nullptr) continue;
 | 
									if (pClass == nullptr) continue;
 | 
				
			||||||
				const auto pAClass = new Class();
 | 
									const auto pAClass = new Class();
 | 
				
			||||||
| 
						 | 
					@ -2586,6 +2664,7 @@ public:
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	inline static Mode                                   mode_{};
 | 
						inline static Mode                                   mode_{};
 | 
				
			||||||
	inline static void* hmodule_;
 | 
						inline static void* hmodule_;
 | 
				
			||||||
 | 
						inline static bool lazyInit_;
 | 
				
			||||||
	inline static std::unordered_map<std::string, void*> address_{};
 | 
						inline static std::unordered_map<std::string, void*> address_{};
 | 
				
			||||||
	inline static void* pDomain{};
 | 
						inline static void* pDomain{};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,10 @@ JavaVM* g_javaVM = nullptr;
 | 
				
			||||||
jclass g_gakumasHookMainClass = nullptr;
 | 
					jclass g_gakumasHookMainClass = nullptr;
 | 
				
			||||||
jmethodID showToastMethodId = nullptr;
 | 
					jmethodID showToastMethodId = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool UnityResolveProgress::startInit = false;
 | 
				
			||||||
 | 
					UnityResolveProgress::Progress UnityResolveProgress::assembliesProgress{};
 | 
				
			||||||
 | 
					UnityResolveProgress::Progress UnityResolveProgress::classProgress{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace
 | 
					namespace
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    class AndroidHookInstaller : public GakumasLocal::HookInstaller
 | 
					    class AndroidHookInstaller : public GakumasLocal::HookInstaller
 | 
				
			||||||
| 
						 | 
					@ -114,8 +118,37 @@ Java_io_github_chinosk_gakumas_localify_GakumasHookMain_loadConfig(JNIEnv *env,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern "C"
 | 
					extern "C"
 | 
				
			||||||
JNIEXPORT void JNICALL
 | 
					JNIEXPORT jint JNICALL
 | 
				
			||||||
Java_io_github_chinosk_gakumas_localify_GakumasHookMain_pluginCallbackLooper(JNIEnv *env,
 | 
					Java_io_github_chinosk_gakumas_localify_GakumasHookMain_pluginCallbackLooper(JNIEnv *env,
 | 
				
			||||||
                                                                             jclass clazz) {
 | 
					                                                                             jclass clazz) {
 | 
				
			||||||
    GakumasLocal::Log::ToastLoop(env, clazz);
 | 
					    GakumasLocal::Log::ToastLoop(env, clazz);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (UnityResolveProgress::startInit) {
 | 
				
			||||||
 | 
					        return 9;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C"
 | 
				
			||||||
 | 
					JNIEXPORT void JNICALL
 | 
				
			||||||
 | 
					Java_io_github_chinosk_gakumas_localify_models_NativeInitProgress_pluginInitProgressLooper(
 | 
				
			||||||
 | 
					        JNIEnv *env, jclass clazz, jobject progress) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // jclass progressClass = env->GetObjectClass(progress);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static jfieldID startInitFieldID = env->GetStaticFieldID(clazz, "startInit", "Z");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static jmethodID setAssembliesProgressDataMethodID = env->GetMethodID(clazz, "setAssembliesProgressData", "(JJ)V");
 | 
				
			||||||
 | 
					    static jmethodID setClassProgressDataMethodID = env->GetMethodID(clazz, "setClassProgressData", "(JJ)V");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // jboolean startInit = env->GetStaticBooleanField(clazz, startInitFieldID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    env->SetStaticBooleanField(clazz, startInitFieldID, UnityResolveProgress::startInit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    env->CallVoidMethod(progress, setAssembliesProgressDataMethodID,
 | 
				
			||||||
 | 
					                        UnityResolveProgress::assembliesProgress.current, UnityResolveProgress::assembliesProgress.total);
 | 
				
			||||||
 | 
					    env->CallVoidMethod(progress, setClassProgressDataMethodID,
 | 
				
			||||||
 | 
					                        UnityResolveProgress::classProgress.current, UnityResolveProgress::classProgress.total);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -17,6 +17,7 @@ interface ConfigListener {
 | 
				
			||||||
    fun onForceExportResourceChanged(value: Boolean)
 | 
					    fun onForceExportResourceChanged(value: Boolean)
 | 
				
			||||||
    fun onTextTestChanged(value: Boolean)
 | 
					    fun onTextTestChanged(value: Boolean)
 | 
				
			||||||
    fun onReplaceFontChanged(value: Boolean)
 | 
					    fun onReplaceFontChanged(value: Boolean)
 | 
				
			||||||
 | 
					    fun onLazyInitChanged(value: Boolean)
 | 
				
			||||||
    fun onEnableFreeCameraChanged(value: Boolean)
 | 
					    fun onEnableFreeCameraChanged(value: Boolean)
 | 
				
			||||||
    fun onTargetFpsChanged(s: CharSequence, start: Int, before: Int, count: Int)
 | 
					    fun onTargetFpsChanged(s: CharSequence, start: Int, before: Int, count: Int)
 | 
				
			||||||
    fun onUnlockAllLiveChanged(value: Boolean)
 | 
					    fun onUnlockAllLiveChanged(value: Boolean)
 | 
				
			||||||
| 
						 | 
					@ -111,6 +112,11 @@ interface ConfigUpdateListener: ConfigListener, IHasConfigItems {
 | 
				
			||||||
        pushKeyEvent(KeyEvent(1145, 30))
 | 
					        pushKeyEvent(KeyEvent(1145, 30))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun onLazyInitChanged(value: Boolean) {
 | 
				
			||||||
 | 
					        config.lazyInit = value
 | 
				
			||||||
 | 
					        saveConfig()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun onTextTestChanged(value: Boolean) {
 | 
					    override fun onTextTestChanged(value: Boolean) {
 | 
				
			||||||
        config.textTest = value
 | 
					        config.textTest = value
 | 
				
			||||||
        saveConfig()
 | 
					        saveConfig()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,7 +34,9 @@ import java.util.Locale
 | 
				
			||||||
import kotlin.system.measureTimeMillis
 | 
					import kotlin.system.measureTimeMillis
 | 
				
			||||||
import io.github.chinosk.gakumas.localify.hookUtils.FileHotUpdater
 | 
					import io.github.chinosk.gakumas.localify.hookUtils.FileHotUpdater
 | 
				
			||||||
import io.github.chinosk.gakumas.localify.mainUtils.json
 | 
					import io.github.chinosk.gakumas.localify.mainUtils.json
 | 
				
			||||||
 | 
					import io.github.chinosk.gakumas.localify.models.NativeInitProgress
 | 
				
			||||||
import io.github.chinosk.gakumas.localify.models.ProgramConfig
 | 
					import io.github.chinosk.gakumas.localify.models.ProgramConfig
 | 
				
			||||||
 | 
					import io.github.chinosk.gakumas.localify.ui.game_attach.InitProgressUI
 | 
				
			||||||
 | 
					
 | 
				
			||||||
val TAG = "GakumasLocalify"
 | 
					val TAG = "GakumasLocalify"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,6 +51,7 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private var getConfigError: Exception? = null
 | 
					    private var getConfigError: Exception? = null
 | 
				
			||||||
    private var externalFilesChecked: Boolean = false
 | 
					    private var externalFilesChecked: Boolean = false
 | 
				
			||||||
 | 
					    private var gameActivity: Activity? = null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
 | 
					    override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
 | 
				
			||||||
//        if (lpparam.packageName == "io.github.chinosk.gakumas.localify") {
 | 
					//        if (lpparam.packageName == "io.github.chinosk.gakumas.localify") {
 | 
				
			||||||
| 
						 | 
					@ -135,6 +138,7 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit {
 | 
				
			||||||
                super.beforeHookedMethod(param)
 | 
					                super.beforeHookedMethod(param)
 | 
				
			||||||
                Log.d(TAG, "onStart")
 | 
					                Log.d(TAG, "onStart")
 | 
				
			||||||
                val currActivity = param.thisObject as Activity
 | 
					                val currActivity = param.thisObject as Activity
 | 
				
			||||||
 | 
					                gameActivity = currActivity
 | 
				
			||||||
                if (getConfigError != null) {
 | 
					                if (getConfigError != null) {
 | 
				
			||||||
                    showGetConfigFailed(currActivity)
 | 
					                    showGetConfigFailed(currActivity)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
| 
						 | 
					@ -148,6 +152,7 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit {
 | 
				
			||||||
            override fun beforeHookedMethod(param: MethodHookParam) {
 | 
					            override fun beforeHookedMethod(param: MethodHookParam) {
 | 
				
			||||||
                Log.d(TAG, "onResume")
 | 
					                Log.d(TAG, "onResume")
 | 
				
			||||||
                val currActivity = param.thisObject as Activity
 | 
					                val currActivity = param.thisObject as Activity
 | 
				
			||||||
 | 
					                gameActivity = currActivity
 | 
				
			||||||
                if (getConfigError != null) {
 | 
					                if (getConfigError != null) {
 | 
				
			||||||
                    showGetConfigFailed(currActivity)
 | 
					                    showGetConfigFailed(currActivity)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
| 
						 | 
					@ -206,9 +211,30 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit {
 | 
				
			||||||
    private fun startLoop() {
 | 
					    private fun startLoop() {
 | 
				
			||||||
        GlobalScope.launch {
 | 
					        GlobalScope.launch {
 | 
				
			||||||
            val interval = 1000L / 30
 | 
					            val interval = 1000L / 30
 | 
				
			||||||
 | 
					            var lastFrameStartInit = NativeInitProgress.startInit
 | 
				
			||||||
 | 
					            val initProgressUI = InitProgressUI()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            while (isActive) {
 | 
					            while (isActive) {
 | 
				
			||||||
                val timeTaken = measureTimeMillis {
 | 
					                val timeTaken = measureTimeMillis {
 | 
				
			||||||
                    pluginCallbackLooper()
 | 
					                    val returnValue = pluginCallbackLooper()  // plugin main thread loop
 | 
				
			||||||
 | 
					                    if (returnValue == 9) {
 | 
				
			||||||
 | 
					                        NativeInitProgress.startInit = true
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (NativeInitProgress.startInit) {  // if init, update data
 | 
				
			||||||
 | 
					                        NativeInitProgress.pluginInitProgressLooper(NativeInitProgress)
 | 
				
			||||||
 | 
					                        gameActivity?.let { initProgressUI.updateData(it) }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if ((gameActivity != null) && (lastFrameStartInit != NativeInitProgress.startInit)) {  // change status
 | 
				
			||||||
 | 
					                        if (NativeInitProgress.startInit) {
 | 
				
			||||||
 | 
					                            initProgressUI.createView(gameActivity!!)
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else {
 | 
				
			||||||
 | 
					                            initProgressUI.finishLoad(gameActivity!!)
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    lastFrameStartInit = NativeInitProgress.startInit
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                delay(interval - timeTaken)
 | 
					                delay(interval - timeTaken)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -413,7 +439,7 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        @JvmStatic
 | 
					        @JvmStatic
 | 
				
			||||||
        external fun pluginCallbackLooper()
 | 
					        external fun pluginCallbackLooper(): Int
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    init {
 | 
					    init {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@ import kotlinx.serialization.Serializable
 | 
				
			||||||
data class GakumasConfig (
 | 
					data class GakumasConfig (
 | 
				
			||||||
    var dbgMode: Boolean = false,
 | 
					    var dbgMode: Boolean = false,
 | 
				
			||||||
    var enabled: Boolean = true,
 | 
					    var enabled: Boolean = true,
 | 
				
			||||||
 | 
					    var lazyInit: Boolean = true,
 | 
				
			||||||
    var replaceFont: Boolean = true,
 | 
					    var replaceFont: Boolean = true,
 | 
				
			||||||
    var textTest: Boolean = false,
 | 
					    var textTest: Boolean = false,
 | 
				
			||||||
    var dumpText: Boolean = false,
 | 
					    var dumpText: Boolean = false,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,25 @@
 | 
				
			||||||
 | 
					package io.github.chinosk.gakumas.localify.models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					data class ProgressData(
 | 
				
			||||||
 | 
					    var current: Long = 0,
 | 
				
			||||||
 | 
					    var total: Long = 1
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object NativeInitProgress {
 | 
				
			||||||
 | 
					    var assembliesProgress = ProgressData()
 | 
				
			||||||
 | 
					    var classProgress = ProgressData()
 | 
				
			||||||
 | 
					    var startInit: Boolean = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun setAssembliesProgressData(current: Long, total: Long) {
 | 
				
			||||||
 | 
					        assembliesProgress.current = current
 | 
				
			||||||
 | 
					        assembliesProgress.total = total
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun setClassProgressData(current: Long, total: Long) {
 | 
				
			||||||
 | 
					        classProgress.current = current
 | 
				
			||||||
 | 
					        classProgress.total = total
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @JvmStatic
 | 
				
			||||||
 | 
					    external fun pluginInitProgressLooper(progress: NativeInitProgress)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,176 @@
 | 
				
			||||||
 | 
					package io.github.chinosk.gakumas.localify.ui.game_attach
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.annotation.SuppressLint
 | 
				
			||||||
 | 
					import android.app.Activity
 | 
				
			||||||
 | 
					import android.content.Context
 | 
				
			||||||
 | 
					import android.content.res.ColorStateList
 | 
				
			||||||
 | 
					import android.content.res.Resources
 | 
				
			||||||
 | 
					import android.graphics.Color
 | 
				
			||||||
 | 
					import android.graphics.Typeface
 | 
				
			||||||
 | 
					import android.graphics.drawable.GradientDrawable
 | 
				
			||||||
 | 
					import android.graphics.drawable.LayerDrawable
 | 
				
			||||||
 | 
					import android.graphics.drawable.ShapeDrawable
 | 
				
			||||||
 | 
					import android.graphics.drawable.shapes.RectShape
 | 
				
			||||||
 | 
					import android.util.Log
 | 
				
			||||||
 | 
					import android.view.Gravity
 | 
				
			||||||
 | 
					import android.view.ViewGroup
 | 
				
			||||||
 | 
					import android.widget.FrameLayout
 | 
				
			||||||
 | 
					import android.widget.ImageButton
 | 
				
			||||||
 | 
					import android.widget.ImageView
 | 
				
			||||||
 | 
					import android.widget.LinearLayout
 | 
				
			||||||
 | 
					import android.widget.ProgressBar
 | 
				
			||||||
 | 
					import android.widget.TextView
 | 
				
			||||||
 | 
					import io.github.chinosk.gakumas.localify.TAG
 | 
				
			||||||
 | 
					import io.github.chinosk.gakumas.localify.models.NativeInitProgress
 | 
				
			||||||
 | 
					import kotlinx.coroutines.DelicateCoroutinesApi
 | 
				
			||||||
 | 
					import kotlinx.coroutines.GlobalScope
 | 
				
			||||||
 | 
					import kotlinx.coroutines.delay
 | 
				
			||||||
 | 
					import kotlinx.coroutines.launch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InitProgressUI {
 | 
				
			||||||
 | 
					    private var uiCreated = false
 | 
				
			||||||
 | 
					    private lateinit var rootView: ViewGroup
 | 
				
			||||||
 | 
					    private lateinit var container: LinearLayout
 | 
				
			||||||
 | 
					    private lateinit var assembliesProgressBar: ProgressBar
 | 
				
			||||||
 | 
					    private lateinit var classProgressBar: ProgressBar
 | 
				
			||||||
 | 
					    private lateinit var titleText: TextView
 | 
				
			||||||
 | 
					    private lateinit var assembliesProgressText: TextView
 | 
				
			||||||
 | 
					    private lateinit var classProgressText: TextView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @SuppressLint("SetTextI18n")
 | 
				
			||||||
 | 
					    fun createView(context: Context) {
 | 
				
			||||||
 | 
					        if (uiCreated) return
 | 
				
			||||||
 | 
					        uiCreated = true
 | 
				
			||||||
 | 
					        val activity = context as? Activity ?: return
 | 
				
			||||||
 | 
					        rootView = activity.findViewById<ViewGroup>(android.R.id.content)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        container = LinearLayout(context).apply {
 | 
				
			||||||
 | 
					            orientation = LinearLayout.VERTICAL
 | 
				
			||||||
 | 
					            layoutParams = FrameLayout.LayoutParams(
 | 
				
			||||||
 | 
					                FrameLayout.LayoutParams.MATCH_PARENT,
 | 
				
			||||||
 | 
					                FrameLayout.LayoutParams.WRAP_CONTENT
 | 
				
			||||||
 | 
					            ).apply {
 | 
				
			||||||
 | 
					                gravity = Gravity.TOP or Gravity.END
 | 
				
			||||||
 | 
					                marginEnd = 20
 | 
				
			||||||
 | 
					                marginStart = 20
 | 
				
			||||||
 | 
					                topMargin = 100
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            setBackgroundColor(Color.WHITE)
 | 
				
			||||||
 | 
					            setPadding(20, 20, 20, 20)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Set up the container layout
 | 
				
			||||||
 | 
					        assembliesProgressBar = ProgressBar(context, null, android.R.attr.progressBarStyleHorizontal).apply {
 | 
				
			||||||
 | 
					            layoutParams = LinearLayout.LayoutParams(
 | 
				
			||||||
 | 
					                LinearLayout.LayoutParams.MATCH_PARENT,
 | 
				
			||||||
 | 
					                LinearLayout.LayoutParams.WRAP_CONTENT
 | 
				
			||||||
 | 
					            ).apply {
 | 
				
			||||||
 | 
					                topMargin = 20
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            max = 100
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Set up the class progress bar
 | 
				
			||||||
 | 
					        classProgressBar = ProgressBar(context, null, android.R.attr.progressBarStyleHorizontal).apply {
 | 
				
			||||||
 | 
					            layoutParams = LinearLayout.LayoutParams(
 | 
				
			||||||
 | 
					                LinearLayout.LayoutParams.MATCH_PARENT,
 | 
				
			||||||
 | 
					                LinearLayout.LayoutParams.WRAP_CONTENT
 | 
				
			||||||
 | 
					            ).apply {
 | 
				
			||||||
 | 
					                topMargin = 20
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            max = 100
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assembliesProgressBar.progressTintList = ColorStateList.valueOf(Color.parseColor("#FFF89400"))
 | 
				
			||||||
 | 
					        classProgressBar.progressTintList = ColorStateList.valueOf(Color.parseColor("#FFF89400"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Set up the text views
 | 
				
			||||||
 | 
					        titleText = TextView(context).apply {
 | 
				
			||||||
 | 
					            layoutParams = FrameLayout.LayoutParams(
 | 
				
			||||||
 | 
					                FrameLayout.LayoutParams.WRAP_CONTENT,
 | 
				
			||||||
 | 
					                FrameLayout.LayoutParams.WRAP_CONTENT
 | 
				
			||||||
 | 
					            ).apply {
 | 
				
			||||||
 | 
					                topMargin = 20
 | 
				
			||||||
 | 
					                gravity = Gravity.CENTER_HORIZONTAL
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            setTextColor(Color.BLACK)
 | 
				
			||||||
 | 
					            text = "Initializing"
 | 
				
			||||||
 | 
					            textSize = 20f
 | 
				
			||||||
 | 
					            setTypeface(typeface, Typeface.BOLD)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val textLayout = FrameLayout.LayoutParams(
 | 
				
			||||||
 | 
					            FrameLayout.LayoutParams.WRAP_CONTENT,
 | 
				
			||||||
 | 
					            FrameLayout.LayoutParams.WRAP_CONTENT
 | 
				
			||||||
 | 
					        ).apply {
 | 
				
			||||||
 | 
					            topMargin = 20
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assembliesProgressText = TextView(context).apply {
 | 
				
			||||||
 | 
					            layoutParams = textLayout
 | 
				
			||||||
 | 
					            setTextColor(Color.BLACK)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        classProgressText = TextView(context).apply {
 | 
				
			||||||
 | 
					            layoutParams = textLayout
 | 
				
			||||||
 | 
					            setTextColor(Color.BLACK)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Add container to the root view
 | 
				
			||||||
 | 
					        context.runOnUiThread {
 | 
				
			||||||
 | 
					            // Add views to the container
 | 
				
			||||||
 | 
					            container.addView(titleText)
 | 
				
			||||||
 | 
					            container.addView(assembliesProgressText)
 | 
				
			||||||
 | 
					            container.addView(assembliesProgressBar)
 | 
				
			||||||
 | 
					            container.addView(classProgressText)
 | 
				
			||||||
 | 
					            container.addView(classProgressBar)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            rootView.addView(container)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @SuppressLint("SetTextI18n")
 | 
				
			||||||
 | 
					    @OptIn(DelicateCoroutinesApi::class)
 | 
				
			||||||
 | 
					    fun finishLoad(context: Activity) {
 | 
				
			||||||
 | 
					        if (!uiCreated) return
 | 
				
			||||||
 | 
					        uiCreated = false
 | 
				
			||||||
 | 
					        GlobalScope.launch {
 | 
				
			||||||
 | 
					            context.runOnUiThread {
 | 
				
			||||||
 | 
					                assembliesProgressBar.progressTintList = ColorStateList.valueOf(Color.parseColor("#FF28B463"))
 | 
				
			||||||
 | 
					                classProgressBar.progressTintList = ColorStateList.valueOf(Color.parseColor("#FF28B463"))
 | 
				
			||||||
 | 
					                titleText.text = "Finished"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            delay(1500L)
 | 
				
			||||||
 | 
					            context.runOnUiThread {
 | 
				
			||||||
 | 
					                rootView.removeView(container)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun removeView(context: Activity) {
 | 
				
			||||||
 | 
					        if (!uiCreated) return
 | 
				
			||||||
 | 
					        uiCreated = false
 | 
				
			||||||
 | 
					        context.runOnUiThread {
 | 
				
			||||||
 | 
					            rootView.removeView(container)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @SuppressLint("SetTextI18n")
 | 
				
			||||||
 | 
					    fun updateData(context: Activity) {
 | 
				
			||||||
 | 
					        if (!uiCreated) return
 | 
				
			||||||
 | 
					        //return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        context.runOnUiThread {
 | 
				
			||||||
 | 
					            val assembliesProgress = NativeInitProgress.assembliesProgress
 | 
				
			||||||
 | 
					            val classProgress = NativeInitProgress.classProgress
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            assembliesProgressText.text = "${assembliesProgress.current}/${assembliesProgress.total}"
 | 
				
			||||||
 | 
					            classProgressText.text = "${classProgress.current}/${classProgress.total}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            assembliesProgressBar.setProgress((assembliesProgress.current * 100 / assembliesProgress.total).toInt(), true)
 | 
				
			||||||
 | 
					            classProgressBar.setProgress((classProgress.current * 100 / classProgress.total).toInt(), true)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -141,9 +141,14 @@ fun HomePage(modifier: Modifier = Modifier,
 | 
				
			||||||
                            v -> context?.onEnabledChanged(v)
 | 
					                            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) {
 | 
					                    GakuSwitch(modifier, stringResource(R.string.replace_font), checked = config.value.replaceFont) {
 | 
				
			||||||
                            v -> context?.onReplaceFontChanged(v)
 | 
					                            v -> context?.onReplaceFontChanged(v)
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Spacer(Modifier.height(6.dp))
 | 
					            Spacer(Modifier.height(6.dp))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
    <string name="gakumas_localify">Gakumas Localify</string>
 | 
					    <string name="gakumas_localify">Gakumas Localify</string>
 | 
				
			||||||
    <string name="enable_plugin">启用插件 (不可热重载)</string>
 | 
					    <string name="enable_plugin">启用插件 (不可热重载)</string>
 | 
				
			||||||
    <string name="replace_font">替换字体</string>
 | 
					    <string name="replace_font">替换字体</string>
 | 
				
			||||||
 | 
					    <string name="lazy_init">快速初始化(懒加载配置)</string>
 | 
				
			||||||
    <string name="enable_free_camera">启用自由视角(可热重载; 需使用实体键盘)</string>
 | 
					    <string name="enable_free_camera">启用自由视角(可热重载; 需使用实体键盘)</string>
 | 
				
			||||||
    <string name="start_game">以上述配置启动游戏/重载配置</string>
 | 
					    <string name="start_game">以上述配置启动游戏/重载配置</string>
 | 
				
			||||||
    <string name="setFpsTitle">最大 FPS (0 为保持游戏原设置)</string>
 | 
					    <string name="setFpsTitle">最大 FPS (0 为保持游戏原设置)</string>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
    <string name="gakumas_localify">Gakumas Localify</string>
 | 
					    <string name="gakumas_localify">Gakumas Localify</string>
 | 
				
			||||||
    <string name="enable_plugin">Enable Plugin (Not Hot Reloadable)</string>
 | 
					    <string name="enable_plugin">Enable Plugin (Not Hot Reloadable)</string>
 | 
				
			||||||
    <string name="replace_font">Replace Font</string>
 | 
					    <string name="replace_font">Replace Font</string>
 | 
				
			||||||
 | 
					    <string name="lazy_init">Fast Initialization (Lazy loading)</string>
 | 
				
			||||||
    <string name="enable_free_camera">Enable Free Camera</string>
 | 
					    <string name="enable_free_camera">Enable Free Camera</string>
 | 
				
			||||||
    <string name="start_game">Start Game / Hot Reload Config</string>
 | 
					    <string name="start_game">Start Game / Hot Reload Config</string>
 | 
				
			||||||
    <string name="setFpsTitle">Max FPS (0 is Use Original Settings)</string>
 | 
					    <string name="setFpsTitle">Max FPS (0 is Use Original Settings)</string>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue