diff --git a/WickedSeed/dllmain.cpp b/WickedSeed/dllmain.cpp new file mode 100644 index 0000000..15e63a5 --- /dev/null +++ b/WickedSeed/dllmain.cpp @@ -0,0 +1,229 @@ +#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_CameraMultiplier = 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_CameraMultiplier = 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_CameraMultiplier; // 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; +} \ No newline at end of file