From b31b7c0f40c18d7d091b836bc4ccdd8dd0acc1d6 Mon Sep 17 00:00:00 2001 From: The Cheaterman Date: Fri, 1 May 2026 15:41:03 +0200 Subject: [PATCH 1/2] Fix XTensionFOVFix for non-Steam version - TODO: test on Steam --- source/fixes/XTensionFOVFix/dllmain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/fixes/XTensionFOVFix/dllmain.cpp b/source/fixes/XTensionFOVFix/dllmain.cpp index 41a867f8..a9e025d8 100644 --- a/source/fixes/XTensionFOVFix/dllmain.cpp +++ b/source/fixes/XTensionFOVFix/dllmain.cpp @@ -209,7 +209,7 @@ void FOVFix() fAspectRatioScale = fNewAspectRatio / fOldAspectRatio; - std::uint8_t* CameraFOVInstructionScanResult = Memory::PatternScan(exeModule, "DB 05 ?? ?? ?? ?? DC 0D ?? ?? ?? ?? D9 C9"); + std::uint8_t* CameraFOVInstructionScanResult = Memory::PatternScan(exeModule, "DB 05 ?? ?? ?? ?? DC 0D"); if (CameraFOVInstructionScanResult) { spdlog::info("Camera FOV Instruction: Address is {:s}+{:x}", sExeName.c_str(), CameraFOVInstructionScanResult - (std::uint8_t*)exeModule); From cac3e6b1579c6fc08a13f634a8c61a917542bc84 Mon Sep 17 00:00:00 2001 From: The Cheaterman Date: Sat, 2 May 2026 16:32:21 +0200 Subject: [PATCH 2/2] Fix FOV when/after boosting in X-BTF and X-Tension --- .../XBeyondTheFrontierFOVFix/dllmain.cpp | 71 ++++++++++++++++++- source/fixes/XTensionFOVFix/dllmain.cpp | 71 ++++++++++++++++++- 2 files changed, 136 insertions(+), 6 deletions(-) diff --git a/source/fixes/XBeyondTheFrontierFOVFix/dllmain.cpp b/source/fixes/XBeyondTheFrontierFOVFix/dllmain.cpp index b79d2b38..47c5510c 100644 --- a/source/fixes/XBeyondTheFrontierFOVFix/dllmain.cpp +++ b/source/fixes/XBeyondTheFrontierFOVFix/dllmain.cpp @@ -189,6 +189,8 @@ bool DetectGame() } static SafetyHookMid CameraFOVInstructionHook{}; +static SafetyHookMid ProjectionMatrixPreHook{}; +static SafetyHookMid ProjectionMatrixPostHook{}; int32_t ConvertFOV(int32_t baseFOV, double baseAR, double newAR) { @@ -210,7 +212,11 @@ void FOVFix() fAspectRatioScale = fNewAspectRatio / fOldAspectRatio; std::uint8_t* CameraFOVInstructionScanResult = Memory::PatternScan(exeModule, "DB 05 ?? ?? ?? ?? DC 0D"); - if (CameraFOVInstructionScanResult) + if (!CameraFOVInstructionScanResult) + { + spdlog::error("Failed to locate camera FOV instruction memory address."); + } + else { spdlog::info("Camera FOV Instruction: Address is {:s}+{:x}", sExeName.c_str(), CameraFOVInstructionScanResult - (std::uint8_t*)exeModule); @@ -227,10 +233,69 @@ void FOVFix() FPU::FILD(iNewFOV); }); } + + std::uint8_t* ProjectionSetTransformScanResult = Memory::PatternScan( + exeModule, + "8B 51 64 56 6A 03 50 FF D2" + ); + + if (!ProjectionSetTransformScanResult) + { + spdlog::error("Failed to locate projection matrix SetTransform call."); + } else { - spdlog::error("Failed to locate camera FOV instruction memory address."); - return; + std::uint8_t* ProjectionSetTransformPreHookAddress = + ProjectionSetTransformScanResult + 3; + + std::uint8_t* ProjectionSetTransformPostHookAddress = + ProjectionSetTransformScanResult + 9; + + spdlog::info( + "Projection matrix SetTransform call: Address is {:s}+{:x}", + sExeName.c_str(), + ProjectionSetTransformPreHookAddress - reinterpret_cast(exeModule) + ); + + static float fOriginalProjectionM00 = 0.0f; + static float fOriginalProjectionM11 = 0.0f; + static float* pCurrentProjectionMatrix = nullptr; + + ProjectionMatrixPreHook = safetyhook::create_mid( + ProjectionSetTransformPreHookAddress, + [](SafetyHookContext& ctx) + { + pCurrentProjectionMatrix = reinterpret_cast(ctx.esi); + + if (pCurrentProjectionMatrix == nullptr) + { + return; + } + + fOriginalProjectionM00 = pCurrentProjectionMatrix[0]; + fOriginalProjectionM11 = pCurrentProjectionMatrix[5]; + + const float projectionScale = 1.0f / fAspectRatioScale; + + pCurrentProjectionMatrix[0] *= projectionScale; + pCurrentProjectionMatrix[5] *= projectionScale; + } + ); + + ProjectionMatrixPostHook = safetyhook::create_mid( + ProjectionSetTransformPostHookAddress, + [](SafetyHookContext& ctx) + { + if (pCurrentProjectionMatrix == nullptr) + { + return; + } + + pCurrentProjectionMatrix[0] = fOriginalProjectionM00; + pCurrentProjectionMatrix[5] = fOriginalProjectionM11; + pCurrentProjectionMatrix = nullptr; + } + ); } } } diff --git a/source/fixes/XTensionFOVFix/dllmain.cpp b/source/fixes/XTensionFOVFix/dllmain.cpp index a9e025d8..5e8e56ca 100644 --- a/source/fixes/XTensionFOVFix/dllmain.cpp +++ b/source/fixes/XTensionFOVFix/dllmain.cpp @@ -189,6 +189,8 @@ bool DetectGame() } static SafetyHookMid CameraFOVInstructionHook{}; +static SafetyHookMid ProjectionMatrixPreHook{}; +static SafetyHookMid ProjectionMatrixPostHook{}; int32_t ConvertFOV(int32_t baseFOV, double baseAR, double newAR) { @@ -210,7 +212,11 @@ void FOVFix() fAspectRatioScale = fNewAspectRatio / fOldAspectRatio; std::uint8_t* CameraFOVInstructionScanResult = Memory::PatternScan(exeModule, "DB 05 ?? ?? ?? ?? DC 0D"); - if (CameraFOVInstructionScanResult) + if (!CameraFOVInstructionScanResult) + { + spdlog::error("Failed to locate camera FOV instruction memory address."); + } + else { spdlog::info("Camera FOV Instruction: Address is {:s}+{:x}", sExeName.c_str(), CameraFOVInstructionScanResult - (std::uint8_t*)exeModule); @@ -227,10 +233,69 @@ void FOVFix() FPU::FILD(iNewFOV); }); } + + std::uint8_t* ProjectionSetTransformScanResult = Memory::PatternScan( + exeModule, + "8B 51 64 56 6A 03 50 FF D2" + ); + + if (!ProjectionSetTransformScanResult) + { + spdlog::error("Failed to locate projection matrix SetTransform call."); + } else { - spdlog::error("Failed to locate camera FOV instruction memory address."); - return; + std::uint8_t* ProjectionSetTransformPreHookAddress = + ProjectionSetTransformScanResult + 3; + + std::uint8_t* ProjectionSetTransformPostHookAddress = + ProjectionSetTransformScanResult + 9; + + spdlog::info( + "Projection matrix SetTransform call: Address is {:s}+{:x}", + sExeName.c_str(), + ProjectionSetTransformPreHookAddress - reinterpret_cast(exeModule) + ); + + static float fOriginalProjectionM00 = 0.0f; + static float fOriginalProjectionM11 = 0.0f; + static float* pCurrentProjectionMatrix = nullptr; + + ProjectionMatrixPreHook = safetyhook::create_mid( + ProjectionSetTransformPreHookAddress, + [](SafetyHookContext& ctx) + { + pCurrentProjectionMatrix = reinterpret_cast(ctx.esi); + + if (pCurrentProjectionMatrix == nullptr) + { + return; + } + + fOriginalProjectionM00 = pCurrentProjectionMatrix[0]; + fOriginalProjectionM11 = pCurrentProjectionMatrix[5]; + + const float projectionScale = 1.0f / fAspectRatioScale; + + pCurrentProjectionMatrix[0] *= projectionScale; + pCurrentProjectionMatrix[5] *= projectionScale; + } + ); + + ProjectionMatrixPostHook = safetyhook::create_mid( + ProjectionSetTransformPostHookAddress, + [](SafetyHookContext& ctx) + { + if (pCurrentProjectionMatrix == nullptr) + { + return; + } + + pCurrentProjectionMatrix[0] = fOriginalProjectionM00; + pCurrentProjectionMatrix[5] = fOriginalProjectionM11; + pCurrentProjectionMatrix = nullptr; + } + ); } } }