#include "CommonHeaders.h" #include "Monoloader.hpp" #include "Logger.hpp" // Constants const std::string PLUGIN_NAME = "WickedSeed"; const std::string PLUGIN_LOG = PLUGIN_NAME + ".log"; // Logger std::shared_ptr logger; // Screen informations static int g_CurrentWidth = 1; static int g_CurrentHeight = 1; static float g_AspectRatio = (float)g_CurrentWidth / g_CurrentHeight; float baseAspect = 1.777778f; // Plugin states static bool AOBScanDone = false; static bool g_fix_enabled = false; static bool g_fov_fix_enabled = false; static bool g_camera_fix_enabled = false; static int g_AdditionalFOVValue = 0; static float g_OutdoorCameraMultiplier = 1.f; static float g_IndoorCameraMultiplier = 1.f; static bool g_PendingCameraRefresh = true; static float g_CameraIn = 1.f; static float g_CameraOut = 1.f; // Shared values static float g_FOV_In = 90.f; static float g_FOV_Out = 90.f; // AOB Scan pointers static uint8_t* FOVaddress = nullptr; static uint8_t* screenWidthadress = nullptr; static uint8_t* screenHeightaddress = nullptr; static uint8_t* FollowCameraaddress = nullptr; static uint8_t* Cameraaddress = nullptr; // Hooking static SafetyHookMid FOVHook{}; static SafetyHookMid CameraHook{}; // Unity variables static bool g_coreReady = false; int (*GetWidth)() = nullptr; int (*GetHeight)() = nullptr; static MonoLoader loader; static MonoMethod* setFollowNoParamMethod = nullptr; static MonoObject* thirdPersonInstance = nullptr; // Prototypes static void FOVFixEnabled(); static void CameraFixEnabled(); static void ForceCameraRefresh(); extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) { g_fix_enabled = enabled; if (!AOBScanDone) { logger->info("--------------- AOB scan started ---------------"); constexpr auto FOVStringObfuscated = make_obfuscated<0x83>("83 F8 01 74 ?? 83 F8 08 75 ?? 48 8B 0D ?? ?? ?? ?? 48 8B 01 FF 90 ?? ?? 00 00 F3 0F 10 8B ?? ?? ?? ?? 0F 2E C8 7A ?? 74 ?? F3 0F 11 8B ?? ?? ?? ?? F3 0F 11 83 ?? ?? ?? ?? F3 0F 10 83 ?? ?? ?? ?? 48 83 C4 20"); constexpr auto CameraDistanceStringObfuscated = make_obfuscated<0x38>("F3 0F ?? ?? F2 0F 11 ?? ?? F2 0F 10 ?? ?? F2 0F 11 ?? ?? 48 8B 86 ?? ?? ?? ?? 48 8B C8 83 38 00"); using AOBScan::Make; // Prepare all data for scanning std::vector signatures = { Make(&FOVaddress, FOVStringObfuscated, "FOV", "UnityPlayer.dll") }; // Scan all signature in a batch Memory::AOBScanBatch(signatures, logger); Cameraaddress = Memory::AOBScanRange(FollowCameraaddress, "Camera", 0x800, CameraDistanceStringObfuscated, PAGE_EXECUTE_READWRITE, logger); if (FOVaddress && Cameraaddress) logger->info("All AOB signatures found. Ready to patch..."); logger->info("-------------- Fixes initialisation -------------"); AOBScanDone = true; } if (!init && FOVaddress) FOVFixEnabled(); if (!init && FollowCameraaddress) CameraFixEnabled(); } // Unity Core Mono initialization static MonoClass* thirdPersonClass; extern "C" __declspec(dllexport) void InitializeCore() { logger->info("----------- Unity Mono intializating -----------"); if (!loader.Initialize(logger)) { logger->error("MonoLoader initialization failed."); return; } // Search for assembly CoreModule MonoClass* screenClass = loader.FindClass("UnityEngine.CoreModule", "UnityEngine", "Screen"); MonoClass* cameraClass = loader.FindClass("UnityEngine.CoreModule", "UnityEngine", "Camera"); // Search for methods address screenWidthadress = loader.GetCompiledMethod(screenClass, "get_width", 0); screenHeightaddress = loader.GetCompiledMethod(screenClass, "get_height", 0); LOG_SIGNATURE_FOUND("Screen width", reinterpret_cast(screenWidthadress)); LOG_SIGNATURE_FOUND("Screen height", reinterpret_cast(screenHeightaddress)); // Retrieves width and height getters methods using GetWidthFn = int(*)(); using GetHeightFn = int(*)(); GetWidth = reinterpret_cast(screenWidthadress); GetHeight = reinterpret_cast(screenHeightaddress); // Retrieves current game resolution rendering g_CurrentWidth = GetWidth(); g_CurrentHeight = GetHeight(); thirdPersonClass = loader.FindClass("Assembly-CSharp","StarterAssets","ThirdPersonController"); FollowCameraaddress = loader.GetCompiledMethod(thirdPersonClass, "SetFollowCameraDistance", 0); // Pointer for AOB Scan setFollowNoParamMethod = loader.GetMethod(thirdPersonClass,"SetFollowCameraDistance",0); // MonoMethod pointer LOG_SIGNATURE_FOUND("Follow camera distance", reinterpret_cast(FollowCameraaddress)); g_coreReady = true; logger->info("Core ready."); } // Unity Engine exposed methods usually called from Reshade present event extern "C" __declspec(dllexport) void UpdateEngine() { if (g_PendingCameraRefresh && thirdPersonInstance && setFollowNoParamMethod) { g_PendingCameraRefresh = false; ForceCameraRefresh(); } } extern "C" __declspec(dllexport) bool IsCoreReady() { return g_coreReady; } // Setters for Reshade addon call extern "C" __declspec(dllexport) void SetFixesEnabled(GameFixes fix, bool enabled) { // Set each fix individually if (fix == GameFixes::FOV) { g_fov_fix_enabled = enabled; FOVFixEnabled(); } if (fix == GameFixes::Camera) { g_camera_fix_enabled = enabled; CameraFixEnabled(); } if (fix == GameFixes::None) { logger->info("------------------ User inputs ------------------"); } } extern "C" __declspec(dllexport) void SetValues(GameSetting setting, float value) { if (setting == GameSetting::FOV) g_AdditionalFOVValue = (int)(value); if (setting == GameSetting::CameraDistance) { g_OutdoorCameraMultiplier = value; ForceCameraRefresh(); } if (setting == GameSetting::AITimeDilation) { g_IndoorCameraMultiplier = value; ForceCameraRefresh(); } } // Getters for Reshade addon call extern "C" __declspec(dllexport) void GetGameInfos(GameInfos* infos) { if (!infos) return; infos->FOVIn = g_FOV_In; infos->FOVOut = g_FOV_Out; infos->screenWidth = g_CurrentWidth; infos->screenHeight = g_CurrentHeight; infos->aspectRatio = g_AspectRatio; infos->cameraIn = g_CameraIn; infos->cameraOut = g_CameraOut; } // Hook injections static void FOVFixEnabled() { if (g_fix_enabled && g_fov_fix_enabled && FOVaddress) { if (!FOVHook) { // Hook on UnityPlayer.dll FOVHook = safetyhook::create_mid(FOVaddress + 0x41, [](SafetyHookContext& ctx) { g_CurrentWidth = GetWidth(); g_CurrentHeight = GetHeight(); g_AspectRatio = (float)g_CurrentWidth / g_CurrentHeight; g_FOV_In = Maths::FOVVToH(ctx.xmm0.f32[0], g_AspectRatio); float targetFovH = g_FOV_In + (g_fix_enabled && g_fov_fix_enabled ? g_AdditionalFOVValue : 0.0f); float targetFovV = Maths::FOVHToV(targetFovH, g_AspectRatio); ctx.xmm0.f32[0] = targetFovV; g_FOV_Out = targetFovH; }); } else FOVHook.enable(); } if (!(g_fix_enabled && g_fov_fix_enabled) && FOVaddress) if (FOVHook) FOVHook.disable(); if (FOVaddress && FOVHook) logger->info("FOV fix {}", g_fix_enabled && g_fov_fix_enabled ? "enabled" : "disabled"); } static void ForceCameraRefresh() { if (thirdPersonInstance && setFollowNoParamMethod) // Force Unity engine to refresh of camera position loader.InvokeMethod(setFollowNoParamMethod, thirdPersonInstance, nullptr, nullptr); else if (!thirdPersonInstance || !setFollowNoParamMethod) g_PendingCameraRefresh = true; } static void CameraFixEnabled() { if (g_fix_enabled && g_camera_fix_enabled && Cameraaddress) { if (!CameraHook) { // Hook only once CameraHook = safetyhook::create_mid(Cameraaddress + 0xe, [](SafetyHookContext& ctx) { if (!ctx.rsi) return; MonoObject* currentInstance = (MonoObject*)ctx.rsi; // Current object instance if (thirdPersonInstance != currentInstance) thirdPersonInstance = currentInstance; // Refresh third person instance g_CameraIn = (float)ctx.xmm0.f64[0]; ctx.xmm0.f64[0] *= g_CameraIn < 1.7 ? g_IndoorCameraMultiplier : g_OutdoorCameraMultiplier; // Apply multiplier g_CameraOut = (float)ctx.xmm0.f64[0]; }); } else CameraHook.enable(); ForceCameraRefresh(); logger->info("Camera distance fix enabled"); } if (!(g_fix_enabled && g_camera_fix_enabled) && Cameraaddress) { if (CameraHook) CameraHook.disable(); ForceCameraRefresh(); logger->info("Camera distance fix disabled"); } } // Standard dll entry BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID) { if (reason == DLL_PROCESS_ATTACH) { logger = InitializeLogger("Wicked Seed", PLUGIN_LOG); logger->info("Plugin {} loaded.", PLUGIN_NAME); } else if (reason == DLL_PROCESS_DETACH) { logger->info("Plugin {} unloaded.", PLUGIN_NAME); spdlog::drop_all(); } return TRUE; }