diff --git a/d3d9ex/AutoFix.cpp b/d3d9ex/AutoFix.cpp index b81f6d2..ff2182e 100644 --- a/d3d9ex/AutoFix.cpp +++ b/d3d9ex/AutoFix.cpp @@ -25,6 +25,9 @@ void MainContext::EnableAutoFix() spdlog::info("AutoFix for \"Final Fantasy XIII-2\" enabled"); FF13_2_InitializeGameAddresses(); FF13_2_CreateSetFrameRateCodeBlock(); + FF13_2_CreateSetPressedButtonsCodeBlock(); + FF13_2_CreateSetLeftAnalogCodeBlock(); + FF13_2_CreateSetRightAnalogCodeBlock(); } } @@ -154,6 +157,8 @@ HRESULT MainContext::SetScissorRect(IDirect3DDevice9* pIDirect3DDevice9, CONST R // hate this workaround but we cant directly mix d3d9 include with and without defined CINTERFACE namespace cinterface { void VertexBufferFix(IDirect3DVertexBuffer9* pVertexBuffer); + void InitHookPresent(IDirect3DSwapChain9* pDirect3DSwapChain9); + void ShareValuesWithSwapChainHook(XInputManager* xInputManager, uint32_t* ff13ButtonPressed, float* ff13AnalogValues); } HRESULT MainContext::CreateVertexBuffer(IDirect3DDevice9* pIDirect3DDevice9, UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer9** ppVertexBuffer, HANDLE* pSharedHandle) @@ -172,12 +177,23 @@ HRESULT MainContext::CreateVertexBuffer(IDirect3DDevice9* pIDirect3DDevice9, UIN //Pool = D3DPOOL_DEFAULT; cinterface::VertexBufferFix(*ppVertexBuffer); } + + + // TODO Move this somewhere else... + // I've tried to move it to hkIDirect3D9::ApplyCreateDeviceFix but I got an incorrect ref count error message in the log (why?) + IDirect3DSwapChain9* swapChain = NULL; + HRESULT getSwapChainResult = pIDirect3DDevice9->GetSwapChain(0, &swapChain); + context.HookPresent(&swapChain); return hr; } } return pIDirect3DDevice9->CreateVertexBuffer(Length, Usage, FVF, Pool, ppVertexBuffer, pSharedHandle); } +void MainContext::HookPresent(IDirect3DSwapChain9** swapChain){ + cinterface::InitHookPresent(*swapChain); +} + HRESULT MainContext::DrawPrimitiveUP(IDirect3DDevice9* pIDirect3DDevice9, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, const void* pVertexStreamZeroData, UINT VertexStreamZeroStride) { if (PrimitiveType == D3DPT_TRIANGLEFAN && PrimitiveCount == 2 && VertexStreamZeroStride == 20 && MatchesExpectedVertexStream((const float*)pVertexStreamZeroData)) { @@ -248,8 +264,6 @@ void MainContext::FF13_InitializeGameAddresses() ff13_continuous_scan_instruction_address = baseAddr + 0x420868; ff13_enemy_scan_box_code_address = baseAddr + 0x54C920; ff13_base_controller_input_address_ptr = (uint8_t**)(baseAddr + 0x02411220); - ff13_vibration_low_set_zero_address = baseAddr + 0x4210DF; - ff13_vibration_high_set_zero_address = baseAddr + 0x4210F3; ff13_internal_res_w = (uint32_t*)(baseAddr + 0x22E5168); ff13_internal_res_h = ff13_internal_res_w + 1; ff13_loading_screen_scissor_scaling_factor_1 = baseAddr + 0x616596; @@ -265,6 +279,9 @@ void MainContext::FF13_InitializeGameAddresses() ff13_message_box_stack_push_address = baseAddr + 0xA8A982; ff13_exe_large_address_aware_flag_address = baseAddr + 0x126; ff13_exe_checksum_address = (uint32_t*)(baseAddr + 0x168); + ff13_or_pressed_buttons_instruction_address = baseAddr + 0x422C50; + ff13_set_eax_to_left_analog_pointer_instruction_address = baseAddr + 0x422BB2; + ff13_set_eax_to_right_analog_pointer_instruction_address = baseAddr + 0x422C0B; } void MainContext::FF13_HandleLargeAddressAwarePatch() { @@ -315,13 +332,47 @@ void MainContext::FF13_OneTimeFixes() { FF13_NOPIngameFrameRateLimitSetter(); FF13_RemoveContinuousControllerScan(); FF13_FixScissorRect(); - FF13_EnableControllerVibration(); FF13_SetFrameRateVariables(); + FF13_DisableInternalGamepadInput(); + CheckAndEnableXInputImplementation(ff13_base_controller_input_address_ptr); AdjustVertexData(*ff13_internal_res_w, *ff13_internal_res_h); spdlog::info("Finished FF13 One Time Fixes"); } +void MainContext::FF13_DisableInternalGamepadInput() +{ + + // Use our variable with the pressed buttons instead of the one update by the game + // + // instructions: + // or ecx,[ff13ButtonsPressed] + // nop + uint8_t newButtonsInstructions[7]; + newButtonsInstructions[0] = 0x0B; + newButtonsInstructions[1] = 0x0D; + *(uint32_t**)(newButtonsInstructions + 2) = &ff13ButtonsPressed; + newButtonsInstructions[6] = 0x90; + MemPatch::Patch(ff13_or_pressed_buttons_instruction_address, newButtonsInstructions, 7); + + + uint8_t newLeftAnalogInstructions[7]; + newLeftAnalogInstructions[0] = 0xB8; + *(float**)(newLeftAnalogInstructions + 1) = ff13AnalogValues; + newLeftAnalogInstructions[5] = 0x90; + newLeftAnalogInstructions[6] = 0x90; + MemPatch::Patch(ff13_set_eax_to_left_analog_pointer_instruction_address, newLeftAnalogInstructions, 7); + + + uint8_t newRightAnalogInstructions[7]; + newRightAnalogInstructions[0] = 0xB8; + *(float**)(newRightAnalogInstructions + 1) = (ff13AnalogValues + 4); + newRightAnalogInstructions[5] = 0x90; + newRightAnalogInstructions[6] = 0x90; + MemPatch::Patch(ff13_set_eax_to_right_analog_pointer_instruction_address, newRightAnalogInstructions, 7); + +} + void MainContext::FF13_PatchMessageBox() { spdlog::info("Removing 'Quit game' textbox"); @@ -333,26 +384,10 @@ void MainContext::FF13_PatchMessageBox() PatchMessageBoxCall(ff13_message_box_call_address); } -void MainContext::FF13_EnableControllerVibration() -{ - if (!config.GetFFXIIIEnableControllerVibration()) { - spdlog::info("Vibration should not be enabled (config file)"); - return; - } - if (!config.GetFFXIIIDisableIngameControllerHotSwapping()) { - spdlog::info("Vibration disabled because FFXIIIDisableIngameControllerHotSwapping is set to false (config file)"); - return; - } - spdlog::info("Enabling controller vibration..."); - MemPatch::Nop(ff13_vibration_low_set_zero_address, 5); - MemPatch::Nop(ff13_vibration_high_set_zero_address, 5); - - xinputManager = new XInputManager(ff13_base_controller_input_address_ptr, config.GetFFXIIIVibrationStrengthFactor()); -} void MainContext::FF13_RemoveContinuousControllerScan() { - if (!config.GetFFXIIIDisableIngameControllerHotSwapping()) { + if (!config.GetFFXIIIDisableIngameControllerHotSwapping() && !config.GetFFXIII_XInputEnable()) { spdlog::info("Continuous controller scanning not disabled (config)"); return; } @@ -418,7 +453,8 @@ void MainContext::FF13_SetFrameRateVariables() float* ingameFrameRateLimitPtr = framePacerTargetPtr + 1; *ingameFrameRateLimitPtr = frameRateLimit; - spdlog::info("Target frame rate set to {}", frameRateLimit); } + spdlog::info("Target frame rate set to {}", frameRateLimit); + } } else { spdlog::info("Unable to find frame pacer / frame rate address. This shouldn't happen! Report this."); @@ -437,8 +473,11 @@ void MainContext::FF13_2_OneTimeFixes() spdlog::info("Frame pacer disabled"); FF13_2_AddHookIngameFrameRateLimitSetter(); + FF13_2_AddHookPressedButtons(); + FF13_2_AddSetLeftAnalogHook(); + FF13_2_AddSetRightAnalogHook(); FF13_2_RemoveContinuousControllerScan(); - FF13_2_EnableControllerVibration(); + CheckAndEnableXInputImplementation(ff13_2_base_controller_input_address_ptr); AdjustVertexData(*ff13_2_internal_res_w, *ff13_2_internal_res_h); spdlog::info("Finished FF13-2 One Time Fixes"); } @@ -447,6 +486,35 @@ void MainContext::FF13_2_OneTimeFixes() } } +void MainContext::FF13_2_AddHookPressedButtons() +{ + AddJumpHook(ff13_2_pressed_buttons_instruction_jump_injected_address, FF13_2_SET_PRESSED_BUTTONS_INJECTED_CODE, 3); +} + +void MainContext::FF13_2_AddSetLeftAnalogHook() +{ + AddJumpHook(ff13_2_left_analog_instruction_jump_injected_address, FF13_2_SET_LEFT_ANALOG_INJECTED_CODE, 5); +} + +void MainContext::FF13_2_AddSetRightAnalogHook() +{ + AddJumpHook(ff13_2_right_analog_instruction_jump_injected_address, FF13_2_SET_RIGHT_ANALOG_INJECTED_CODE, 5); +} + +void MainContext::AddJumpHook(uint8_t* addrToAddJump, const uint8_t* codeBlockAddr, const int& numberOfNops) +{ + const int jumpInstructionSize = 5; + MemPatch::CUnprotect unp(addrToAddJump, jumpInstructionSize + numberOfNops); + // jmp codeBlockAddr + addrToAddJump[0] = 0xE9; + *((uint32_t*)(addrToAddJump + 1)) = codeBlockAddr - addrToAddJump - jumpInstructionSize; + + for (int i = 5; i < 5 + numberOfNops; i++) { + // nop + addrToAddJump[i] = 0x90; + } +} + void MainContext::FF13_2_PatchMessageBox() { spdlog::info("Removing 'Quit game' textbox"); @@ -471,18 +539,17 @@ void MainContext::PatchMessageBoxCall(uint8_t* callInstructionAddress) MemPatch::Patch(callInstructionAddress, patch, patchSize); } -void MainContext::FF13_2_EnableControllerVibration() +void MainContext::CheckAndEnableXInputImplementation(uint8_t** inputAddress) { - if (!config.GetFFXIIIEnableControllerVibration()) { - spdlog::info("Vibration should not be enabled (config file)"); + if (!config.GetFFXIII_XInputEnable()) { + spdlog::info("XInput implementation should not be enabled (config file)"); return; } - spdlog::info("Enabling controller vibration..."); + spdlog::info("Enabling XInput implementation..."); - MemPatch::Nop(ff13_2_vibration_low_set_zero_address, 5); - MemPatch::Nop(ff13_2_vibration_high_set_zero_address, 5); - - xinputManager = new XInputManager(ff13_2_base_controller_input_address_ptr, config.GetFFXIIIVibrationStrengthFactor()); + const float vibrationStrength = config.GetFFXIII_XInputEnableControllerVibration() ? config.GetFFXIII_XInputVibrationStrengthFactor() : -1.0f; + xinputManager = new XInputManager(inputAddress, vibrationStrength); + cinterface::ShareValuesWithSwapChainHook(xinputManager, &ff13ButtonsPressed, ff13AnalogValues); } void MainContext::AdjustVertexData(const uint32_t width, const uint32_t height) @@ -506,17 +573,18 @@ void MainContext::FF13_2_InitializeGameAddresses() ff13_2_set_frame_rate_address = baseAddr + 0x802616; ff13_2_frame_pacer_ptr_address = (float**)(baseAddr + 0x4D67208); ff13_2_base_controller_input_address_ptr = (uint8_t**)(baseAddr + 0x212A164); - ff13_2_vibration_low_set_zero_address = baseAddr + 0x2A7221; - ff13_2_vibration_high_set_zero_address = baseAddr + 0x2A7226; ff13_2_internal_res_w = (uint32_t*)(baseAddr + 0x1FA864C); ff13_2_internal_res_h = ff13_2_internal_res_w + 1; ff13_2_message_box_call_address = baseAddr + 0x8047C0; ff13_2_message_box_stack_push_address = baseAddr + 0x8047B4; + ff13_2_pressed_buttons_instruction_jump_injected_address = baseAddr + 0x2A79AB; + ff13_2_left_analog_instruction_jump_injected_address = baseAddr + 0x2A793F; + ff13_2_right_analog_instruction_jump_injected_address = baseAddr + 0x2A7964; } void MainContext::FF13_2_RemoveContinuousControllerScan() { - if (!config.GetFFXIIIDisableIngameControllerHotSwapping()) { + if (!config.GetFFXIIIDisableIngameControllerHotSwapping() && !config.GetFFXIII_XInputEnable()) { spdlog::info("Continuous controller scanning not disabled (config)"); return; } @@ -536,13 +604,107 @@ void MainContext::FF13_2_AddHookIngameFrameRateLimitSetter() spdlog::info("Hooking the instruction that sets the frame rate..."); - MemPatch::CUnprotect unp(ff13_2_set_frame_rate_address, 5); + AddJumpHook(ff13_2_set_frame_rate_address, FF13_2_SET_FRAME_RATE_INJECTED_CODE, 0); +} + +void MainContext::FF13_2_CreateSetPressedButtonsCodeBlock() +{ + const int blockSize = 15; + FF13_2_SET_PRESSED_BUTTONS_INJECTED_CODE = new(std::nothrow) uint8_t[blockSize]; + spdlog::debug("FF13_2_SET_PRESSED_BUTTONS_INJECTED_CODE = {}", (void*)FF13_2_SET_PRESSED_BUTTONS_INJECTED_CODE); + if (!FF13_2_SET_PRESSED_BUTTONS_INJECTED_CODE) { + spdlog::info("Failed to initialize FFXIII-2 pressed buttons code block"); + return; + } + DWORD oldProtect; + VirtualProtect(FF13_2_SET_PRESSED_BUTTONS_INJECTED_CODE, blockSize, PAGE_EXECUTE_READWRITE, &oldProtect); + + //mov eax, [esp + 3C] + FF13_2_SET_PRESSED_BUTTONS_INJECTED_CODE[0] = 0x8B; + FF13_2_SET_PRESSED_BUTTONS_INJECTED_CODE[1] = 0x44; + FF13_2_SET_PRESSED_BUTTONS_INJECTED_CODE[2] = 0x24; + FF13_2_SET_PRESSED_BUTTONS_INJECTED_CODE[3] = 0x3C; + + //mov edx,[&ff13ButtonsPressed] + FF13_2_SET_PRESSED_BUTTONS_INJECTED_CODE[4] = 0x8B; + FF13_2_SET_PRESSED_BUTTONS_INJECTED_CODE[5] = 0x15; + *((uint32_t**) (FF13_2_SET_PRESSED_BUTTONS_INJECTED_CODE + 6)) = &ff13ButtonsPressed; + + //jmp ffxiii2img.exe + 2A79B3 + FF13_2_SET_PRESSED_BUTTONS_INJECTED_CODE[10] = 0xE9; + *(uint32_t*)(FF13_2_SET_PRESSED_BUTTONS_INJECTED_CODE + 11) = ff13_2_pressed_buttons_instruction_jump_injected_address - FF13_2_SET_PRESSED_BUTTONS_INJECTED_CODE - 10; +} + +void MainContext::FF13_2_CreateSetRightAnalogCodeBlock() { + const int blockSize = 20; + FF13_2_SET_RIGHT_ANALOG_INJECTED_CODE = new(std::nothrow) uint8_t[blockSize]; + spdlog::debug("FF13_2_SET_RIGHT_ANALOG_INJECTED_CODE = {}", (void*)FF13_2_SET_RIGHT_ANALOG_INJECTED_CODE); + if (!FF13_2_SET_RIGHT_ANALOG_INJECTED_CODE) { + spdlog::info("Failed to initialize FFXIII-2 set right analog code block"); + return; + } + DWORD oldProtect; + VirtualProtect(FF13_2_SET_PRESSED_BUTTONS_INJECTED_CODE, blockSize, PAGE_EXECUTE_READWRITE, &oldProtect); + + //mov eax,ff13AnalogValues+4 + FF13_2_SET_RIGHT_ANALOG_INJECTED_CODE[0] = 0xB8; + *(float **)(FF13_2_SET_RIGHT_ANALOG_INJECTED_CODE + 1) = ff13AnalogValues + 4; + + //movq xmm0, [eax] + FF13_2_SET_RIGHT_ANALOG_INJECTED_CODE[5] = 0xF3; + FF13_2_SET_RIGHT_ANALOG_INJECTED_CODE[6] = 0x0F; + FF13_2_SET_RIGHT_ANALOG_INJECTED_CODE[7] = 0x7E; + FF13_2_SET_RIGHT_ANALOG_INJECTED_CODE[8] = 0x00; + + // movq[esp + 2C], xmm0 + FF13_2_SET_RIGHT_ANALOG_INJECTED_CODE[9] = 0x66; + FF13_2_SET_RIGHT_ANALOG_INJECTED_CODE[10] = 0x0F; + FF13_2_SET_RIGHT_ANALOG_INJECTED_CODE[11] = 0xD6; + FF13_2_SET_RIGHT_ANALOG_INJECTED_CODE[12] = 0x44; + FF13_2_SET_RIGHT_ANALOG_INJECTED_CODE[13] = 0x24; + FF13_2_SET_RIGHT_ANALOG_INJECTED_CODE[14] = 0x2C; + + // jmp ff13_2_right_analog_instruction_jump_injected_address + FF13_2_SET_RIGHT_ANALOG_INJECTED_CODE[15] = 0xE9; + *(uint32_t*)(FF13_2_SET_RIGHT_ANALOG_INJECTED_CODE + 16) = ff13_2_right_analog_instruction_jump_injected_address - FF13_2_SET_RIGHT_ANALOG_INJECTED_CODE - 15; +} + +void MainContext::FF13_2_CreateSetLeftAnalogCodeBlock() { + const int blockSize = 20; + FF13_2_SET_LEFT_ANALOG_INJECTED_CODE = new(std::nothrow) uint8_t[blockSize]; + spdlog::debug("FF13_2_SET_LEFT_ANALOG_INJECTED_CODE = {}", (void*)FF13_2_SET_LEFT_ANALOG_INJECTED_CODE); + if (!FF13_2_SET_LEFT_ANALOG_INJECTED_CODE) { + spdlog::info("Failed to initialize FFXIII-2 set left analog code block"); + return; + } + DWORD oldProtect; + VirtualProtect(FF13_2_SET_LEFT_ANALOG_INJECTED_CODE, blockSize, PAGE_EXECUTE_READWRITE, &oldProtect); + + //mov eax,ff13AnalogValues + FF13_2_SET_LEFT_ANALOG_INJECTED_CODE[0] = 0xB8; + *(float**)(FF13_2_SET_LEFT_ANALOG_INJECTED_CODE + 1) = ff13AnalogValues; + + //movq xmm0, [eax] + FF13_2_SET_LEFT_ANALOG_INJECTED_CODE[5] = 0xF3; + FF13_2_SET_LEFT_ANALOG_INJECTED_CODE[6] = 0x0F; + FF13_2_SET_LEFT_ANALOG_INJECTED_CODE[7] = 0x7E; + FF13_2_SET_LEFT_ANALOG_INJECTED_CODE[8] = 0x00; - // 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; + // movq[esp + 2C], xmm0 + FF13_2_SET_LEFT_ANALOG_INJECTED_CODE[9] = 0x66; + FF13_2_SET_LEFT_ANALOG_INJECTED_CODE[10] = 0x0F; + FF13_2_SET_LEFT_ANALOG_INJECTED_CODE[11] = 0xD6; + FF13_2_SET_LEFT_ANALOG_INJECTED_CODE[12] = 0x44; + FF13_2_SET_LEFT_ANALOG_INJECTED_CODE[13] = 0x24; + FF13_2_SET_LEFT_ANALOG_INJECTED_CODE[14] = 0x34; + + // jmp ff13_2_left_analog_instruction_jump_injected_address + FF13_2_SET_LEFT_ANALOG_INJECTED_CODE[15] = 0xE9; + *(uint32_t*)(FF13_2_SET_LEFT_ANALOG_INJECTED_CODE + 16) = ff13_2_left_analog_instruction_jump_injected_address - FF13_2_SET_LEFT_ANALOG_INJECTED_CODE - 15; } + + void MainContext::FF13_2_CreateSetFrameRateCodeBlock() { const int blockSize = 31; @@ -584,7 +746,7 @@ void MainContext::FF13_2_CreateSetFrameRateCodeBlock() *(FF13_2_SET_FRAME_RATE_INJECTED_CODE + 11) = 0x76; *(FF13_2_SET_FRAME_RATE_INJECTED_CODE + 12) = 0x08; - // movss xmm0,[&FF13_2_30_FPS] + // movss xmm0,[&ff13_2_targetFrameRate] *(FF13_2_SET_FRAME_RATE_INJECTED_CODE + 13) = 0xF3; *(FF13_2_SET_FRAME_RATE_INJECTED_CODE + 14) = 0x0F; *(FF13_2_SET_FRAME_RATE_INJECTED_CODE + 15) = 0x10; diff --git a/d3d9ex/Context.h b/d3d9ex/Context.h index 2d3f54b..ba74028 100644 --- a/d3d9ex/Context.h +++ b/d3d9ex/Context.h @@ -12,7 +12,7 @@ #include "XInputManager.h" static const char* inifilename = "FF13Fix.ini"; -#define CONFIG_VERSION 7 +#define CONFIG_VERSION 8 class Config { @@ -57,6 +57,7 @@ class MainContext void ApplyBehaviorFlagsFix(DWORD* flags); HRESULT SetScissorRect(IDirect3DDevice9* pIDirect3DDevice9, CONST RECT* rect); HRESULT CreateVertexBuffer(IDirect3DDevice9* pIDirect3DDevice9, UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer9** ppVertexBuffer, HANDLE* pSharedHandle); + void HookPresent(IDirect3DSwapChain9** swapChain); HRESULT DrawPrimitiveUP(IDirect3DDevice9* pIDirect3DDevice9, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, CONST void* pVertexStreamZeroData, UINT VertexStreamZeroStride); bool BehaviorFlagsToString(DWORD BehaviorFlags, std::string* BehaviorFlagsString); @@ -69,7 +70,6 @@ class MainContext void OneTimeFix(); bool IsDXVK(); - private: enum class AutoFixes : u32 { @@ -94,8 +94,6 @@ class MainContext uint8_t* ff13_continuous_scan_instruction_address = NULL; uint8_t* ff13_enemy_scan_box_code_address = NULL; uint8_t** ff13_base_controller_input_address_ptr = NULL; - uint8_t* ff13_vibration_high_set_zero_address = NULL; - uint8_t* ff13_vibration_low_set_zero_address = NULL; uint8_t* ff13_loading_screen_scissor_scaling_factor_1 = NULL; uint8_t* ff13_loading_screen_scissor_scaling_factor_2 = NULL; uint8_t* ff13_loading_screen_scissor_scaling_factor_3 = NULL; @@ -109,17 +107,24 @@ class MainContext uint8_t* ff13_message_box_call_address = NULL; uint8_t* ff13_exe_large_address_aware_flag_address = NULL; uint32_t* ff13_exe_checksum_address = NULL; + uint8_t* ff13_or_pressed_buttons_instruction_address = NULL; + uint8_t* ff13_set_eax_to_left_analog_pointer_instruction_address = NULL; + uint8_t* ff13_set_eax_to_right_analog_pointer_instruction_address = NULL; uint32_t* ff13_internal_res_w; uint32_t* ff13_internal_res_h; uint8_t* FF13_2_SET_FRAME_RATE_INJECTED_CODE = NULL; + uint8_t* FF13_2_SET_PRESSED_BUTTONS_INJECTED_CODE = NULL; + uint8_t* FF13_2_SET_LEFT_ANALOG_INJECTED_CODE = NULL; + uint8_t* FF13_2_SET_RIGHT_ANALOG_INJECTED_CODE = NULL; uint8_t* ff13_2_continuous_scan_instruction_address; uint8_t* ff13_2_set_frame_rate_address; + uint8_t* ff13_2_pressed_buttons_instruction_jump_injected_address = NULL; + uint8_t* ff13_2_right_analog_instruction_jump_injected_address = NULL; + uint8_t* ff13_2_left_analog_instruction_jump_injected_address = NULL; float** ff13_2_frame_pacer_ptr_address; float ff13_2_targetFrameRate; uint8_t** ff13_2_base_controller_input_address_ptr = NULL; - uint8_t* ff13_2_vibration_high_set_zero_address = NULL; - uint8_t* ff13_2_vibration_low_set_zero_address = NULL; uint8_t* ff13_2_message_box_stack_push_address = NULL; uint8_t* ff13_2_message_box_call_address = NULL; uint32_t* ff13_2_internal_res_w; @@ -139,6 +144,10 @@ class MainContext -1.00f, -1.00f, 0.0f, 0.0f, 1.0f }; + + uint32_t ff13ButtonsPressed = 0; + float ff13AnalogValues[8] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; + const float FF13_2_30_FPS = 30.0F; const float FF13_2_MAX_FRAME_CAP = 1000.0F; @@ -157,7 +166,6 @@ class MainContext void PrintVersionInfo(); void FF13_InitializeGameAddresses(); - void FF13_OneTimeFixes(); void FF13_PatchMessageBox(); void FF13_EnableControllerVibration(); @@ -166,14 +174,24 @@ class MainContext void FF13_FixScissorRect(); void FF13_RemoveContinuousControllerScan(); void FF13_HandleLargeAddressAwarePatch(); + void FF13_DisableInternalGamepadInput(); void FF13_2_CreateSetFrameRateCodeBlock(); void FF13_2_InitializeGameAddresses(); void FF13_2_RemoveContinuousControllerScan(); void FF13_2_AddHookIngameFrameRateLimitSetter(); + void FF13_2_CreateSetPressedButtonsCodeBlock(); + void FF13_2_CreateSetRightAnalogCodeBlock(); + void FF13_2_CreateSetLeftAnalogCodeBlock(); + void FF13_2_AddHookPressedButtons(); + void FF13_2_AddSetLeftAnalogHook(); + void FF13_2_AddSetRightAnalogHook(); + void AddJumpHook(uint8_t* addrToAddJump, const uint8_t* codeBlockAddr, const int& numberOfNops); void FF13_2_OneTimeFixes(); void FF13_2_PatchMessageBox(); - void FF13_2_EnableControllerVibration(); + void FF13_2_EnableXInputImplementation(); + + void CheckAndEnableXInputImplementation(uint8_t** inputAddress); void AdjustVertexData(const uint32_t width, const uint32_t height); bool MatchesExpectedVertexStream(const float* pVertexStreamZeroData); diff --git a/d3d9ex/IDirect3DSwapChain9Hook.cpp b/d3d9ex/IDirect3DSwapChain9Hook.cpp new file mode 100644 index 0000000..f428fe1 --- /dev/null +++ b/d3d9ex/IDirect3DSwapChain9Hook.cpp @@ -0,0 +1,46 @@ +#define CINTERFACE +#include + +#include "spdlog/spdlog.h" +#include "MinHook.h" +#include "XInputManager.h" + +namespace cinterface +{ + static XInputManager* pXInputManager; + static uint32_t* pff13ButtonPressed; + static float* pff13AnalogValues; + + HRESULT(STDMETHODCALLTYPE* TruePresent)(IDirect3DSwapChain9* This, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags) = nullptr; + + HRESULT STDMETHODCALLTYPE HookPresent(IDirect3DSwapChain9* This, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags) + { + HRESULT result = TruePresent(This, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags); + if (pXInputManager != NULL) { + pXInputManager->ReadValues(pff13ButtonPressed, pff13AnalogValues); + pXInputManager->SendVibrationToController(); + } + return result; + } + + void InitHookPresent(IDirect3DSwapChain9* pDirect3DSwapChain9) + { + if (pDirect3DSwapChain9->lpVtbl->Present && TruePresent == nullptr) + { + spdlog::info("Enabling PresentHook!"); + const MH_STATUS createHookPresent = MH_CreateHook(pDirect3DSwapChain9->lpVtbl->Present, HookPresent, reinterpret_cast(&TruePresent)); + spdlog::info("CreateHookPresent= {}", createHookPresent); + const MH_STATUS enableHookPresent = MH_EnableHook(pDirect3DSwapChain9->lpVtbl->Present); + spdlog::info("EnableHookPresent = {}", enableHookPresent); + + } + } + + void ShareValuesWithSwapChainHook(XInputManager* xInputManager, uint32_t* ff13ButtonPressed, float* ff13AnalogValues) { + pXInputManager = xInputManager; + pff13ButtonPressed = ff13ButtonPressed; + pff13AnalogValues = ff13AnalogValues; + } +} + + diff --git a/d3d9ex/Settings.h b/d3d9ex/Settings.h index eb8463e..af5573c 100644 --- a/d3d9ex/Settings.h +++ b/d3d9ex/Settings.h @@ -60,16 +60,19 @@ SETTING(bool, BoolValue, DisableIngameControllerHotSwapping, FFXIII, true, L"# DisableIngameControllerHotSwapping\n" L"#\n" L"# By default FF13Fix disables the game's continuous controller scanning that causes stuttering (especially if you do not have any controller connected)\n" - L"# If you with you can enable it again (by setting the config to 'false', so you can re-connect your controller while playing.\n" - L"# Note that EnableControllerVibration is incompatible with the controller hotswapping, \n" - L"# so it is automatically disabled if DisableIngameControllerHotSwapping is set to 'false'" + L"# Note that if you are using the FF13Fix XInput implementation, this setting is forced 'true', as hotswapping will work anyway even if the internal game scanning logic is disabled (FF13Fix will use its on hotswapping logic)" ); -SETTING(bool, BoolValue, EnableControllerVibration, FFXIII, true, +SETTING(bool, BoolValue, Enable, FFXIII_XInput, true, + L"# Replace the internal game controller input logic by FF13Fix XInput implementation\n" + L"#\n" + L"# Controller hotswapping/vibration works without impacting game performance." +); +SETTING(bool, BoolValue, EnableControllerVibration, FFXIII_XInput, true, L"# EnableControllerVibration\n" L"#\n" - L"# Enables controller vibration on the first connected XInput device." + L"# Enables controller vibration." ); -SETTING(bool, DoubleValue, VibrationStrengthFactor, FFXIII, 2.0, +SETTING(bool, DoubleValue, VibrationStrengthFactor, FFXIII_XInput, 1.0, L"# VibrationStrengthFactor\n" L"#\n" L"# Higher numbers = stronger vibration" diff --git a/d3d9ex/XInputManager.cpp b/d3d9ex/XInputManager.cpp index 338c166..18d9fbf 100644 --- a/d3d9ex/XInputManager.cpp +++ b/d3d9ex/XInputManager.cpp @@ -1,71 +1,202 @@ #include "stdafx.h" #include "XInputManager.h" -#include XInputManager::XInputManager(uint8_t** base_controller_input_address_ptr, const float vibrationStrengthFactor) { this->vibrationStrengthFactor = vibrationStrengthFactor; xinputThread = std::thread(&XInputManager::Run, this, base_controller_input_address_ptr); + spdlog::debug("base_controller_input_address_ptr = {}", (void*)base_controller_input_address_ptr); } void XInputManager::Run(uint8_t** base_controller_input_address_ptr) { - bool hasConnected = false; - for (DWORD i = 0; i < XUSER_MAX_COUNT; i++) { - XINPUT_STATE state; - ZeroMemory(&state, sizeof(XINPUT_STATE)); - - const DWORD controllerState = XInputGetState(i, &state); - if (controllerState == ERROR_SUCCESS) { - controllerId = i; - hasConnected = true; - break; + WaitAndSetVibrationAddress(base_controller_input_address_ptr); + ScanForConnectedController(); +} + +void XInputManager::ScanForConnectedController() +{ + spdlog::info("Scanning for connected controllers..."); + + while(true){ + for (uint32_t i = 0; i < XUSER_MAX_COUNT; i++) { + XINPUT_STATE state; + ZeroMemory(&state, sizeof(XINPUT_STATE)); + + const int32_t controllerState = XInputGetState(i, &state); + if (controllerState == ERROR_SUCCESS) { + spdlog::info("Connected controller {}", i); + controllerIdShared.store(i, std::memory_order_release); + controllerIdShared.wait(i, std::memory_order_acquire); + spdlog::info("Controller {} disconnected. Resuming scanning...", i); + break; + } } - } - if (hasConnected) { - WaitAndSetVibrationAddress(base_controller_input_address_ptr); - VibrationLoop(); + std::this_thread::sleep_for(std::chrono::seconds(2)); } } void XInputManager::WaitAndSetVibrationAddress(uint8_t** base_controller_input_address_ptr) { do { - std::this_thread::sleep_for(std::chrono::milliseconds(4)); + std::this_thread::sleep_for(std::chrono::milliseconds(8)); 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; + vibration_address_high_frequency = (float*)(*base_controller_input_address_ptr + 0x40 + 0x5C); + vibration_address_low_frequency = (float*)(*base_controller_input_address_ptr + 0x40 + 0x60); } } while (vibration_address_low_frequency == NULL); } -void XInputManager::VibrationLoop() +void XInputManager::SendVibrationToController() { - 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 > 0.01f || vibrationStrengthHighFrequency > 0.01f) { - const WORD leftMotorVibration = (WORD) (std::min(vibrationStrengthFactor * vibrationStrengthLowFrequency, 1.0f) * maxVibrationStrength); - const WORD rightMotorVibration = (WORD) (std::min(vibrationStrengthFactor * vibrationStrengthHighFrequency, 1.0f) * maxVibrationStrength); - SetControllerVibration(leftMotorVibration, rightMotorVibration); - wasVibrating = true; - } - else if (wasVibrating) { - SetControllerVibration(0, 0); - wasVibrating = false; - } - std::this_thread::sleep_for(std::chrono::milliseconds(4)); + if (vibration_address_low_frequency == NULL || vibrationStrengthFactor < 0.0001f || controllerIdMainThread < 0) { + return; } + const WORD maxVibrationStrength = 65535; + const float vibrationStrengthLowFrequency = *vibration_address_low_frequency; + const float vibrationStrengthHighFrequency = *vibration_address_high_frequency; + const WORD leftMotorVibration = (WORD)(std::min(vibrationStrengthFactor * vibrationStrengthLowFrequency, 1.0f) * maxVibrationStrength); + const WORD rightMotorVibration = (WORD)(std::min(vibrationStrengthFactor * vibrationStrengthHighFrequency, 1.0f) * maxVibrationStrength); + SetControllerVibration(leftMotorVibration, rightMotorVibration); } 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); + int32_t controllerToVibrate = controllerIdMainThread; + + if (controllerToVibrate >= 0) { + XINPUT_VIBRATION vibration; + ZeroMemory(&vibration, sizeof(XINPUT_VIBRATION)); + vibration.wLeftMotorSpeed = leftMotorVibration; + vibration.wRightMotorSpeed = rightMotorVibration; + XInputSetState(controllerIdMainThread, &vibration); + } +} + + +void XInputManager::ReadValues(uint32_t* buttonBuffer, float* ff13AnalogValues) { + if (controllerIdMainThread == -1) { + controllerIdMainThread = controllerIdShared.load(std::memory_order_acquire); + } + if (controllerIdMainThread == -1) { + return; + } + XINPUT_STATE xInputState; + ZeroMemory(&xInputState, sizeof(XINPUT_STATE)); + DWORD getStateStatus = XInputGetState(controllerIdMainThread, &xInputState); + if (getStateStatus == ERROR_SUCCESS) { + uint16_t analogValueLXIfAboveDeadZone = ZeroAnalogIfBelowDeadZone(xInputState.Gamepad.sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); + uint16_t analogValueLYIfAboveDeadZone = ZeroAnalogIfBelowDeadZone(xInputState.Gamepad.sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); + + uint16_t analogValueRXIfAboveDeadZone = ZeroAnalogIfBelowDeadZone(xInputState.Gamepad.sThumbRX, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); + uint16_t analogValueRYIfAboveDeadZone = ZeroAnalogIfBelowDeadZone(xInputState.Gamepad.sThumbRY, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); + + float leftAnalogX = NormalizeXinputAnalogStick(analogValueLXIfAboveDeadZone); + float leftAnalogY = NormalizeXinputAnalogStick(analogValueLYIfAboveDeadZone); + + float rightAnalogX = NormalizeXinputAnalogStick(analogValueRXIfAboveDeadZone); + float rightAnalogY = NormalizeXinputAnalogStick(analogValueRYIfAboveDeadZone); + + uint32_t buttonMask = GetFF13ButtonMask(&xInputState); + + *buttonBuffer = buttonMask; + // ff13AnalogValues contains the analog stick values. the game accesses the positions 2, 3, 6 and 7 too, but they always seem 0 and unused... + ff13AnalogValues[0] = leftAnalogX; + ff13AnalogValues[1] = leftAnalogY; + + ff13AnalogValues[4] = rightAnalogX; + ff13AnalogValues[5] = rightAnalogY; + } + else if (getStateStatus == ERROR_DEVICE_NOT_CONNECTED) { + *buttonBuffer = 0; + ff13AnalogValues[0] = 0.0f; + ff13AnalogValues[1] = 0.0f; + ff13AnalogValues[4] = 0.0f; + ff13AnalogValues[5] = 0.0f; + controllerIdMainThread = -1; + controllerIdShared.store(-1, std::memory_order_release); + controllerIdShared.notify_all(); + } } + +uint32_t XInputManager::GetFF13ButtonMask(const XINPUT_STATE* xInputState) +{ + uint32_t ff13ButtonMask = 0; + + WORD pressedButtons = xInputState->Gamepad.wButtons; + + if (pressedButtons & XINPUT_GAMEPAD_DPAD_UP) { + ff13ButtonMask |= FF13_GAMEPAD_DPAD_UP; + } + if (pressedButtons & XINPUT_GAMEPAD_DPAD_DOWN) { + ff13ButtonMask |= FF13_GAMEPAD_DPAD_DOWN; + } + if (pressedButtons & XINPUT_GAMEPAD_DPAD_LEFT) { + ff13ButtonMask |= FF13_GAMEPAD_DPAD_LEFT; + } + if (pressedButtons & XINPUT_GAMEPAD_DPAD_RIGHT) { + ff13ButtonMask |= FF13_GAMEPAD_DPAD_RIGHT; + } + + if (pressedButtons & XINPUT_GAMEPAD_Y) { + ff13ButtonMask |= FF13_GAMEPAD_TRIANGLE; + } + if (pressedButtons & XINPUT_GAMEPAD_A) { + ff13ButtonMask |= FF13_GAMEPAD_CROSS; + } + if (pressedButtons & XINPUT_GAMEPAD_X) { + ff13ButtonMask |= FF13_GAMEPAD_SQUARE; + } + if (pressedButtons & XINPUT_GAMEPAD_B) { + ff13ButtonMask |= FF13_GAMEPAD_CIRCLE; + } + + if (pressedButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) { + ff13ButtonMask |= FF13_GAMEPAD_L1; + } + if (xInputState->Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) { + ff13ButtonMask |= FF13_GAMEPAD_L2; + } + if (pressedButtons & XINPUT_GAMEPAD_LEFT_THUMB) { + ff13ButtonMask |= FF13_GAMEPAD_L3; + } + + + if (pressedButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) { + ff13ButtonMask |= FF13_GAMEPAD_R1; + } + if (xInputState->Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) { + ff13ButtonMask |= FF13_GAMEPAD_R2; + } + if (pressedButtons & XINPUT_GAMEPAD_RIGHT_THUMB) { + ff13ButtonMask |= FF13_GAMEPAD_R3; + } + + if (pressedButtons & XINPUT_GAMEPAD_BACK) { + ff13ButtonMask |= FF13_GAMEPAD_SELECT; + } + if (pressedButtons & XINPUT_GAMEPAD_START) { + ff13ButtonMask |= FF13_GAMEPAD_START; + } + + return ff13ButtonMask; +} + +float XInputManager::NormalizeXinputAnalogStick(const int16_t value) { + return ((const int)value + 32768) / 32768.0f - 1.0f; +} + +void XInputManager::LogValues() +{ + if (vibration_address_low_frequency == NULL) { + return; + } + + const float vibrationStrengthLowFrequency = *vibration_address_low_frequency; + const float vibrationStrengthHighFrequency = *vibration_address_high_frequency; + spdlog::info("LF({}) = {} HF({}) = {}", (void*)vibration_address_low_frequency, vibrationStrengthLowFrequency, (void*)vibration_address_high_frequency, vibrationStrengthHighFrequency); +} + +int16_t XInputManager::ZeroAnalogIfBelowDeadZone(const int16_t analogValue, const int16_t deadZoneValue) { + return abs(analogValue) > deadZoneValue ? analogValue : 0; +} \ No newline at end of file diff --git a/d3d9ex/XInputManager.h b/d3d9ex/XInputManager.h index a7e1dca..9ee764d 100644 --- a/d3d9ex/XInputManager.h +++ b/d3d9ex/XInputManager.h @@ -1,16 +1,47 @@ #pragma once +#include + class XInputManager { + const uint16_t FF13_GAMEPAD_DPAD_UP = 0x0001; + const uint16_t FF13_GAMEPAD_DPAD_DOWN = 0x0002; + const uint16_t FF13_GAMEPAD_DPAD_LEFT = 0x0004; + const uint16_t FF13_GAMEPAD_DPAD_RIGHT = 0x0008; + const uint16_t FF13_GAMEPAD_TRIANGLE = 0x0010; + const uint16_t FF13_GAMEPAD_CROSS = 0x0020; + const uint16_t FF13_GAMEPAD_SQUARE = 0x0040; + const uint16_t FF13_GAMEPAD_CIRCLE = 0x0080; + const uint16_t FF13_GAMEPAD_L1 = 0x0100; + const uint16_t FF13_GAMEPAD_L2 = 0x0200; + const uint16_t FF13_GAMEPAD_L3 = 0x0400; + const uint16_t FF13_GAMEPAD_R1 = 0x0800; + const uint16_t FF13_GAMEPAD_R2 = 0x1000; + const uint16_t FF13_GAMEPAD_R3 = 0x2000; + const uint16_t FF13_GAMEPAD_SELECT = 0x4000; + const uint16_t FF13_GAMEPAD_START = 0x8000; + float* vibration_address_high_frequency = NULL; - float vibrationStrengthFactor; float* vibration_address_low_frequency = NULL; - DWORD controllerId = -1; + + float vibrationStrengthFactor; + + int32_t controllerIdMainThread = -1; + std::atomic controllerIdShared; std::thread xinputThread; + public: XInputManager(uint8_t** base_controller_input_address_ptr, const float vibrationStrengthFactor); + void ReadValues(uint32_t* buttonBuffer, float* ff13AnalogValues); + void SendVibrationToController(); + +private: void Run(uint8_t** base_controller_input_address_ptr); + int16_t ZeroAnalogIfBelowDeadZone(const int16_t analogValue, const int16_t deadZoneValue); + float NormalizeXinputAnalogStick(int16_t value); + uint32_t GetFF13ButtonMask(const XINPUT_STATE* xInputState); + void ScanForConnectedController(); void WaitAndSetVibrationAddress(uint8_t** base_controller_input_address_ptr); - void VibrationLoop(); void SetControllerVibration(const WORD& leftMotorVibration, const WORD& rightMotorVibration); + void LogValues(); }; diff --git a/d3d9ex/d3d9ex.vcxproj b/d3d9ex/d3d9ex.vcxproj index 09bf727..f3f8353 100644 --- a/d3d9ex/d3d9ex.vcxproj +++ b/d3d9ex/d3d9ex.vcxproj @@ -208,6 +208,10 @@ NotUsing NotUsing + + NotUsing + NotUsing + diff --git a/d3d9ex/d3d9ex.vcxproj.filters b/d3d9ex/d3d9ex.vcxproj.filters index 46f8d6f..bd184b3 100644 --- a/d3d9ex/d3d9ex.vcxproj.filters +++ b/d3d9ex/d3d9ex.vcxproj.filters @@ -68,6 +68,9 @@ Source Files + + Source Files +