diff --git a/app/src/main/cpp/GakumasLocalify/Hook.cpp b/app/src/main/cpp/GakumasLocalify/Hook.cpp index 2a429ea..157eee2 100644 --- a/app/src/main/cpp/GakumasLocalify/Hook.cpp +++ b/app/src/main/cpp/GakumasLocalify/Hook.cpp @@ -466,12 +466,60 @@ namespace GakumasLocal::HookMain { // return UnityResolve::UnityType::String::New("[I18]" + ret->ToString()); } - DEFINE_HOOK(void, PictureBookLiveThumbnailView_SetData, (void* self, void* liveData, bool isUnlocked, bool isNew, void* ct, void* mtd)) { - // Log::DebugFmt("PictureBookLiveThumbnailView_SetData: isUnlocked: %d, isNew: %d", isUnlocked, isNew); + DEFINE_HOOK(void, PictureBookLiveThumbnailView_SetData, (void* self, void* liveData, bool isReleased, bool isUnlocked, bool isNew, bool hasLiveSkin, void* ct, void* mtd)) { + // Log::DebugFmt("PictureBookLiveThumbnailView_SetData: isReleased: %d, isUnlocked: %d, isNew: %d, hasLiveSkin: %d", + // isReleased, isUnlocked, isNew, hasLiveSkin); if (Config::dbgMode && Config::unlockAllLive) { isUnlocked = true; + isReleased = true; } - PictureBookLiveThumbnailView_SetData_Orig(self, liveData, isUnlocked, isNew, ct, mtd); + PictureBookLiveThumbnailView_SetData_Orig(self, liveData, isReleased, isUnlocked, isNew, hasLiveSkin, ct, mtd); + } + + std::vector GetIdolMusicIdAll(const std::string& charaNameId = "") { + // 传入例: fktn + // System.Collections.Generic.List`1> + static auto get_IdolCardSkinMaster = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.Common.Master", "MasterManager", "get_IdolCardSkinMaster"); + static auto Master_GetAllWithSortByKey = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.Common.Master", "IdolCardSkinMaster", "GetAllWithSortByKey"); + static auto IdolCardSkin_get_Id = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.Common.Proto.Client.Master", "IdolCardSkin", "get_Id"); + static auto IdolCardSkin_get_IdolCardId = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.Common.Proto.Client.Master", "IdolCardSkin", "get_IdolCardId"); + static auto IdolCardSkin_GetMusic = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.Common.Proto.Client.Master", "IdolCardSkin", "GetMusic"); + static auto IdolCardSkin_get_MusicId = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.Common.Proto.Client.Master", "IdolCardSkin", "get_MusicId"); + static auto GetLiveMusics = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.OutGame", + "PictureBookWindowPresenter", "GetLiveMusics"); + + auto idolCardSkinMaster = get_IdolCardSkinMaster->Invoke(nullptr); // IdolCardSkinMaster + + std::vector ret{}; + + if (!idolCardSkinMaster) { + Log::ErrorFmt("get_IdolCardSkinMaster failed: %p", idolCardSkinMaster); + return ret; + } + // List + auto idolCardSkinList = Master_GetAllWithSortByKey->Invoke*>(idolCardSkinMaster, 0x0, nullptr); + + auto idolCardSkins = idolCardSkinList->ToArray()->ToVector(); + const auto checkStartCharaId = "i_card-" + charaNameId; + // Log::DebugFmt("checkStartCharaId: %s", checkStartCharaId.c_str()); + + // origMusics->Clear(); + for (auto i : idolCardSkins) { + if (!i) continue; + // auto charaId = IdolCardSkin_get_Id->Invoke(i); + auto musicId = IdolCardSkin_get_MusicId->Invoke(i); + auto cardId = IdolCardSkin_get_IdolCardId->Invoke(i)->ToString(); + auto music = IdolCardSkin_GetMusic->Invoke(i); + + if (charaNameId.empty() || cardId.starts_with(checkStartCharaId)) { + std::string musicIdStr = musicId->ToString(); + // Log::DebugFmt("Add cardId: %s, musicId: %s", cardId.c_str(), musicIdStr.c_str()); + if (std::find(ret.begin(), ret.end(), musicIdStr) == ret.end()) { + ret.emplace_back(musicIdStr); + } + } + } + return ret; } void* PictureBookWindowPresenter_instance = nullptr; @@ -482,19 +530,46 @@ namespace GakumasLocal::HookMain { if (Config::unlockAllLive) { PictureBookWindowPresenter_instance = self; PictureBookWindowPresenter_charaId = charaId->ToString(); + + static auto PictureBookWindowPresenter_klass = Il2cppUtils::GetClass("Assembly-CSharp.dll", "Campus.OutGame", + "PictureBookWindowPresenter"); + static auto existsMusicIds_field = PictureBookWindowPresenter_klass->Get("_existsMusicIds"); + auto existsMusicIds = Il2cppUtils::ClassGetFieldValue*>(self, existsMusicIds_field); + + if (!existsMusicIds) { + static auto List_String_klass = Il2cppUtils::get_system_class_from_reflection_type_str( + "System.Collections.Generic.List`1[System.String]"); + static auto List_String_ctor_mtd = Il2cppUtils::il2cpp_class_get_method_from_name(List_String_klass, ".ctor", 0); + static auto List_String_ctor = reinterpret_cast(List_String_ctor_mtd->methodPointer); + static auto List_String_Add_mtd = Il2cppUtils::il2cpp_class_get_method_from_name(List_String_klass, "Add", 1); + static auto List_String_Add = reinterpret_cast(List_String_Add_mtd->methodPointer); + + auto newList = UnityResolve::Invoke("il2cpp_object_new", List_String_klass); + List_String_ctor(newList, List_String_ctor_mtd); + + auto fullIds = GetIdolMusicIdAll(); + + for (auto& i : fullIds) { + // Log::DebugFmt("GetLiveMusics - Add: %s", i.c_str()); + // newList->Add(Il2cppString::New(i)); + List_String_Add(newList, Il2cppString::New(i), List_String_Add_mtd); + } + Il2cppUtils::ClassSetFieldValue(self, existsMusicIds_field, newList); + // Log::DebugFmt("GetLiveMusics - set end: %d", fullIds.size()); + } } return PictureBookWindowPresenter_GetLiveMusics_Orig(self, charaId, mtd); } - DEFINE_HOOK(void, PictureBookLiveSelectScreenModel_ctor, (void* self, void* transitionParam, void* musics, void* mtd)) { + DEFINE_HOOK(void, PictureBookLiveSelectScreenModel_ctor, (void* self, void* transitionParam, UnityResolve::UnityType::List* musics, void* mtd)) { // Log::DebugFmt("PictureBookLiveSelectScreenModel_ctor"); if (Config::unlockAllLive) { static auto GetLiveMusics = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.OutGame", "PictureBookWindowPresenter", "GetLiveMusics"); if (PictureBookWindowPresenter_instance && !PictureBookWindowPresenter_charaId.empty()) { - auto fullMusics = GetLiveMusics->Invoke(PictureBookWindowPresenter_instance, + auto fullMusics = GetLiveMusics->Invoke*>(PictureBookWindowPresenter_instance, Il2cppString::New(PictureBookWindowPresenter_charaId)); return PictureBookLiveSelectScreenModel_ctor_Orig(self, transitionParam, fullMusics, mtd); } diff --git a/app/src/main/cpp/GakumasLocalify/Il2cppUtils.hpp b/app/src/main/cpp/GakumasLocalify/Il2cppUtils.hpp index 8a296f2..f92ff4c 100644 --- a/app/src/main/cpp/GakumasLocalify/Il2cppUtils.hpp +++ b/app/src/main/cpp/GakumasLocalify/Il2cppUtils.hpp @@ -36,6 +36,74 @@ namespace Il2cppUtils { uint8_t is_marshaled_from_native : 1; }; + struct Il2CppObject + { + union + { + void* klass; + void* vtable; + }; + void* monitor; + }; + + enum Il2CppTypeEnum + { + IL2CPP_TYPE_END = 0x00, /* End of List */ + IL2CPP_TYPE_VOID = 0x01, + IL2CPP_TYPE_BOOLEAN = 0x02, + IL2CPP_TYPE_CHAR = 0x03, + IL2CPP_TYPE_I1 = 0x04, + IL2CPP_TYPE_U1 = 0x05, + IL2CPP_TYPE_I2 = 0x06, + IL2CPP_TYPE_U2 = 0x07, + IL2CPP_TYPE_I4 = 0x08, + IL2CPP_TYPE_U4 = 0x09, + IL2CPP_TYPE_I8 = 0x0a, + IL2CPP_TYPE_U8 = 0x0b, + IL2CPP_TYPE_R4 = 0x0c, + IL2CPP_TYPE_R8 = 0x0d, + IL2CPP_TYPE_STRING = 0x0e, + IL2CPP_TYPE_PTR = 0x0f, + IL2CPP_TYPE_BYREF = 0x10, + IL2CPP_TYPE_VALUETYPE = 0x11, + IL2CPP_TYPE_CLASS = 0x12, + IL2CPP_TYPE_VAR = 0x13, + IL2CPP_TYPE_ARRAY = 0x14, + IL2CPP_TYPE_GENERICINST = 0x15, + IL2CPP_TYPE_TYPEDBYREF = 0x16, + IL2CPP_TYPE_I = 0x18, + IL2CPP_TYPE_U = 0x19, + IL2CPP_TYPE_FNPTR = 0x1b, + IL2CPP_TYPE_OBJECT = 0x1c, + IL2CPP_TYPE_SZARRAY = 0x1d, + IL2CPP_TYPE_MVAR = 0x1e, + IL2CPP_TYPE_CMOD_REQD = 0x1f, + IL2CPP_TYPE_CMOD_OPT = 0x20, + IL2CPP_TYPE_INTERNAL = 0x21, + + IL2CPP_TYPE_MODIFIER = 0x40, + IL2CPP_TYPE_SENTINEL = 0x41, + IL2CPP_TYPE_PINNED = 0x45, + + IL2CPP_TYPE_ENUM = 0x55 + }; + + typedef struct Il2CppType + { + void* dummy; + unsigned int attrs : 16; + Il2CppTypeEnum type : 8; + unsigned int num_mods : 6; + unsigned int byref : 1; + unsigned int pinned : 1; + } Il2CppType; + + struct Il2CppReflectionType + { + Il2CppObject object; + const Il2CppType* type; + }; + struct Resolution_t { int width; int height; @@ -160,5 +228,20 @@ namespace Il2cppUtils { *reinterpret_cast(reinterpret_cast(obj) + field->offset) = value; } + void* get_system_class_from_reflection_type_str(const char* typeStr, const char* assemblyName = "mscorlib") { + using Il2CppString = UnityResolve::UnityType::String; + static auto assemblyLoad = reinterpret_cast( + GetMethodPointer("mscorlib.dll", "System.Reflection", + "Assembly", "Load", {"*"}) + ); + static auto assemblyGetType = reinterpret_cast( + GetMethodPointer("mscorlib.dll", "System.Reflection", + "Assembly", "GetType", {"*"}) + ); + + static auto reflectionAssembly = assemblyLoad(Il2CppString::New(assemblyName)); + auto reflectionType = assemblyGetType(reflectionAssembly, Il2CppString::New(typeStr)); + return UnityResolve::Invoke("il2cpp_class_from_system_type", reflectionType); + } } diff --git a/app/src/main/java/io/github/chinosk/gakumas/localify/ActivityExtends.kt b/app/src/main/java/io/github/chinosk/gakumas/localify/ActivityExtends.kt index 59728fd..15a2af9 100644 --- a/app/src/main/java/io/github/chinosk/gakumas/localify/ActivityExtends.kt +++ b/app/src/main/java/io/github/chinosk/gakumas/localify/ActivityExtends.kt @@ -128,7 +128,15 @@ fun T.onClickStartGame() where T : Activity, T : IHasConfigItems { "io.github.chinosk.gakumas.localify.fileprovider", File(targetFile.absolutePath) ) - intent.setDataAndType(dirUri, "resource/file") + // intent.setDataAndType(dirUri, "resource/file") + + grantUriPermission( + "com.bandainamcoent.idolmaster_gakuen", + dirUri, + Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION + ) + intent.putExtra("resource_file", dirUri) + // intent.clipData = ClipData.newRawUri("resource_file", dirUri) intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION) } diff --git a/app/src/main/java/io/github/chinosk/gakumas/localify/GakumasHookMain.kt b/app/src/main/java/io/github/chinosk/gakumas/localify/GakumasHookMain.kt index ee44a0f..f6cdab0 100644 --- a/app/src/main/java/io/github/chinosk/gakumas/localify/GakumasHookMain.kt +++ b/app/src/main/java/io/github/chinosk/gakumas/localify/GakumasHookMain.kt @@ -8,6 +8,7 @@ import android.content.Context import android.content.Intent import android.content.Intent.FLAG_ACTIVITY_NEW_TASK import android.net.Uri +import android.os.Build import android.os.Handler import android.os.Looper import android.util.Log @@ -282,7 +283,14 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit { // 使用热更新文件 if ((programConfig?.useRemoteAssets == true) || (programConfig?.useAPIAssets == true)) { - val dataUri = intent.data + // val dataUri = intent.data + val dataUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + intent.getParcelableExtra("resource_file", Uri::class.java) + } else { + @Suppress("DEPRECATION") + intent.getParcelableExtra("resource_file") + } + if (dataUri != null) { if (!externalFilesChecked) { externalFilesChecked = true diff --git a/app/src/main/java/io/github/chinosk/gakumas/localify/PatchActivity.kt b/app/src/main/java/io/github/chinosk/gakumas/localify/PatchActivity.kt index 3cccc3b..00cace5 100644 --- a/app/src/main/java/io/github/chinosk/gakumas/localify/PatchActivity.kt +++ b/app/src/main/java/io/github/chinosk/gakumas/localify/PatchActivity.kt @@ -645,7 +645,7 @@ class PatchActivity : ComponentActivity() { val copyFilesCmd: MutableList = mutableListOf() val movedFiles: MutableList = mutableListOf() savedFileNames.forEach { file -> - val movedFileName = "$installDS/${file}" + val movedFileName = "\"$installDS/${file}\"" movedFiles.add(movedFileName) val dlSaveFileName = File(targetDirectory, file) copyFilesCmd.add("$action ${dlSaveFileName.absolutePath} $movedFileName")