From 361c48e2c9ebf0a753030cb728c21112a824c52f Mon Sep 17 00:00:00 2001
From: chinosk <2248589280@qq.com>
Date: Tue, 24 Dec 2024 00:52:11 +0000
Subject: [PATCH] fix: incomplete hooks

---
 app/src/main/cpp/GakumasLocalify/Hook.cpp     | 105 +++++++++++++++++-
 .../cpp/GakumasLocalify/config/Config.cpp     |   2 +
 .../cpp/GakumasLocalify/config/Config.hpp     |   1 +
 .../gakumas/localify/ConfigUpdateListener.kt  |   6 +
 .../gakumas/localify/models/GakumasConfig.kt  |   1 +
 .../ui/pages/subPages/AdvancedSettingsPage.kt |   4 +
 app/src/main/res/values-ja/strings.xml        |   1 +
 app/src/main/res/values-zh-rCN/strings.xml    |   1 +
 app/src/main/res/values/strings.xml           |   1 +
 9 files changed, 116 insertions(+), 6 deletions(-)

diff --git a/app/src/main/cpp/GakumasLocalify/Hook.cpp b/app/src/main/cpp/GakumasLocalify/Hook.cpp
index 157eee2..0da1087 100644
--- a/app/src/main/cpp/GakumasLocalify/Hook.cpp
+++ b/app/src/main/cpp/GakumasLocalify/Hook.cpp
@@ -466,14 +466,71 @@ namespace GakumasLocal::HookMain {
         // return UnityResolve::UnityType::String::New("[I18]" + ret->ToString());
     }
 
-    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);
+    /*
+    DEFINE_HOOK(void*, UserDataManagerBase_get__userIdolCardSkinList, (void* self, void* mtd)) {  // Live默认选择
+        auto ret = UserDataManagerBase_get__userIdolCardSkinList_Orig(self, mtd);
+        Log::DebugFmt("UserDataManagerBase_get__userIdolCardSkinList: %p", ret);
+        return ret;
+    }
+    DEFINE_HOOK(void*, UserDataManagerBase_get__userCostumeList, (void* self, void* mtd)) {  // 服装选择界面
+        auto ret = UserDataManagerBase_get__userCostumeList_Orig(self, mtd);
+        Log::DebugFmt("UserDataManagerBase_get__userCostumeList: %p", ret);
+        return ret;
+    }
+    DEFINE_HOOK(void*, UserDataManagerBase_get__userCostumeHeadList, (void* self, void* mtd)) {  // 服装选择界面
+        auto ret = UserDataManagerBase_get__userCostumeHeadList_Orig(self, mtd);
+        Log::DebugFmt("UserDataManagerBase_get__userCostumeHeadList: %p", ret);
+        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<void* (*)(void*, void*)>(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);
+        if (!Config::unlockAllLive) return ret;
+
+        if (id) {
+            std::string idStr = id->ToString();
+            if (idStr.starts_with("music") || idStr.starts_with("i_card-skin")) {  // eg. music-all-kllj-006, i_card-skin-hski-3-002
+                return true;
+            }
+        }
+        return ret;
+    }
+
+    DEFINE_HOOK(void, PictureBookLiveThumbnailView_SetDataAsync, (void* self, void* liveData, 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_SetData_Orig(self, liveData, isReleased, isUnlocked, isNew, hasLiveSkin, ct, mtd);
+        PictureBookLiveThumbnailView_SetDataAsync_Orig(self, liveData, isReleased, isUnlocked, isNew, hasLiveSkin, ct, mtd);
     }
 
     std::vector<std::string> GetIdolMusicIdAll(const std::string& charaNameId = "") {
@@ -1011,9 +1068,45 @@ namespace GakumasLocal::HookMain {
                  Il2cppUtils::GetMethodPointer("Octo.dll", "Octo",
                                                "OnDownloadProgress", "Invoke"));
 
-        ADD_HOOK(PictureBookLiveThumbnailView_SetData,
+        /*
+        auto UserDataManager_klass = Il2cppUtils::GetClass("Assembly-CSharp.dll", "Campus.Common.User",
+                                                           "UserDataManager");
+        if (UserDataManager_klass) {
+            auto UserDataManagerBase_klass = UnityResolve::Invoke<Il2cppUtils::Il2CppClassHead*>("il2cpp_class_get_parent", UserDataManager_klass->address);
+            if (UserDataManagerBase_klass) {
+                auto get_userIdolCardSkinList_mtd = Il2cppUtils::il2cpp_class_get_method_from_name(UserDataManagerBase_klass, "get__userIdolCardSkinList", 0);
+                if (get_userIdolCardSkinList_mtd) {
+                    ADD_HOOK(UserDataManagerBase_get__userIdolCardSkinList, get_userIdolCardSkinList_mtd->methodPointer);
+                }
+                auto get_userCostumeList_mtd = Il2cppUtils::il2cpp_class_get_method_from_name(UserDataManagerBase_klass, "get__userCostumeList", 0);
+                if (get_userCostumeList_mtd) {
+                    ADD_HOOK(UserDataManagerBase_get__userCostumeList, get_userCostumeList_mtd->methodPointer);
+                }
+                auto get_userCostumeHeadList_mtd = Il2cppUtils::il2cpp_class_get_method_from_name(UserDataManagerBase_klass, "get__userCostumeHeadList", 0);
+                if (get_userCostumeHeadList_mtd) {
+                    ADD_HOOK(UserDataManagerBase_get__userCostumeHeadList, get_userCostumeHeadList_mtd->methodPointer);
+                }
+            }
+        }*/
+
+        auto UserIdolCardSkinCollection_klass = Il2cppUtils::GetClass("Assembly-CSharp.dll", "Campus.Common.User",
+                                                                      "UserIdolCardSkinCollection");
+        auto UserIdolCardSkinCollection_Exists_mtd = Il2cppUtils::il2cpp_class_get_method_from_name(UserIdolCardSkinCollection_klass->address, "Exists", 1);
+        if (UserIdolCardSkinCollection_Exists_mtd) {
+            ADD_HOOK(UserIdolCardSkinCollection_Exists, UserIdolCardSkinCollection_Exists_mtd->methodPointer);
+        }
+
+        auto UserCostumeCollection_klass = Il2cppUtils::GetClass("Assembly-CSharp.dll", "Campus.Common.User",
+                                                                      "UserCostumeCollection");
+        auto UserCostumeCollection_FindBy_mtd = Il2cppUtils::il2cpp_class_get_method_from_name(
+                UserCostumeCollection_klass->address, "FindBy", 1);
+        if (UserCostumeCollection_FindBy_mtd) {
+            ADD_HOOK(UserCostumeCollection_FindBy, UserCostumeCollection_FindBy_mtd->methodPointer);
+        }
+
+        ADD_HOOK(PictureBookLiveThumbnailView_SetDataAsync,
                  Il2cppUtils::GetMethodPointer("Assembly-CSharp.dll", "Campus.OutGame.PictureBook",
-                                               "PictureBookLiveThumbnailView", "SetDataAsync", {"*", "*", "*", "*"}));
+                                               "PictureBookLiveThumbnailView", "SetDataAsync", {"*", "*", "*", "*", "*"}));
         ADD_HOOK(PictureBookWindowPresenter_GetLiveMusics,
                  Il2cppUtils::GetMethodPointer("Assembly-CSharp.dll", "Campus.OutGame",
                                                "PictureBookWindowPresenter", "GetLiveMusics"));
diff --git a/app/src/main/cpp/GakumasLocalify/config/Config.cpp b/app/src/main/cpp/GakumasLocalify/config/Config.cpp
index 83e28a4..f262581 100644
--- a/app/src/main/cpp/GakumasLocalify/config/Config.cpp
+++ b/app/src/main/cpp/GakumasLocalify/config/Config.cpp
@@ -16,6 +16,7 @@ namespace GakumasLocal::Config {
     bool enableFreeCamera = false;
     int targetFrameRate = 0;
     bool unlockAllLive = false;
+    bool unlockAllLiveCostume = false;
 
     bool enableLiveCustomeDress = false;
     std::string liveCustomeHeadId = "";
@@ -67,6 +68,7 @@ namespace GakumasLocal::Config {
             GetConfigItem(targetFrameRate);
             GetConfigItem(enableFreeCamera);
             GetConfigItem(unlockAllLive);
+            GetConfigItem(unlockAllLiveCostume);
             GetConfigItem(enableLiveCustomeDress);
             GetConfigItem(liveCustomeHeadId);
             GetConfigItem(liveCustomeCostumeId);
diff --git a/app/src/main/cpp/GakumasLocalify/config/Config.hpp b/app/src/main/cpp/GakumasLocalify/config/Config.hpp
index 3813a4a..5020e16 100644
--- a/app/src/main/cpp/GakumasLocalify/config/Config.hpp
+++ b/app/src/main/cpp/GakumasLocalify/config/Config.hpp
@@ -14,6 +14,7 @@ namespace GakumasLocal::Config {
     extern bool enableFreeCamera;
     extern int targetFrameRate;
     extern bool unlockAllLive;
+    extern bool unlockAllLiveCostume;
 
     extern bool enableLiveCustomeDress;
     extern std::string liveCustomeHeadId;
diff --git a/app/src/main/java/io/github/chinosk/gakumas/localify/ConfigUpdateListener.kt b/app/src/main/java/io/github/chinosk/gakumas/localify/ConfigUpdateListener.kt
index 3fa7fd9..23c2b87 100644
--- a/app/src/main/java/io/github/chinosk/gakumas/localify/ConfigUpdateListener.kt
+++ b/app/src/main/java/io/github/chinosk/gakumas/localify/ConfigUpdateListener.kt
@@ -24,6 +24,7 @@ interface ConfigListener {
     fun onEnableFreeCameraChanged(value: Boolean)
     fun onTargetFpsChanged(s: CharSequence, start: Int, before: Int, count: Int)
     fun onUnlockAllLiveChanged(value: Boolean)
+    fun onUnlockAllLiveCostumeChanged(value: Boolean)
     fun onLiveCustomeDressChanged(value: Boolean)
     fun onLiveCustomeHeadIdChanged(s: CharSequence, start: Int, before: Int, count: Int)
     fun onLiveCustomeCostumeIdChanged(s: CharSequence, start: Int, before: Int, count: Int)
@@ -152,6 +153,11 @@ interface ConfigUpdateListener: ConfigListener, IHasConfigItems {
         saveConfig()
     }
 
+    override fun onUnlockAllLiveCostumeChanged(value: Boolean) {
+        config.unlockAllLiveCostume = value
+        saveConfig()
+    }
+
     override fun onTargetFpsChanged(s: CharSequence, start: Int, before: Int, count: Int) {
         try {
             val valueStr = s.toString()
diff --git a/app/src/main/java/io/github/chinosk/gakumas/localify/models/GakumasConfig.kt b/app/src/main/java/io/github/chinosk/gakumas/localify/models/GakumasConfig.kt
index fca7b64..e259fd8 100644
--- a/app/src/main/java/io/github/chinosk/gakumas/localify/models/GakumasConfig.kt
+++ b/app/src/main/java/io/github/chinosk/gakumas/localify/models/GakumasConfig.kt
@@ -15,6 +15,7 @@ data class GakumasConfig (
     var enableFreeCamera: Boolean = false,
     var targetFrameRate: Int = 0,
     var unlockAllLive: Boolean = false,
+    var unlockAllLiveCostume: Boolean = false,
     var enableLiveCustomeDress: Boolean = false,
     var liveCustomeHeadId: String = "",
     var liveCustomeCostumeId: String = "",
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 88dbd58..8a41691 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
@@ -357,6 +357,10 @@ fun AdvanceSettingsPage(modifier: Modifier = Modifier,
                             checked = config.value.unlockAllLive) {
                                 v -> context?.onUnlockAllLiveChanged(v)
                         }
+                        GakuSwitch(modifier, stringResource(R.string.unlockAllLiveCostume),
+                            checked = config.value.unlockAllLiveCostume) {
+                                v -> context?.onUnlockAllLiveCostumeChanged(v)
+                        }
                         HorizontalDivider(
                             thickness = 1.dp,
                             color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index b95925c..2ca9d6a 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -118,6 +118,7 @@
     <string name="translation_repository">翻訳のリポジトリ</string>
     <string name="translation_resource_update">翻訳リソースをアップデート</string>
     <string name="unlockAllLive">すべてのライブを開放</string>
+    <string name="unlockAllLiveCostume">すべてのライブ衣装を開放</string>
     <string name="useCustomeGraphicSettings">カスタムグラフィック設定を使用する</string>
     <string name="use_remote_zip_resource">リモート ZIP リソースを使用する</string>
     <string name="usearmcorrection">Arm コレクションを使用する</string>
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index b856d71..029927d 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -8,6 +8,7 @@
     <string name="start_game">以上述配置启动游戏/重载配置</string>
     <string name="setFpsTitle">最大 FPS (0 为保持游戏原设置)</string>
     <string name="unlockAllLive">解锁所有 Live</string>
+    <string name="unlockAllLiveCostume">解锁所有 Live 服装</string>
     <string name="liveUseCustomeDress">Live 使用自定义角色</string>
     <string name="live_costume_head_id">Live 自定义头部 ID (例: costume_head_hski-cstm-0002)</string>
     <string name="live_custome_dress_id">Live 自定义服装 ID (例: hski-cstm-0002)</string>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index ed35cef..76ace6f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -8,6 +8,7 @@
     <string name="start_game">Start Game / Hot Reload Config</string>
     <string name="setFpsTitle">Max FPS (0 is Use Original Settings)</string>
     <string name="unlockAllLive">Unlock All Live</string>
+    <string name="unlockAllLiveCostume">Unlock All Live Costume</string>
     <string name="liveUseCustomeDress">Live Custom Character</string>
     <string name="live_costume_head_id">Live Custom Head ID (eg. costume_head_hski-cstm-0002)</string>
     <string name="live_custome_dress_id">Live Custom Dress ID (eg. hski-cstm-0002)</string>