From 68b6d20da6ab806bca1a193c9bdfafdb784f3486 Mon Sep 17 00:00:00 2001 From: rebtd7 <59185507+rebtd7@users.noreply.github.com> Date: Mon, 23 Dec 2019 23:01:31 -0300 Subject: [PATCH] Add FF13 fixes --- d3d9ex/Context.cpp | 138 +++++++++++++++++++++++++++++++++++++++++++-- d3d9ex/Context.h | 22 +++++++- d3d9ex/Settings.h | 8 ++- 3 files changed, 160 insertions(+), 8 deletions(-) diff --git a/d3d9ex/Context.cpp b/d3d9ex/Context.cpp index 039c554..cbccf72 100644 --- a/d3d9ex/Context.cpp +++ b/d3d9ex/Context.cpp @@ -39,9 +39,9 @@ Config::Config() MainContext::MainContext() : oldWndProc(nullptr) { - LogFile("OneTweakNG.log"); + LogFile("FF13Fix.log"); - if(config.GetAutoFix()) EnableAutoFix(); + if (config.GetAutoFix()) EnableAutoFix(); MH_Initialize(); @@ -66,7 +66,7 @@ MainContext::~MainContext() while (::ShowCursor(TRUE) <= 0); } -IDirect3D9 * WINAPI MainContext::HookDirect3DCreate9(UINT SDKVersion) +IDirect3D9* WINAPI MainContext::HookDirect3DCreate9(UINT SDKVersion) { IDirect3D9* d3d9 = context.TrueDirect3DCreate9(SDKVersion); if (d3d9) @@ -108,9 +108,17 @@ bool MainContext::ApplyPresentationParameters(D3DPRESENT_PARAMETERS* pPresentati { if (pPresentationParameters) { - if (config.GetTrippleBuffering()) + context.backbufferWidth = pPresentationParameters->BackBufferWidth; + if (config.GetTripleBuffering()) { pPresentationParameters->BackBufferCount = 3; + PrintLog("BackBufferCount: BackBufferCount set to %u", pPresentationParameters->BackBufferCount); + } + + if ((s32)config.GetFullScreenRefreshRate() >= 0 && pPresentationParameters->FullScreen_RefreshRateInHz != 0) + { + PrintLog("Changing refresh rate from %u to %u", pPresentationParameters->FullScreen_RefreshRateInHz, config.GetFullScreenRefreshRate()); + pPresentationParameters->FullScreen_RefreshRateInHz = config.GetFullScreenRefreshRate(); } if (config.GetMultisample() > 0) @@ -128,6 +136,12 @@ bool MainContext::ApplyPresentationParameters(D3DPRESENT_PARAMETERS* pPresentati PrintLog("PresentationInterval: PresentationInterval set to %u", pPresentationParameters->PresentationInterval); } + if ((s32)config.GetSwapEffect() != -1) + { + pPresentationParameters->SwapEffect = (D3DSWAPEFFECT)config.GetSwapEffect(); + PrintLog("SwapEffect: SwapEffect set to %u", pPresentationParameters->SwapEffect); + } + if (config.GetBorderless()) { int cx = GetSystemMetrics(SM_CXSCREEN); @@ -302,6 +316,11 @@ HWND WINAPI MainContext::HookCreateWindowExW(DWORD dwExStyle, LPCWSTR lpClassNam return hWnd; } + if (context.autofix == FINAL_FANTASY_XIII && !context.didOneTimeFixes) { + PrintLog("Starting FFXIII one time RAM patches."); + context.FFXIIIOneTimeFixes(); + } + if (context.CheckWindow(hWnd)) { context.ApplyWndProc(hWnd); @@ -310,3 +329,114 @@ HWND WINAPI MainContext::HookCreateWindowExW(DWORD dwExStyle, LPCWSTR lpClassNam return hWnd; } + +void MainContext::FFXIIIOneTimeFixes() { + + bool successSoFar = true; + // The game repeatedly sets the frame rate limit. Disable the instruction that does it. + successSoFar &= MainContext::FFXIIINOPIngameFrameRateLimitSetter(); + + successSoFar &= MainContext::FFXIIISetFrameRateVariables(); + + if (successSoFar) { + context.RemoveContinuousControllerScan(); + context.FixMissingEnemyScan(); + context.didOneTimeFixes = true; + } +} + +void MainContext::ChangeMemoryProtectionToReadWriteExecute(void* address, const int size) { + DWORD oldProtection; + VirtualProtect(address, size, PAGE_EXECUTE_READWRITE, &oldProtection); +} + +void MainContext::RemoveContinuousControllerScan() { + // Disable continuous controller scanning. + + PrintLog("Removing game slow and synchronous controller continuous controller scanning..."); + context.ChangeMemoryProtectionToReadWriteExecute(CONTINUOUS_SCAN_INSTRUCTION_ADDRESS, 1); + // change a jne to jmp + *(byte*)CONTINUOUS_SCAN_INSTRUCTION_ADDRESS = 0xEB; +} + +void MainContext::FixMissingEnemyScan() { + // This patches the variables that eventually will turn into a RECT to be used in a IDirect3DDevice9::SetScissorRect call. + // The game incorrectly uses the same values here regardless of the resolution. + + PrintLog("Patching libra info box instructions to take in account the game resolution..."); + + const float resolutionFactor = (float)context.backbufferWidth / 1280.0F; + + const uint32_t rectHeight = (uint32_t)ceil(130.0F * resolutionFactor); + const uint32_t rectWidth = context.backbufferWidth; + const uint32_t rectPosY = (uint32_t)(496.0F * resolutionFactor); + + context.ChangeMemoryProtectionToReadWriteExecute(ENEMY_SCAN_BOX_CODE_ADDRESS, 18); + + //push boxHeight + *(byte*)(ENEMY_SCAN_BOX_CODE_ADDRESS + 0) = 0x68; + *(uint32_t*)(ENEMY_SCAN_BOX_CODE_ADDRESS + 1) = rectHeight; + + // push boxWidth + *(byte*)(ENEMY_SCAN_BOX_CODE_ADDRESS + 5) = 0x68; + *(uint32_t*)(ENEMY_SCAN_BOX_CODE_ADDRESS + 6) = rectWidth; + + // push boxPosY + *(byte*)(ENEMY_SCAN_BOX_CODE_ADDRESS + 10) = 0x68; + *(uint32_t*)(ENEMY_SCAN_BOX_CODE_ADDRESS + 11) = rectPosY; + + // NOP NOP NOP + *(byte*)(ENEMY_SCAN_BOX_CODE_ADDRESS + 15) = 0x90; + *(byte*)(ENEMY_SCAN_BOX_CODE_ADDRESS + 16) = 0x90; + *(byte*)(ENEMY_SCAN_BOX_CODE_ADDRESS + 17) = 0x90; +} + +bool MainContext::FFXIIINOPIngameFrameRateLimitSetter() { + PrintLog("Using the ingame the instruction that sets the frame rate to get the frame rate address."); + + context.ChangeMemoryProtectionToReadWriteExecute(SET_FRAMERATE_INGAME_INSTRUCTION_ADDRESS, 5); + + // patching to: mov [framePacerTargetPtr], eax + *SET_FRAMERATE_INGAME_INSTRUCTION_ADDRESS = 0xA3; + *((uint32_t*)(SET_FRAMERATE_INGAME_INSTRUCTION_ADDRESS + 1)) = (uint32_t)(&framePacerTargetPtr); + + return true; +} + +bool MainContext::FFXIIISetFrameRateVariables() { + if (framePacerTargetPtr) { + PrintLog("Frame pacer target frame rate is at address %x", framePacerTargetPtr); + + float* ingameFrameRateFramePacerTarget = framePacerTargetPtr; + *ingameFrameRateFramePacerTarget = MAX_FRAME_RATE_LIMIT; + PrintLog("Frame pacer disabled."); + + const float frameRateConfig = (float)context.config.GetFFXIIIIngameFrameRateLimit(); + bool unlimitedFrameRate = areAlmostTheSame(frameRateConfig, -1.0f); + bool shouldSetFrameRateLimit = !areAlmostTheSame(frameRateConfig, 0.0f); + + float frameRateLimit = 0; + + if(unlimitedFrameRate){ + frameRateLimit = MAX_FRAME_RATE_LIMIT; + } + else { + frameRateLimit = frameRateConfig; + } + + if (shouldSetFrameRateLimit) { + float* ingameFrameRateLimitPtr = framePacerTargetPtr + 1; + *ingameFrameRateLimitPtr = frameRateLimit; + PrintLog("Target frame rate set to %f", frameRateLimit); + } + } + else { + PrintLog("Unable to find frame rate pattern. This is normal if the game still hasn't completely started yet."); + } + + return framePacerTargetPtr; +} + +bool MainContext::areAlmostTheSame(float a, float b) { + return fabs(a - b) < 0.01f; +} \ No newline at end of file diff --git a/d3d9ex/Context.h b/d3d9ex/Context.h index 7bdf7c3..2f799dc 100644 --- a/d3d9ex/Context.h +++ b/d3d9ex/Context.h @@ -7,8 +7,8 @@ struct hkIDirect3D9; -static const char* inifilename = "OneTweakNG.ini"; -#define CONFIG_VERSION 3 +static const char* inifilename = "FF13Fix.ini"; +#define CONFIG_VERSION 4 class Config { @@ -70,11 +70,29 @@ private: void EnableAutoFix(); AutoFixes autofix = AutoFixes::NONE; + bool didOneTimeFixes = false; + + const float MAX_FRAME_RATE_LIMIT = 250000.0F; + byte* SET_FRAMERATE_INGAME_INSTRUCTION_ADDRESS = (byte*)0x00E8D65F; + byte* CONTINUOUS_SCAN_INSTRUCTION_ADDRESS = (byte*)0x00820868; + byte* ENEMY_SCAN_BOX_CODE_ADDRESS = (byte*)0x0094C920; + + float* framePacerTargetPtr = NULL; + UINT backbufferWidth = 0; + void FixBehaviorFlagConflict(const DWORD flags_in, DWORD* flags_out); static const std::map behaviorflags_fixes; static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); WNDPROC oldWndProc; + + void FFXIIIOneTimeFixes(); + bool FFXIIINOPIngameFrameRateLimitSetter(); + bool FFXIIISetFrameRateVariables(); + void ChangeMemoryProtectionToReadWriteExecute(void* address, const int size); + void FixMissingEnemyScan(); + void RemoveContinuousControllerScan(); + bool areAlmostTheSame(float a, float b); }; extern MainContext context; \ No newline at end of file diff --git a/d3d9ex/Settings.h b/d3d9ex/Settings.h index b30bbbb..13525fd 100644 --- a/d3d9ex/Settings.h +++ b/d3d9ex/Settings.h @@ -1,6 +1,8 @@ -SETTING(u32, LongValue, PresentationInterval, Options, -1); -SETTING(bool, BoolValue, TrippleBuffering, Options, false); +SETTING(u32, LongValue, PresentationInterval, Options, 1); +SETTING(bool, BoolValue, TripleBuffering, Options, true); +SETTING(u32, LongValue, FullScreenRefreshRate, Options, 0); +SETTING(u32, LongValue, SwapEffect, Options, -1); SETTING(bool, BoolValue, AlwaysActive, Options, false); SETTING(bool, BoolValue, AutoFix, Options, true); SETTING(u32, LongValue, Multisample, Options, 0); @@ -8,6 +10,8 @@ SETTING(bool, BoolValue, HideCursor, Options, false); SETTING(bool, BoolValue, ForceHideCursor, Options, false); SETTING(u32, LongValue, BehaviorFlags, Options, 0); +SETTING(double, DoubleValue, FFXIIIIngameFrameRateLimit, Options, -1.0); + SETTING(bool, BoolValue, Adapter, Adapter, false); SETTING(u32, LongValue, VendorId, Adapter, 0); SETTING(u32, LongValue, DeviceId, Adapter, 0);