866 lines
45 KiB
C++
866 lines
45 KiB
C++
#include <android/log.h>
|
||
#include "Hook.h"
|
||
#include "Plugin.h"
|
||
#include "Log.h"
|
||
#include "../deps/UnityResolve/UnityResolve.hpp"
|
||
#include "Il2cppUtils.hpp"
|
||
#include "Local.h"
|
||
#include <unordered_set>
|
||
#include "camera/camera.hpp"
|
||
#include "config/Config.hpp"
|
||
#include "shadowhook.h"
|
||
#include <jni.h>
|
||
#include <thread>
|
||
#include <map>
|
||
|
||
|
||
std::unordered_set<void*> hookedStubs{};
|
||
|
||
#define DEFINE_HOOK(returnType, name, params) \
|
||
using name##_Type = returnType(*) params; \
|
||
name##_Type name##_Addr = nullptr; \
|
||
name##_Type name##_Orig = nullptr; \
|
||
returnType name##_Hook params
|
||
|
||
|
||
#define ADD_HOOK(name, addr) \
|
||
name##_Addr = reinterpret_cast<name##_Type>(addr); \
|
||
if (addr) { \
|
||
auto stub = hookInstaller->InstallHook(reinterpret_cast<void*>(addr), \
|
||
reinterpret_cast<void*>(name##_Hook), \
|
||
reinterpret_cast<void**>(&name##_Orig)); \
|
||
if (stub == NULL) { \
|
||
int error_num = shadowhook_get_errno(); \
|
||
const char *error_msg = shadowhook_to_errmsg(error_num); \
|
||
Log::ErrorFmt("ADD_HOOK: %s at %p failed: %s", #name, addr, error_msg); \
|
||
} \
|
||
else { \
|
||
hookedStubs.emplace(stub); \
|
||
GakumasLocal::Log::InfoFmt("ADD_HOOK: %s at %p", #name, addr); \
|
||
} \
|
||
} \
|
||
else GakumasLocal::Log::ErrorFmt("Hook failed: %s is NULL", #name, addr)
|
||
|
||
void UnHookAll() {
|
||
for (const auto i: hookedStubs) {
|
||
int result = shadowhook_unhook(i);
|
||
if(result != 0)
|
||
{
|
||
int error_num = shadowhook_get_errno();
|
||
const char *error_msg = shadowhook_to_errmsg(error_num);
|
||
GakumasLocal::Log::ErrorFmt("unhook failed: %d - %s", error_num, error_msg);
|
||
}
|
||
}
|
||
}
|
||
|
||
namespace GakumasLocal::HookMain {
|
||
using Il2cppString = UnityResolve::UnityType::String;
|
||
|
||
UnityResolve::UnityType::String* environment_get_stacktrace() {
|
||
/*
|
||
static auto mtd = Il2cppUtils::GetMethod("mscorlib.dll", "System",
|
||
"Environment", "get_StackTrace");
|
||
return mtd->Invoke<UnityResolve::UnityType::String*>();*/
|
||
const auto pClass = Il2cppUtils::GetClass("mscorlib.dll", "System.Diagnostics",
|
||
"StackTrace");
|
||
|
||
const auto ctor_mtd = Il2cppUtils::GetMethod("mscorlib.dll", "System.Diagnostics",
|
||
"StackTrace", ".ctor");
|
||
const auto toString_mtd = Il2cppUtils::GetMethod("mscorlib.dll", "System.Diagnostics",
|
||
"StackTrace", "ToString");
|
||
|
||
const auto klassInstance = pClass->New<void*>();
|
||
ctor_mtd->Invoke<void>(klassInstance);
|
||
return toString_mtd->Invoke<Il2cppString*>(klassInstance);
|
||
}
|
||
|
||
DEFINE_HOOK(void, Internal_LogException, (void* ex, void* obj)) {
|
||
Internal_LogException_Orig(ex, obj);
|
||
static auto Exception_ToString = Il2cppUtils::GetMethod("mscorlib.dll", "System", "Exception", "ToString");
|
||
Log::LogUnityLog(ANDROID_LOG_ERROR, "UnityLog - Internal_LogException:\n%s", Exception_ToString->Invoke<Il2cppString*>(ex)->ToString().c_str());
|
||
}
|
||
|
||
DEFINE_HOOK(void, Internal_Log, (int logType, int logOption, UnityResolve::UnityType::String* content, void* context)) {
|
||
Internal_Log_Orig(logType, logOption, content, context);
|
||
// 2022.3.21f1
|
||
Log::LogUnityLog(ANDROID_LOG_VERBOSE, "Internal_Log:\n%s", content->ToString().c_str());
|
||
}
|
||
|
||
bool IsNativeObjectAlive(void* obj) {
|
||
static UnityResolve::Method* IsNativeObjectAliveMtd = NULL;
|
||
if (!IsNativeObjectAliveMtd) IsNativeObjectAliveMtd = Il2cppUtils::GetMethod("UnityEngine.CoreModule.dll", "UnityEngine",
|
||
"Object", "IsNativeObjectAlive");
|
||
return IsNativeObjectAliveMtd->Invoke<bool>(obj);
|
||
}
|
||
|
||
UnityResolve::UnityType::Camera* mainCameraCache = nullptr;
|
||
UnityResolve::UnityType::Transform* cameraTransformCache = nullptr;
|
||
void CheckAndUpdateMainCamera() {
|
||
if (!Config::enableFreeCamera) return;
|
||
if (IsNativeObjectAlive(mainCameraCache)) return;
|
||
|
||
mainCameraCache = UnityResolve::UnityType::Camera::GetMain();
|
||
cameraTransformCache = mainCameraCache->GetTransform();
|
||
}
|
||
|
||
Il2cppUtils::Resolution_t GetResolution() {
|
||
static auto GetResolution = Il2cppUtils::GetMethod("UnityEngine.CoreModule.dll", "UnityEngine",
|
||
"Screen", "get_currentResolution");
|
||
return GetResolution->Invoke<Il2cppUtils::Resolution_t>();
|
||
}
|
||
|
||
DEFINE_HOOK(void, Unity_set_fieldOfView, (UnityResolve::UnityType::Camera* _this, float value)) {
|
||
if (Config::enableFreeCamera) {
|
||
if (_this == mainCameraCache) {
|
||
value = GKCamera::baseCamera.fov;
|
||
}
|
||
}
|
||
Unity_set_fieldOfView_Orig(_this, value);
|
||
}
|
||
|
||
DEFINE_HOOK(float, Unity_get_fieldOfView, (UnityResolve::UnityType::Camera* _this)) {
|
||
if (Config::enableFreeCamera) {
|
||
if (_this == mainCameraCache) {
|
||
static auto get_orthographic = reinterpret_cast<bool (*)(void*)>(Il2cppUtils::il2cpp_resolve_icall(
|
||
"UnityEngine.Camera::get_orthographic()"
|
||
));
|
||
static auto set_orthographic = reinterpret_cast<bool (*)(void*, bool)>(Il2cppUtils::il2cpp_resolve_icall(
|
||
"UnityEngine.Camera::set_orthographic(System.Boolean)"
|
||
));
|
||
|
||
for (const auto& i : UnityResolve::UnityType::Camera::GetAllCamera()) {
|
||
// Log::DebugFmt("get_orthographic: %d", get_orthographic(i));
|
||
// set_orthographic(i, false);
|
||
Unity_set_fieldOfView_Orig(i, GKCamera::baseCamera.fov);
|
||
}
|
||
Unity_set_fieldOfView_Orig(_this, GKCamera::baseCamera.fov);
|
||
|
||
// Log::DebugFmt("main - get_orthographic: %d", get_orthographic(_this));
|
||
return GKCamera::baseCamera.fov;
|
||
}
|
||
}
|
||
return Unity_get_fieldOfView_Orig(_this);
|
||
}
|
||
|
||
UnityResolve::UnityType::Transform* cacheTrans = NULL;
|
||
UnityResolve::UnityType::Quaternion cacheRotation{};
|
||
UnityResolve::UnityType::Vector3 cachePosition{};
|
||
UnityResolve::UnityType::Vector3 cacheForward{};
|
||
UnityResolve::UnityType::Vector3 cacheLookAt{};
|
||
|
||
DEFINE_HOOK(void, Unity_set_rotation_Injected, (UnityResolve::UnityType::Transform* _this, UnityResolve::UnityType::Quaternion* value)) {
|
||
if (Config::enableFreeCamera) {
|
||
static auto lookat_injected = reinterpret_cast<void (*)(void*_this,
|
||
UnityResolve::UnityType::Vector3* worldPosition, UnityResolve::UnityType::Vector3* worldUp)>(
|
||
Il2cppUtils::il2cpp_resolve_icall(
|
||
"UnityEngine.Transform::Internal_LookAt_Injected(UnityEngine.Vector3&,UnityEngine.Vector3&)"));
|
||
static auto worldUp = UnityResolve::UnityType::Vector3(0, 1, 0);
|
||
|
||
if (cameraTransformCache == _this) {
|
||
const auto cameraMode = GKCamera::GetCameraMode();
|
||
if (cameraMode == GKCamera::CameraMode::FIRST_PERSON) {
|
||
if (cacheTrans && IsNativeObjectAlive(cacheTrans)) {
|
||
if (GKCamera::GetFirstPersonRoll() == GKCamera::FirstPersonRoll::ENABLE_ROLL) {
|
||
*value = cacheRotation;
|
||
}
|
||
else {
|
||
static GakumasLocal::Misc::FixedSizeQueue<float> recordsY(60);
|
||
const auto newY = GKCamera::CheckNewY(cacheLookAt, true, recordsY);
|
||
UnityResolve::UnityType::Vector3 newCacheLookAt{cacheLookAt.x, newY, cacheLookAt.z};
|
||
lookat_injected(_this, &newCacheLookAt, &worldUp);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
else if (cameraMode == GKCamera::CameraMode::FOLLOW) {
|
||
auto newLookAtPos = GKCamera::CalcFollowModeLookAt(cachePosition,
|
||
GKCamera::followPosOffset, true);
|
||
lookat_injected(_this, &newLookAtPos, &worldUp);
|
||
return;
|
||
}
|
||
else {
|
||
auto& origCameraLookat = GKCamera::baseCamera.lookAt;
|
||
lookat_injected(_this, &origCameraLookat, &worldUp);
|
||
// Log::DebugFmt("fov: %f, target: %f", Unity_get_fieldOfView_Orig(mainCameraCache), GKCamera::baseCamera.fov);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
return Unity_set_rotation_Injected_Orig(_this, value);
|
||
}
|
||
|
||
DEFINE_HOOK(void, Unity_set_position_Injected, (UnityResolve::UnityType::Transform* _this, UnityResolve::UnityType::Vector3* data)) {
|
||
if (Config::enableFreeCamera) {
|
||
CheckAndUpdateMainCamera();
|
||
|
||
if (cameraTransformCache == _this) {
|
||
const auto cameraMode = GKCamera::GetCameraMode();
|
||
if (cameraMode == GKCamera::CameraMode::FIRST_PERSON) {
|
||
if (cacheTrans && IsNativeObjectAlive(cacheTrans)) {
|
||
*data = GKCamera::CalcFirstPersonPosition(cachePosition, cacheForward, GKCamera::firstPersonPosOffset);
|
||
}
|
||
|
||
}
|
||
else if (cameraMode == GKCamera::CameraMode::FOLLOW) {
|
||
auto newLookAtPos = GKCamera::CalcFollowModeLookAt(cachePosition, GKCamera::followPosOffset);
|
||
auto pos = GKCamera::CalcPositionFromLookAt(newLookAtPos, GKCamera::followPosOffset);
|
||
data->x = pos.x;
|
||
data->y = pos.y;
|
||
data->z = pos.z;
|
||
}
|
||
else {
|
||
//Log::DebugFmt("MainCamera set pos: %f, %f, %f", data->x, data->y, data->z);
|
||
auto& origCameraPos = GKCamera::baseCamera.pos;
|
||
data->x = origCameraPos.x;
|
||
data->y = origCameraPos.y;
|
||
data->z = origCameraPos.z;
|
||
}
|
||
}
|
||
}
|
||
|
||
return Unity_set_position_Injected_Orig(_this, data);
|
||
}
|
||
|
||
DEFINE_HOOK(void*, InternalSetOrientationAsync, (void* _this, int type, void* c, void* tc, void* mtd)) {
|
||
switch (Config::gameOrientation) {
|
||
case 1: type = 0x2; break; // FixedPortrait
|
||
case 2: type = 0x3; break; // FixedLandscape
|
||
default: break;
|
||
}
|
||
return InternalSetOrientationAsync_Orig(_this, type, c, tc, mtd);
|
||
}
|
||
|
||
DEFINE_HOOK(void, EndCameraRendering, (void* ctx, void* camera, void* method)) {
|
||
EndCameraRendering_Orig(ctx, camera, method);
|
||
|
||
if (Config::enableFreeCamera && mainCameraCache) {
|
||
Unity_set_fieldOfView_Orig(mainCameraCache, GKCamera::baseCamera.fov);
|
||
if (GKCamera::GetCameraMode() == GKCamera::CameraMode::FIRST_PERSON) {
|
||
mainCameraCache->SetNearClipPlane(0.001f);
|
||
}
|
||
}
|
||
}
|
||
|
||
DEFINE_HOOK(void, Unity_set_targetFrameRate, (int value)) {
|
||
const auto configFps = Config::targetFrameRate;
|
||
return Unity_set_targetFrameRate_Orig(configFps == 0 ? value: configFps);
|
||
}
|
||
|
||
std::unordered_map<void*, std::string> loadHistory{};
|
||
|
||
DEFINE_HOOK(void*, AssetBundle_LoadAssetAsync, (void* _this, Il2cppString* name, void* type)) {
|
||
// Log::InfoFmt("AssetBundle_LoadAssetAsync: %s, type: %s", name->ToString().c_str());
|
||
auto ret = AssetBundle_LoadAssetAsync_Orig(_this, name, type);
|
||
loadHistory.emplace(ret, name->ToString());
|
||
return ret;
|
||
}
|
||
|
||
DEFINE_HOOK(void*, AssetBundleRequest_GetResult, (void* _this)) {
|
||
auto result = AssetBundleRequest_GetResult_Orig(_this);
|
||
if (const auto iter = loadHistory.find(_this); iter != loadHistory.end()) {
|
||
const auto name = iter->second;
|
||
loadHistory.erase(iter);
|
||
|
||
// const auto assetClass = Il2cppUtils::get_class_from_instance(result);
|
||
// Log::InfoFmt("AssetBundleRequest_GetResult: %s, type: %s", name.c_str(), static_cast<Il2CppClassHead*>(assetClass)->name);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
DEFINE_HOOK(void*, Resources_Load, (Il2cppString* path, void* systemTypeInstance)) {
|
||
auto ret = Resources_Load_Orig(path, systemTypeInstance);
|
||
|
||
// if (ret) Log::DebugFmt("Resources_Load: %s, type: %s", path->ToString().c_str(), Il2cppUtils::get_class_from_instance(ret)->name);
|
||
|
||
return ret;
|
||
}
|
||
|
||
DEFINE_HOOK(void, I18nHelper_SetUpI18n, (void* _this, Il2cppString* lang, Il2cppString* localizationText, int keyComparison)) {
|
||
// Log::InfoFmt("SetUpI18n lang: %s, key: %d text: %s", lang->ToString().c_str(), keyComparison, localizationText->ToString().c_str());
|
||
// TODO 此处为 dump 原文 csv
|
||
I18nHelper_SetUpI18n_Orig(_this, lang, localizationText, keyComparison);
|
||
}
|
||
|
||
DEFINE_HOOK(void, I18nHelper_SetValue, (void* _this, Il2cppString* key, Il2cppString* value)) {
|
||
// Log::InfoFmt("I18nHelper_SetValue: %s - %s", key->ToString().c_str(), value->ToString().c_str());
|
||
std::string local;
|
||
if (Local::GetI18n(key->ToString(), &local)) {
|
||
I18nHelper_SetValue_Orig(_this, key, UnityResolve::UnityType::String::New(local));
|
||
return;
|
||
}
|
||
Local::DumpI18nItem(key->ToString(), value->ToString());
|
||
if (Config::textTest) {
|
||
I18nHelper_SetValue_Orig(_this, key, Il2cppString::New("[I18]" + value->ToString()));
|
||
}
|
||
else {
|
||
I18nHelper_SetValue_Orig(_this, key, value);
|
||
}
|
||
}
|
||
|
||
void* fontCache = nullptr;
|
||
void* GetReplaceFont() {
|
||
static auto CreateFontFromPath = reinterpret_cast<void (*)(void* self, Il2cppString* path)>(
|
||
Il2cppUtils::il2cpp_resolve_icall("UnityEngine.Font::Internal_CreateFontFromPath(UnityEngine.Font,System.String)")
|
||
);
|
||
static auto Font_klass = Il2cppUtils::GetClass("UnityEngine.TextRenderingModule.dll",
|
||
"UnityEngine", "Font");
|
||
static auto Font_ctor = Il2cppUtils::GetMethod("UnityEngine.TextRenderingModule.dll",
|
||
"UnityEngine", "Font", ".ctor");
|
||
if (fontCache) {
|
||
if (IsNativeObjectAlive(fontCache)) {
|
||
return fontCache;
|
||
}
|
||
}
|
||
|
||
const auto newFont = Font_klass->New<void*>();
|
||
Font_ctor->Invoke<void>(newFont);
|
||
|
||
static std::string fontName = Local::GetBasePath() / "local-files" / "gkamsZHFontMIX.otf";
|
||
CreateFontFromPath(newFont, Il2cppString::New(fontName));
|
||
fontCache = newFont;
|
||
return newFont;
|
||
}
|
||
|
||
std::unordered_set<void*> updatedFontPtrs{};
|
||
void UpdateFont(void* TMP_Text_this) {
|
||
static auto get_font = Il2cppUtils::GetMethod("Unity.TextMeshPro.dll",
|
||
"TMPro", "TMP_Text", "get_font");
|
||
static auto set_font = Il2cppUtils::GetMethod("Unity.TextMeshPro.dll",
|
||
"TMPro", "TMP_Text", "set_font");
|
||
|
||
static auto set_sourceFontFile = Il2cppUtils::GetMethod("Unity.TextMeshPro.dll", "TMPro",
|
||
"TMP_FontAsset", "set_sourceFontFile");
|
||
static auto UpdateFontAssetData = Il2cppUtils::GetMethod("Unity.TextMeshPro.dll", "TMPro",
|
||
"TMP_FontAsset", "UpdateFontAssetData");
|
||
|
||
auto fontAsset = get_font->Invoke<void*>(TMP_Text_this);
|
||
auto newFont = GetReplaceFont();
|
||
if (fontAsset && newFont) {
|
||
set_sourceFontFile->Invoke<void>(fontAsset, newFont);
|
||
if (!updatedFontPtrs.contains(fontAsset)) {
|
||
updatedFontPtrs.emplace(fontAsset);
|
||
UpdateFontAssetData->Invoke<void>(fontAsset);
|
||
}
|
||
}
|
||
set_font->Invoke<void>(TMP_Text_this, fontAsset);
|
||
}
|
||
|
||
DEFINE_HOOK(void, TMP_Text_PopulateTextBackingArray, (void* _this, UnityResolve::UnityType::String* text, int start, int length)) {
|
||
if (!text) {
|
||
return TMP_Text_PopulateTextBackingArray_Orig(_this, text, start, length);
|
||
}
|
||
|
||
static auto Substring = Il2cppUtils::GetMethod("mscorlib.dll", "System", "String", "Substring",
|
||
{"System.Int32", "System.Int32"});
|
||
|
||
const std::string origText = Substring->Invoke<Il2cppString*>(text, start, length)->ToString();
|
||
std::string transText;
|
||
if (Local::GetGenericText(origText, &transText)) {
|
||
const auto newText = UnityResolve::UnityType::String::New(transText);
|
||
return TMP_Text_PopulateTextBackingArray_Orig(_this, newText, 0, newText->length);
|
||
}
|
||
|
||
if (Config::textTest) {
|
||
TMP_Text_PopulateTextBackingArray_Orig(_this, UnityResolve::UnityType::String::New("[TP]" + text->ToString()), start, length + 4);
|
||
}
|
||
else {
|
||
TMP_Text_PopulateTextBackingArray_Orig(_this, text, start, length);
|
||
}
|
||
UpdateFont(_this);
|
||
}
|
||
|
||
DEFINE_HOOK(void, TextMeshProUGUI_Awake, (void* _this, void* method)) {
|
||
// Log::InfoFmt("TextMeshProUGUI_Awake at %p, _this at %p", TextMeshProUGUI_Awake_Orig, _this);
|
||
|
||
const auto TMP_Text_klass = Il2cppUtils::GetClass("Unity.TextMeshPro.dll",
|
||
"TMPro", "TMP_Text");
|
||
const auto get_Text_method = TMP_Text_klass->Get<UnityResolve::Method>("get_text");
|
||
const auto set_Text_method = TMP_Text_klass->Get<UnityResolve::Method>("set_text");
|
||
const auto currText = get_Text_method->Invoke<UnityResolve::UnityType::String*>(_this);
|
||
if (currText) {
|
||
//Log::InfoFmt("TextMeshProUGUI_Awake: %s", currText->ToString().c_str());
|
||
std::string transText;
|
||
if (Local::GetGenericText(currText->ToString(), &transText)) {
|
||
if (Config::textTest) {
|
||
set_Text_method->Invoke<void>(_this, UnityResolve::UnityType::String::New("[TA]" + transText));
|
||
}
|
||
else {
|
||
set_Text_method->Invoke<void>(_this, UnityResolve::UnityType::String::New(transText));
|
||
}
|
||
}
|
||
}
|
||
|
||
// set_font->Invoke<void>(_this, font);
|
||
UpdateFont(_this);
|
||
TextMeshProUGUI_Awake_Orig(_this, method);
|
||
}
|
||
|
||
// TODO 文本未hook完整
|
||
DEFINE_HOOK(void, TextField_set_value, (void* _this, Il2cppString* value)) {
|
||
Log::DebugFmt("TextField_set_value: %s", value->ToString().c_str());
|
||
TextField_set_value_Orig(_this, value);
|
||
}
|
||
|
||
DEFINE_HOOK(Il2cppString*, OctoCaching_GetResourceFileName, (void* data, void* method)) {
|
||
auto ret = OctoCaching_GetResourceFileName_Orig(data, method);
|
||
//Log::DebugFmt("OctoCaching_GetResourceFileName: %s", ret->ToString().c_str());
|
||
return ret;
|
||
}
|
||
|
||
DEFINE_HOOK(void, OctoResourceLoader_LoadFromCacheOrDownload,
|
||
(void* _this, Il2cppString* resourceName, void* onComplete, void* onProgress, void* method)) {
|
||
|
||
Log::DebugFmt("OctoResourceLoader_LoadFromCacheOrDownload: %s\n", resourceName->ToString().c_str());
|
||
|
||
std::string replaceStr;
|
||
if (Local::GetResourceText(resourceName->ToString(), &replaceStr)) {
|
||
const auto onComplete_klass = Il2cppUtils::get_class_from_instance(onComplete);
|
||
const auto onComplete_invoke_mtd = UnityResolve::Invoke<Il2cppUtils::MethodInfo*>(
|
||
"il2cpp_class_get_method_from_name", onComplete_klass, "Invoke", 2);
|
||
if (onComplete_invoke_mtd) {
|
||
const auto onComplete_invoke = reinterpret_cast<void (*)(void*, Il2cppString*, void*)>(
|
||
onComplete_invoke_mtd->methodPointer
|
||
);
|
||
onComplete_invoke(onComplete, UnityResolve::UnityType::String::New(replaceStr), NULL);
|
||
return;
|
||
}
|
||
}
|
||
|
||
return OctoResourceLoader_LoadFromCacheOrDownload_Orig(_this, resourceName, onComplete, onProgress, method);
|
||
}
|
||
|
||
DEFINE_HOOK(void, OnDownloadProgress_Invoke, (void* _this, Il2cppString* name, uint64_t receivedLength, uint64_t contentLength)) {
|
||
Log::DebugFmt("OnDownloadProgress_Invoke: %s, %lu/%lu", name->ToString().c_str(), receivedLength, contentLength);
|
||
OnDownloadProgress_Invoke_Orig(_this, name, receivedLength, contentLength);
|
||
}
|
||
|
||
// UnHooked
|
||
DEFINE_HOOK(UnityResolve::UnityType::String*, UI_I18n_GetOrDefault, (void* _this,
|
||
UnityResolve::UnityType::String* key, UnityResolve::UnityType::String* defaultKey, void* method)) {
|
||
|
||
auto ret = UI_I18n_GetOrDefault_Orig(_this, key, defaultKey, method);
|
||
|
||
// Log::DebugFmt("UI_I18n_GetOrDefault: key: %s, default: %s, result: %s", key->ToString().c_str(), defaultKey->ToString().c_str(), ret->ToString().c_str());
|
||
|
||
return ret;
|
||
// return UnityResolve::UnityType::String::New("[I18]" + ret->ToString());
|
||
}
|
||
|
||
DEFINE_HOOK(void, PictureBookLiveThumbnailView_SetData, (void* _this, void* liveData, bool isUnlocked, bool isNew)) {
|
||
// Log::DebugFmt("PictureBookLiveThumbnailView_SetData: isUnlocked: %d, isNew: %d", isUnlocked, isNew);
|
||
if (Config::unlockAllLive) {
|
||
isUnlocked = true;
|
||
}
|
||
PictureBookLiveThumbnailView_SetData_Orig(_this, liveData, isUnlocked, isNew);
|
||
}
|
||
|
||
bool needRestoreHides = false;
|
||
DEFINE_HOOK(void*, PictureBookLiveSelectScreenPresenter_MoveLiveScene, (void* _this, void* produceLive,
|
||
Il2cppString* characterId, Il2cppString* costumeId, Il2cppString* costumeHeadId)) {
|
||
needRestoreHides = false;
|
||
Log::InfoFmt("MoveLiveScene: characterId: %s, costumeId: %s, costumeHeadId: %s,",
|
||
characterId->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::enableLiveCustomeDress) {
|
||
// 修改 LiveFixedData_GetCharacter 可以更改 Loading 角色和演唱者名字,而不变更实际登台人
|
||
return PictureBookLiveSelectScreenPresenter_MoveLiveScene_Orig(_this, produceLive, characterId,
|
||
Config::liveCustomeCostumeId.empty() ? costumeId : Il2cppString::New(Config::liveCustomeCostumeId),
|
||
Config::liveCustomeHeadId.empty() ? costumeHeadId : Il2cppString::New(Config::liveCustomeHeadId));
|
||
}
|
||
|
||
return PictureBookLiveSelectScreenPresenter_MoveLiveScene_Orig(_this, produceLive, characterId, costumeId, costumeHeadId);
|
||
}
|
||
|
||
// std::string lastMusicId;
|
||
DEFINE_HOOK(void, PictureBookLiveSelectScreenPresenter_OnSelectMusic, (void* _this, void* itemModel, bool isFirst, void* mtd)) {
|
||
/* // 修改角色后,Live 结束返回时, itemModel 为 null
|
||
Log::DebugFmt("OnSelectMusic itemModel at %p", itemModel);
|
||
|
||
static auto GetMusic = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.OutGame",
|
||
"PlaylistMusicContext", "GetMusic");
|
||
static auto GetCurrMusic = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.OutGame.PictureBook",
|
||
"PictureBookLiveSelectMusicListItemModel", "get_Music");
|
||
static auto GetMusicId = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.Common.Proto.Client.Master",
|
||
"Music", "get_Id");
|
||
|
||
static auto PictureBookLiveSelectMusicListItemModel_klass = Il2cppUtils::GetClass("Assembly-CSharp.dll", "Campus.OutGame.PictureBook",
|
||
"PictureBookLiveSelectMusicListItemModel");
|
||
static auto PictureBookLiveSelectMusicListItemModel_ctor = Il2cppUtils::GetMethod("Assembly-CSharp.dll", "Campus.OutGame.PictureBook",
|
||
"PictureBookLiveSelectMusicListItemModel", ".ctor", {"*", "*"});
|
||
|
||
if (!itemModel) {
|
||
Log::DebugFmt("OnSelectMusic block", itemModel);
|
||
auto music = GetMusic->Invoke<void*>(lastMusicId);
|
||
auto newItemModel = PictureBookLiveSelectMusicListItemModel_klass->New<void*>();
|
||
PictureBookLiveSelectMusicListItemModel_ctor->Invoke<void>(newItemModel, music, false);
|
||
|
||
return PictureBookLiveSelectScreenPresenter_OnSelectMusic_Orig(_this, newItemModel, isFirst, mtd);
|
||
}
|
||
|
||
if (itemModel) {
|
||
auto currMusic = GetCurrMusic->Invoke<void*>(itemModel);
|
||
auto musicId = GetMusicId->Invoke<Il2cppString*>(currMusic);
|
||
lastMusicId = musicId->ToString();
|
||
}*/
|
||
if (!itemModel) return;
|
||
return PictureBookLiveSelectScreenPresenter_OnSelectMusic_Orig(_this, itemModel, isFirst, mtd);
|
||
}
|
||
|
||
DEFINE_HOOK(bool, VLDOF_IsActive, (void* _this)) {
|
||
if (Config::enableFreeCamera) return false;
|
||
return VLDOF_IsActive_Orig(_this);
|
||
}
|
||
|
||
DEFINE_HOOK(void, CampusQualityManager_set_TargetFrameRate, (void* _this, float value)) {
|
||
// Log::InfoFmt("CampusQualityManager_set_TargetFrameRate: %f", value);
|
||
const auto configFps = Config::targetFrameRate;
|
||
CampusQualityManager_set_TargetFrameRate_Orig(_this, configFps == 0 ? value : (float)configFps);
|
||
}
|
||
|
||
DEFINE_HOOK(void, CampusQualityManager_ApplySetting, (void* _this, int qualitySettingsLevel, int maxBufferPixel, float renderScale, int volumeIndex)) {
|
||
if (Config::targetFrameRate != 0) {
|
||
CampusQualityManager_set_TargetFrameRate_Orig(_this, Config::targetFrameRate);
|
||
}
|
||
if (Config::useCustomeGraphicSettings) {
|
||
static auto SetReflectionQuality = Il2cppUtils::GetMethod("campus-submodule.Runtime.dll", "Campus.Common",
|
||
"CampusQualityManager", "SetReflectionQuality");
|
||
static auto SetLODQuality = Il2cppUtils::GetMethod("campus-submodule.Runtime.dll", "Campus.Common",
|
||
"CampusQualityManager", "SetLODQuality");
|
||
|
||
static auto Enum_GetValues = Il2cppUtils::GetMethod("mscorlib.dll", "System", "Enum", "GetValues");
|
||
|
||
static auto QualityLevel_klass = Il2cppUtils::GetClass("campus-submodule.Runtime.dll", "", "QualityLevel");
|
||
|
||
static auto values = Enum_GetValues->Invoke<UnityResolve::UnityType::Array<int>*>(QualityLevel_klass->GetType())->ToVector();
|
||
if (values.empty()) {
|
||
values = {0x0, 0xa, 0x14, 0x1e, 0x28, 0x64};
|
||
}
|
||
if (Config::lodQualityLevel >= values.size()) Config::lodQualityLevel = values.size() - 1;
|
||
if (Config::reflectionQualityLevel >= values.size()) Config::reflectionQualityLevel = values.size() - 1;
|
||
|
||
SetLODQuality->Invoke<void>(_this, values[Config::lodQualityLevel]);
|
||
SetReflectionQuality->Invoke<void>(_this, values[Config::reflectionQualityLevel]);
|
||
|
||
qualitySettingsLevel = Config::qualitySettingsLevel;
|
||
maxBufferPixel = Config::maxBufferPixel;
|
||
renderScale = Config::renderScale;
|
||
volumeIndex = Config::volumeIndex;
|
||
|
||
Log::ShowToastFmt("ApplySetting\nqualityLevel: %d, maxBufferPixel: %d\nenderScale: %f, volumeIndex: %d\nLODQualityLv: %d, ReflectionLv: %d",
|
||
qualitySettingsLevel, maxBufferPixel, renderScale, volumeIndex, Config::lodQualityLevel, Config::reflectionQualityLevel);
|
||
}
|
||
|
||
CampusQualityManager_ApplySetting_Orig(_this, qualitySettingsLevel, maxBufferPixel, renderScale, volumeIndex);
|
||
}
|
||
|
||
DEFINE_HOOK(void, UIManager_UpdateRenderTarget, (UnityResolve::UnityType::Vector2 ratio, void* mtd)) {
|
||
// const auto resolution = GetResolution();
|
||
// Log::DebugFmt("UIManager_UpdateRenderTarget: %f, %f", ratio.x, ratio.y);
|
||
return UIManager_UpdateRenderTarget_Orig(ratio, mtd);
|
||
}
|
||
|
||
DEFINE_HOOK(void, VLSRPCameraController_UpdateRenderTarget, (void* _this, int width, int height, bool forceAlpha, void* method)) {
|
||
// const auto resolution = GetResolution();
|
||
// Log::DebugFmt("VLSRPCameraController_UpdateRenderTarget: %d, %d", width, height);
|
||
return VLSRPCameraController_UpdateRenderTarget_Orig(_this, width, height, forceAlpha, method);
|
||
}
|
||
|
||
DEFINE_HOOK(void*, VLUtility_GetLimitedResolution, (int32_t screenWidth, int32_t screenHeight,
|
||
UnityResolve::UnityType::Vector2 aspectRatio, int32_t maxBufferPixel, float bufferScale, bool firstCall)) {
|
||
|
||
if (Config::useCustomeGraphicSettings && (Config::renderScale > 1.0f)) {
|
||
screenWidth *= Config::renderScale;
|
||
screenHeight *= Config::renderScale;
|
||
}
|
||
//Log::DebugFmt("VLUtility_GetLimitedResolution: %d, %d, %f, %f", screenWidth, screenHeight, aspectRatio.x, aspectRatio.y);
|
||
return VLUtility_GetLimitedResolution_Orig(screenWidth, screenHeight, aspectRatio, maxBufferPixel, bufferScale, firstCall);
|
||
}
|
||
|
||
|
||
DEFINE_HOOK(void, CampusActorModelParts_OnRegisterBone, (void* _this, Il2cppString** name, UnityResolve::UnityType::Transform* bone)) {
|
||
CampusActorModelParts_OnRegisterBone_Orig(_this, name, bone);
|
||
// Log::DebugFmt("CampusActorModelParts_OnRegisterBone: %s, %p", (*name)->ToString().c_str(), bone);
|
||
}
|
||
|
||
bool InitBodyParts() {
|
||
static auto isInit = false;
|
||
if (isInit) return true;
|
||
|
||
const auto Enum_GetValues = Il2cppUtils::GetMethod("mscorlib.dll", "System", "Enum", "GetValues");
|
||
const auto Enum_GetNames = Il2cppUtils::GetMethod("mscorlib.dll", "System", "Enum", "GetNames");
|
||
|
||
const auto HumanBodyBones_klass = Il2cppUtils::GetClass(
|
||
"UnityEngine.AnimationModule.dll", "UnityEngine", "HumanBodyBones");
|
||
|
||
const auto values = Enum_GetValues->Invoke<UnityResolve::UnityType::Array<int>*>(HumanBodyBones_klass->GetType())->ToVector();
|
||
const auto names = Enum_GetNames->Invoke<UnityResolve::UnityType::Array<Il2cppString*>*>(HumanBodyBones_klass->GetType())->ToVector();
|
||
if (values.size() != names.size()) {
|
||
Log::ErrorFmt("InitBodyParts Error: values count: %ld, names count: %ld", values.size(), names.size());
|
||
return false;
|
||
}
|
||
|
||
std::vector<std::string> namesVec{};
|
||
for (auto i :names) {
|
||
namesVec.push_back(i->ToString());
|
||
}
|
||
GKCamera::bodyPartsEnum = Misc::CSEnum(namesVec, values);
|
||
GKCamera::bodyPartsEnum.SetIndex(GKCamera::bodyPartsEnum.GetValueByName("Head"));
|
||
isInit = true;
|
||
return true;
|
||
}
|
||
|
||
void HideHead(UnityResolve::UnityType::GameObject* obj, const bool isFace) {
|
||
static UnityResolve::UnityType::GameObject* lastFaceObj = nullptr;
|
||
static UnityResolve::UnityType::GameObject* lastHairObj = nullptr;
|
||
|
||
#define lastHidedObj (isFace ? lastFaceObj : lastHairObj)
|
||
|
||
static auto get_activeInHierarchy = reinterpret_cast<bool (*)(void*)>(
|
||
Il2cppUtils::il2cpp_resolve_icall("UnityEngine.GameObject::get_activeInHierarchy()"));
|
||
|
||
const auto isFirstPerson = GKCamera::GetCameraMode() == GKCamera::CameraMode::FIRST_PERSON;
|
||
|
||
if (isFirstPerson && obj) {
|
||
if (obj == lastHidedObj) return;
|
||
if (lastHidedObj && IsNativeObjectAlive(lastHidedObj) && get_activeInHierarchy(lastHidedObj)) {
|
||
lastHidedObj->SetActive(true);
|
||
}
|
||
if (IsNativeObjectAlive(obj)) {
|
||
obj->SetActive(false);
|
||
lastHidedObj = obj;
|
||
}
|
||
}
|
||
else {
|
||
if (lastHidedObj && IsNativeObjectAlive(lastHidedObj)) {
|
||
lastHidedObj->SetActive(true);
|
||
lastHidedObj = nullptr;
|
||
}
|
||
}
|
||
}
|
||
|
||
DEFINE_HOOK(void, CampusActorController_LateUpdate, (void* _this, void* mtd)) {
|
||
if (!Config::enableFreeCamera || (GKCamera::GetCameraMode() == GKCamera::CameraMode::FREE)) {
|
||
if (needRestoreHides) {
|
||
needRestoreHides = false;
|
||
HideHead(NULL, false);
|
||
HideHead(NULL, true);
|
||
}
|
||
return CampusActorController_LateUpdate_Orig(_this, mtd);
|
||
}
|
||
|
||
static auto CampusActorController_klass = Il2cppUtils::GetClass("campus-submodule.Runtime.dll",
|
||
"Campus.Common", "CampusActorController");
|
||
static auto rootBody_field = CampusActorController_klass->Get<UnityResolve::Field>("_rootBody");
|
||
static auto parentKlass = UnityResolve::Invoke<void*>("il2cpp_class_get_parent", CampusActorController_klass->address);
|
||
static auto GetHumanBodyBoneTransform_mtd = Il2cppUtils::il2cpp_class_get_method_from_name(parentKlass, "GetHumanBodyBoneTransform", 1);
|
||
static auto GetHumanBodyBoneTransform = reinterpret_cast<UnityResolve::UnityType::Transform* (*)(void*, int)>(
|
||
GetHumanBodyBoneTransform_mtd->methodPointer
|
||
);
|
||
static auto get_index_mtd = Il2cppUtils::il2cpp_class_get_method_from_name(CampusActorController_klass->address, "get_index", 0);
|
||
static auto get_Index = get_index_mtd ? reinterpret_cast<int (*)(void*)>(
|
||
get_index_mtd->methodPointer) : [](void*){return 0;};
|
||
|
||
const auto currIndex = get_Index(_this);
|
||
if (currIndex == GKCamera::followCharaIndex) {
|
||
static auto initPartsSuccess = InitBodyParts();
|
||
static auto headBodyId = initPartsSuccess ? GKCamera::bodyPartsEnum.GetValueByName("Head") : 0xA;
|
||
const auto isFirstPerson = GKCamera::GetCameraMode() == GKCamera::CameraMode::FIRST_PERSON;
|
||
|
||
auto targetTrans = GetHumanBodyBoneTransform(_this,
|
||
isFirstPerson ? headBodyId : GKCamera::bodyPartsEnum.GetCurrent().second);
|
||
|
||
if (targetTrans) {
|
||
cacheTrans = targetTrans;
|
||
cacheRotation = cacheTrans->GetRotation();
|
||
cachePosition = cacheTrans->GetPosition();
|
||
cacheForward = cacheTrans->GetForward();
|
||
cacheLookAt = cacheTrans->GetPosition() + cacheTrans->GetForward() * 3;
|
||
|
||
auto rootBody = Il2cppUtils::ClassGetFieldValue<UnityResolve::UnityType::Transform*>(_this, rootBody_field);
|
||
auto rootModel = rootBody->GetParent();
|
||
auto rootModelChildCount = rootModel->GetChildCount();
|
||
for (int i = 0; i < rootModelChildCount; i++) {
|
||
auto rootChild = rootModel->GetChild(i);
|
||
const auto childName = rootChild->GetName();
|
||
if (childName == "Root_Face") {
|
||
for (int n = 0; n < rootChild->GetChildCount(); n++) {
|
||
auto vLSkinningRenderer = rootChild->GetChild(n);
|
||
if (vLSkinningRenderer->GetName() == "VLSkinningRenderer") {
|
||
HideHead(vLSkinningRenderer->GetGameObject(), true);
|
||
needRestoreHides = true;
|
||
}
|
||
}
|
||
}
|
||
else if (childName == "Root_Hair") {
|
||
HideHead(rootChild->GetGameObject(), false);
|
||
needRestoreHides = true;
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
cacheTrans = NULL;
|
||
}
|
||
|
||
}
|
||
|
||
CampusActorController_LateUpdate_Orig(_this, mtd);
|
||
}
|
||
|
||
void StartInjectFunctions() {
|
||
const auto hookInstaller = Plugin::GetInstance().GetHookInstaller();
|
||
UnityResolve::Init(xdl_open(hookInstaller->m_il2cppLibraryPath.c_str(), RTLD_NOW), UnityResolve::Mode::Il2Cpp);
|
||
|
||
ADD_HOOK(AssetBundle_LoadAssetAsync, Il2cppUtils::il2cpp_resolve_icall(
|
||
"UnityEngine.AssetBundle::LoadAssetAsync_Internal(System.String,System.Type)"));
|
||
ADD_HOOK(AssetBundleRequest_GetResult, Il2cppUtils::il2cpp_resolve_icall(
|
||
"UnityEngine.AssetBundleRequest::GetResult()"));
|
||
ADD_HOOK(Resources_Load, Il2cppUtils::il2cpp_resolve_icall(
|
||
"UnityEngine.ResourcesAPIInternal::Load(System.String,System.Type)"));
|
||
|
||
ADD_HOOK(I18nHelper_SetUpI18n, Il2cppUtils::GetMethodPointer("quaunity-ui.Runtime.dll", "Qua.UI",
|
||
"I18nHelper", "SetUpI18n"));
|
||
ADD_HOOK(I18nHelper_SetValue, Il2cppUtils::GetMethodPointer("quaunity-ui.Runtime.dll", "Qua.UI",
|
||
"I18n", "SetValue"));
|
||
|
||
//ADD_HOOK(UI_I18n_GetOrDefault, Il2cppUtils::GetMethodPointer("quaunity-ui.Runtime.dll", "Qua.UI",
|
||
// "I18n", "GetOrDefault"));
|
||
|
||
ADD_HOOK(TextMeshProUGUI_Awake, Il2cppUtils::GetMethodPointer("Unity.TextMeshPro.dll", "TMPro",
|
||
"TextMeshProUGUI", "Awake"));
|
||
|
||
ADD_HOOK(TMP_Text_PopulateTextBackingArray, Il2cppUtils::GetMethodPointer("Unity.TextMeshPro.dll", "TMPro",
|
||
"TMP_Text", "PopulateTextBackingArray",
|
||
{"System.String", "System.Int32", "System.Int32"}));
|
||
|
||
ADD_HOOK(TextField_set_value, Il2cppUtils::GetMethodPointer("UnityEngine.UIElementsModule.dll", "UnityEngine.UIElements",
|
||
"TextField", "set_value"));
|
||
|
||
ADD_HOOK(OctoCaching_GetResourceFileName, Il2cppUtils::GetMethodPointer("Octo.dll", "Octo.Caching",
|
||
"OctoCaching", "GetResourceFileName"));
|
||
|
||
ADD_HOOK(OctoResourceLoader_LoadFromCacheOrDownload,
|
||
Il2cppUtils::GetMethodPointer("Octo.dll", "Octo.Loader",
|
||
"OctoResourceLoader", "LoadFromCacheOrDownload",
|
||
{"System.String", "System.Action<System.String,Octo.LoadError>", "Octo.OnDownloadProgress"}));
|
||
|
||
ADD_HOOK(OnDownloadProgress_Invoke,
|
||
Il2cppUtils::GetMethodPointer("Octo.dll", "Octo",
|
||
"OnDownloadProgress", "Invoke"));
|
||
|
||
ADD_HOOK(PictureBookLiveThumbnailView_SetData,
|
||
Il2cppUtils::GetMethodPointer("Assembly-CSharp.dll", "Campus.OutGame.PictureBook",
|
||
"PictureBookLiveThumbnailView", "SetData"));
|
||
|
||
ADD_HOOK(PictureBookLiveSelectScreenPresenter_MoveLiveScene,
|
||
Il2cppUtils::GetMethodPointer("Assembly-CSharp.dll", "Campus.OutGame",
|
||
"PictureBookLiveSelectScreenPresenter", "MoveLiveScene"));
|
||
ADD_HOOK(PictureBookLiveSelectScreenPresenter_OnSelectMusic,
|
||
Il2cppUtils::GetMethodPointer("Assembly-CSharp.dll", "Campus.OutGame",
|
||
"PictureBookLiveSelectScreenPresenter", "OnSelectMusic"));
|
||
|
||
ADD_HOOK(VLDOF_IsActive,
|
||
Il2cppUtils::GetMethodPointer("Unity.RenderPipelines.Universal.Runtime.dll", "VL.Rendering",
|
||
"VLDOF", "IsActive"));
|
||
|
||
ADD_HOOK(CampusQualityManager_ApplySetting,
|
||
Il2cppUtils::GetMethodPointer("campus-submodule.Runtime.dll", "Campus.Common",
|
||
"CampusQualityManager", "ApplySetting"));
|
||
|
||
ADD_HOOK(UIManager_UpdateRenderTarget,
|
||
Il2cppUtils::GetMethodPointer("ADV.Runtime.dll", "Campus.ADV",
|
||
"UIManager", "UpdateRenderTarget"));
|
||
ADD_HOOK(VLSRPCameraController_UpdateRenderTarget,
|
||
Il2cppUtils::GetMethodPointer("vl-unity.Runtime.dll", "VL.Rendering",
|
||
"VLSRPCameraController", "UpdateRenderTarget",
|
||
{"*", "*", "*"}));
|
||
|
||
ADD_HOOK(VLUtility_GetLimitedResolution,
|
||
Il2cppUtils::GetMethodPointer("vl-unity.Runtime.dll", "VL",
|
||
"VLUtility", "GetLimitedResolution",
|
||
{"*", "*", "*", "*", "*", "*"}));
|
||
|
||
ADD_HOOK(CampusActorModelParts_OnRegisterBone,
|
||
Il2cppUtils::GetMethodPointer("campus-submodule.Runtime.dll", "Campus.Common",
|
||
"CampusActorModelParts", "OnRegisterBone"));
|
||
ADD_HOOK(CampusActorController_LateUpdate,
|
||
Il2cppUtils::GetMethodPointer("campus-submodule.Runtime.dll", "Campus.Common",
|
||
"CampusActorController", "LateUpdate"));
|
||
/*
|
||
static auto CampusActorController_klass = Il2cppUtils::GetClass("campus-submodule.Runtime.dll",
|
||
"Campus.Common", "CampusActorController");
|
||
for (const auto& i : CampusActorController_klass->methods) {
|
||
Log::DebugFmt("CampusActorController.%s at %p", i->name.c_str(), i->function);
|
||
}*/
|
||
|
||
ADD_HOOK(CampusQualityManager_set_TargetFrameRate,
|
||
Il2cppUtils::GetMethodPointer("campus-submodule.Runtime.dll", "Campus.Common",
|
||
"CampusQualityManager", "set_TargetFrameRate"));
|
||
|
||
ADD_HOOK(Internal_LogException, Il2cppUtils::il2cpp_resolve_icall(
|
||
"UnityEngine.DebugLogHandler::Internal_LogException(System.Exception,UnityEngine.Object)"));
|
||
ADD_HOOK(Internal_Log, Il2cppUtils::il2cpp_resolve_icall(
|
||
"UnityEngine.DebugLogHandler::Internal_Log(UnityEngine.LogType,UnityEngine.LogOption,System.String,UnityEngine.Object)"));
|
||
|
||
ADD_HOOK(InternalSetOrientationAsync,
|
||
Il2cppUtils::GetMethodPointer("campus-submodule.Runtime.dll", "Campus.Common",
|
||
"ScreenOrientationControllerBase", "InternalSetOrientationAsync"));
|
||
|
||
ADD_HOOK(Unity_set_position_Injected, Il2cppUtils::il2cpp_resolve_icall(
|
||
"UnityEngine.Transform::set_position_Injected(UnityEngine.Vector3&)"));
|
||
ADD_HOOK(Unity_set_rotation_Injected, Il2cppUtils::il2cpp_resolve_icall(
|
||
"UnityEngine.Transform::set_rotation_Injected(UnityEngine.Quaternion&)"));
|
||
ADD_HOOK(Unity_get_fieldOfView, Il2cppUtils::GetMethodPointer("UnityEngine.CoreModule.dll", "UnityEngine",
|
||
"Camera", "get_fieldOfView"));
|
||
ADD_HOOK(Unity_set_fieldOfView, Il2cppUtils::GetMethodPointer("UnityEngine.CoreModule.dll", "UnityEngine",
|
||
"Camera", "set_fieldOfView"));
|
||
ADD_HOOK(Unity_set_targetFrameRate, Il2cppUtils::il2cpp_resolve_icall(
|
||
"UnityEngine.Application::set_targetFrameRate(System.Int32)"));
|
||
ADD_HOOK(EndCameraRendering, Il2cppUtils::GetMethodPointer("UnityEngine.CoreModule.dll", "UnityEngine.Rendering",
|
||
"RenderPipeline", "EndCameraRendering"));
|
||
}
|
||
// 77 2640 5000
|
||
|
||
DEFINE_HOOK(int, il2cpp_init, (const char* domain_name)) {
|
||
const auto ret = il2cpp_init_Orig(domain_name);
|
||
// InjectFunctions();
|
||
|
||
Log::Info("Waiting for config...");
|
||
|
||
while (!Config::isConfigInit) {
|
||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||
}
|
||
if (!Config::enabled) {
|
||
Log::Info("Plugin not enabled");
|
||
return ret;
|
||
}
|
||
|
||
Log::Info("Start init plugin...");
|
||
|
||
StartInjectFunctions();
|
||
GKCamera::initCameraSettings();
|
||
Local::LoadData();
|
||
|
||
Log::Info("Plugin init finished.");
|
||
return ret;
|
||
}
|
||
}
|
||
|
||
|
||
namespace GakumasLocal::Hook {
|
||
void Install() {
|
||
const auto hookInstaller = Plugin::GetInstance().GetHookInstaller();
|
||
|
||
Log::Info("Installing hook");
|
||
|
||
ADD_HOOK(HookMain::il2cpp_init,
|
||
Plugin::GetInstance().GetHookInstaller()->LookupSymbol("il2cpp_init"));
|
||
|
||
Log::Info("Hook installed");
|
||
}
|
||
}
|