diff --git a/app/src/main/cpp/GakumasLocalify/Hook.cpp b/app/src/main/cpp/GakumasLocalify/Hook.cpp index 0da1087..680de29 100644 --- a/app/src/main/cpp/GakumasLocalify/Hook.cpp +++ b/app/src/main/cpp/GakumasLocalify/Hook.cpp @@ -483,32 +483,6 @@ namespace GakumasLocal::HookMain { return ret; }*/ - DEFINE_HOOK(void*, UserCostumeCollection_FindBy, (void* self, void* predicate, void* mtd)) { - auto ret = UserCostumeCollection_FindBy_Orig(self, predicate, mtd); - if (!Config::unlockAllLiveCostume) return ret; - - auto this_klass = Il2cppUtils::get_class_from_instance(self); - // auto predicate_klass = Il2cppUtils::get_class_from_instance(predicate); // System::Predicate`1 - // Log::DebugFmt("UserCostumeCollection_FindBy this: %s::%s, predicate: %s::%s", this_klass->namespaze, this_klass->name, - // predicate_klass->namespaze, predicate_klass->name); - - static auto UserCostumeCollection_klass = Il2cppUtils::GetClass("Assembly-CSharp.dll", "Campus.Common.User", - "UserCostumeCollection"); - static auto UserCostumeCollection_GetAllList_mtd = Il2cppUtils::il2cpp_class_get_method_from_name( - UserCostumeCollection_klass->address, "GetAllList", 1); - static auto UserCostumeCollection_GetAllList = reinterpret_cast(UserCostumeCollection_GetAllList_mtd->methodPointer); - - std::string thisKlassName(this_klass->name); - // Campus.Common.User::UserCostumeHeadCollection || Campus.Common.User::UserCostumeCollection - // 两个 class 的 GetAllList 均使用的父类 Qua.UserDataManagement.UserDataCollectionBase`2 的方法,地址一致 - if ((thisKlassName == "UserCostumeHeadCollection") || (thisKlassName == "UserCostumeCollection")) { - // auto ret_klass = Il2cppUtils::get_class_from_instance(ret); // WhereEnumerableIterator - return UserCostumeCollection_GetAllList(self, nullptr); - } - - return ret; - } - DEFINE_HOOK(bool, UserIdolCardSkinCollection_Exists, (void* self, Il2cppString* id, void* mtd)) { // Live默认选择 auto ret = UserIdolCardSkinCollection_Exists_Orig(self, id, mtd); // Log::DebugFmt("UserIdolCardSkinCollection_Exists: %s, ret: %d", id->ToString().c_str(), ret); @@ -533,7 +507,13 @@ namespace GakumasLocal::HookMain { PictureBookLiveThumbnailView_SetDataAsync_Orig(self, liveData, isReleased, isUnlocked, isNew, hasLiveSkin, ct, mtd); } - std::vector GetIdolMusicIdAll(const std::string& charaNameId = "") { + enum class GetIdolIdType { + MusicId, + CostumeId, + CostumeHeadId + }; + + std::vector GetIdolMusicIdAll(const std::string& charaNameId = "", GetIdolIdType getType = GetIdolIdType::MusicId) { // 传入例: fktn // System.Collections.Generic.List`1> static auto get_IdolCardSkinMaster = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.Common.Master", "MasterManager", "get_IdolCardSkinMaster"); @@ -542,6 +522,8 @@ namespace GakumasLocal::HookMain { 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 IdolCardSkin_get_CostumeId = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.Common.Proto.Client.Master", "IdolCardSkin", "get_CostumeId"); + static auto IdolCardSkin_get_CostumeHeadId = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.Common.Proto.Client.Master", "IdolCardSkin", "get_CostumeHeadId"); static auto GetLiveMusics = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.OutGame", "PictureBookWindowPresenter", "GetLiveMusics"); @@ -561,15 +543,27 @@ namespace GakumasLocal::HookMain { // Log::DebugFmt("checkStartCharaId: %s", checkStartCharaId.c_str()); // origMusics->Clear(); + UnityResolve::Method* idGetFunc = nullptr; + switch (getType) { + case GetIdolIdType::MusicId: idGetFunc = IdolCardSkin_get_MusicId; + break; + case GetIdolIdType::CostumeId: idGetFunc = IdolCardSkin_get_CostumeId; + break; + case GetIdolIdType::CostumeHeadId: idGetFunc = IdolCardSkin_get_CostumeHeadId; + break; + default: + idGetFunc = IdolCardSkin_get_MusicId; + } + for (auto i : idolCardSkins) { if (!i) continue; // auto charaId = IdolCardSkin_get_Id->Invoke(i); - auto musicId = IdolCardSkin_get_MusicId->Invoke(i); + auto targetId = idGetFunc->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(); + std::string musicIdStr = targetId->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); @@ -579,6 +573,92 @@ namespace GakumasLocal::HookMain { return ret; } + void* AddIdsToUserDataCollectionFromMaster(void* origList, std::vector& allIds, + UnityResolve::Method* get_CostumeId, UnityResolve::Method* set_CostumeId, UnityResolve::Method* Clone) { + Il2cppUtils::Tools::CSListEditor listEditor(origList); + if (listEditor.get_Count() <= 0) { + return origList; + } + + for (auto i : listEditor) { + auto currCostumeId = get_CostumeId->Invoke(i); + if (!currCostumeId) continue; + std::string currCostumeIdStr = currCostumeId->ToString(); + if (std::find(allIds.begin(), allIds.end(), currCostumeIdStr) == allIds.end()) { + allIds.emplace_back(currCostumeIdStr); + } + } + + int currIndex = 0; + int origSize = listEditor.get_Count(); + for (auto& i : allIds) { + if (i.empty()) continue; + // Log::DebugFmt("Try add %s", i.c_str()); + + if (currIndex < origSize) { + auto userCostume = listEditor.get_Item(currIndex); + set_CostumeId->Invoke(userCostume, Il2cppString::New(i)); + listEditor.set_Item(currIndex, userCostume); + } + else { + auto userCostume = Clone->Invoke(listEditor.get_Item(0)); + set_CostumeId->Invoke(userCostume, Il2cppString::New(i)); + listEditor.Add(userCostume); + } + currIndex++; + } + return origList; + } + + DEFINE_HOOK(void*, UserCostumeCollection_FindBy, (void* self, void* predicate, void* mtd)) { + auto ret = UserCostumeCollection_FindBy_Orig(self, predicate, mtd); + if (!Config::unlockAllLiveCostume) return ret; + + auto this_klass = Il2cppUtils::get_class_from_instance(self); + // auto predicate_klass = Il2cppUtils::get_class_from_instance(predicate); // System::Predicate`1 + // Log::DebugFmt("UserCostumeCollection_FindBy this: %s::%s, predicate: %s::%s", this_klass->namespaze, this_klass->name, + // predicate_klass->namespaze, predicate_klass->name); + + static auto UserCostumeCollection_klass = Il2cppUtils::GetClass("Assembly-CSharp.dll", "Campus.Common.User", + "UserCostumeCollection"); + static auto UserCostumeCollection_GetAllList_mtd = Il2cppUtils::il2cpp_class_get_method_from_name( + UserCostumeCollection_klass->address, "GetAllList", 1); + static auto UserCostumeCollection_GetAllList = reinterpret_cast(UserCostumeCollection_GetAllList_mtd->methodPointer); + + std::string thisKlassName(this_klass->name); + // Campus.Common.User::UserCostumeHeadCollection || Campus.Common.User::UserCostumeCollection + // 两个 class 的 GetAllList 均使用的父类 Qua.UserDataManagement.UserDataCollectionBase`2 的方法,地址一致 + if (thisKlassName == "UserCostumeHeadCollection") { + static auto UserCostume_Clone = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.Common.Proto.Client.Transaction", "UserCostumeHead", "Clone"); + static auto UserCostume_get_CostumeHeadId = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.Common.Proto.Client.Transaction", "UserCostumeHead", "get_CostumeHeadId"); + static auto UserCostume_set_CostumeHeadId = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.Common.Proto.Client.Transaction", "UserCostumeHead", "set_CostumeHeadId"); + + // auto ret_klass = Il2cppUtils::get_class_from_instance(ret); // WhereEnumerableIterator + auto origList = UserCostumeCollection_GetAllList(self, nullptr); + + auto allIds = GetIdolMusicIdAll("", GetIdolIdType::CostumeHeadId); + + // List + return AddIdsToUserDataCollectionFromMaster(origList, allIds, UserCostume_get_CostumeHeadId, UserCostume_set_CostumeHeadId, UserCostume_Clone); + } + else if (thisKlassName == "UserCostumeCollection") { + // static auto UserCostume_klass = Il2cppUtils::GetClass("Assembly-CSharp.dll", "Campus.Common.Proto.Client.Transaction", "UserCostume"); + static auto UserCostume_Clone = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.Common.Proto.Client.Transaction", "UserCostume", "Clone"); + static auto UserCostume_get_CostumeId = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.Common.Proto.Client.Transaction", "UserCostume", "get_CostumeId"); + static auto UserCostume_set_CostumeId = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.Common.Proto.Client.Transaction", "UserCostume", "set_CostumeId"); + + // auto ret_klass = Il2cppUtils::get_class_from_instance(ret); // WhereEnumerableIterator + auto origList = UserCostumeCollection_GetAllList(self, nullptr); + + auto allIds = GetIdolMusicIdAll("", GetIdolIdType::CostumeId); + + // List + return AddIdsToUserDataCollectionFromMaster(origList, allIds, UserCostume_get_CostumeId, UserCostume_set_CostumeId, UserCostume_Clone); + } + + return ret; + } + void* PictureBookWindowPresenter_instance = nullptr; std::string PictureBookWindowPresenter_charaId; DEFINE_HOOK(void*, PictureBookWindowPresenter_GetLiveMusics, (void* self, Il2cppString* charaId, void* mtd)) { @@ -598,18 +678,16 @@ namespace GakumasLocal::HookMain { "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); + Il2cppUtils::Tools::CSListEditor newListEditor(newList); 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); + newListEditor.Add(Il2cppString::New(i)); } Il2cppUtils::ClassSetFieldValue(self, existsMusicIds_field, newList); // Log::DebugFmt("GetLiveMusics - set end: %d", fullIds.size()); diff --git a/app/src/main/cpp/GakumasLocalify/Il2cppUtils.hpp b/app/src/main/cpp/GakumasLocalify/Il2cppUtils.hpp index f92ff4c..06f33a9 100644 --- a/app/src/main/cpp/GakumasLocalify/Il2cppUtils.hpp +++ b/app/src/main/cpp/GakumasLocalify/Il2cppUtils.hpp @@ -244,4 +244,95 @@ namespace Il2cppUtils { auto reflectionType = assemblyGetType(reflectionAssembly, Il2CppString::New(typeStr)); return UnityResolve::Invoke("il2cpp_class_from_system_type", reflectionType); } + + namespace Tools { + + template + class CSListEditor { + public: + CSListEditor(void* list) { + list_klass = get_class_from_instance(list); + lst = list; + + lst_get_Count_method = il2cpp_class_get_method_from_name(list_klass, "get_Count", 0); + lst_get_Item_method = il2cpp_class_get_method_from_name(list_klass, "get_Item", 1); + lst_set_Item_method = il2cpp_class_get_method_from_name(list_klass, "set_Item", 2); + lst_Add_method = il2cpp_class_get_method_from_name(list_klass, "Add", 1); + + lst_get_Count = reinterpret_cast(lst_get_Count_method->methodPointer); + lst_get_Item = reinterpret_cast(lst_get_Item_method->methodPointer); + lst_set_Item = reinterpret_cast(lst_set_Item_method->methodPointer); + lst_Add = reinterpret_cast(lst_Add_method->methodPointer); + } + + void Add(T value) { + lst_Add(lst, value, lst_Add_method); + } + + T get_Item(int index) { + return lst_get_Item(lst, index, lst_get_Item_method); + } + + void set_Item(int index, T value) { + return lst_set_Item(lst, index, value, lst_set_Item_method); + } + + int get_Count() { + return lst_get_Count(lst, lst_get_Count_method); + } + + T operator[] (int key) { + return get_Item(key); + } + + class Iterator { + public: + Iterator(CSListEditor* editor, int index) : editor(editor), index(index) {} + + T operator*() const { + return editor->get_Item(index); + } + + Iterator& operator++() { + ++index; + return *this; + } + + bool operator!=(const Iterator& other) const { + return index != other.index; + } + + private: + CSListEditor* editor; + int index; + }; + + Iterator begin() { + return Iterator(this, 0); + } + + Iterator end() { + return Iterator(this, get_Count()); + } + + void* lst; + void* list_klass; + private: + typedef T(*lst_get_Item_t)(void*, int, void* mtd); + typedef void(*lst_Add_t)(void*, T, void* mtd); + typedef void(*lst_set_Item_t)(void*, int, T, void* mtd); + typedef int(*lst_get_Count_t)(void*, void* mtd); + + MethodInfo* lst_get_Item_method; + MethodInfo* lst_Add_method; + MethodInfo* lst_get_Count_method; + MethodInfo* lst_set_Item_method; + + lst_get_Item_t lst_get_Item; + lst_set_Item_t lst_set_Item; + lst_Add_t lst_Add; + lst_get_Count_t lst_get_Count; + }; + + } }