#include "CommonHeaders.h" #include "Monoloader.hpp" #include "Logger.hpp" // Constants const std::string PLUGIN_NAME = "Paragnosia"; 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_DOF_fix_enabled = false; static bool g_CA_fix_enabled = false; static bool g_LensDistortion_fix_enabled = false; static bool g_Vignetting_fix_enabled = false; static int g_AdditionalFOVValue = 0; // 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* FOV1address = nullptr; static uint8_t* screenWidthadress = nullptr; static uint8_t* screenHeightaddress = nullptr; static uint8_t* CAaddress = nullptr; static uint8_t* lensDistortionaddress = nullptr; static uint8_t* vignetteaddress = nullptr; static uint8_t* DOFaddress = nullptr; // Hooking static SafetyHookMid FOVHook{}; static SafetyHookMid GetWidthHook{}; static SafetyHookMid GetHeightHook{}; // Unity variables static bool g_coreReady = false; int (*GetWidth)() = nullptr; int (*GetHeight)() = nullptr; // Prototypes static void FOVFixEnabled(); static void ToggleFixMethod(uint8_t* address, bool specificFixEnabled, const char* name); 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"); 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); if (FOVaddress) logger->info("All AOB signatures found. Ready to patch..."); logger->info("-------------- Fixes initialisation -------------"); AOBScanDone = true; } if (!init && FOVaddress) FOVFixEnabled(); if (!init && CAaddress) ToggleFixMethod(CAaddress, g_CA_fix_enabled, "Chromatic aberrations"); if (!init && lensDistortionaddress) ToggleFixMethod(lensDistortionaddress, g_LensDistortion_fix_enabled, "Lens distortion"); if (!init && vignetteaddress) ToggleFixMethod(vignetteaddress, g_Vignetting_fix_enabled, "Vignetting"); if (!init && DOFaddress) ToggleFixMethod(DOFaddress, g_DOF_fix_enabled, "Depth of field"); } // Unity Core Mono initialization extern "C" __declspec(dllexport) void InitializeCore() { logger->info("-------------- Unity mono hooking --------------"); static MonoLoader loader; 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); logger->info("Screen width found at {:p}", (void*)screenWidthadress); logger->info("Screen height found at {:p}", (void*)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(); MonoClass* caClass = loader.FindClass("Unity.RenderPipelines.Universal.Runtime", "UnityEngine.Rendering.Universal", "ChromaticAberration"); CAaddress = loader.GetCompiledMethod(caClass, "IsActive", 0); logger->info("Chromatic aberrations found at {:p}", (void*)CAaddress); MonoClass* lensDistortionClass = loader.FindClass("Unity.RenderPipelines.Universal.Runtime", "UnityEngine.Rendering.Universal", "LensDistortion"); lensDistortionaddress = loader.GetCompiledMethod(lensDistortionClass, "IsActive", 0); logger->info("Lens Distortion found at {:p}", (void*)lensDistortionaddress); MonoClass* vignetteClass = loader.FindClass("Unity.RenderPipelines.Universal.Runtime", "UnityEngine.Rendering.Universal", "Vignette"); vignetteaddress = loader.GetCompiledMethod(vignetteClass, "IsActive", 0); logger->info("Vignetting found at {:p}", (void*)vignetteaddress); MonoClass* DOFClass = loader.FindClass("Unity.RenderPipelines.Universal.Runtime", "UnityEngine.Rendering.Universal", "DepthOfField"); DOFaddress = loader.GetCompiledMethod(DOFClass, "IsActive", 0); logger->info("Depth of field found at {:p}", (void*)DOFaddress); g_coreReady = true; logger->info("Core ready."); } 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::ChromaticAberrations) { g_CA_fix_enabled = enabled; ToggleFixMethod(CAaddress, g_CA_fix_enabled, "Chromatic aberrations"); } if (fix == GameFixes::LensDistortion) { g_LensDistortion_fix_enabled = enabled; ToggleFixMethod(lensDistortionaddress, g_LensDistortion_fix_enabled, "Lens distortion"); } if (fix == GameFixes::Vignetting) { g_Vignetting_fix_enabled = enabled; ToggleFixMethod(vignetteaddress, g_Vignetting_fix_enabled, "Vignetting"); } if (fix == GameFixes::DOF) { g_DOF_fix_enabled = enabled; ToggleFixMethod(DOFaddress, g_DOF_fix_enabled, "Depth of field"); } 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); } // 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; } // 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"); } // Memory patches static void ToggleFixMethod(uint8_t* address, bool specificFixEnabled, const char* name) { if (!address) return; if (g_fix_enabled && specificFixEnabled) { Memory::PatchBytes(address, "\x31\xC0\xC3", 3); // xor eax,eax; ret -> Will return IsActive false for effects (Vignetting, chromatic aberrations ...) logger->info("{} fix enabled", name); } else { Memory::RestoreBytes(address); logger->info("{} fix disabled", name); } } // Standard dll entry BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID) { if (reason == DLL_PROCESS_ATTACH) { logger = InitializeLogger("Paragnosia", 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; }