#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; static uint8_t* GameAssemblyDLLModule = 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(); std::thread([]() { HMODULE hModule = nullptr; for (int i = 0; i < 100; ++i) { // gives 10 seconds to find Unity GameAssembly.dll std::this_thread::sleep_for(std::chrono::milliseconds(100)); hModule = GetModuleHandleA("GameAssembly.dll"); if (hModule) break; } if (hModule) { GameAssemblyDLLModule = reinterpret_cast(hModule); logger->debug("GameAssembly loaded @ {}", (void*)GameAssemblyDLLModule); } }).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; }