From 22d08fa0a0a525b1b7f1586afbbca06f42c0d9b5 Mon Sep 17 00:00:00 2001 From: Emmanuel AYME Date: Sun, 22 Feb 2026 11:33:05 +0100 Subject: [PATCH] Add Paragnosia fixes --- Paragnosia/dllmain.cpp | 210 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 Paragnosia/dllmain.cpp diff --git a/Paragnosia/dllmain.cpp b/Paragnosia/dllmain.cpp new file mode 100644 index 0000000..f5a0fc2 --- /dev/null +++ b/Paragnosia/dllmain.cpp @@ -0,0 +1,210 @@ +#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; +} \ No newline at end of file