Add files for version 1.4.0

This commit is contained in:
rebtd7 2020-01-22 19:34:48 -03:00 committed by GitHub
parent c470d53a9e
commit bf87990a5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 421 additions and 232 deletions

View File

@ -2,6 +2,7 @@
#include "Context.h"
#include "IDirect3DVertexBuffer9.h"
#include <intrin.h>
void MainContext::EnableAutoFix()
{
@ -24,6 +25,7 @@ void MainContext::EnableAutoFix()
{
autofix = FINAL_FANTASY_XIII;
PrintLog("AutoFix for \"Final Fantasy XIII\" enabled");
FF13_InitializeGameAddresses();
}
if (exe_name == "ffxiii2img.exe")
@ -35,6 +37,287 @@ void MainContext::EnableAutoFix()
}
}
const std::map<const MainContext::AutoFixes, const uint32_t> MainContext::behaviorflags_fixes =
{
{ RESIDENT_EVIL_4, D3DCREATE_SOFTWARE_VERTEXPROCESSING },
{ KINGS_BOUNTY_LEGEND, D3DCREATE_MIXED_VERTEXPROCESSING }
};
void MainContext::FixBehaviorFlagConflict(const DWORD flags_in, DWORD* flags_out)
{
if (flags_in & D3DCREATE_SOFTWARE_VERTEXPROCESSING)
{
*flags_out &= ~(D3DCREATE_PUREDEVICE | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_MIXED_VERTEXPROCESSING);
*flags_out |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
else if (flags_in & D3DCREATE_MIXED_VERTEXPROCESSING)
{
*flags_out &= ~(D3DCREATE_PUREDEVICE | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_SOFTWARE_VERTEXPROCESSING);
*flags_out |= D3DCREATE_MIXED_VERTEXPROCESSING;
}
else if (flags_in & D3DCREATE_HARDWARE_VERTEXPROCESSING)
{
*flags_out &= ~(D3DCREATE_MIXED_VERTEXPROCESSING | D3DCREATE_SOFTWARE_VERTEXPROCESSING);
*flags_out |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
}
}
bool MainContext::ApplyBehaviorFlagsFix(DWORD* flags)
{
if (autofix == AutoFixes::NONE) return false;
auto&& fix = behaviorflags_fixes.find(autofix);
if (fix != behaviorflags_fixes.end())
{
FixBehaviorFlagConflict(fix->second, flags);
return true;
}
return false;
}
HRESULT APIENTRY MainContext::ApplyVertexBufferFix(IDirect3DDevice9* pIDirect3DDevice9, UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer9** ppVertexBuffer, HANDLE* pSharedHandle)
{
switch (autofix) {
case AutoFixes::NONE:
return pIDirect3DDevice9->CreateVertexBuffer(Length, Usage, FVF, Pool, ppVertexBuffer, pSharedHandle);
case FINAL_FANTASY_XIII:
case FINAL_FANTASY_XIII2:
// Both games lock a vertex buffer 358400 before drawing any 2D element on screen (sometimes multiple times per frame)
if (Length == 358400 && Pool == D3DPOOL_MANAGED) {
Usage = D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY;
Pool = D3DPOOL_SYSTEMMEM;
//IDirect3DVertexBuffer9* buffer = nullptr;
//HRESULT hr = pIDirect3DDevice9->CreateVertexBuffer(Length, Usage, FVF, Pool, &buffer, NULL);
//if (FAILED(hr))
//{
// return pIDirect3DDevice9->CreateVertexBuffer(Length, Usage, FVF, Pool, ppVertexBuffer, pSharedHandle);
//}
//if(ppVertexBuffer) *ppVertexBuffer = new hkIDirect3DVertexBuffer9(pIDirect3DDevice9, buffer);
//return hr;
}
break;
}
return pIDirect3DDevice9->CreateVertexBuffer(Length, Usage, FVF, Pool, ppVertexBuffer, pSharedHandle);
}
void MainContext::FF13_InitializeGameAddresses()
{
// FF13 always seem to use the same addresses (even if you force ASLR on the OS), but we are calculating the addresses just in case...
byte* baseAddr = (byte*)GetModuleHandle(NULL); // Should be 400000
PrintLog("Base Addr = %x", baseAddr);
ff13_frame_pacer_ptr = (float**)(baseAddr + 0x243E34C);
ff13_set_framerate_ingame_instruction_address = baseAddr + 0xA8D65F;
ff13_continuous_scan_instruction_address = baseAddr + 0x420868;
ff13_enemy_scan_box_code_address = baseAddr + 0x54C920;
ff13_base_controller_input_address_ptr = (byte**)(baseAddr + 0x02411220);
ff13_vibration_low_set_zero_address = baseAddr + 0x4210DF;
ff13_vibration_high_set_zero_address = baseAddr + 0x4210F3;
}
void MainContext::FF13_OneTimeFixes() {
MainContext::FF13_NOPIngameFrameRateLimitSetter();
MainContext::FF13_SetFrameRateVariables();
MainContext::FF13_RemoveContinuousControllerScan();
MainContext::FF13_FixMissingEnemyScan();
MainContext::FF13_EnableControllerVibration();
PrintLog("Finished FF13 One Time Fixes");
MainContext::didOneTimeFixes = true;
}
void MainContext::FF13_EnableControllerVibration()
{
if (!config.GetFFXIIIEnableControllerVibration()) {
PrintLog("Vibration should not be enabled (config file)");
return;
}
PrintLog("Enabling controller vibration...");
ChangeMemoryProtectionToReadWriteExecute(ff13_vibration_low_set_zero_address, 5);
*ff13_vibration_low_set_zero_address = 0x90;
*(ff13_vibration_low_set_zero_address + 1) = 0x90;
*(ff13_vibration_low_set_zero_address + 2) = 0x90;
*(ff13_vibration_low_set_zero_address + 3) = 0x90;
*(ff13_vibration_low_set_zero_address + 4) = 0x90;
ChangeMemoryProtectionToReadWriteExecute(ff13_vibration_high_set_zero_address, 5);
*ff13_vibration_high_set_zero_address = 0x90;
*(ff13_vibration_high_set_zero_address + 1) = 0x90;
*(ff13_vibration_high_set_zero_address + 2) = 0x90;
*(ff13_vibration_high_set_zero_address + 3) = 0x90;
*(ff13_vibration_high_set_zero_address + 4) = 0x90;
xinputManager = new XInputManager(ff13_base_controller_input_address_ptr);
}
void MainContext::FF13_RemoveContinuousControllerScan() {
// Disable continuous controller scanning.
PrintLog("Removing game slow and synchronous controller continuous controller scanning...");
context.ChangeMemoryProtectionToReadWriteExecute(ff13_continuous_scan_instruction_address, 1);
// change a jne to jmp
*(byte*)ff13_continuous_scan_instruction_address = 0xEB;
}
void MainContext::FF13_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(ff13_enemy_scan_box_code_address, 18);
//push rectHeight
*(byte*)(ff13_enemy_scan_box_code_address + 0) = 0x68;
*(uint32_t*)(ff13_enemy_scan_box_code_address + 1) = rectHeight;
// push rectWidth
*(byte*)(ff13_enemy_scan_box_code_address + 5) = 0x68;
*(uint32_t*)(ff13_enemy_scan_box_code_address + 6) = rectWidth;
// push rectPosY
*(byte*)(ff13_enemy_scan_box_code_address + 10) = 0x68;
*(uint32_t*)(ff13_enemy_scan_box_code_address + 11) = rectPosY;
// NOP NOP NOP
*(byte*)(ff13_enemy_scan_box_code_address + 15) = 0x90;
*(byte*)(ff13_enemy_scan_box_code_address + 16) = 0x90;
*(byte*)(ff13_enemy_scan_box_code_address + 17) = 0x90;
}
void MainContext::FF13_NOPIngameFrameRateLimitSetter() {
PrintLog("NOPing the in-game instruction that sets the frame rate.");
context.ChangeMemoryProtectionToReadWriteExecute(ff13_set_framerate_ingame_instruction_address, 5);
// patching to: NOP NOP NOP NOP
*ff13_set_framerate_ingame_instruction_address = 0x90;
*(ff13_set_framerate_ingame_instruction_address + 1) = 0x90;
*(ff13_set_framerate_ingame_instruction_address + 2) = 0x90;
*(ff13_set_framerate_ingame_instruction_address + 3) = 0x90;
*(ff13_set_framerate_ingame_instruction_address + 4) = 0x90;
}
void MainContext::FF13_SetFrameRateVariables() {
float* framePacerTargetPtr = *ff13_frame_pacer_ptr;
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();
const bool unlimitedFrameRate = AreAlmostTheSame(frameRateConfig, -1.0f);
const 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 pacer / frame rate address. This shouldn't happen! Report this.");
}
}
void MainContext::FF13_2_OneTimeFixes() {
if (*ff13_2_frame_pacer_ptr_address) {
**ff13_2_frame_pacer_ptr_address = MAX_FRAME_RATE_LIMIT;
PrintLog("Frame pacer disabled");
context.FF13_2_AddHookIngameFrameRateLimitSetter();
context.FF13_2_RemoveContinuousControllerScan();
context.FF13_2_EnableControllerVibration();
PrintLog("Finished FF13-2 One Time Fixes");
context.didOneTimeFixes = true;
}
}
void MainContext::FF13_2_EnableControllerVibration()
{
if (!config.GetFFXIIIEnableControllerVibration()) {
PrintLog("Vibration should not be enabled (config file)");
return;
}
PrintLog("Enabling controller vibration...");
ChangeMemoryProtectionToReadWriteExecute(ff13_2_vibration_low_set_zero_address, 5);
*ff13_2_vibration_low_set_zero_address = 0x90;
*(ff13_2_vibration_low_set_zero_address + 1) = 0x90;
*(ff13_2_vibration_low_set_zero_address + 2) = 0x90;
*(ff13_2_vibration_low_set_zero_address + 3) = 0x90;
*(ff13_2_vibration_low_set_zero_address + 4) = 0x90;
ChangeMemoryProtectionToReadWriteExecute(ff13_2_vibration_high_set_zero_address, 5);
*ff13_2_vibration_high_set_zero_address = 0x90;
*(ff13_2_vibration_high_set_zero_address + 1) = 0x90;
*(ff13_2_vibration_high_set_zero_address + 2) = 0x90;
*(ff13_2_vibration_high_set_zero_address + 3) = 0x90;
*(ff13_2_vibration_high_set_zero_address + 4) = 0x90;
xinputManager = new XInputManager(ff13_2_base_controller_input_address_ptr);
}
void MainContext::FF13_2_InitializeGameAddresses()
{
// FF13-2 uses address space layout randomization (ASLR) so we can't rely on fixed addresses without considering the base address
byte* baseAddr = (byte*)GetModuleHandle(NULL);
PrintLog("Base Addr = %x", baseAddr);
ff13_2_continuous_scan_instruction_address = baseAddr + 0x2A6E7F;
ff13_2_set_frame_rate_address = baseAddr + 0x802616;
ff13_2_frame_pacer_ptr_address = (float**)(baseAddr + 0x4D67208);
ff13_2_base_controller_input_address_ptr = (byte**)(baseAddr + 0x212A164);
ff13_2_vibration_low_set_zero_address = baseAddr + 0x2A7221;
ff13_2_vibration_high_set_zero_address = baseAddr + 0x2A7226;
}
void MainContext::FF13_2_RemoveContinuousControllerScan() {
// Disable continuous controller scanning.
PrintLog("Removing game slow and synchronous controller continuous controller scanning...");
context.ChangeMemoryProtectionToReadWriteExecute(ff13_2_continuous_scan_instruction_address, 1);
// change a jne to jmp
*(byte*)ff13_2_continuous_scan_instruction_address = 0xEB;
}
void MainContext::FF13_2_AddHookIngameFrameRateLimitSetter() {
if (context.AreAlmostTheSame((float)context.config.GetFFXIIIIngameFrameRateLimit(), 0.0F)) {
PrintLog("Frame rate should not be changed (config = 0)");
return;
}
PrintLog("Hooking the instruction that sets the frame rate...");
context.ChangeMemoryProtectionToReadWriteExecute(ff13_2_set_frame_rate_address, 5);
// patching to: jmp FF13_2_SET_FRAME_RATE_INJECTED_CODE
*ff13_2_set_frame_rate_address = 0xE9;
*((uint32_t*)(ff13_2_set_frame_rate_address + 1)) = FF13_2_SET_FRAME_RATE_INJECTED_CODE - ff13_2_set_frame_rate_address - 5;
}
void MainContext::FF13_2_CreateSetFrameRateCodeBlock()
{
const int blockSize = 31;
@ -73,6 +356,7 @@ void MainContext::FF13_2_CreateSetFrameRateCodeBlock()
*(FF13_2_SET_FRAME_RATE_INJECTED_CODE + 16) = 0x05;
*(float**)(FF13_2_SET_FRAME_RATE_INJECTED_CODE + 17) = (float*)(&ff13_2_targetFrameRate);
// SetFrameRateVar:
// movss [ecx+04],xmm0
*(FF13_2_SET_FRAME_RATE_INJECTED_CODE + 21) = 0xF3;
*(FF13_2_SET_FRAME_RATE_INJECTED_CODE + 22) = 0x0F;
@ -80,222 +364,11 @@ void MainContext::FF13_2_CreateSetFrameRateCodeBlock()
*(FF13_2_SET_FRAME_RATE_INJECTED_CODE + 24) = 0x41;
*(FF13_2_SET_FRAME_RATE_INJECTED_CODE + 25) = 0x04;
//jmp ffxiii2img.exe + 80261B
// jmp ffxiii2img.exe + 80261B
*(FF13_2_SET_FRAME_RATE_INJECTED_CODE + 26) = 0xE9;
*(uint32_t*)(FF13_2_SET_FRAME_RATE_INJECTED_CODE + 27) = ff13_2_set_frame_rate_address - FF13_2_SET_FRAME_RATE_INJECTED_CODE - 26;
}
void MainContext::FF13_2_InitializeGameAddresses()
{
// FF13-2 uses address space layout randomization (ASLR) so we can't rely on fixed addresses without considering the base address
byte* baseAddr = (byte*)GetModuleHandle(NULL);
ff13_2_continuous_scan_instruction_address = baseAddr + 0x2A6E7F;
ff13_2_set_frame_rate_address = baseAddr + 0x802616;
ff13_2_frame_pacer_ptr_address = (float**)(baseAddr + 0x4D67208);
}
const std::map<const MainContext::AutoFixes, const uint32_t> MainContext::behaviorflags_fixes =
{
{ RESIDENT_EVIL_4, D3DCREATE_SOFTWARE_VERTEXPROCESSING },
{ KINGS_BOUNTY_LEGEND, D3DCREATE_MIXED_VERTEXPROCESSING }
};
void MainContext::FixBehaviorFlagConflict(const DWORD flags_in, DWORD* flags_out)
{
if (flags_in & D3DCREATE_SOFTWARE_VERTEXPROCESSING)
{
*flags_out &= ~(D3DCREATE_PUREDEVICE | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_MIXED_VERTEXPROCESSING);
*flags_out |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
else if (flags_in & D3DCREATE_MIXED_VERTEXPROCESSING)
{
*flags_out &= ~(D3DCREATE_PUREDEVICE | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_SOFTWARE_VERTEXPROCESSING);
*flags_out |= D3DCREATE_MIXED_VERTEXPROCESSING;
}
else if (flags_in & D3DCREATE_HARDWARE_VERTEXPROCESSING)
{
*flags_out &= ~(D3DCREATE_MIXED_VERTEXPROCESSING | D3DCREATE_SOFTWARE_VERTEXPROCESSING);
*flags_out |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
}
}
bool MainContext::ApplyBehaviorFlagsFix(DWORD* flags)
{
if (autofix == AutoFixes::NONE) return false;
auto && fix = behaviorflags_fixes.find(autofix);
if (fix != behaviorflags_fixes.end())
{
FixBehaviorFlagConflict(fix->second, flags);
return true;
}
return false;
}
HRESULT APIENTRY MainContext::ApplyVertexBufferFix(IDirect3DDevice9* pIDirect3DDevice9, UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer9** ppVertexBuffer, HANDLE* pSharedHandle)
{
switch (autofix) {
case AutoFixes::NONE:
return pIDirect3DDevice9->CreateVertexBuffer(Length, Usage, FVF, Pool, ppVertexBuffer, pSharedHandle);
case FINAL_FANTASY_XIII:
case FINAL_FANTASY_XIII2:
// Both games lock a vertex buffer 358400 before drawing any 2D element on screen (sometimes multiple times per frame)
if (Length == 358400 && Pool == D3DPOOL_MANAGED) {
Usage = D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY;
Pool = D3DPOOL_SYSTEMMEM;
//IDirect3DVertexBuffer9* buffer = nullptr;
//HRESULT hr = pIDirect3DDevice9->CreateVertexBuffer(Length, Usage, FVF, Pool, &buffer, NULL);
//if (FAILED(hr))
//{
// return pIDirect3DDevice9->CreateVertexBuffer(Length, Usage, FVF, Pool, ppVertexBuffer, pSharedHandle);
//}
//if(ppVertexBuffer) *ppVertexBuffer = new hkIDirect3DVertexBuffer9(pIDirect3DDevice9, buffer);
//return hr;
}
break;
}
return pIDirect3DDevice9->CreateVertexBuffer(Length, Usage, FVF, Pool, ppVertexBuffer, pSharedHandle);
}
void MainContext::FF13_OneTimeFixes() {
bool successSoFar = true;
// The game repeatedly sets the frame rate limit. Disable the instruction that does it.
MainContext::FF13_AddHookIngameFrameRateLimitSetter();
successSoFar &= MainContext::FF13_SetFrameRateVariables();
if (successSoFar) {
context.FF13_RemoveContinuousControllerScan();
context.FF13_FixMissingEnemyScan();
context.didOneTimeFixes = true;
}
}
void MainContext::FF13_RemoveContinuousControllerScan() {
// Disable continuous controller scanning.
PrintLog("Removing game slow and synchronous controller continuous controller scanning...");
context.ChangeMemoryProtectionToReadWriteExecute(FF13_CONTINUOUS_SCAN_INSTRUCTION_ADDRESS, 1);
// change a jne to jmp
*(byte*)FF13_CONTINUOUS_SCAN_INSTRUCTION_ADDRESS = 0xEB;
}
void MainContext::FF13_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(FF13_ENEMY_SCAN_BOX_CODE_ADDRESS, 18);
//push boxHeight
*(byte*)(FF13_ENEMY_SCAN_BOX_CODE_ADDRESS + 0) = 0x68;
*(uint32_t*)(FF13_ENEMY_SCAN_BOX_CODE_ADDRESS + 1) = rectHeight;
// push boxWidth
*(byte*)(FF13_ENEMY_SCAN_BOX_CODE_ADDRESS + 5) = 0x68;
*(uint32_t*)(FF13_ENEMY_SCAN_BOX_CODE_ADDRESS + 6) = rectWidth;
// push boxPosY
*(byte*)(FF13_ENEMY_SCAN_BOX_CODE_ADDRESS + 10) = 0x68;
*(uint32_t*)(FF13_ENEMY_SCAN_BOX_CODE_ADDRESS + 11) = rectPosY;
// NOP NOP NOP
*(byte*)(FF13_ENEMY_SCAN_BOX_CODE_ADDRESS + 15) = 0x90;
*(byte*)(FF13_ENEMY_SCAN_BOX_CODE_ADDRESS + 16) = 0x90;
*(byte*)(FF13_ENEMY_SCAN_BOX_CODE_ADDRESS + 17) = 0x90;
}
void MainContext::FF13_AddHookIngameFrameRateLimitSetter() {
PrintLog("Using the ingame the instruction that sets the frame rate to get the frame rate address.");
context.ChangeMemoryProtectionToReadWriteExecute(FF13_SET_FRAMERATE_INGAME_INSTRUCTION_ADDRESS, 5);
// patching to: mov [framePacerTargetPtr], eax
*FF13_SET_FRAMERATE_INGAME_INSTRUCTION_ADDRESS = 0xA3;
*((uint32_t*)(FF13_SET_FRAMERATE_INGAME_INSTRUCTION_ADDRESS + 1)) = (uint32_t)(&framePacerTargetPtr);
}
bool MainContext::FF13_SetFrameRateVariables() {
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();
const bool unlimitedFrameRate = AreAlmostTheSame(frameRateConfig, -1.0f);
const 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;
}
void MainContext::FF13_2_OneTimeFixes() {
if (*ff13_2_frame_pacer_ptr_address) {
**ff13_2_frame_pacer_ptr_address = MAX_FRAME_RATE_LIMIT;
PrintLog("Frame pacer disabled");
context.FF13_2_AddHookIngameFrameRateLimitSetter();
context.FF13_2_RemoveContinuousControllerScan();
context.didOneTimeFixes = true;
}
}
void MainContext::FF13_2_RemoveContinuousControllerScan() {
// Disable continuous controller scanning.
PrintLog("Removing game slow and synchronous controller continuous controller scanning...");
context.ChangeMemoryProtectionToReadWriteExecute(ff13_2_continuous_scan_instruction_address, 1);
// change a jne to jmp
*(byte*)ff13_2_continuous_scan_instruction_address = 0xEB;
}
void MainContext::FF13_2_AddHookIngameFrameRateLimitSetter() {
if (context.AreAlmostTheSame((float)context.config.GetFFXIIIIngameFrameRateLimit(), 0.0F)) {
PrintLog("Frame rate should not be changed (config = 0)");
return;
}
PrintLog("Hooking the instruction that sets the frame rate...");
context.ChangeMemoryProtectionToReadWriteExecute(ff13_2_set_frame_rate_address, 5);
// patching to: jmp FF13_2_SET_FRAME_RATE_INJECTED_CODE
*ff13_2_set_frame_rate_address = 0xE9;
*((uint32_t*)(ff13_2_set_frame_rate_address + 1)) = FF13_2_SET_FRAME_RATE_INJECTED_CODE - ff13_2_set_frame_rate_address - 5;
}
void MainContext::ChangeMemoryProtectionToReadWriteExecute(void* address, const int size) {
DWORD oldProtection;
@ -303,7 +376,7 @@ void MainContext::ChangeMemoryProtectionToReadWriteExecute(void* address, const
}
void MainContext::PrintVersionInfo() {
PrintLog("FF13Fix 1.3.1 https://github.com/rebtd7/FF13Fix");
PrintLog("FF13Fix 1.4.0 https://github.com/rebtd7/FF13Fix");
}
bool MainContext::AreAlmostTheSame(float a, float b) {

View File

@ -5,6 +5,7 @@
#include "Context.h"
#include "IDirect3D9.h"
#include <thread>
MainContext context;
@ -41,7 +42,7 @@ Config::Config()
MainContext::MainContext() : oldWndProc(nullptr)
{
LogFile("FF13Fix.log");
PrintVersionInfo();
context.PrintVersionInfo();
if (config.GetAutoFix()) EnableAutoFix();
@ -61,6 +62,8 @@ MainContext::MainContext() : oldWndProc(nullptr)
MH_CreateHook(SetWindowLongW, HookSetWindowLongW, reinterpret_cast<void**>(&TrueSetWindowLongW));
MH_EnableHook(SetWindowLongW);
}
MainContext::~MainContext()
@ -178,13 +181,19 @@ bool MainContext::CheckWindow(HWND hWnd)
PrintLog("HWND 0x%p: ClassName \"%ls\", WindowName: \"%ls\"", hWnd, className.get(), windowName.get());
if (!context.didOneTimeFixes) {
if (context.autofix == FINAL_FANTASY_XIII) {
PrintLog("Starting FFXIII one time RAM patches.");
context.FF13_OneTimeFixes();
if (context.autofix == FINAL_FANTASY_XIII && wcscmp(windowName.get(), L"DIEmWin") == 0) {
const std::lock_guard<std::mutex> lock(context.oneTimeFixesMutex);
if(!context.didOneTimeFixes){
PrintLog("Starting FFXIII one time RAM patches.");
context.FF13_OneTimeFixes();
}
}
else if (context.autofix == FINAL_FANTASY_XIII2 && wcscmp(windowName.get(), L"DIEmWin") == 0) {
PrintLog("Starting FFXIII-2 one time RAM patches.");
context.FF13_2_OneTimeFixes();
const std::lock_guard<std::mutex> lock(context.oneTimeFixesMutex);
if (!context.didOneTimeFixes) {
PrintLog("Starting FFXIII-2 one time RAM patches.");
context.FF13_2_OneTimeFixes();
}
}
}
bool class_found = config.GetWindowClass().compare(className.get()) == 0;

View File

@ -4,6 +4,7 @@
#include "d3d9.h"
#include <MinHook.h>
#include "SimpleIni.h"
#include "XInputManager.h"
struct hkIDirect3D9;
@ -43,7 +44,8 @@ class MainContext
DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam);
public:
MainContext();
MainContext();
void Foo();
~MainContext();
bool ApplyPresentationParameters(D3DPRESENT_PARAMETERS* pPresentationParameters);
@ -68,28 +70,35 @@ private:
FINAL_FANTASY_XIII2,
};
void EnableAutoFix();
void FF13_2_CreateSetFrameRateCodeBlock();
void FF13_2_InitializeGameAddresses();
void EnableAutoFix();
AutoFixes autofix = AutoFixes::NONE;
std::mutex oneTimeFixesMutex;
bool didOneTimeFixes = false;
const float MAX_FRAME_RATE_LIMIT = 250000.0F;
byte* FF13_SET_FRAMERATE_INGAME_INSTRUCTION_ADDRESS = (byte*)0x00E8D65F;
byte* FF13_CONTINUOUS_SCAN_INSTRUCTION_ADDRESS = (byte*)0x00820868;
byte* FF13_ENEMY_SCAN_BOX_CODE_ADDRESS = (byte*)0x0094C920;
float** ff13_frame_pacer_ptr = NULL;
byte* ff13_set_framerate_ingame_instruction_address = NULL;
byte* ff13_continuous_scan_instruction_address = NULL;
byte* ff13_enemy_scan_box_code_address = NULL;
byte** ff13_base_controller_input_address_ptr = NULL;
byte* ff13_vibration_high_set_zero_address = NULL;
byte* ff13_vibration_low_set_zero_address = NULL;
byte* FF13_2_SET_FRAME_RATE_INJECTED_CODE = NULL;
byte* ff13_2_continuous_scan_instruction_address;
byte* ff13_2_set_frame_rate_address;
float** ff13_2_frame_pacer_ptr_address;
float ff13_2_targetFrameRate;
byte** ff13_2_base_controller_input_address_ptr = NULL;
byte* ff13_2_vibration_high_set_zero_address = NULL;
byte* ff13_2_vibration_low_set_zero_address = NULL;
const float FF13_2_30_FPS = 30.0F;
const float FF13_2_MAX_FRAME_CAP = 1000.0F;
XInputManager* xinputManager;
float* framePacerTargetPtr = NULL;
UINT backbufferWidth = 0;
void FixBehaviorFlagConflict(const DWORD flags_in, DWORD* flags_out);
@ -102,15 +111,20 @@ private:
bool AreAlmostTheSame(float a, float b);
void PrintVersionInfo();
void FF13_OneTimeFixes();
void FF13_AddHookIngameFrameRateLimitSetter();
bool FF13_SetFrameRateVariables();
void FF13_InitializeGameAddresses();
void FF13_OneTimeFixes();
void FF13_EnableControllerVibration();
void FF13_NOPIngameFrameRateLimitSetter();
void FF13_SetFrameRateVariables();
void FF13_FixMissingEnemyScan();
void FF13_RemoveContinuousControllerScan();
void FF13_2_CreateSetFrameRateCodeBlock();
void FF13_2_InitializeGameAddresses();
void FF13_2_RemoveContinuousControllerScan();
void FF13_2_AddHookIngameFrameRateLimitSetter();
void FF13_2_OneTimeFixes();
void FF13_2_OneTimeFixes();
void FF13_2_EnableControllerVibration();
};
extern MainContext context;

View File

@ -11,6 +11,7 @@ SETTING(bool, BoolValue, ForceHideCursor, Options, false);
SETTING(u32, LongValue, BehaviorFlags, Options, 0);
SETTING(double, DoubleValue, FFXIIIIngameFrameRateLimit, Options, 0.0);
SETTING(bool, BoolValue, FFXIIIEnableControllerVibration, Options, true);
SETTING(bool, BoolValue, Adapter, Adapter, false);
SETTING(u32, LongValue, VendorId, Adapter, 0);

69
d3d9ex/XInputManager.cpp Normal file
View File

@ -0,0 +1,69 @@
#include "stdafx.h"
#include "XInputManager.h"
#include <XInput.h>
XInputManager::XInputManager(byte** base_controller_input_address_ptr)
{
xinputThread = std::thread(&XInputManager::Run, this, base_controller_input_address_ptr);
}
void XInputManager::Run(byte** base_controller_input_address_ptr)
{
DWORD controllerState;
bool hasConnected = false;
for (DWORD i = 0; i < XUSER_MAX_COUNT; i++) {
XINPUT_STATE state;
ZeroMemory(&state, sizeof(XINPUT_STATE));
controllerState = XInputGetState(i, &state);
if (controllerState == ERROR_SUCCESS) {
controllerId = i;
hasConnected = true;
break;
}
}
if (hasConnected) {
WaitAndSetVibrationAddress(base_controller_input_address_ptr);
VibrationLoop();
}
}
void XInputManager::WaitAndSetVibrationAddress(byte** base_controller_input_address_ptr)
{
do {
std::this_thread::sleep_for(std::chrono::milliseconds(4));
if (base_controller_input_address_ptr && *base_controller_input_address_ptr) {
vibration_address_low_frequency = (float*)(*base_controller_input_address_ptr + 0x40 + 0x60 - 0x4);
vibration_address_high_frequency = vibration_address_low_frequency + 1;
}
} while (vibration_address_low_frequency == NULL);
}
void XInputManager::VibrationLoop()
{
const WORD maxVibrationStrength = 65535;
bool wasVibrating = false;
SetControllerVibration(0, 0);
while (true) {
const float vibrationStrengthLowFrequency = *vibration_address_low_frequency;
const float vibrationStrengthHighFrequency = *vibration_address_high_frequency;
if (vibrationStrengthLowFrequency || vibrationStrengthHighFrequency) {
SetControllerVibration(vibrationStrengthLowFrequency * maxVibrationStrength, vibrationStrengthHighFrequency * maxVibrationStrength);
wasVibrating = true;
}
else if(wasVibrating) {
SetControllerVibration(0, 0);
wasVibrating = false;
}
std::this_thread::sleep_for(std::chrono::milliseconds(4));
}
}
void XInputManager::SetControllerVibration(const WORD& leftMotorVibration, const WORD& rightMotorVibration)
{
XINPUT_VIBRATION vibration;
ZeroMemory(&vibration, sizeof(XINPUT_VIBRATION));
vibration.wLeftMotorSpeed = leftMotorVibration;
vibration.wRightMotorSpeed = rightMotorVibration;
XInputSetState(controllerId, &vibration);
}

15
d3d9ex/XInputManager.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
class XInputManager
{
float* vibration_address_high_frequency = NULL;
float* vibration_address_low_frequency = NULL;
DWORD controllerId = -1;
std::thread xinputThread;
public:
XInputManager(byte** base_controller_input_address_ptr);
void Run(byte** base_controller_input_address_ptr);
void WaitAndSetVibrationAddress(byte** base_controller_input_address_ptr);
void VibrationLoop();
void SetControllerVibration(const WORD& leftMotorVibration, const WORD& rightMotorVibration);
};

View File

@ -137,7 +137,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>XINPUT9_1_0.LIB;d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
@ -172,6 +172,7 @@
<ClInclude Include="Settings.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="XInputManager.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="AutoFix.cpp" />
@ -199,6 +200,7 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="XInputManager.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="exports.def" />

View File

@ -42,6 +42,9 @@
<ClInclude Include="IDirect3DVertexBuffer9.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="XInputManager.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
@ -65,6 +68,9 @@
<ClCompile Include="IDirect3DVertexBuffer9.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="XInputManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="exports.def">