From 1e63da5df872051be9846158c212ab26e66840e4 Mon Sep 17 00:00:00 2001 From: Emmanuel AYME Date: Sun, 1 Mar 2026 19:06:48 +0100 Subject: [PATCH] Add Tales Of Berseria fixes --- TalesOfBerseria/dllmain.cpp | 177 ++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 TalesOfBerseria/dllmain.cpp diff --git a/TalesOfBerseria/dllmain.cpp b/TalesOfBerseria/dllmain.cpp new file mode 100644 index 0000000..ea00bbd --- /dev/null +++ b/TalesOfBerseria/dllmain.cpp @@ -0,0 +1,177 @@ +#include "CommonHeaders.h" +#include "UEngine.hpp" +#include "Logger.hpp" + +// Constants +const std::string PLUGIN_NAME = "TalesOfBerseria"; +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 aspectRatio = 1.77778; + +// Plugin states +static bool AOBScanDone = false; +static bool g_fix_enabled = false; +static bool g_fov_fix_enabled = false; +static bool g_ultrawide_fix_enabled = false; +static int g_AdditionalFOVValue = 0; +static std::atomic g_coreReady = false; + +// Shared values +static float g_FOV_In = 45.f; +static float g_FOV_Out = 45.f; + +// AOB Scan pointers +static uint8_t* FOVaddress = nullptr; +static uint8_t* UltraWideaddress = nullptr; +static uint8_t* Resolutionaddress = nullptr; +static uint8_t* pluginDLLModule = nullptr; +// Hooking +static SafetyHookMid FOVHook{}; +static SafetyHookMid UWHook{}; +static SafetyHookMid ResolutionHook1{}; +static SafetyHookMid ResolutionHook2{}; + +// Prototypes +static void FOVFixEnabled(); +static void UltraWideFixEnabled(); +static void GetGameResolution(); + +extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) { + if (!pluginDLLModule) return; + g_fix_enabled = enabled; + if (!AOBScanDone) { // Unity Engine + logger->info("--------------- AOB scan started ---------------"); + constexpr auto FOVStringObfuscated = make_obfuscated<0x5E>("F3 0F 59 ?? ?? ?? ?? ?? F3 0F 5E ?? ?? ?? ?? ?? F3 0F 11 ?? ?? ?? ?? ?? 48 8B ?? ?? ?? 48 ?? ?? E8"); + constexpr auto UWStringObfuscated = make_obfuscated<0x41>("F3 0F 10 ?? ?? F3 0F 10 ?? ?? 0F 2E ?? 7A ?? 74 ?? F3 0F 11 ?? ?? C6 41 ?? ?? F3 0F 10"); + constexpr auto ResolutionStringObfuscated = make_obfuscated<0x57>("F3 0F 11 ?? ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B C0 0F 57 ?? 0F 57 ?? 0F 11"); + + logger->info("Scanning region: {} - {}", (void*)pluginDLLModule, (void*)(pluginDLLModule + MAXINT)); + FOVaddress = Memory::AOBScanRange(pluginDLLModule, "FOV", MAXINT, FOVStringObfuscated, PAGE_EXECUTE_READ, logger); + UltraWideaddress = Memory::AOBScanRange(pluginDLLModule, "Ultrawide", MAXINT, UWStringObfuscated, PAGE_EXECUTE_READ, logger); + Resolutionaddress = Memory::AOBScanRange(pluginDLLModule, "Screen resolution", MAXINT, ResolutionStringObfuscated, PAGE_EXECUTE_READ, logger); + + if (FOVaddress && UltraWideaddress) + logger->info("All AOB signatures found. Ready to patch..."); + + logger->info("-------------- Fixes initialisation -------------"); + AOBScanDone = true; + } + + if (!init && FOVaddress) FOVFixEnabled(); + if (!init && UltraWideaddress) UltraWideFixEnabled(); + GetGameResolution(); +} + +extern "C" __declspec(dllexport) bool IsCoreReady() { + return g_coreReady; +} + +extern "C" __declspec(dllexport) void InitializeCore() { + logger->info("---------- Unity IL2CPP intializating ----------"); + + std::thread([]() { + HMODULE hModule = nullptr; + for (int i = 0; i < 100; ++i) { // gives 10 seconds to find UE Engine + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + hModule = GetModuleHandleA("TLSampleViewerTO12.dll"); + if (hModule) break; + } + if (hModule) { + pluginDLLModule = reinterpret_cast(hModule); + g_coreReady = true; + logger->info("Core ready."); + } + }).detach(); +} + +// 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::UltraWide) { g_ultrawide_fix_enabled = enabled; UltraWideFixEnabled(); } + 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 = aspectRatio; +} + +// Hook injections +static void GetGameResolution() { + if (Resolutionaddress && !ResolutionHook1 && !ResolutionHook2) { + ResolutionHook1 = safetyhook::create_mid(Resolutionaddress, + [](SafetyHookContext& ctx) { + g_CurrentWidth = (int)ctx.xmm0.f32[0]; + }); + ResolutionHook2 = safetyhook::create_mid(Resolutionaddress + 0x1f, + [](SafetyHookContext& ctx) { + g_CurrentHeight = (int)ctx.xmm0.f32[0]; + }); + } +} + +static void FOVFixEnabled() { + if (g_fix_enabled && g_fov_fix_enabled && FOVaddress) { + if (!FOVHook) { // Hook only once + FOVHook = safetyhook::create_mid(FOVaddress, + [](SafetyHookContext& ctx) { + aspectRatio = (float)g_CurrentWidth / g_CurrentHeight; + + g_FOV_In = Maths::FOVVToH(ctx.xmm1.f32[0], aspectRatio); + float targetFovH = g_FOV_In + (g_fix_enabled && g_fov_fix_enabled ? g_AdditionalFOVValue : 0.f); + float targetFovV = Maths::FOVHToV(targetFovH, aspectRatio); + ctx.xmm1.f32[0] = targetFovV; + g_FOV_Out = targetFovH; + }); + } + else FOVHook.enable(); + } + if (!(g_fix_enabled && g_fov_fix_enabled) && FOVaddress) + if (FOVHook) FOVHook.disable(); + + logger->info("FOV fix {}", g_fix_enabled && g_fov_fix_enabled ? "enabled" : "disabled"); +} + +static void UltraWideFixEnabled() { + if (g_fix_enabled && g_ultrawide_fix_enabled && UltraWideaddress) { + if (!UWHook) { + UWHook = safetyhook::create_mid(UltraWideaddress + 0x5, + [](SafetyHookContext& ctx) { + ctx.xmm1.f32[0] = aspectRatio; + }); + } + else UWHook.enable(); + } + if (!(g_fix_enabled && g_ultrawide_fix_enabled) && UltraWideaddress) + if (UWHook) UWHook.disable(); + + logger->info("Ultrawide fix {}", g_fix_enabled && g_ultrawide_fix_enabled ? "enabled" : "disabled"); +} + +// Standard dll entry +BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID) { + if (reason == DLL_PROCESS_ATTACH) { + logger = InitializeLogger("Tales Of Berseria", 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