Skip to content

Commit

Permalink
add plugin init progress
Browse files Browse the repository at this point in the history
  • Loading branch information
chinosk6 committed Jul 3, 2024
1 parent c28e05e commit c810a27
Show file tree
Hide file tree
Showing 5 changed files with 283 additions and 3 deletions.
20 changes: 20 additions & 0 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 Down Expand Up @@ -284,9 +296,11 @@ class UnityResolve final {
hmodule_ = hmodule;

if (mode_ == Mode::Il2Cpp) {
UnityResolveProgress::startInit = true;
pDomain = Invoke<void*>("il2cpp_domain_get");
Invoke<void*>("il2cpp_thread_attach", pDomain);
ForeachAssembly();
UnityResolveProgress::startInit = false;
}
else {
pDomain = Invoke<void*>("mono_get_root_domain");
Expand Down Expand Up @@ -561,7 +575,11 @@ class UnityResolve final {
if (mode_ == Mode::Il2Cpp) {
size_t nrofassemblies = 0;
const auto assemblies = Invoke<void**>("il2cpp_domain_get_assemblies", pDomain, &nrofassemblies);

UnityResolveProgress::assembliesProgress.total = nrofassemblies;

for (auto i = 0; i < nrofassemblies; i++) {
UnityResolveProgress::assembliesProgress.current = i + 1;
const auto ptr = assemblies[i];
if (ptr == nullptr) continue;
auto assembly = new Assembly{ .address = ptr };
Expand Down Expand Up @@ -594,7 +612,9 @@ class UnityResolve final {
// 遍历类
if (mode_ == Mode::Il2Cpp) {
const auto count = Invoke<int>("il2cpp_image_get_class_count", image);
UnityResolveProgress::classProgress.total = count;
for (auto i = 0; i < count; i++) {
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
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 @@ -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
@@ -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)
}
Original file line number Diff line number Diff line change
@@ -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 Plugins"
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)
}
}
}

0 comments on commit c810a27

Please sign in to comment.