From e859589125f43533c6c7ad8a702b83df5b7f8ec7 Mon Sep 17 00:00:00 2001 From: chinosk <2248589280@qq.com> Date: Sun, 27 Apr 2025 15:50:38 +0100 Subject: [PATCH] fixed live --- app/build.gradle | 2 +- app/src/main/cpp/GakumasLocalify/Hook.cpp | 231 ++++++++++++++++-- .../main/cpp/GakumasLocalify/Il2cppUtils.hpp | 76 ++++++ app/src/main/cpp/GakumasLocalify/Local.cpp | 12 +- app/src/main/cpp/GakumasLocalify/Misc.cpp | 23 +- .../cpp/GakumasLocalify/config/Config.cpp | 4 + .../cpp/GakumasLocalify/config/Config.hpp | 2 + .../ui/pages/subPages/AdvancedSettingsPage.kt | 4 +- 8 files changed, 325 insertions(+), 29 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 7f906c9..ec2fa7f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,7 +16,7 @@ android { minSdk 29 targetSdk 34 versionCode 12 - versionName "v3.0.0" + versionName "v3.0.4" buildConfigField "String", "VERSION_NAME", "\"${versionName}\"" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/cpp/GakumasLocalify/Hook.cpp b/app/src/main/cpp/GakumasLocalify/Hook.cpp index 4d5073f..f66f5b3 100644 --- a/app/src/main/cpp/GakumasLocalify/Hook.cpp +++ b/app/src/main/cpp/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) { @@ -514,6 +526,26 @@ namespace GakumasLocal::HookMain { UpdateFont(self); } + DEFINE_HOOK(void, TMP_Text_SetText_2, (void* self, Il2cppString* sourceText, bool syncTextInputBox, void* mtd)) { + if (!sourceText) { + return TMP_Text_SetText_2_Orig(self, sourceText, syncTextInputBox, mtd); + } + const std::string origText = sourceText->ToString(); + std::string transText; + if (Local::GetGenericText(origText, &transText)) { + const auto newText = UnityResolve::UnityType::String::New(transText); + UpdateFont(self); + return TMP_Text_SetText_2_Orig(self, newText, syncTextInputBox, mtd); + } + if (Config::textTest) { + TMP_Text_SetText_2_Orig(self, UnityResolve::UnityType::String::New("[TS]" + sourceText->ToString()), syncTextInputBox, mtd); + } + else { + TMP_Text_SetText_2_Orig(self, sourceText, syncTextInputBox, mtd); + } + UpdateFont(self); + } + DEFINE_HOOK(void, TextMeshProUGUI_Awake, (void* self, void* method)) { // Log::InfoFmt("TextMeshProUGUI_Awake at %p, self at %p", TextMeshProUGUI_Awake_Orig, self); @@ -683,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 @@ -845,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)) { @@ -857,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); @@ -886,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()) { @@ -900,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, @@ -918,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; @@ -1240,6 +1332,70 @@ namespace GakumasLocal::HookMain { return ret; } +#ifdef GKMS_WINDOWS + // DMM Only + DEFINE_HOOK(void*, WindowHandle_SetWindowLong, (int32_t nIndex, intptr_t dwNewLong, void* mtd)) { + if (GakumasLocal::Config::dmmUnlockSize) { + // Log::DebugFmt("WindowHandle_SetWindowLong: %d, %p\n", nIndex, dwNewLong); + + if (nIndex == GWLP_WNDPROC) { + return 0; + } + } + + return WindowHandle_SetWindowLong_Orig(nIndex, dwNewLong, mtd); + } + + // DMM Only + void SetResolution(int width, int height, bool fullscreen) { + static auto Screen_SetResolution = reinterpret_cast( + Il2cppUtils::il2cpp_resolve_icall("UnityEngine.Screen::SetResolution_Injected(System.Int32,System.Int32,UnityEngine.FullScreenMode,UnityEngine.RefreshRate&)")); + + int64_t v8[3]; + v8[0] = 0x100000000LL; + Screen_SetResolution(width, height, 2 * !fullscreen + 1, v8); + } + + // DMM Only + DEFINE_HOOK(void, WindowManager_ApplyOrientationSettings, (int orientation, void* method)) { + if (!GakumasLocal::Config::dmmUnlockSize) return WindowManager_ApplyOrientationSettings_Orig(orientation, method); + + static auto get_Height = reinterpret_cast(Il2cppUtils::il2cpp_resolve_icall("UnityEngine.Screen::get_height()")); + static auto get_Width = reinterpret_cast(Il2cppUtils::il2cpp_resolve_icall("UnityEngine.Screen::get_width()")); + + static auto lastWidth = -1; + static auto lastHeight = -1; + + const auto currWidth = get_Width(); + const auto currHeight = get_Height(); + + if (lastWidth == -1) { + lastWidth = currWidth; + lastHeight = currHeight; + return; + } + + const bool lastIsPortrait = lastWidth < lastHeight; + const bool currIsPortrait = currWidth < currHeight; + if (lastIsPortrait == currIsPortrait) { + lastWidth = currWidth; + lastHeight = currHeight; + return; + } + + SetResolution(lastWidth, lastHeight, false); + lastWidth = currWidth; + lastHeight = currHeight; + + Log::DebugFmt("WindowManager_ApplyOrientationSettings: %d (%d, %d)\n", orientation, get_Width(), get_Height()); + } + + // DMM Only + DEFINE_HOOK(void, AspectRatioHandler_NudgeWindow, (void* method)) { + if (!GakumasLocal::Config::dmmUnlockSize) return AspectRatioHandler_NudgeWindow_Orig(method); + // printf("AspectRatioHandler_NudgeWindow\n"); + } +#endif void UpdateSwingBreastBonesData(void* initializeData) { if (!Config::enableBreastParam) return; @@ -1444,6 +1600,9 @@ namespace GakumasLocal::HookMain { ADD_HOOK(TMP_Text_PopulateTextBackingArray, Il2cppUtils::GetMethodPointer("Unity.TextMeshPro.dll", "TMPro", "TMP_Text", "PopulateTextBackingArray", {"System.String", "System.Int32", "System.Int32"})); + ADD_HOOK(TMP_Text_SetText_2, Il2cppUtils::GetMethodPointer("Unity.TextMeshPro.dll", "TMPro", + "TMP_Text", "SetText", + { "System.String", "System.Boolean" })); ADD_HOOK(TextField_set_value, Il2cppUtils::GetMethodPointer("UnityEngine.UIElementsModule.dll", "UnityEngine.UIElements", "TextField", "set_value")); @@ -1537,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")); @@ -1634,6 +1797,32 @@ namespace GakumasLocal::HookMain { "RenderPipeline", "EndCameraRendering")); #ifdef GKMS_WINDOWS + ADD_HOOK(WindowHandle_SetWindowLong, Il2cppUtils::GetMethodPointer("Assembly-CSharp.dll", "Campus.Common.StandAloneWindow", + "WindowHandle", "SetWindowLong")); + //ADD_HOOK(WindowHandle_SetWindowLong32, Il2cppUtils::GetMethodPointer("Assembly-CSharp.dll", "Campus.Common.StandAloneWindow", + // "WindowHandle", "SetWindowLong32")); + //ADD_HOOK(WindowHandle_SetWindowLongPtr64, Il2cppUtils::GetMethodPointer("Assembly-CSharp.dll", "Campus.Common.StandAloneWindow", + // "WindowHandle", "SetWindowLongPtr64")); + //ADD_HOOK(WindowSizeUtility_RestoreWindowSize, Il2cppUtils::GetMethodPointer("Assembly-CSharp.dll", "Campus.Common.StandAloneWindow", + // "WindowSizeUtility", "RestoreWindowSize")); + ADD_HOOK(WindowManager_ApplyOrientationSettings, Il2cppUtils::GetMethodPointer("Assembly-CSharp.dll", "Campus.Common.StandAloneWindow", + "WindowManager", "ApplyOrientationSettings")); + ADD_HOOK(AspectRatioHandler_NudgeWindow, Il2cppUtils::GetMethodPointer("Assembly-CSharp.dll", "Campus.Common.StandAloneWindow", + "AspectRatioHandler", "NudgeWindow")); + //ADD_HOOK(AspectRatioHandler_WindowProc, Il2cppUtils::GetMethodPointer("Assembly-CSharp.dll", "Campus.Common.StandAloneWindow", + // "AspectRatioHandler", "WindowProc")); + + if (GakumasLocal::Config::dmmUnlockSize) { + std::thread([]() { + std::this_thread::sleep_for(std::chrono::seconds(3)); + auto hWnd = FindWindowW(L"UnityWndClass", L"gakumas"); + // 添加可调整大小的边框和最大化按钮 + LONG style = GetWindowLong(hWnd, GWL_STYLE); + style |= WS_THICKFRAME | WS_MAXIMIZEBOX; + SetWindowLong(hWnd, GWL_STYLE, style); + }).detach(); + } + g_extra_assetbundle_paths.push_back((gakumasLocalPath / "local-files/gakumasassets").string()); LoadExtraAssetBundle(); GkmsResourceUpdate::CheckUpdateFromAPI(false); diff --git a/app/src/main/cpp/GakumasLocalify/Il2cppUtils.hpp b/app/src/main/cpp/GakumasLocalify/Il2cppUtils.hpp index 07f6322..bd9e5d2 100644 --- a/app/src/main/cpp/GakumasLocalify/Il2cppUtils.hpp +++ b/app/src/main/cpp/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/app/src/main/cpp/GakumasLocalify/Local.cpp b/app/src/main/cpp/GakumasLocalify/Local.cpp index 7a4f0b9..08f065f 100644 --- a/app/src/main/cpp/GakumasLocalify/Local.cpp +++ b/app/src/main/cpp/GakumasLocalify/Local.cpp @@ -17,6 +17,8 @@ #include "BaseDefine.h" #include "string_parser/StringParser.hpp" +// #include "cpprest/details/http_helpers.h" + namespace GakumasLocal::Local { std::unordered_map i18nData{}; @@ -249,7 +251,7 @@ namespace GakumasLocal::Local { } bool GetSplitTagsTranslation(const std::string& origText, std::string* newText, std::vector& unTransResultRet) { - if (!origText.contains(L'<')) return false; + if (!origText.contains('<')) return false; const auto splitResult = SplitByTags(origText); if (splitResult.empty()) return false; @@ -289,10 +291,18 @@ namespace GakumasLocal::Local { std::u16string currentWaitingReplaceText; +#ifdef GKMS_WINDOWS +#define checkCurrentWaitingReplaceTextAndClear() \ + if (!currentWaitingReplaceText.empty()) { \ + auto trimmed = trim(Misc::ToUTF8(currentWaitingReplaceText)); \ + waitingReplaceTexts.push_back(trimmed); \ + currentWaitingReplaceText.clear(); } +#else #define checkCurrentWaitingReplaceTextAndClear() \ if (!currentWaitingReplaceText.empty()) { \ waitingReplaceTexts.push_back(Misc::ToUTF8(currentWaitingReplaceText)); \ currentWaitingReplaceText.clear(); } +#endif for (char16_t currChar : origText) { if (currChar == u'<') { diff --git a/app/src/main/cpp/GakumasLocalify/Misc.cpp b/app/src/main/cpp/GakumasLocalify/Misc.cpp index 47fc3e4..0f63390 100644 --- a/app/src/main/cpp/GakumasLocalify/Misc.cpp +++ b/app/src/main/cpp/GakumasLocalify/Misc.cpp @@ -14,6 +14,24 @@ namespace GakumasLocal::Misc { + +#ifdef GKMS_WINDOWS + std::string ToUTF8(const std::wstring_view& str) { + return utility::conversions::to_utf8string(str.data()); + } + + std::u16string ToUTF16(const std::string_view& str) { + std::string input(str); + std::wstring wstr = utility::conversions::utf8_to_utf16(input); + return std::u16string(wstr.begin(), wstr.end()); + } + + std::string ToUTF8(const std::u16string_view& str) { + std::u16string u16(str); + std::wstring wstr(u16.begin(), u16.end()); + return utility::conversions::utf16_to_utf8(wstr); + } +#else std::u16string ToUTF16(const std::string_view& str) { std::wstring_convert, char16_t> utf16conv; return utf16conv.from_bytes(str.data(), str.data() + str.size()); @@ -23,11 +41,6 @@ namespace GakumasLocal::Misc { std::wstring_convert, char16_t> utf16conv; return utf16conv.to_bytes(str.data(), str.data() + str.size()); } - -#ifdef GKMS_WINDOWS - std::string ToUTF8(const std::wstring_view& str) { - return utility::conversions::to_utf8string(str.data()); - } #endif #ifndef GKMS_WINDOWS diff --git a/app/src/main/cpp/GakumasLocalify/config/Config.cpp b/app/src/main/cpp/GakumasLocalify/config/Config.cpp index f8dd59a..57ea8e3 100644 --- a/app/src/main/cpp/GakumasLocalify/config/Config.cpp +++ b/app/src/main/cpp/GakumasLocalify/config/Config.cpp @@ -54,6 +54,8 @@ namespace GakumasLocal::Config { float bLimitZx = 1.0f; float bLimitZy = 1.0f; + bool dmmUnlockSize = false; + void LoadConfig(const std::string& configStr) { try { const auto config = nlohmann::json::parse(configStr); @@ -102,6 +104,7 @@ namespace GakumasLocal::Config { GetConfigItem(bLimitYy); GetConfigItem(bLimitZx); GetConfigItem(bLimitZy); + GetConfigItem(dmmUnlockSize); } catch (std::exception& e) { Log::ErrorFmt("LoadConfig error: %s", e.what()); @@ -157,6 +160,7 @@ namespace GakumasLocal::Config { SetConfigItem(bLimitYy); SetConfigItem(bLimitZx); SetConfigItem(bLimitZy); + SetConfigItem(dmmUnlockSize); std::ofstream out(configPath); if (!out) { diff --git a/app/src/main/cpp/GakumasLocalify/config/Config.hpp b/app/src/main/cpp/GakumasLocalify/config/Config.hpp index 49f2a67..1147f53 100644 --- a/app/src/main/cpp/GakumasLocalify/config/Config.hpp +++ b/app/src/main/cpp/GakumasLocalify/config/Config.hpp @@ -51,6 +51,8 @@ namespace GakumasLocal::Config { extern float bLimitZx; extern float bLimitZy; + extern bool dmmUnlockSize; + void LoadConfig(const std::string& configStr); void SaveConfig(const std::string& configPath); } diff --git a/app/src/main/java/io/github/chinosk/gakumas/localify/ui/pages/subPages/AdvancedSettingsPage.kt b/app/src/main/java/io/github/chinosk/gakumas/localify/ui/pages/subPages/AdvancedSettingsPage.kt index cfc8e07..70145dd 100644 --- a/app/src/main/java/io/github/chinosk/gakumas/localify/ui/pages/subPages/AdvancedSettingsPage.kt +++ b/app/src/main/java/io/github/chinosk/gakumas/localify/ui/pages/subPages/AdvancedSettingsPage.kt @@ -365,6 +365,8 @@ fun AdvanceSettingsPage(modifier: Modifier = Modifier, checked = config.value.unlockAllLiveCostume) { v -> context?.onUnlockAllLiveCostumeChanged(v) } + + /* HorizontalDivider( thickness = 1.dp, color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f) @@ -389,7 +391,7 @@ fun AdvanceSettingsPage(modifier: Modifier = Modifier, value = config.value.liveCustomeCostumeId, onValueChange = { c -> context?.onLiveCustomeCostumeIdChanged(c, 0, 0, 0)}, label = { Text(stringResource(R.string.live_custome_dress_id)) } - ) + )*/ } } }