Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add plugin initialization progress #38

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions app/src/main/cpp/GakumasLocalify/Hook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ std::unordered_set<void*> 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) {
Expand Down Expand Up @@ -97,7 +98,7 @@ namespace GakumasLocal::HookMain {
UnityResolve::UnityType::Transform* cameraTransformCache = nullptr;
void CheckAndUpdateMainCamera() {
if (!Config::enableFreeCamera) return;
if (IsNativeObjectAlive(mainCameraCache)) return;
if (IsNativeObjectAlive(mainCameraCache) && IsNativeObjectAlive(cameraTransformCache)) return;

mainCameraCache = UnityResolve::UnityType::Camera::GetMain();
cameraTransformCache = mainCameraCache->GetTransform();
Expand Down Expand Up @@ -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)"));
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/cpp/GakumasLocalify/config/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -55,6 +56,7 @@ namespace GakumasLocal::Config {

GetConfigItem(dbgMode);
GetConfigItem(enabled);
GetConfigItem(lazyInit);
GetConfigItem(replaceFont);
GetConfigItem(forceExportResource);
GetConfigItem(gameOrientation);
Expand Down
1 change: 1 addition & 0 deletions app/src/main/cpp/GakumasLocalify/config/Config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
82 changes: 79 additions & 3 deletions app/src/main/cpp/deps/UnityResolve/UnityResolve.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@
#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;
Expand All @@ -69,8 +81,16 @@ class UnityResolve final {

[[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;
return nullptr;
if (lazyInit_) {
return FillClass_Il2ccpp(const_cast<Assembly *>(this), strNamespace.c_str(), strClass.c_str());
}
return nullptr;
}
};

Expand Down Expand Up @@ -279,14 +299,17 @@ class UnityResolve final {
}
}

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) {
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");
Expand Down Expand Up @@ -561,15 +584,21 @@ class UnityResolve final {
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);
ForeachClass(assembly, image);
if (!lazyInit_) {
ForeachClass(assembly, image);
}
}
}
else {
Expand All @@ -590,11 +619,57 @@ class UnityResolve final {
}
}

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 == 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();
Expand Down Expand Up @@ -2586,6 +2661,7 @@ class UnityResolve final {
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{};
};
Expand Down
35 changes: 34 additions & 1 deletion app/src/main/cpp/libMarryKotone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ JavaVM* g_javaVM = nullptr;
jclass g_gakumasHookMainClass = nullptr;
jmethodID showToastMethodId = nullptr;

bool UnityResolveProgress::startInit = false;
UnityResolveProgress::Progress UnityResolveProgress::assembliesProgress{};
UnityResolveProgress::Progress UnityResolveProgress::classProgress{};

namespace
{
class AndroidHookInstaller : public GakumasLocal::HookInstaller
Expand Down Expand Up @@ -114,8 +118,37 @@ Java_io_github_chinosk_gakumas_localify_GakumasHookMain_loadConfig(JNIEnv *env,
}

extern "C"
JNIEXPORT void JNICALL
JNIEXPORT jint JNICALL
Java_io_github_chinosk_gakumas_localify_GakumasHookMain_pluginCallbackLooper(JNIEnv *env,
jclass 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);

}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ import java.util.Locale
import kotlin.system.measureTimeMillis
import io.github.chinosk.gakumas.localify.hookUtils.FileHotUpdater
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.ui.game_attach.InitProgressUI

val TAG = "GakumasLocalify"

Expand All @@ -49,6 +51,7 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit {

private var getConfigError: Exception? = null
private var externalFilesChecked: Boolean = false
private var gameActivity: Activity? = null

override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
// if (lpparam.packageName == "io.github.chinosk.gakumas.localify") {
Expand Down Expand Up @@ -135,6 +138,7 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit {
super.beforeHookedMethod(param)
Log.d(TAG, "onStart")
val currActivity = param.thisObject as Activity
gameActivity = currActivity
if (getConfigError != null) {
showGetConfigFailed(currActivity)
}
Expand All @@ -148,6 +152,7 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit {
override fun beforeHookedMethod(param: MethodHookParam) {
Log.d(TAG, "onResume")
val currActivity = param.thisObject as Activity
gameActivity = currActivity
if (getConfigError != null) {
showGetConfigFailed(currActivity)
}
Expand Down Expand Up @@ -206,9 +211,30 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit {
private fun startLoop() {
GlobalScope.launch {
val interval = 1000L / 30
var lastFrameStartInit = NativeInitProgress.startInit
val initProgressUI = InitProgressUI()

while (isActive) {
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)
}
Expand Down Expand Up @@ -413,7 +439,7 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit {
}

@JvmStatic
external fun pluginCallbackLooper()
external fun pluginCallbackLooper(): Int
}

init {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading
Loading