From 7cc0c95e5cb6caf6b71bc917860110faec1dd6bb Mon Sep 17 00:00:00 2001 From: chinosk <2248589280@qq.com> Date: Sun, 27 Apr 2025 15:50:13 +0100 Subject: [PATCH] fixed live --- src/GakumasLocalify/Hook.cpp | 118 +++++++++++++++++++++++----- src/GakumasLocalify/Il2cppUtils.hpp | 76 ++++++++++++++++++ src/GakumasLocalify/Local.cpp | 2 +- src/gkmsGUI/gkmsGUILoop.cpp | 4 +- src/platformDefine.hpp | 2 +- 5 files changed, 177 insertions(+), 25 deletions(-) diff --git a/src/GakumasLocalify/Hook.cpp b/src/GakumasLocalify/Hook.cpp index 932e5d1..f66f5b3 100644 --- a/src/GakumasLocalify/Hook.cpp +++ b/src/GakumasLocalify/Hook.cpp @@ -99,6 +99,18 @@ namespace GakumasLocal::HookMain { return GetResolution->Invoke(); } + Il2cppString* ToJsonStr(void* object) { + static Il2cppString* (*toJsonStr)(void*) = nullptr; + if (!toJsonStr) { + toJsonStr = reinterpret_cast(Il2cppUtils::GetMethodPointer("Newtonsoft.Json.dll", "Newtonsoft.Json", + "JsonConvert", "SerializeObject", { "*" })); + } + if (!toJsonStr) { + return nullptr; + } + return toJsonStr(object); + } + DEFINE_HOOK(void, Unity_set_fieldOfView, (UnityResolve::UnityType::Camera* self, float value)) { if (Config::enableFreeCamera) { if (self == mainCameraCache) { @@ -703,24 +715,24 @@ namespace GakumasLocal::HookMain { } #ifdef GKMS_WINDOWS - DEFINE_HOOK(void, PictureBookLiveThumbnailView_SetDataAsync, (void* retstr, void* self, void* liveData, bool isReleased, bool isUnlocked, bool isNew, bool hasLiveSkin, void* ct, void* mtd)) { + DEFINE_HOOK(void, PictureBookLiveThumbnailView_SetDataAsync, (void* retstr, void* self, void* liveData, Il2cppString* characterId, bool isReleased, bool isUnlocked, bool isNew, bool hasLiveSkin, void* ct, void* mtd)) { // Log::DebugFmt("PictureBookLiveThumbnailView_SetDataAsync: isReleased: %d, isUnlocked: %d, isNew: %d, hasLiveSkin: %d", isReleased, isUnlocked, isNew, hasLiveSkin); if (Config::dbgMode && Config::unlockAllLive) { isUnlocked = true; isReleased = true; hasLiveSkin = true; } - PictureBookLiveThumbnailView_SetDataAsync_Orig(retstr, self, liveData, isReleased, isUnlocked, isNew, hasLiveSkin, ct, mtd); + PictureBookLiveThumbnailView_SetDataAsync_Orig(retstr, self, liveData, characterId, isReleased, isUnlocked, isNew, hasLiveSkin, ct, mtd); } #else - DEFINE_HOOK(void, PictureBookLiveThumbnailView_SetDataAsync, (void* self, void* liveData, bool isReleased, bool isUnlocked, bool isNew, bool hasLiveSkin, void* ct, void* mtd)) { + DEFINE_HOOK(void, PictureBookLiveThumbnailView_SetDataAsync, (void* self, void* liveData, Il2cppString* characterId, bool isReleased, bool isUnlocked, bool isNew, bool hasLiveSkin, void* ct, void* mtd)) { // Log::DebugFmt("PictureBookLiveThumbnailView_SetDataAsync: isReleased: %d, isUnlocked: %d, isNew: %d, hasLiveSkin: %d", isReleased, isUnlocked, isNew, hasLiveSkin); if (Config::dbgMode && Config::unlockAllLive) { isUnlocked = true; isReleased = true; hasLiveSkin = true; } - PictureBookLiveThumbnailView_SetDataAsync_Orig(self, liveData, isReleased, isUnlocked, isNew, hasLiveSkin, ct, mtd); + PictureBookLiveThumbnailView_SetDataAsync_Orig(self, liveData, characterId, isReleased, isUnlocked, isNew, hasLiveSkin, ct, mtd); } #endif @@ -865,6 +877,34 @@ namespace GakumasLocal::HookMain { return ret; } + void* getCompletedUniTask() { + static auto unitask_klass = Il2cppUtils::GetClass("UniTask.dll", "Cysharp.Threading.Tasks", "UniTask"); + static auto CompletedTask_field = unitask_klass->Get("CompletedTask"); + auto ret = UnityResolve::Invoke("il2cpp_object_new", unitask_klass->address); + UnityResolve::Invoke("il2cpp_field_static_get_value", CompletedTask_field->address, ret); + return ret; + } + +#ifdef GKMS_WINDOWS + // 绕过切歌时的等待以及网络请求 + DEFINE_HOOK(void*, Produce_ViewPictureBookLiveAsync, (void* retstr, Il2cppString* musicId, Il2cppString* characterId, + void* ct, void* callOption, void* errorHandlerIl, Il2cppString* requestIdForResponseCache, void* mtd)) { + + // Log::DebugFmt("Produce_ViewPictureBookLiveAsync: %s - %s", musicId->ToString().c_str(), characterId->ToString().c_str()); + if (Config::unlockAllLive) return getCompletedUniTask(); + return Produce_ViewPictureBookLiveAsync_Orig(retstr, musicId, characterId, ct, callOption, errorHandlerIl, requestIdForResponseCache, mtd); + } +#else + DEFINE_HOOK(void*, Produce_ViewPictureBookLiveAsync, (Il2cppString* musicId, Il2cppString* characterId, + void* ct, void* callOption, void* errorHandlerIl, Il2cppString* requestIdForResponseCache, void* mtd)) { + + // Log::DebugFmt("Produce_ViewPictureBookLiveAsync: %s - %s", musicId->ToString().c_str(), characterId->ToString().c_str()); + if (Config::unlockAllLive) return getCompletedUniTask(); + return Produce_ViewPictureBookLiveAsync_Orig(musicId, characterId, ct, callOption, errorHandlerIl, requestIdForResponseCache, mtd); + } +#endif // GKMS_WINDOWS + + void* PictureBookWindowPresenter_instance = nullptr; std::string PictureBookWindowPresenter_charaId; DEFINE_HOOK(void*, PictureBookWindowPresenter_GetLiveMusics, (void* self, Il2cppString* charaId, void* mtd)) { @@ -877,27 +917,59 @@ namespace GakumasLocal::HookMain { 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); + // auto existsMusicIds = Il2cppUtils::ClassGetFieldValue*>(self, existsMusicIds_field); + auto existsMusicIds = Il2cppUtils::ClassGetFieldValue>*>(self, existsMusicIds_field); if (!existsMusicIds) { + static auto Dict_List_String_klass = Il2cppUtils::get_system_class_from_reflection_type_str( + "System.Collections.Generic.Dictionary`2[System.String, System.Collections.Generic.List`1[System.String]]"); static auto List_String_klass = Il2cppUtils::get_system_class_from_reflection_type_str( - "System.Collections.Generic.List`1[System.String]"); + "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); - 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(); + static auto Dict_List_String_ctor_mtd = Il2cppUtils::il2cpp_class_get_method_from_name(Dict_List_String_klass, ".ctor", 0); + static auto Dict_List_String_ctor = reinterpret_cast(Dict_List_String_ctor_mtd->methodPointer); + + auto newDict = UnityResolve::Invoke("il2cpp_object_new", Dict_List_String_klass); + Dict_List_String_ctor(newDict, Dict_List_String_ctor_mtd); + Il2cppUtils::Tools::CSDictEditor newDictEditor(newDict, Dict_List_String_klass); + + // auto fullIds = GetIdolMusicIdAll(); + for (auto& i : fullIds) { - // Log::DebugFmt("GetLiveMusics - Add: %s", i.c_str()); - newListEditor.Add(Il2cppString::New(i)); + // Log::DebugFmt("GetLiveMusics - Add: %s", i.c_str()); // eg. music-all-amao-001, music-char-hski-001 + //newListEditor.Add(Il2cppString::New(i)); + auto newList = UnityResolve::Invoke("il2cpp_object_new", List_String_klass); + List_String_ctor(newList, List_String_ctor_mtd); + newDictEditor.Add(Il2cppString::New(i), newList); } - Il2cppUtils::ClassSetFieldValue(self, existsMusicIds_field, newList); + Il2cppUtils::ClassSetFieldValue(self, existsMusicIds_field, newDict); + existsMusicIds = reinterpret_cast(newDict); // Log::DebugFmt("GetLiveMusics - set end: %d", fullIds.size()); } + + /* + Il2cppUtils::Tools::CSDictEditor dicCheckEditor(existsMusicIds, Dict_List_String_klass); + for (auto& i : fullIds) { + auto currKeyStr = Il2cppString::New(i); + void* currList; + if (dicCheckEditor.ContainsKey(currKeyStr)) { + currList = dicCheckEditor.get_Item(currKeyStr); + } + else { + currList = UnityResolve::Invoke("il2cpp_object_new", List_String_klass); + List_String_ctor(currList, List_String_ctor_mtd); + } + Il2cppUtils::Tools::CSListEditor currListEditor(currList); + if (!currListEditor.Contains(charaId)) { + currListEditor.Add(charaId); + } + + }*/ + } return PictureBookWindowPresenter_GetLiveMusics_Orig(self, charaId, mtd); @@ -906,7 +978,7 @@ namespace GakumasLocal::HookMain { DEFINE_HOOK(void, PictureBookLiveSelectScreenModel_ctor, (void* self, void* transitionParam, UnityResolve::UnityType::List* musics, void* mtd)) { // Log::DebugFmt("PictureBookLiveSelectScreenModel_ctor"); - if (Config::unlockAllLive) { + if (Config::dbgMode && Config::unlockAllLive) { static auto GetLiveMusics = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.OutGame", "PictureBookWindowPresenter", "GetLiveMusics"); if (PictureBookWindowPresenter_instance && !PictureBookWindowPresenter_charaId.empty()) { @@ -920,17 +992,16 @@ namespace GakumasLocal::HookMain { } bool needRestoreHides = false; - DEFINE_HOOK(void*, PictureBookLiveSelectScreenPresenter_MoveLiveScene, (void* self, void* produceLive, - Il2cppString* characterId, Il2cppString* idolCardId, Il2cppString* costumeId, Il2cppString* costumeHeadId, void* mtd)) { + DEFINE_HOOK(void*, PictureBookLiveSelectScreenPresenter_MoveLiveScene, (void* self, void* produceLive, bool isPlayCharacterFocusCamera, void* mtd)) { needRestoreHides = false; - Log::InfoFmt("MoveLiveScene: characterId: %s, idolCardId: %s, costumeId: %s, costumeHeadId: %s,", - characterId->ToString().c_str(), idolCardId->ToString().c_str(), costumeId->ToString().c_str(), costumeHeadId->ToString().c_str()); + // Log::InfoFmt("MoveLiveScene: characterId: %s, idolCardId: %s, costumeId: %s, costumeHeadId: %s,", + // characterId->ToString().c_str(), idolCardId->ToString().c_str(), costumeId->ToString().c_str(), costumeHeadId->ToString().c_str()); /* characterId: hski, costumeId: hski-cstm-0002, costumeHeadId: costume_head_hski-cstm-0002, characterId: shro, costumeId: shro-cstm-0006, costumeHeadId: costume_head_shro-cstm-0006, */ - + /* if (Config::dbgMode && Config::enableLiveCustomeDress) { // 修改 LiveFixedData_GetCharacter 可以更改 Loading 角色和演唱者名字,而不变更实际登台人 return PictureBookLiveSelectScreenPresenter_MoveLiveScene_Orig(self, produceLive, characterId, idolCardId, @@ -938,8 +1009,9 @@ namespace GakumasLocal::HookMain { Config::liveCustomeHeadId.empty() ? costumeHeadId : Il2cppString::New(Config::liveCustomeHeadId), mtd); } - - return PictureBookLiveSelectScreenPresenter_MoveLiveScene_Orig(self, produceLive, characterId, idolCardId, costumeId, costumeHeadId, mtd); + */ + // return PictureBookLiveSelectScreenPresenter_MoveLiveScene_Orig(self, produceLive, characterId, idolCardId, costumeId, costumeHeadId, mtd); + return PictureBookLiveSelectScreenPresenter_MoveLiveScene_Orig(self, produceLive, isPlayCharacterFocusCamera, mtd); } // std::string lastMusicId; @@ -1624,6 +1696,10 @@ namespace GakumasLocal::HookMain { ADD_HOOK(PictureBookWindowPresenter_GetLiveMusics, Il2cppUtils::GetMethodPointer("Assembly-CSharp.dll", "Campus.OutGame", "PictureBookWindowPresenter", "GetLiveMusics")); + + ADD_HOOK(Produce_ViewPictureBookLiveAsync, + Il2cppUtils::GetMethodPointer("Assembly-CSharp.dll", "", + "Produce", "ViewPictureBookLiveAsync")); ADD_HOOK(PictureBookLiveSelectScreenModel_ctor, Il2cppUtils::GetMethodPointer("Assembly-CSharp.dll", "Campus.OutGame", "PictureBookLiveSelectScreenModel", ".ctor")); diff --git a/src/GakumasLocalify/Il2cppUtils.hpp b/src/GakumasLocalify/Il2cppUtils.hpp index 07f6322..bd9e5d2 100644 --- a/src/GakumasLocalify/Il2cppUtils.hpp +++ b/src/GakumasLocalify/Il2cppUtils.hpp @@ -337,17 +337,23 @@ namespace Il2cppUtils { 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_Contains_method = il2cpp_class_get_method_from_name(list_klass, "Contains", 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); + lst_Contains = reinterpret_cast(lst_Contains_method->methodPointer); } void Add(T value) { lst_Add(lst, value, lst_Add_method); } + bool Contains(T value) { + return lst_Contains(lst, value, lst_Contains_method); + } + T get_Item(int index) { return lst_get_Item(lst, index, lst_get_Item_method); } @@ -401,16 +407,86 @@ namespace Il2cppUtils { 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); + typedef bool(*lst_Contains_t)(void*, T, void* mtd); MethodInfo* lst_get_Item_method; MethodInfo* lst_Add_method; MethodInfo* lst_get_Count_method; MethodInfo* lst_set_Item_method; + MethodInfo* lst_Contains_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; + lst_Contains_t lst_Contains; + }; + + + template + class CSDictEditor { + public: + // @param dict: Dictionary instance. + // @param dictTypeStr: Reflection type. eg: "System.Collections.Generic.Dictionary`2[System.Int32, System.Int32]" + CSDictEditor(void* dict, const char* dictTypeStr) { + dic_klass = Il2cppUtils::get_system_class_from_reflection_type_str(dictTypeStr); + initDict(dict); + } + + CSDictEditor(void* dict) { + dic_klass = get_class_from_instance(dict); + initDict(dict); + } + + CSDictEditor(void* dict, void* dicClass) { + dic_klass = dicClass; + initDict(dict); + } + + void Add(KT key, VT value) { + dic_Add(dict, key, value, Add_method); + } + + bool ContainsKey(KT key) { + return dic_containsKey(dict, key, ContainsKey_method); + } + + VT get_Item(KT key) { + return dic_get_Item(dict, key, get_Item_method); + } + + VT operator[] (KT key) { + return get_Item(key); + } + + void* dict; + void* dic_klass; + + private: + void initDict(void* dict) { + // dic_klass = dicClass; + this->dict = dict; + + get_Item_method = il2cpp_class_get_method_from_name(dic_klass, "get_Item", 1); + Add_method = il2cpp_class_get_method_from_name(dic_klass, "Add", 2); + ContainsKey_method = il2cpp_class_get_method_from_name(dic_klass, "ContainsKey", 1); + + dic_get_Item = (dic_get_Item_t)get_Item_method->methodPointer; + dic_Add = (dic_Add_t)Add_method->methodPointer; + dic_containsKey = (dic_containsKey_t)ContainsKey_method->methodPointer; + } + + typedef VT(*dic_get_Item_t)(void*, KT, void* mtd); + typedef VT(*dic_Add_t)(void*, KT, VT, void* mtd); + typedef VT(*dic_containsKey_t)(void*, KT, void* mtd); + + CSDictEditor(); + MethodInfo* get_Item_method; + MethodInfo* Add_method; + MethodInfo* ContainsKey_method; + dic_get_Item_t dic_get_Item; + dic_Add_t dic_Add; + dic_containsKey_t dic_containsKey; }; } diff --git a/src/GakumasLocalify/Local.cpp b/src/GakumasLocalify/Local.cpp index 9c6c277..08f065f 100644 --- a/src/GakumasLocalify/Local.cpp +++ b/src/GakumasLocalify/Local.cpp @@ -17,7 +17,7 @@ #include "BaseDefine.h" #include "string_parser/StringParser.hpp" -#include "cpprest/details/http_helpers.h" +// #include "cpprest/details/http_helpers.h" namespace GakumasLocal::Local { diff --git a/src/gkmsGUI/gkmsGUILoop.cpp b/src/gkmsGUI/gkmsGUILoop.cpp index a4fc227..a3b8d11 100644 --- a/src/gkmsGUI/gkmsGUILoop.cpp +++ b/src/gkmsGUI/gkmsGUILoop.cpp @@ -396,11 +396,11 @@ namespace GkmsGUILoop { ImGui::Checkbox(ts("unlockAllLive"), &Config::unlockAllLive); ImGui::Checkbox(ts("unlockAllLiveCostume"), &Config::unlockAllLiveCostume); - ImGui::Checkbox(ts("liveUseCustomeDress"), &Config::enableLiveCustomeDress); + /*ImGui::Checkbox(ts("liveUseCustomeDress"), &Config::enableLiveCustomeDress); if (Config::enableLiveCustomeDress) { InputTextString(ts("live_costume_head_id"), &Config::liveCustomeHeadId); InputTextString(ts("live_custome_dress_id"), &Config::liveCustomeCostumeId); - } + }*/ ImGui::Unindent(indentWidth); } diff --git a/src/platformDefine.hpp b/src/platformDefine.hpp index d8c024e..732ff86 100644 --- a/src/platformDefine.hpp +++ b/src/platformDefine.hpp @@ -11,7 +11,7 @@ #define LogMinVersion ANDROID_LOG_DEBUG -#define PLUGIN_VERSION "3.0.3" +#define PLUGIN_VERSION "3.0.4" #define ADD_HOOK(name, addr) \ name##_Addr = reinterpret_cast(addr); \