From 09bb67220ebe2f62e2769cde938f544c2ed36075 Mon Sep 17 00:00:00 2001 From: Silent Date: Wed, 30 Oct 2024 18:28:53 +0100 Subject: [PATCH] SA: Fix incompatibilities with wshps.asi * Map Screen cursor fix is now split between the cursor thickness and the cursor positioning fix. The latter gets out of the way for the ws fix. * Text background padding not scaling to resolution now gives priority to the same fix in the widescreen fix. Fixes #33 --- SilentPatchSA/SilentPatchSA.cpp | 215 +++++++++++++++++++------------- 1 file changed, 131 insertions(+), 84 deletions(-) diff --git a/SilentPatchSA/SilentPatchSA.cpp b/SilentPatchSA/SilentPatchSA.cpp index 87cf3ff..3258ce1 100644 --- a/SilentPatchSA/SilentPatchSA.cpp +++ b/SilentPatchSA/SilentPatchSA.cpp @@ -3073,9 +3073,7 @@ namespace MapScreenScalingFixes ((CursorYSize_Recalculated = ScaleY(*orgCursorYSize)), ...); } - static void (*orgLimitToMap)(float* x, float* y); - - template + static void (*orgLimitToMap_Scale)(float* x, float* y); static void LimitToMap_Scale(float* x, float* y) { // LimitToMap assumes it's given scaled coordinates, but then the caller assumes it returns unscaled coordinates. @@ -3085,12 +3083,17 @@ namespace MapScreenScalingFixes *x *= XScale; *y *= YScale; - orgLimitToMap(x, y); + orgLimitToMap_Scale(x, y); *x /= XScale; *y /= YScale; + } - // This is also a comfortable spot to scale the cursor dimensions + static void (*orgLimitToMap_RecalculateSizes)(float* x, float* y); + template + static void LimitToMap_RecalculateSizes(float* x, float* y) + { + orgLimitToMap_RecalculateSizes(x, y); RecalculateXSize(std::make_index_sequence{}); RecalculateYSize(std::make_index_sequence{}); } @@ -4181,6 +4184,12 @@ BOOL InjectDelayedPatches_10() const bool bHasDebugMenu = DebugMenuLoad(); + auto PatchFloat = [](float** address, const float*& org, float& replaced) + { + org = *address; + Patch(address, &replaced); + }; + #ifdef _DEBUG if ( bHasDebugMenu ) { @@ -4643,6 +4652,62 @@ BOOL InjectDelayedPatches_10() } + // Fix Map screen boundaries and the cursor not scaling to resolution + // Debugged by Wesser + // Moved here for compatibility with wshps.asi + { + using namespace MapScreenScalingFixes; + + // Even though those two patch the same function, treating them as separate patches makes retaining compatibility + // with the widescreen fix easy. + std::array cursorXSizes = { (float**)(0x588251 + 2), (float**)(0x588265 + 2) }; + std::array cursorYSizes = { (float**)(0x5882A8 + 2), (float**)(0x5882C6 + 2) }; + + HookEach_CursorXSize(cursorXSizes, PatchFloat); + HookEach_CursorYSize(cursorYSizes, PatchFloat); + InterceptCall(0x58822D, orgLimitToMap_RecalculateSizes, LimitToMap_RecalculateSizes); + + // Only patch this function if wshps.asi hasn't changed the way it's being called + // The expected code: + // lea edx, [esp+70h+a1.y] + // push edx + // lea eax, [esp+74h+a1] + // push eax + if (MemEquals(0x588223, {0x8D, 0x54, 0x24, 0x4C, 0x52, 0x8D, 0x44, 0x24, 0x4C, 0x50 })) + { + InterceptCall(0x58822D, orgLimitToMap_Scale, LimitToMap_Scale); + } + } + + + // Fix text background padding not scaling to resolution + // Debugged by Wesser + // Moved here for compatibility with wshps.asi + { + using namespace TextRectPaddingScalingFixes; + + // Verify that all fadd and fsub instructions are intact + // Patterns would do it for us for free, but 1.0 does not use them... + const std::initializer_list fadd = { 0xD8, 0x05 }; + const std::initializer_list fsub = { 0xD8, 0x25 }; + if (MemEquals(0x71A653, fadd) && MemEquals(0x71A66B, fadd) && MemEquals(0x71A69D, fsub) && MemEquals(0x71A6AB, fadd) && + MemEquals(0x71A6BF, fsub) && MemEquals(0x71A6EC, fadd)) + { + std::array paddingXSizes = { + (float**)(0x71A653 + 2), (float**)(0x71A66B + 2), + (float**)(0x71A69D + 2), (float**)(0x71A6AB + 2), + }; + std::array paddingYSizes = { + (float**)(0x71A6BF + 2), (float**)(0x71A6EC + 2), + }; + + HookEach_PaddingXSize(paddingXSizes, PatchFloat); + HookEach_PaddingYSize(paddingYSizes, PatchFloat); + InterceptCall(0x71A631, orgProcessCurrentString, ProcessCurrentString_Scale); + } + } + + #ifndef NDEBUG if ( const int QPCDays = GetPrivateProfileIntW(L"Debug", L"AddDaysToQPC", 0, wcModulePath); QPCDays != 0 ) { @@ -5027,6 +5092,12 @@ BOOL InjectDelayedPatches_NewBinaries() const bool bHasDebugMenu = DebugMenuLoad(); + auto PatchDouble = [](double** address, const double*& org, double& replaced) + { + org = *address; + Patch(address, &replaced); + }; + // Race condition in CdStream fixed // Not taking effect with modloader //if ( !ModCompat::ModloaderCdStreamRaceConditionAware( modloaderModule ) ) @@ -5123,6 +5194,61 @@ BOOL InjectDelayedPatches_NewBinaries() TXN_CATCH(); + // Fix Map screen boundaries and the cursor not scaling to resolution + // Debugged by Wesser + // Moved here for compatibility with wshps.asi + { + using namespace MapScreenScalingFixes; + + // These two are entirely separate fixes + try + { + // Updated the pattern to also ensure this function's arguments are not changed by other mods + auto limitToMap = get_pattern("8D 45 F0 50 8B CA 51 E8 ? ? ? ? DB 05 ? ? ? ? 83 C4 1C", 7); + InterceptCall(limitToMap, orgLimitToMap_Scale, LimitToMap_Scale); + } + TXN_CATCH(); + + // Cursor X/Y scaling need to be done differently than in 1.0, as the game has one fld1 for width and one fld1 for height + try + { + auto scaleX = pattern("D9 E8 DC E9 D9 C9 D9 5D 94").get_one(); + auto scaleY = pattern("D9 E8 DC E9 D9 C9 D9 5D B0").get_one(); + + Nop(scaleX.get(), 1); + InjectHook(scaleX.get(1), ScaleX_NewBinaries, HookType::Call); + + Nop(scaleY.get(), 1); + InjectHook(scaleY.get(1), ScaleY_NewBinaries, HookType::Call); + } + TXN_CATCH(); + } + + + // Fix text background padding not scaling to resolution + // Debugged by Wesser + // Moved here for compatibility with wshps.asi + try + { + using namespace TextRectPaddingScalingFixes; + + auto processCurrentString = get_pattern("E8 ? ? ? ? DD 05 ? ? ? ? 8B 4D 08"); + + // In new binaries, 4.0f is shared for width and height. + // Make height determine the scale, so it works nicer in widescreen. + auto paddingSize = pattern("DD 05 ? ? ? ? DC E9 D9 C9 D9 19").count(2); + std::array paddingYSizes = { + get_pattern("D8 CA DD 05 ? ? ? ? DC C1", 2 + 2), + paddingSize.get(0).get(2), + paddingSize.get(1).get(2), + }; + + HookEach_PaddingYSize_Double(paddingYSizes, PatchDouble); + InterceptCall(processCurrentString, orgProcessCurrentString, ProcessCurrentString_Scale_NewBinaries); + } + TXN_CATCH(); + + return FALSE; } return TRUE; @@ -6270,39 +6396,6 @@ void Patch_SA_10(HINSTANCE hInstance) } - // Fix Map screen boundaries and the cursor not scaling to resolution - // Debugged by Wesser - { - using namespace MapScreenScalingFixes; - - std::array cursorXSizes = { (float**)(0x588251 + 2), (float**)(0x588265 + 2) }; - std::array cursorYSizes = { (float**)(0x5882A8 + 2), (float**)(0x5882C6 + 2) }; - - HookEach_CursorXSize(cursorXSizes, PatchFloat); - HookEach_CursorYSize(cursorYSizes, PatchFloat); - InterceptCall(0x58822D, orgLimitToMap, LimitToMap_Scale); - } - - - // Fix text background padding not scaling to resolution - // Debugged by Wesser - { - using namespace TextRectPaddingScalingFixes; - - std::array paddingXSizes = { - (float**)(0x71A653 + 2), (float**)(0x71A66B + 2), - (float**)(0x71A69D + 2), (float**)(0x71A6AB + 2), - }; - std::array paddingYSizes = { - (float**)(0x71A6BF + 2), (float**)(0x71A6EC + 2), - }; - - HookEach_PaddingXSize(paddingXSizes, PatchFloat); - HookEach_PaddingYSize(paddingYSizes, PatchFloat); - InterceptCall(0x71A631, orgProcessCurrentString, ProcessCurrentString_Scale); - } - - // Fix nitrous recharging faster when reversing the car // By Wesser { @@ -8482,52 +8575,6 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) TXN_CATCH(); - // Fix Map screen boundaries and the cursor not scaling to resolution - // Debugged by Wesser - try - { - using namespace MapScreenScalingFixes; - - auto limitToMap = get_pattern("E8 ? ? ? ? DB 05 ? ? ? ? 83 C4 1C"); - - // Cursor X/Y scaling need to be done differently than in 1.0, as the game has one fld1 for width and one fld1 for height - auto scaleX = pattern("D9 E8 DC E9 D9 C9 D9 5D 94").get_one(); - auto scaleY = pattern("D9 E8 DC E9 D9 C9 D9 5D B0").get_one(); - - InterceptCall(limitToMap, orgLimitToMap, LimitToMap_Scale<0, 0>); - - Nop(scaleX.get(), 1); - InjectHook(scaleX.get(1), ScaleX_NewBinaries, HookType::Call); - - Nop(scaleY.get(), 1); - InjectHook(scaleY.get(1), ScaleY_NewBinaries, HookType::Call); - } - TXN_CATCH(); - - - // Fix text background padding not scaling to resolution - // Debugged by Wesser - try - { - using namespace TextRectPaddingScalingFixes; - - auto processCurrentString = get_pattern("E8 ? ? ? ? DD 05 ? ? ? ? 8B 4D 08"); - - // In new binaries, 4.0f is shared for width and height. - // Make height determine the scale, so it works nicer in widescreen. - auto paddingSize = pattern("DD 05 ? ? ? ? DC E9 D9 C9 D9 19").count(2); - std::array paddingYSizes = { - get_pattern("D8 CA DD 05 ? ? ? ? DC C1", 2 + 2), - paddingSize.get(0).get(2), - paddingSize.get(1).get(2), - }; - - HookEach_PaddingYSize_Double(paddingYSizes, PatchDouble); - InterceptCall(processCurrentString, orgProcessCurrentString, ProcessCurrentString_Scale_NewBinaries); - } - TXN_CATCH(); - - // Fix nitrous recharging faster when reversing the car // By Wesser try