diff --git a/README.md b/README.md index fb267fc..98f0183 100644 --- a/README.md +++ b/README.md @@ -43,11 +43,19 @@ This considerably improves the frame rate when 2D elements are being disabled on ## Fix the enemy scan text on resolutions over 720p (FFXIII only) The game calls [SetScissorRect](https://docs.microsoft.com/en-us/windows/win32/api/d3d9helper/nf-d3d9helper-idirect3ddevice9-setscissorrect) using a rectangle hardcoded with the 720p coordenates. This correct the coordenates and rectangle size in order to fix it. -## Reporting issues +# Usage with the 4GB Large Address Aware patch +You may wish to patch the games to allow them to access more than 4GB of RAM. This seems to avoid crashes in FF13-2 (and may help FF13 under some configurations). +## FF13: +* Create a copy of the unpatched ```ffxiiiimg.exe``` to the folder ```FINAL FANTASY XIII\white_data\prog\win\bin```. Name it ```untouched.exe```. +* Patch the original ```ffxiiiimg.exe``` (you can use https://ntcore.com/?page_id=371) +## FF13-2: +* Patch ```ffxiii2img.exe``` (you can use https://ntcore.com/?page_id=371) + +# Reporting issues * Please specify what game are you talking about, which mods are you using (dxvk?) post system specs, and post FF13Fix.log * Add a save file and steps to reproduce the issue if possible -## Other notes +# Other notes * This is currently not compatible with GeDoSaTo. * I strongly recommend forcing anisotropic filtering on your GPU driver to improve the quality of the textures. * Using "Maximum Performance" power management in the GPU driver can also help keeping the frame rate smooth. diff --git a/d3d9ex/AutoFix.cpp b/d3d9ex/AutoFix.cpp index f547523..e95e73f 100644 --- a/d3d9ex/AutoFix.cpp +++ b/d3d9ex/AutoFix.cpp @@ -4,7 +4,7 @@ #include "MemPatch.h" #include "Context.h" -//#include "IDirect3DVertexBuffer9.h" +#include void MainContext::EnableAutoFix() { @@ -16,6 +16,7 @@ void MainContext::EnableAutoFix() autofix = AutoFixes::FINAL_FANTASY_XIII; PrintLog("AutoFix for \"Final Fantasy XIII\" enabled"); FF13_InitializeGameAddresses(); + FF13_HandleLargeAddressAwarePatch(); } if (exe_name == "ffxiii2img.exe") @@ -38,6 +39,67 @@ const std::map MainContext::behavi //{ AutoFixes::FINAL_FANTASY_XIII2, D3DCREATE_PUREDEVICE } }; + +HANDLE WINAPI MainContext::HookCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { + const char* ffxiiiimgPrt = strstr(lpFileName, "ffxiiiimg.exe"); + if (ffxiiiimgPrt) { + PrintLog("HookCreateFileA Before Replacement: %s", lpFileName); + + int arrayPosition = ffxiiiimgPrt - lpFileName; + int len = strlen(lpFileName); + char* newFileName = new char[len + 1]; + strcpy_s(newFileName, len + 1, lpFileName); + const char* untouched = "untouched"; // needs to have the size of "ffxiiiimg" + + memcpy(newFileName + arrayPosition, untouched, strlen(untouched)); + PrintLog("HookCreateFileA After Replacement: %s", newFileName); + MH_STATUS disableHookCreateFileA = MH_DisableHook(CreateFileA); + PrintLog("disableHookCreateFileA = %d", disableHookCreateFileA); + MH_STATUS disableHookCreateFileW = MH_DisableHook(CreateFileW); + PrintLog("disableHookCreateFileW = %d", disableHookCreateFileW); + if (GetFileAttributesA(newFileName) == INVALID_FILE_ATTRIBUTES) { + PrintLog("ERROR: Unable to get attributes of %s. Does the file exist?", newFileName); + } + HANDLE fileHandle = context.TrueCreateFileA(newFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);; + delete[] newFileName; + PrintLog("Returning File Handle"); + return fileHandle; + } + else { + return context.TrueCreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); + } +} + +HANDLE WINAPI MainContext::HookCreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { + const wchar_t* ffxiiiimgPrt = wcsstr(lpFileName, L"ffxiiiimg.exe");; + + if (ffxiiiimgPrt) { + PrintLog("HookCreateFileW Before Replacement: %s", lpFileName); + + int arrayPosition = ffxiiiimgPrt - lpFileName; + int len = wcslen(lpFileName); + wchar_t* newFileName = new wchar_t[len + 1]; + wcscpy_s(newFileName, len + 1, lpFileName); + const wchar_t* untouched = L"untouched"; //needs to have the size of L"ffxiiiimg" + wmemcpy(newFileName + arrayPosition, untouched, wcslen(untouched)); + PrintLog("HookCreateFileW After Replacement: %s", newFileName); + MH_STATUS disableHookCreateFileA = MH_DisableHook(CreateFileA); + PrintLog("disableHookCreateFileA = %d", disableHookCreateFileA); + MH_STATUS disableHookCreateFileW = MH_DisableHook(CreateFileW); + PrintLog("disableHookCreateFileW = %d", disableHookCreateFileW); + if (GetFileAttributesW(newFileName) == INVALID_FILE_ATTRIBUTES) { + PrintLog("ERROR: Unable to get attributes of %s. Does the file exist?", newFileName); + } + HANDLE fileHandle = context.TrueCreateFileW(newFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);; + delete[] newFileName; + PrintLog("Returning File Handle"); + return fileHandle; + } + else { + return context.TrueCreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); + } +} + void MainContext::FixBehaviorFlagConflict(const DWORD flags_in, DWORD* flags_out) { if (flags_in & D3DCREATE_SOFTWARE_VERTEXPROCESSING) @@ -199,6 +261,38 @@ void MainContext::FF13_InitializeGameAddresses() ff13_party_screen_scissor_scaling_factor_4 = baseAddr + 0x668E91; ff13_message_box_call_address = baseAddr + 0xA8A98F; ff13_message_box_stack_push_address = baseAddr + 0xA8A982; + ff13_exe_large_address_aware_flag_address = baseAddr + 0x126; + ff13_exe_checksum_address = baseAddr + 0x168; +} + +void MainContext::FF13_HandleLargeAddressAwarePatch() { + const uint8_t laaMask = 0x20; + if (*ff13_exe_large_address_aware_flag_address && laaMask) { + PrintLog("LargeAddressAwarePatch found. Make sure untouched.exe is an unmodified copy of ffxiiiimg.exe"); + const MH_STATUS createHookCreateFileA = MH_CreateHook(CreateFileA, HookCreateFileA, reinterpret_cast(&TrueCreateFileA)); + PrintLog("createHookCreateFileA = %d", createHookCreateFileA); + const MH_STATUS enableHookCreateFileA = MH_EnableHook(CreateFileA); + PrintLog("enableHookCreateFileA = %d", enableHookCreateFileA); + + const MH_STATUS createHookCreateFileW = MH_CreateHook(CreateFileW, HookCreateFileW, reinterpret_cast(&TrueCreateFileW)); + PrintLog("createHookCreateFileW = %d", createHookCreateFileW); + const MH_STATUS enableHookCreateFileW = MH_EnableHook(CreateFileW); + PrintLog("enableHookCreateFileW = %d", enableHookCreateFileW); + + uint8_t new_ff13_exe_large_address_aware_flag = *ff13_exe_large_address_aware_flag_address & ~laaMask; + MemPatch::Patch(ff13_exe_large_address_aware_flag_address, &new_ff13_exe_large_address_aware_flag, 1); + PrintLog("LargeAddressAware patched back = %d", *ff13_exe_large_address_aware_flag_address); + + uint32_t new_ff13_exe_checksum = 0; + MemPatch::Patch(ff13_exe_checksum_address, &new_ff13_exe_checksum, sizeof(uint32_t)); + PrintLog("Checksum patched back = %d", *ff13_exe_checksum_address); + + PrintLog("LargeAddressAwarePatch handled"); + } + else { + PrintLog("LargeAddressAwarePatch not found."); + } + } void MainContext::ForceWindowActivate(const HWND hWnd) { diff --git a/d3d9ex/Context.cpp b/d3d9ex/Context.cpp index 90d22f7..9a58033 100644 --- a/d3d9ex/Context.cpp +++ b/d3d9ex/Context.cpp @@ -50,8 +50,6 @@ MainContext::MainContext() LogFile("FF13Fix.log"); context.PrintVersionInfo(); - if (config.GetOptionsAutoFix()) EnableAutoFix(); - PrintLog("Enabling hooks:"); const MH_STATUS initializeHooks = MH_Initialize(); PrintLog("initializeHooks = %d", initializeHooks); @@ -80,6 +78,8 @@ MainContext::MainContext() PrintLog("createHookSetWindowLongW = %d", createHookSetWindowLongW); const MH_STATUS enableHookSetWindowLongW = MH_EnableHook(SetWindowLongW); PrintLog("enableHookSetWindowLongW = %d", enableHookSetWindowLongW); + + if (config.GetOptionsAutoFix()) EnableAutoFix(); } MainContext::~MainContext() diff --git a/d3d9ex/Context.h b/d3d9ex/Context.h index 8cfba47..ca1b670 100644 --- a/d3d9ex/Context.h +++ b/d3d9ex/Context.h @@ -41,6 +41,8 @@ class MainContext DECLARE_HOOK(HWND, WINAPI, CreateWindowExW, DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam); + DECLARE_HOOK(HANDLE, WINAPI, CreateFileA, LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); + DECLARE_HOOK(HANDLE, WINAPI, CreateFileW, LPCWSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile); public: MainContext(); virtual ~MainContext(); @@ -95,6 +97,8 @@ private: uint8_t* ff13_party_screen_scissor_scaling_factor_4 = NULL; uint8_t* ff13_message_box_stack_push_address = NULL; uint8_t* ff13_message_box_call_address = NULL; + uint8_t* ff13_exe_large_address_aware_flag_address = NULL; + uint8_t* ff13_exe_checksum_address = NULL; uint32_t* ff13_internal_res_w; uint32_t* ff13_internal_res_h; @@ -151,6 +155,7 @@ private: void FF13_SetFrameRateVariables(); void FF13_FixScissorRect(); void FF13_RemoveContinuousControllerScan(); + void FF13_HandleLargeAddressAwarePatch(); void FF13_2_CreateSetFrameRateCodeBlock(); void FF13_2_InitializeGameAddresses();