add ListEditor tool function

This commit is contained in:
chinosk 2024-12-24 02:33:56 +00:00
parent c27085772f
commit 6ac94178fa
Signed by: chinosk
GPG Key ID: 00610B08C1BF7BE9
2 changed files with 202 additions and 33 deletions

View File

@ -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<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);
@ -533,7 +507,13 @@ namespace GakumasLocal::HookMain {
PictureBookLiveThumbnailView_SetDataAsync_Orig(self, liveData, isReleased, isUnlocked, isNew, hasLiveSkin, ct, mtd);
}
std::vector<std::string> GetIdolMusicIdAll(const std::string& charaNameId = "") {
enum class GetIdolIdType {
MusicId,
CostumeId,
CostumeHeadId
};
std::vector<std::string> GetIdolMusicIdAll(const std::string& charaNameId = "", GetIdolIdType getType = GetIdolIdType::MusicId) {
// 传入例: fktn
// System.Collections.Generic.List`1<valuetype [mscorlib]System.ValueTuple`2<class Campus.Common.Proto.Client.Master.IdolCardSkin, class Campus.Common.Proto.Client.Master.Music>>
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<Il2cppString*>(i);
auto musicId = IdolCardSkin_get_MusicId->Invoke<Il2cppString*>(i);
auto targetId = idGetFunc->Invoke<Il2cppString*>(i);
auto cardId = IdolCardSkin_get_IdolCardId->Invoke<Il2cppString*>(i)->ToString();
auto music = IdolCardSkin_GetMusic->Invoke<void*>(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<std::string>& 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<Il2cppString*>(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<void>(userCostume, Il2cppString::New(i));
listEditor.set_Item(currIndex, userCostume);
}
else {
auto userCostume = Clone->Invoke<void*>(listEditor.get_Item(0));
set_CostumeId->Invoke<void>(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<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") {
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<Campus.Common.Proto.Client.Transaction.UserCostumeHead>
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<Campus.Common.Proto.Client.Transaction.UserCostume>
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<void (*)(void*, void*)>(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<void (*)(void*, void*, void*)>(List_String_Add_mtd->methodPointer);
auto newList = UnityResolve::Invoke<void*>("il2cpp_object_new", List_String_klass);
List_String_ctor(newList, List_String_ctor_mtd);
Il2cppUtils::Tools::CSListEditor<Il2cppString*> 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());

View File

@ -244,4 +244,95 @@ namespace Il2cppUtils {
auto reflectionType = assemblyGetType(reflectionAssembly, Il2CppString::New(typeStr));
return UnityResolve::Invoke<void*>("il2cpp_class_from_system_type", reflectionType);
}
namespace Tools {
template <typename T = void*>
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_t>(lst_get_Count_method->methodPointer);
lst_get_Item = reinterpret_cast<lst_get_Item_t>(lst_get_Item_method->methodPointer);
lst_set_Item = reinterpret_cast<lst_set_Item_t>(lst_set_Item_method->methodPointer);
lst_Add = reinterpret_cast<lst_Add_t>(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<T>* 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<T>* 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;
};
}
}