diff --git a/DDraw/DDraw.vcxproj b/DDraw/DDraw.vcxproj index 8acacba..9b253a6 100644 --- a/DDraw/DDraw.vcxproj +++ b/DDraw/DDraw.vcxproj @@ -75,7 +75,6 @@ true ..\SilentPatch;..\DDraw;%(AdditionalIncludeDirectories) _HAS_EXCEPTIONS=0;%(PreprocessorDefinitions) - false MultiThreadedDebug NoExtensions true @@ -107,7 +106,6 @@ copy /y "$(TargetPath)" "D:\Steam\steamapps\common\Grand Theft Auto Vice City\dd ..\SilentPatch;..\DDraw;%(AdditionalIncludeDirectories) _HAS_EXCEPTIONS=0;%(PreprocessorDefinitions) true - false MultiThreaded NoExtensions true @@ -141,7 +139,6 @@ copy /y "$(TargetPath)" "D:\Steam\steamapps\common\Grand Theft Auto Vice City\dd ..\SilentPatch;..\DDraw;%(AdditionalIncludeDirectories) _HAS_EXCEPTIONS=0;NDEBUG;%(PreprocessorDefinitions) true - false MultiThreaded NoExtensions true diff --git a/SilentPatch/Common.cpp b/SilentPatch/Common.cpp index f1741ee..0dc0307 100644 --- a/SilentPatch/Common.cpp +++ b/SilentPatch/Common.cpp @@ -208,30 +208,38 @@ namespace Common { void III_VC_Common() { using namespace Memory; - using namespace hook; + using namespace hook::txn; // Delayed patching + try { using namespace DelayedPatches; auto addr_mssHook = get_pattern( "6A 00 6A 02 6A 10 68 00 7D 00 00", -6 + 2 ); + auto addr_ualHook = get_pattern( "FF 15 ? ? ? ? 6A 00 6A 18", 0xA ); + OldSetPreference = *static_cast(addr_mssHook); Patch( addr_mssHook, &pInjectMSS ); - auto addr_ualHook = get_pattern( "FF 15 ? ? ? ? 6A 00 6A 18", 0xA ); ReadCall( addr_ualHook, RsEventHandler ); InjectHook( addr_ualHook, Inject_UAL ); } + TXN_CATCH(); + // Fixed bomb ownership/bombs saving for bikes + try { auto addr = get_pattern( "83 3C 33 00 74 19 89 F9 E8", 8 ); ReadCall( addr, CStoredCar::orgRestoreCar ); InjectHook( addr, &CStoredCar::RestoreCar_SilentPatch ); } + TXN_CATCH(); + // Fixed handling.cfg name matching (names don't need unique prefixes anymore) + try { using namespace HandlingNameLoadFix; @@ -240,9 +248,11 @@ namespace Common { InjectHook( findExactWord.get( -5 ), strncpy_Fix ); InjectHook( findExactWord.get( 0xD ), strncmp_Fix ); } + TXN_CATCH(); // Fixed corona lines rendering on non-nvidia cards + try { using namespace CoronaLinesFix; @@ -250,9 +260,11 @@ namespace Common { InterceptCall(renderLine, orgRwIm2DRenderLine, RenderLine_SetRecipZ); } + TXN_CATCH(); // Fixed static shadows not rendering under fire and pickups + try { using namespace StaticShadowAlphaFix; @@ -281,9 +293,11 @@ namespace Common { HookEach_StoreAlphaTest(disableAlphaTestAndSetState, InterceptCall); HookEach_RestoreAlphaTest(setStateAndReenableAlphaTest, InterceptCall); } + TXN_CATCH(); // Reset requested extras if created vehicle has no extras + try { using namespace CompsToUseFix; @@ -291,10 +305,12 @@ namespace Common { InjectHook( resetComps.get( -14 ), ResetCompsForNoExtras, HookType::Call ); Nop( resetComps.get( -9 ), 9 ); } + TXN_CATCH(); // Rescale light switching randomness in CAutomobile::PreRender/CBike::PreRender for PC the randomness range // The original randomness was 50000 out of 65535, which is impossible to hit with PC's 32767 range + try { // GTA III expects 2 matches, VC expects 4 due to the addition of CBike::PreRender #if _GTA_III @@ -310,9 +326,11 @@ namespace Common { Patch(match.get(2), &LightStatusRandomnessThreshold); }); } + TXN_CATCH(); // Make script randomness 16-bit, like on PS2 + try { using namespace Rand16bit; @@ -323,6 +341,7 @@ namespace Common { HookEach_Rand(rands, InterceptCall); } + TXN_CATCH(); } void III_VC_SetDelayedPatchesFunc( void(*func)() ) @@ -333,24 +352,21 @@ namespace Common { void III_VC_DelayedCommon( bool /*hasDebugMenu*/, const wchar_t* wcModulePath ) { using namespace Memory; - using namespace hook; + using namespace hook::txn; ExtraCompSpecularity::ReadExtraCompSpecularityExceptions(wcModulePath); // Corrected taxi light placement for Taxi - if ( GetPrivateProfileIntW(L"SilentPatch", L"EnableVehicleCoronaFixes", -1, wcModulePath) == 1 ) + if ( GetPrivateProfileIntW(L"SilentPatch", L"EnableVehicleCoronaFixes", -1, wcModulePath) == 1 ) try { using namespace TaxiCoronaFix; - auto getTaxiLightPos = pattern( "E8 ? ? ? ? D9 84 24 ? ? ? ? D8 84 24 ? ? ? ? 83 C4 0C FF 35" ); + auto getTaxiLightPos = pattern( "E8 ? ? ? ? D9 84 24 ? ? ? ? D8 84 24 ? ? ? ? 83 C4 0C FF 35" ).get_one(); - if ( getTaxiLightPos.count_hint(1).size() == 1 ) - { - auto match = getTaxiLightPos.get_one(); - Patch( match.get( -15 ), 0x55 ); // push eax -> push ebp - InjectHook( match.get(), GetTransformedCoronaPos ); - } + Patch( getTaxiLightPos.get( -15 ), 0x55 ); // push eax -> push ebp + InjectHook( getTaxiLightPos.get(), GetTransformedCoronaPos ); } + TXN_CATCH(); } } } \ No newline at end of file diff --git a/SilentPatch/Common_ddraw.cpp b/SilentPatch/Common_ddraw.cpp index 652ab72..62e1240 100644 --- a/SilentPatch/Common_ddraw.cpp +++ b/SilentPatch/Common_ddraw.cpp @@ -39,25 +39,37 @@ namespace Common { namespace Patches { - bool FixRwcseg_Patterns() + bool FixRwcseg_Patterns() try { - using namespace hook; + using namespace hook::txn; - auto begin = pattern( "55 8B EC 50 53 51 52 8B 5D 14 8B 4D 10 8B 45 0C 8B 55 08" ); - auto end = pattern( "9B D9 3D ? ? ? ? 81 25 ? ? ? ? FF FC FF FF 83 0D ? ? ? ? 3F" ); + // _rwcseg can be placed far after the code section, and the default pattern heuristics currently break with it + // (it's only using SizeOfCode instead of scanning all code sections). + // To fix this, explicitly scan the entire module + const uintptr_t module = reinterpret_cast(GetModuleHandle(nullptr)); + PIMAGE_DOS_HEADER dosHeader = reinterpret_cast(module); + PIMAGE_NT_HEADERS ntHeader = reinterpret_cast(module + dosHeader->e_lfanew); - if ( begin.count_hint(1).size() == 1 && end.count_hint(1).size() == 1 ) + const uintptr_t sizeOfHeaders = ntHeader->OptionalHeader.SizeOfHeaders; + const uintptr_t moduleBegin = module + sizeOfHeaders; + const uintptr_t moduleEnd = module + (ntHeader->OptionalHeader.SizeOfImage - sizeOfHeaders); + + auto begin = make_range_pattern(moduleBegin, moduleEnd, "55 8B EC 50 53 51 52 8B 5D 14 8B 4D 10 8B 45 0C 8B 55 08").get_first(); + auto end = make_range_pattern(moduleBegin, moduleEnd, "9B D9 3D ? ? ? ? 81 25 ? ? ? ? FF FC FF FF 83 0D ? ? ? ? 3F").get_first(31); + + const ptrdiff_t size = reinterpret_cast(end) - reinterpret_cast(begin); + if ( size > 0 ) { - const ptrdiff_t size = (intptr_t)end.get_first( 24 ) - (intptr_t)begin.get_first(); - if ( size > 0 ) - { - DWORD dwProtect; - VirtualProtect( begin.get_first(), size, PAGE_EXECUTE_READ, &dwProtect ); - return true; - } + DWORD dwProtect; + VirtualProtect( begin, size, PAGE_EXECUTE_READ, &dwProtect ); + return true; } return false; } + catch (const hook::txn_exception&) + { + return false; + } // ================= III ================= void DDraw_III_10( uint32_t width, uint32_t height, const char* desktopText ) @@ -207,38 +219,34 @@ namespace Common { void DDraw_Common() { using namespace Memory; - using namespace hook; + using namespace hook::txn; // Remove FILE_FLAG_NO_BUFFERING from CdStreams + try { - auto mem = pattern( "81 7C 24 04 00 08 00 00" ).count_hint(1); - if ( mem.size() == 1 ) - { - Patch( mem.get_first( 0x12 ), 0xEB ); - } + auto mem = get_pattern("81 7C 24 04 00 08 00 00", 0x12); + Patch( mem, 0xEB ); } + TXN_CATCH(); // No censorships + try { - auto addr = pattern( "83 FB 07 74 0A 83 FD 07 74 05 83 FE 07 75 15" ).count_hint(1); - if ( addr.size() == 1 ) - { - Patch( addr.get_first(), { 0xEB, 0x5E } ); - } - + auto addr = get_pattern( "83 FB 07 74 0A 83 FD 07 74 05 83 FE 07 75 15" ); + Patch( addr, { 0xEB, 0x5E } ); } + TXN_CATCH(); // unnamed CdStream semaphore + try { - auto mem = pattern( "8D 04 85 00 00 00 00 50 6A 40 FF 15" ).count_hint(1); - if ( mem.size() == 1 ) - { - Patch( mem.get_first( 0x25 ), { 0x6A, 0x00 } ); // push 0 \ nop - Nop( mem.get_first( 0x25 + 2 ), 3 ); - } - + auto mem = pattern( "8D 04 85 00 00 00 00 50 6A 40 FF 15" ).get_one(); + + Patch( mem.get( 0x25 ), { 0x6A, 0x00 } ); // push 0 \ nop + Nop( mem.get( 0x25 + 2 ), 3 ); } + TXN_CATCH(); } } } \ No newline at end of file diff --git a/SilentPatchIII/SilentPatchIII.cpp b/SilentPatchIII/SilentPatchIII.cpp index 308be88..56fc348 100644 --- a/SilentPatchIII/SilentPatchIII.cpp +++ b/SilentPatchIII/SilentPatchIII.cpp @@ -842,7 +842,7 @@ namespace SitInBoat void InjectDelayedPatches_III_Common( bool bHasDebugMenu, const wchar_t* wcModulePath ) { using namespace Memory; - using namespace hook; + using namespace hook::txn; const ModuleList moduleList; @@ -876,135 +876,124 @@ void InjectDelayedPatches_III_Common( bool bHasDebugMenu, const wchar_t* wcModul } // Make crane be unable to lift Coach instead of Blista + try { // There is a possible incompatibility with limit adjusters, so patch it in a delayed hook point and gracefully handle failure - auto canPickBlista = pattern( "83 FA 66 74" ).count_hint(1); - if ( canPickBlista.size() == 1 ) - { - Patch( canPickBlista.get_first( 2 ), 127 ); // coach - } + auto canPickBlista = get_pattern("83 FA 66 74", 2); + Patch( canPickBlista, 127 ); // coach } + TXN_CATCH(); // Corrected siren corona placement for emergency vehicles if ( GetPrivateProfileIntW(L"SilentPatch", L"EnableVehicleCoronaFixes", -1, wcModulePath) == 1 ) { // Other mods might be touching it, so only patch specific vehicles if their code has not been touched at all + try { - auto firetruckX1 = pattern( "C7 84 24 9C 05 00 00 CD CC 8C 3F" ); - auto firetruckY1 = pattern( "C7 84 24 A4 05 00 00 9A 99 D9 3F" ); - auto firetruckZ1 = pattern( "C7 84 24 A8 05 00 00 00 00 00 40" ); + auto firetruckX1 = get_pattern("C7 84 24 9C 05 00 00 CD CC 8C 3F", 7); + auto firetruckY1 = get_pattern("C7 84 24 A4 05 00 00 9A 99 D9 3F", 7); + auto firetruckZ1 = get_pattern("C7 84 24 A8 05 00 00 00 00 00 40", 7); - auto firetruckX2 = pattern( "C7 84 24 A8 05 00 00 CD CC 8C BF" ); - auto firetruckY2 = pattern( "C7 84 24 B0 05 00 00 9A 99 D9 3F" ); - auto firetruckZ2 = pattern( "C7 84 24 B4 05 00 00 00 00 00 40" ); + auto firetruckX2 = get_pattern("C7 84 24 A8 05 00 00 CD CC 8C BF", 7); + auto firetruckY2 = get_pattern("C7 84 24 B0 05 00 00 9A 99 D9 3F", 7); + auto firetruckZ2 = get_pattern("C7 84 24 B4 05 00 00 00 00 00 40", 7); - if ( firetruckX1.count_hint(1).size() == 1 && firetruckY1.count_hint(1).size() == 1 && firetruckZ1.count_hint(1).size() == 1 && - firetruckX2.count_hint(1).size() == 1 && firetruckY2.count_hint(1).size() == 1 && firetruckZ2.count_hint(1).size() == 1 ) - { - constexpr CVector FIRETRUCK_SIREN_POS(0.95f, 3.2f, 1.4f); + constexpr CVector FIRETRUCK_SIREN_POS(0.95f, 3.2f, 1.4f); - Patch( firetruckX1.get_first( 7 ), FIRETRUCK_SIREN_POS.x ); - Patch( firetruckY1.get_first( 7 ), FIRETRUCK_SIREN_POS.y ); - Patch( firetruckZ1.get_first( 7 ), FIRETRUCK_SIREN_POS.z ); + Patch( firetruckX1, FIRETRUCK_SIREN_POS.x ); + Patch( firetruckY1, FIRETRUCK_SIREN_POS.y ); + Patch( firetruckZ1, FIRETRUCK_SIREN_POS.z ); - Patch( firetruckX2.get_first( 7 ), -FIRETRUCK_SIREN_POS.x ); - Patch( firetruckY2.get_first( 7 ), FIRETRUCK_SIREN_POS.y ); - Patch( firetruckZ2.get_first( 7 ), FIRETRUCK_SIREN_POS.z ); - } + Patch( firetruckX2, -FIRETRUCK_SIREN_POS.x ); + Patch( firetruckY2, FIRETRUCK_SIREN_POS.y ); + Patch( firetruckZ2, FIRETRUCK_SIREN_POS.z ); } + TXN_CATCH(); + + try { - auto ambulanceX1 = pattern( "C7 84 24 84 05 00 00 CD CC 8C 3F" ); - auto ambulanceY1 = pattern( "C7 84 24 8C 05 00 00 66 66 66 3F" ); - auto ambulanceZ1 = pattern( "C7 84 24 90 05 00 00 CD CC CC 3F" ); + auto ambulanceX1 = get_pattern("C7 84 24 84 05 00 00 CD CC 8C 3F", 7); + auto ambulanceY1 = get_pattern("C7 84 24 8C 05 00 00 66 66 66 3F", 7); + auto ambulanceZ1 = get_pattern("C7 84 24 90 05 00 00 CD CC CC 3F", 7); - auto ambulanceX2 = pattern( "C7 84 24 90 05 00 00 CD CC 8C BF" ); - auto ambulanceY2 = pattern( "C7 84 24 98 05 00 00 66 66 66 3F" ); - auto ambulanceZ2 = pattern( "C7 84 24 9C 05 00 00 CD CC CC 3F" ); + auto ambulanceX2 = get_pattern("C7 84 24 90 05 00 00 CD CC 8C BF", 7); + auto ambulanceY2 = get_pattern("C7 84 24 98 05 00 00 66 66 66 3F", 7); + auto ambulanceZ2 = get_pattern("C7 84 24 9C 05 00 00 CD CC CC 3F", 7); - if ( ambulanceX1.count_hint(1).size() == 1 && ambulanceY1.count_hint(1).size() == 1 && ambulanceZ1.count_hint(1).size() == 1 && - ambulanceX2.count_hint(1).size() == 1 && ambulanceY2.count_hint(1).size() == 1 && ambulanceZ2.count_hint(1).size() == 1 ) - { - constexpr CVector AMBULANCE_SIREN_POS(0.7f, 0.65f, 1.55f); + constexpr CVector AMBULANCE_SIREN_POS(0.7f, 0.65f, 1.55f); - Patch( ambulanceX1.get_first( 7 ), AMBULANCE_SIREN_POS.x ); - Patch( ambulanceY1.get_first( 7 ), AMBULANCE_SIREN_POS.y ); - Patch( ambulanceZ1.get_first( 7 ), AMBULANCE_SIREN_POS.z ); + Patch( ambulanceX1, AMBULANCE_SIREN_POS.x ); + Patch( ambulanceY1, AMBULANCE_SIREN_POS.y ); + Patch( ambulanceZ1, AMBULANCE_SIREN_POS.z ); - Patch( ambulanceX2.get_first( 7 ), -AMBULANCE_SIREN_POS.x ); - Patch( ambulanceY2.get_first( 7 ), AMBULANCE_SIREN_POS.y ); - Patch( ambulanceZ2.get_first( 7 ), AMBULANCE_SIREN_POS.z ); - } + Patch( ambulanceX2, -AMBULANCE_SIREN_POS.x ); + Patch( ambulanceY2, AMBULANCE_SIREN_POS.y ); + Patch( ambulanceZ2, AMBULANCE_SIREN_POS.z ); } + TXN_CATCH(); + + try { - auto enforcerX1 = pattern( "C7 84 24 6C 05 00 00 CD CC 8C 3F" ); - auto enforcerY1 = pattern( "C7 84 24 74 05 00 00 CD CC 4C 3F" ); - auto enforcerZ1 = pattern( "C7 84 24 78 05 00 00 9A 99 99 3F" ); + auto enforcerX1 = get_pattern("C7 84 24 6C 05 00 00 CD CC 8C 3F", 7); + auto enforcerY1 = get_pattern("C7 84 24 74 05 00 00 CD CC 4C 3F", 7); + auto enforcerZ1 = get_pattern("C7 84 24 78 05 00 00 9A 99 99 3F", 7); - auto enforcerX2 = pattern( "C7 84 24 78 05 00 00 CD CC 8C BF" ); - auto enforcerY2 = pattern( "C7 84 24 80 05 00 00 CD CC 4C 3F" ); - auto enforcerZ2 = pattern( "C7 84 24 84 05 00 00 9A 99 99 3F" ); + auto enforcerX2 = get_pattern("C7 84 24 78 05 00 00 CD CC 8C BF", 7); + auto enforcerY2 = get_pattern("C7 84 24 80 05 00 00 CD CC 4C 3F", 7); + auto enforcerZ2 = get_pattern("C7 84 24 84 05 00 00 9A 99 99 3F", 7); - if ( enforcerX1.count_hint(1).size() == 1 && enforcerY1.count_hint(1).size() == 1 && enforcerZ1.count_hint(1).size() == 1 && - enforcerX2.count_hint(1).size() == 1 && enforcerY2.count_hint(1).size() == 1 && enforcerZ2.count_hint(1).size() == 1 ) - { - constexpr CVector ENFORCER_SIREN_POS(0.6f, 1.05f, 1.4f); + constexpr CVector ENFORCER_SIREN_POS(0.6f, 1.05f, 1.4f); - Patch( enforcerX1.get_first( 7 ), ENFORCER_SIREN_POS.x ); - Patch( enforcerY1.get_first( 7 ), ENFORCER_SIREN_POS.y ); - Patch( enforcerZ1.get_first( 7 ), ENFORCER_SIREN_POS.z ); + Patch( enforcerX1, ENFORCER_SIREN_POS.x ); + Patch( enforcerY1, ENFORCER_SIREN_POS.y ); + Patch( enforcerZ1, ENFORCER_SIREN_POS.z ); - Patch( enforcerX2.get_first( 7 ), -ENFORCER_SIREN_POS.x ); - Patch( enforcerY2.get_first( 7 ), ENFORCER_SIREN_POS.y ); - Patch( enforcerZ2.get_first( 7 ), ENFORCER_SIREN_POS.z ); - } + Patch( enforcerX2, -ENFORCER_SIREN_POS.x ); + Patch( enforcerY2, ENFORCER_SIREN_POS.y ); + Patch( enforcerZ2, ENFORCER_SIREN_POS.z ); } + TXN_CATCH(); + + try { - auto chopper1 = pattern( "C7 44 24 44 00 00 E0 40 50 C7 44 24 4C 00 00 00 00" ); // Front light + auto chopper1 = pattern("C7 44 24 44 00 00 E0 40 50 C7 44 24 4C 00 00 00 00").get_one(); // Front light - if ( chopper1.count_hint(1).size() == 1 ) - { - constexpr CVector CHOPPER_SEARCH_LIGHT_POS(0.0f, 3.0f, -1.25f); + constexpr CVector CHOPPER_SEARCH_LIGHT_POS(0.0f, 3.0f, -1.25f); - auto match = chopper1.get_one(); - - Patch( match.get( 4 ), CHOPPER_SEARCH_LIGHT_POS.y ); - Patch( match.get( 9 + 4 ), CHOPPER_SEARCH_LIGHT_POS.z ); - } + Patch( chopper1.get( 4 ), CHOPPER_SEARCH_LIGHT_POS.y ); + Patch( chopper1.get( 9 + 4 ), CHOPPER_SEARCH_LIGHT_POS.z ); } + TXN_CATCH(); } // Corrected FBI Car secondary siren sound + try { using namespace SirenSwitchingFix; // Other mods might be touching it, so only patch specific vehicles if their code has not been touched at all - auto usesSirenSwitching = pattern( "E8 ? ? ? ? 84 C0 74 12 83 C4 08" ).count_hint(1); - if ( usesSirenSwitching.size() == 1 ) - { - auto match = usesSirenSwitching.get_one(); - ReadCall( match.get(), orgUsesSirenSwitching ); - InjectHook( match.get(), UsesSirenSwitching_FbiCar ); - } + auto usesSirenSwitching = pattern("E8 ? ? ? ? 84 C0 74 12 83 C4 08").get_one(); + + InterceptCall(usesSirenSwitching.get(), orgUsesSirenSwitching, UsesSirenSwitching_FbiCar); } + TXN_CATCH(); // Corrected CSimpleModelInfo::SetupBigBuilding minimum draw distance for big buildings without a matching model // Fixes cranes in Portland and bright windows in the city // By aap + try { - auto setupMinDist = pattern( "C7 43 44 00 00 C8 42" ).count_hint(1); - if ( setupMinDist.size() == 1 ) // In case of another mod or second instance of SP changing it - { - auto match = setupMinDist.get_one(); + auto setupMinDist = pattern("C7 43 44 00 00 C8 42").get_one(); - // mov ecx, ebx - // call CSimpleModelInfo::SetNearDistanceForLOD - Patch( match.get(), { 0x89, 0xD9 } ); - InjectHook( match.get( 2 ), &CSimpleModelInfo::SetNearDistanceForLOD_SilentPatch, HookType::Call ); - } + // mov ecx, ebx + // call CSimpleModelInfo::SetNearDistanceForLOD + Patch( setupMinDist.get(), { 0x89, 0xD9 } ); + InjectHook( setupMinDist.get( 2 ), &CSimpleModelInfo::SetNearDistanceForLOD_SilentPatch, HookType::Call ); } + TXN_CATCH(); FLAUtils::Init(moduleList); } @@ -1346,10 +1335,11 @@ void Patch_III_Steam(uint32_t width, uint32_t height) void Patch_III_Common() { using namespace Memory; - using namespace hook; + using namespace hook::txn; // New timers fix + try { auto hookPoint = pattern( "83 E4 F8 89 44 24 08 C7 44 24 0C 00 00 00 00 DF 6C 24 08" ).get_one(); auto jmpPoint = get_pattern( "DD D8 E9 37 FF FF FF DD D8" ); @@ -1357,8 +1347,11 @@ void Patch_III_Common() InjectHook( hookPoint.get( 0x21 ), CTimer::Update_SilentPatch, HookType::Call ); InjectHook( hookPoint.get( 0x21 + 5 ), jmpPoint, HookType::Jump ); } + TXN_CATCH(); + // Alt+F4 + try { auto addr = pattern( "59 59 31 C0 83 C4 48 5D 5F 5E 5B C2 10 00" ).count(2); auto dest = get_pattern( "53 55 56 FF 74 24 68 FF 15" ); @@ -1367,8 +1360,11 @@ void Patch_III_Common() InjectHook( match.get( 2 ), dest, HookType::Jump ); }); } + TXN_CATCH(); + // Proper panels damage + try { auto addr = pattern( "C6 43 09 03 C6 43 0A 03 C6 43 0B 03" ).get_one(); @@ -1376,8 +1372,11 @@ void Patch_III_Common() Patch( addr.get( 0x23 + 1 ), 6 ); Nop( addr.get( 0x3F ), 7 ); } + TXN_CATCH(); + // Proper metric-imperial conversion constants + try { static const float METERS_TO_MILES = 0.0006213711922f; static const float METERS_TO_FEET = 3.280839895f; @@ -1389,8 +1388,11 @@ void Patch_III_Common() Patch( addr.get(2).get( 2 ), &METERS_TO_FEET ); Patch( addr.get(3).get( 2 ), &METERS_TO_FEET ); } + TXN_CATCH(); + // Improved pathfinding in PickNextNodeAccordingStrategy - PickNextNodeToChaseCar with XYZ coords + try { auto addr = pattern( "E8 ? ? ? ? 50 8D 44 24 10 50 E8" ).get_one(); ReadCall( addr.get( 0x25 ), orgPickNextNodeToChaseCar ); @@ -1421,25 +1423,31 @@ void Patch_III_Common() // Uncomment this to get rid of "treadable hack" in CCarCtrl::PickNextNodeToChaseCar (to mirror VC behaviour) InjectHook( funcAddr + 0x2A, funcAddr + 0x182, HookType::Jump ); } + TXN_CATCH(); // No censorships + try { auto addr = get_pattern( "8B 15 ? ? ? ? C6 05 ? ? ? ? 00 89 D0" ); Patch( addr, { 0x83, 0xC4, 0x08, 0xC3 } ); // add esp, 8 \ retn } + TXN_CATCH(); // 014C cargen counter fix (by spaceeinstein) + try { auto do_processing = pattern( "0F B7 45 28 83 F8 FF 7D 04 66 FF 4D 28" ).get_one(); Patch( do_processing.get(1), 0xBF ); // movzx eax, word ptr [ebx+28h] -> movsx eax, word ptr [ebx+28h] Patch( do_processing.get(7), 0x74 ); // jge -> jz } + TXN_CATCH(); // Fixed ammo from SCM + try { using namespace ZeroAmmoFix; @@ -1449,9 +1457,11 @@ void Patch_III_Common() }; HookEach_GiveWeapon(give_weapon, InterceptCall); } + TXN_CATCH(); // Credits =) + try { auto renderCredits = pattern( "83 C4 14 8D 45 F4 50 FF 35 ? ? ? ? E8 ? ? ? ? 59 59 8D 45 F4 50 FF 35 ? ? ? ? E8 ? ? ? ? 59 59 E8" ).get_one(); @@ -1459,9 +1469,11 @@ void Patch_III_Common() ReadCall( renderCredits.get( -5 ), Credits::PrintCreditText_Hooked ); InjectHook( renderCredits.get( -5 ), Credits::PrintSPCredits ); } + TXN_CATCH(); // Decreased keyboard input latency + try { using namespace KeyboardInputFix; @@ -1477,20 +1489,20 @@ void Patch_III_Common() InjectHook( simButtonCheckers, ClearSimButtonPressCheckers ); InjectHook( updatePads.get( 10 ), jmpDest, HookType::Jump ); } + TXN_CATCH(); // Locale based metric/imperial system + try { using namespace Localization; void* updateCompareFlag = get_pattern( "89 E9 6A 00 E8 ? ? ? ? 30 C0 83 C4 70 5D 5E 5B C2 04 00", 4 ); + auto constructStatLine = pattern( "FF 24 9D ? ? ? ? 39 D0" ).get_one(); ReadCall( updateCompareFlag, orgUpdateCompareFlag_IsMetric ); InjectHook( updateCompareFlag, UpdateCompareFlag_IsMetric ); - // Stats - auto constructStatLine = pattern( "FF 24 9D ? ? ? ? 39 D0" ).get_one(); - // push eax // push edx // call IsMetric_LocaleBased @@ -1503,25 +1515,29 @@ void Patch_III_Common() Patch( constructStatLine.get( -0xF + 7 ), { 0x0F, 0xB6, 0xD8, 0x5A, 0x58 } ); Nop( constructStatLine.get( -0xF + 12 ), 3 ); } + TXN_CATCH(); // Add cDMAudio::IsAudioInitialised checks before constructing cAudioScriptObject, like in VC + try { using namespace AudioInitializedFix; auto processCommands300 = pattern( "E8 ? ? ? ? 85 C0 59 74 ? 89 C1 E8 ? ? ? ? D9 05" ).get_one(); + auto processCommands300_2 = pattern( "6A 14 E8 ? ? ? ? 89 C3 59 85 DB 74" ).get_one(); + auto bulletInfoUpdate_Switch = *get_pattern( "FF 24 85 ? ? ? ? 6A 14", 3 ); + auto playlayOneShotScriptObject = pattern( "6A 14 E8 ? ? ? ? 85 C0 59 74 ? 89 C1 E8 ? ? ? ? D9 03 D9 58 04" ).get_one(); + auto loadAllAudioScriptObjects = get_pattern( "FF B5 78 FF FF FF E8 ? ? ? ? 59 59 8B 45 C8", 6 ); + ReadCall( processCommands300.get( 0 ), operatorNew ); InjectHook( processCommands300.get( 0 ), operatorNew_InitializedCheck ); Patch( processCommands300.get( 8 + 1 ), 0x440B62 - 0x440B24 ); - auto processCommands300_2 = pattern( "6A 14 E8 ? ? ? ? 89 C3 59 85 DB 74" ).get_one(); InjectHook( processCommands300_2.get( 2 ), operatorNew_InitializedCheck ); Patch( processCommands300_2.get( 0xC + 1 ), 0x440BD7 - 0x440B8B ); // We need to patch switch cases 0, 3, 4 - auto bulletInfoUpdate_Switch = *get_pattern( "FF 24 85 ? ? ? ? 6A 14", 3 ); - const uintptr_t bulletInfoUpdate_0 = bulletInfoUpdate_Switch[0]; const uintptr_t bulletInfoUpdate_3 = bulletInfoUpdate_Switch[3]; const uintptr_t bulletInfoUpdate_4 = bulletInfoUpdate_Switch[4]; @@ -1535,32 +1551,31 @@ void Patch_III_Common() InjectHook( bulletInfoUpdate_4 + 2, operatorNew_InitializedCheck ); Patch( bulletInfoUpdate_4 + 0xA + 1, 0x558C19 - 0x558BE3 ); - auto playlayOneShotScriptObject = pattern( "6A 14 E8 ? ? ? ? 85 C0 59 74 ? 89 C1 E8 ? ? ? ? D9 03 D9 58 04" ).get_one(); InjectHook( playlayOneShotScriptObject.get( 2 ), operatorNew_InitializedCheck ); Patch( playlayOneShotScriptObject.get( 0xA + 1 ), 0x57C633 - 0x57C601 ); - auto loadAllAudioScriptObjects = get_pattern( "FF B5 78 FF FF FF E8 ? ? ? ? 59 59 8B 45 C8", 6 ); ReadCall( loadAllAudioScriptObjects, orgLoadAllAudioScriptObjects ); InjectHook( loadAllAudioScriptObjects, LoadAllAudioScriptObjects_InitializedCheck ); } + TXN_CATCH(); // Give chopper/escape a properly sized collision bounding box instead of using ped's + try { - auto initHelisPattern = pattern( "C6 40 2C 00 A1" ).count_hint(1); - if ( initHelisPattern.size() == 1 ) - { - static constexpr CColModel colModelChopper( CColSphere( 8.5f, CVector(0.0f, -1.75f, 0.73f), 0, 0 ), - CColBox( CVector(-2.18f, -8.52f, -0.67f), CVector(-2.18f, 4.58f, 2.125f), 0, 0 ) ); + auto initHelis = pattern( "C6 40 2C 00 A1" ).get_one(); - auto initHelis = initHelisPattern.get_one(); - Patch( initHelis.get( -7 + 3 ), &colModelChopper ); - Patch( initHelis.get( 9 + 3 ), &colModelChopper ); - } + static constexpr CColModel colModelChopper( CColSphere( 8.5f, CVector(0.0f, -1.75f, 0.73f), 0, 0 ), + CColBox( CVector(-2.18f, -8.52f, -0.67f), CVector(-2.18f, 4.58f, 2.125f), 0, 0 ) ); + + Patch( initHelis.get( -7 + 3 ), &colModelChopper ); + Patch( initHelis.get( 9 + 3 ), &colModelChopper ); } + TXN_CATCH(); // Fixed vehicles exploding twice if the driver leaves the car while it's exploding + try { using namespace RemoveDriverStatusFix; @@ -1581,35 +1596,43 @@ void Patch_III_Common() Nop(processCommands4, 3); Nop(pedSetOutCar, 3); } + TXN_CATCH(); // Fixed an inverted condition in CCarCtrl::PickNextNodeRandomly // leading to cars being unable to turn right from one way roads // By Nick007J + try { auto pickNodeRandomly = get_pattern("3B 44 24 24 74 09", 4); Patch(pickNodeRandomly, 0x75); } + TXN_CATCH(); // Apply bilinear filtering on the player skin + try { using namespace SkinTextureFilter; auto getSkinTexture = get_pattern("E8 ? ? ? ? 89 C3 59 55"); InterceptCall(getSkinTexture, orgRwTextureCreate, RwTextureCreate_SetLinearFilter); } + TXN_CATCH(); // Apply the environment mapping on extra components + try { auto setEnvironmentMap = get_pattern("C7 83 D8 01 00 00 00 00 00 00 E8", 10); InterceptCall(setEnvironmentMap, CVehicleModelInfo::orgSetEnvironmentMap, &CVehicleModelInfo::SetEnvironmentMap_ExtraComps); } + TXN_CATCH(); // Fix the evasive dive miscalculating the angle, resulting in peds diving towards the vehicle + try { using namespace EvasiveDiveFix; @@ -1618,9 +1641,11 @@ void Patch_III_Common() Nop(setEvasiveDive.get(), 1); InjectHook(setEvasiveDive.get(1), &CalculateAngle_Hook, HookType::Call); } + TXN_CATCH(); // Fix probabilities in CVehicle::InflictDamage incorrectly assuming a random range from 0 to 100.000 + try { auto probability_do_nothing = get_pattern("66 81 7E 5A ? ? 73 50", 4); auto probability_flee = get_pattern("0F B7 46 5A 3D ? ? ? ? 0F 8E", 4 + 1); @@ -1628,9 +1653,11 @@ void Patch_III_Common() Patch(probability_do_nothing, 35000u * 32767u / 100000u); Patch(probability_flee, 75000u * 32767u / 100000u); } + TXN_CATCH(); // Null terminate read lines in CPlane::LoadPath and CTrain::ReadAndInterpretTrackFile + try { using namespace NullTerminatedLines; @@ -1648,25 +1675,26 @@ void Patch_III_Common() Nop(readTrackFile2.get(), 2); InjectHook(readTrackFile2.get(2), ReadTrackFile_Terminate, HookType::Call); } + TXN_CATCH(); // Backport 1.1 Stats menu font fix to 1.0 + try { using namespace StatsMenuFont; // This pattern fails by design on 1.1/Steam - auto constructStatLine = pattern("E8 ? ? ? ? D9 05 ? ? ? ? DC 0D ? ? ? ? 89 C7").count_hint(1); - if (constructStatLine.size() == 1) - { - auto setFontStyle = get_pattern("6A 00 E8 ? ? ? ? 83 3D ? ? ? ? ? 59 0F 84", 2); + auto constructStatLine = pattern("E8 ? ? ? ? D9 05 ? ? ? ? DC 0D ? ? ? ? 89 C7").get_one(); + auto setFontStyle = get_pattern("6A 00 E8 ? ? ? ? 83 3D ? ? ? ? ? 59 0F 84", 2); - ReadCall(setFontStyle, orgSetFontStyle); - InterceptCall(constructStatLine.get_first(), orgConstructStatLine, ConstructStatLine_SetFontStyle); - } + ReadCall(setFontStyle, orgSetFontStyle); + InterceptCall(constructStatLine.get(), orgConstructStatLine, ConstructStatLine_SetFontStyle); } + TXN_CATCH(); // Enable Dodo keyboard controls for all cars when the flying cars cheat is enabled + try { using namespace DodoKeyboardControls; @@ -1676,9 +1704,11 @@ void Patch_III_Common() bAllDodosCheat = allDodosCheat; InterceptCall(findPlayerVehicle, orgFindPlayerVehicle, FindPlayerVehicle_DodoCheck); } + TXN_CATCH(); // Reset variables on New Game + try { using namespace VariableResets; @@ -1696,9 +1726,11 @@ void Patch_III_Common() GameVariablesToReset.emplace_back(*get_pattern("7D 72 A1 ? ? ? ? 05", 2 + 1)); // LastTimeAmbulanceCreated GameVariablesToReset.emplace_back(*get_pattern("74 7F A1 ? ? ? ? 05", 2 + 1)); // LastTimeFireTruckCreated } + TXN_CATCH(); // Clean up the pickup object when reusing a temporary slot + try { using namespace GenerateNewPickup_ReuseObjectFix; @@ -1707,10 +1739,12 @@ void Patch_III_Common() pPickupObject = *give_us_a_pick_up_object.get(7 + 2); InterceptCall(give_us_a_pick_up_object.get(2), orgGiveUsAPickUpObject, GiveUsAPickUpObject_CleanUpObject); } + TXN_CATCH(); // Sitting in boat (Speeder), implemented as a special vehicle feature // Based off SitInBoat from Fire_Head, with extra improvements + try { using namespace SitInBoat; @@ -1730,36 +1764,40 @@ void Patch_III_Common() // This is intended - we don't actually need the original SetFinishCallback, only its parameters! InjectHook(finish_callback, FinishCallback_CallImmediately); } + TXN_CATCH(); // Copy the atomic render CB in CloneAtomicToFrameCB instead of overriding it // Fixes detached limbs rendering the normal and LOD atomics together + try { auto set_render_cb = get_pattern("55 E8 ? ? ? ? 89 D8 59", 1); Nop(set_render_cb, 5); } + TXN_CATCH(); // Fix dark car reflections in the Steam EXE // Based off Sergenaur's fix + try { - auto reflection = pattern("A1 ? ? ? ? 85 C0 74 34"); - if (reflection.count_hint(1).size() == 1) // This will only pass on the Steam EXE, and if Sergenaur's standalone fix isn't present - { - auto match = reflection.get_one(); + // This will only pass on the Steam EXE, and if Sergenaur's standalone fix isn't present + auto reflection = pattern("A1 ? ? ? ? 85 C0 74 34").get_one(); - // xor eax, eax \ nop - Patch(match.get(), { 0x31, 0xC0 }); - Nop(match.get(2), 3); - } + // xor eax, eax \ nop + Patch(reflection.get(), { 0x31, 0xC0 }); + Nop(reflection.get(2), 3); } + TXN_CATCH(); // Don't override the color of the FBI car + try { auto spawn_one_car = get_pattern("83 7C 24 ? ? 75 0E C6 85", 5); Patch(spawn_one_car, 0xEB); } + TXN_CATCH(); } BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) diff --git a/SilentPatchIII/SilentPatchIII.vcxproj b/SilentPatchIII/SilentPatchIII.vcxproj index 0c4d665..8f4ccc7 100644 --- a/SilentPatchIII/SilentPatchIII.vcxproj +++ b/SilentPatchIII/SilentPatchIII.vcxproj @@ -152,7 +152,6 @@ stdcpp17 true false - false Windows @@ -186,7 +185,6 @@ stdcpp17 true false - false true @@ -222,7 +220,6 @@ stdcpp17 true false - false true diff --git a/SilentPatchSA/SilentPatchSA.cpp b/SilentPatchSA/SilentPatchSA.cpp index f5219e2..f0e51ea 100644 --- a/SilentPatchSA/SilentPatchSA.cpp +++ b/SilentPatchSA/SilentPatchSA.cpp @@ -4261,7 +4261,7 @@ BOOL InjectDelayedPatches_Newsteam() if ( !IsAlreadyRunning() ) { using namespace Memory; - using namespace hook; + using namespace hook::txn; const HINSTANCE hInstance = GetModuleHandle( nullptr ); std::unique_ptr Protect = ScopedUnprotect::UnprotectSectionOrFullModule( hInstance, ".text" ); @@ -4276,15 +4276,16 @@ BOOL InjectDelayedPatches_Newsteam() constexpr bool flaBugAware = false; constexpr bool usesEnhancedImages = false; - if constexpr ( !usesEnhancedImages || flaBugAware ) + if constexpr ( !usesEnhancedImages || flaBugAware ) try { void* initThread = get_pattern( "74 14 81 25 ? ? ? ? ? ? ? ? C7 05", 0x16 ); + auto cdStreamSync = pattern( "8B 0D ? ? ? ? 8D 04 40 03 C0" ).get_one(); // 0x4064E6 + auto cdStreamInitThread = pattern( "6A 00 6A 02 6A 00 6A 00 FF D3" ).get_one(); + auto cdStreamShutdown = pattern( "8B 4C 07 14" ).get_one(); ReadCall( initThread, CdStreamSync::orgCdStreamInitThread ); InjectHook( initThread, CdStreamSync::CdStreamInitThread ); - auto cdStreamSync = pattern( "8B 0D ? ? ? ? 8D 04 40 03 C0" ).get_one(); // 0x4064E6 - Patch( cdStreamSync.get( 0x18 ), { 0x56, 0xFF, 0x15 } ); Patch( cdStreamSync.get( 0x18 + 3 ), &CdStreamSync::CdStreamSyncOnObject ); Patch( cdStreamSync.get( 0x18 + 3 + 4 ), { 0x5E, 0x5D, 0xC3 } ); // pop ebp / retn @@ -4292,7 +4293,7 @@ BOOL InjectDelayedPatches_Newsteam() Patch( cdStreamSync.get( 0x5E + 2 ), &CdStreamSync::pGetOverlappedResult ); Patch( cdStreamSync.get( 0x5E + 6 ), { 0x5E, 0x5D, 0xC3 } ); // pop esi / pop ebp / retn - if constexpr ( !usesEnhancedImages ) + if constexpr ( !usesEnhancedImages ) try { auto cdStreamThread = pattern( "C7 46 04 00 00 00 00 8A 4E 0D" ).get_one(); @@ -4300,17 +4301,17 @@ BOOL InjectDelayedPatches_Newsteam() Patch( cdStreamThread.get( 3 ), &CdStreamSync::CdStreamThreadOnObject ); Patch( cdStreamThread.get( 3 + 4 ), { 0xEB, 0x17 } ); } + TXN_CATCH(); - auto cdStreamInitThread = pattern( "6A 00 6A 02 6A 00 6A 00 FF D3" ).get_one(); Patch( cdStreamInitThread.get(), { 0xFF, 0x15 } ); Patch( cdStreamInitThread.get( 2 ), &CdStreamSync::CdStreamInitializeSyncObject ); Nop( cdStreamInitThread.get( 6 ), 4 ); Nop( cdStreamInitThread.get( 0x16 ), 2 ); - auto cdStreamShutdown = pattern( "8B 4C 07 14" ).get_one(); Patch( cdStreamShutdown.get(), { 0x56, 0x50 } ); InjectHook( cdStreamShutdown.get( 2 ), CdStreamSync::CdStreamShutdownSyncObject_Stub, HookType::Call ); } + TXN_CATCH(); } @@ -6093,15 +6094,19 @@ void Patch_SA_Steam() void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) { using namespace Memory; - using namespace hook; + using namespace hook::txn; + try { void* isAlreadyRunning = get_pattern( "85 C0 74 08 33 C0 8B E5 5D C2 10 00", -5 ); ReadCall( isAlreadyRunning, IsAlreadyRunning ); InjectHook(isAlreadyRunning, InjectDelayedPatches_Newsteam); } + TXN_CATCH(); + // (Hopefully) more precise frame limiter + try { void* rsEventHandler = get_pattern( "83 C4 08 39 3D ? ? ? ? 75 23", -5 ); void* getTimeSinceLastFrame = get_pattern( "EB 7F E8 ? ? ? ? 89 45 08", 2 ); @@ -6110,53 +6115,54 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) InjectHook( rsEventHandler, NewFrameRender ); InjectHook( getTimeSinceLastFrame, GetTimeSinceLastFrame ); } + TXN_CATCH(); + // No framedelay + try { - // TODO: Simplify with transactional patching - auto framedelay_jmpSrc = pattern( "83 EC 08 E8 ? ? ? ? E8" ).count(1); - auto framedelay_jmpDest = pattern( "33 D2 8B C6 F7 F1 A3" ).count(1); - auto popEsi = pattern( "83 C4 04 83 7D 08 00 5E" ).count(1); + auto framedelay_jmpSrc = get_pattern("83 EC 08 E8 ? ? ? ? E8", 3); + auto framedelay_jmpDest = get_pattern("33 D2 8B C6 F7 F1 A3", 11); + auto popEsi = pattern("83 C4 04 83 7D 08 00 5E").get_one(); - if ( framedelay_jmpSrc.size() == 1 && framedelay_jmpDest.size() == 1 && popEsi.size() == 1 ) - { - // TODO: Let this place long or short jump, whatever it prefers - InjectHook( framedelay_jmpSrc.get_first( 3 ), framedelay_jmpDest.get_first( 11 ), HookType::Jump ); + InjectHook( framedelay_jmpSrc, framedelay_jmpDest, HookType::Jump ); - auto popEsiMatch = popEsi.get_one(); - Patch( popEsiMatch.get( 3 + 2 ), 0x4); - Nop( popEsiMatch.get( 3 + 4 ), 1 ); - } + Patch( popEsi.get( 3 + 2 ), 0x4); + Nop( popEsi.get( 3 + 4 ), 1 ); } + TXN_CATCH(); + // Unlock 1.0/1.01 saves loading + try { - auto sizeCheck = pattern( "0F 84 ? ? ? ? 8D 45 FC" ).count(1); - if ( sizeCheck.size() == 1 ) - { - Patch( sizeCheck.get_first(), { 0x90, 0xE9 } ); // nop / jmp - } + auto sizeCheck = get_pattern( "0F 84 ? ? ? ? 8D 45 FC" ); + Patch( sizeCheck, { 0x90, 0xE9 } ); // nop / jmp } + TXN_CATCH(); + // Old .set files working again + try { void* setFileSave = get_pattern( "C6 45 FD 5F", 0xE + 1 ); - auto setCheckVersion1 = pattern( "83 7D F8 07" ).count(1); - auto setCheckVersion2 = pattern( "83 C4 18 83 7D FC 07" ).count(1); + auto setCheckVersion1 = get_pattern( "83 7D F8 07", 3); + auto setCheckVersion2 = get_pattern( "83 C4 18 83 7D FC 07", 3 + 3); - if ( setCheckVersion1.size() == 1 && setCheckVersion2.size() == 1 ) - { - static const DWORD dwSetVersion = 6; - Patch( setFileSave, &dwSetVersion ); - Patch( setCheckVersion1.get_first( 3 ), dwSetVersion ); - Patch( setCheckVersion2.get_first( 3 + 3 ), dwSetVersion ); - } + static const DWORD dwSetVersion = 6; + Patch( setFileSave, &dwSetVersion ); + Patch( setCheckVersion1, dwSetVersion ); + Patch( setCheckVersion2, dwSetVersion ); } + TXN_CATCH(); + // Disable re-initialization of DirectInput mouse device by the game + try { void* reinitMouse1 = get_pattern( "84 C0 ? 0F E8 ? ? ? ? 6A 01 E8", 2 ); auto reinitMouse2 = pattern( "84 C0 ? 0E E8 ? ? ? ? 53 E8" ).count(2); + void* diInitMouse = get_pattern( "6A 00 83 C1 1C", -3 ); Patch( reinitMouse1, 0xEB ); @@ -6164,72 +6170,71 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) Patch( match.get( 2 ), 0xEB ); }); - void* diInitMouse = get_pattern( "6A 00 83 C1 1C", -3 ); - // Make sure DirectInput mouse device is set non-exclusive (may not be needed?) // nop / mov al, 1 Patch( diInitMouse, { 0x90, 0xB0, 0x01 } ); } + TXN_CATCH(); + // Unlocked widescreen resolutions { // Assume anybody could have changed those, so bail out if ANYTHING goes wrong // However, all those patches are independent so try one by one - auto wsRes_jmpSrc = pattern( "81 F9 E0 01 00 00 7C").count(1); - auto wsRes1_jmpDest = pattern( "8B 45 EC 0F AF C2" ).count(1); - auto wsRes2 = pattern( "0F 8C ? ? ? ? 81 7D ? ? ? ? ? 0F 8C" ).count(1); - auto wsRes3 = pattern( "7A 4D EB 02" ).count(1); - - if ( wsRes_jmpSrc.size() == 1 && wsRes1_jmpDest.size() == 1 ) + try { - auto wsRes_jmpSrcMatch = wsRes_jmpSrc.get_one(); - auto wsRes1_jmpDestMatch = wsRes1_jmpDest.get_one(); + auto wsRes_jmpSrc = pattern( "81 F9 E0 01 00 00 7C").get_one(); + auto wsRes1_jmpDest = pattern( "8B 45 EC 0F AF C2" ).get_one(); - const uintptr_t jumpSource = reinterpret_cast(wsRes_jmpSrcMatch.get( 6 + 2 )); - const uintptr_t jumpDestination = reinterpret_cast(wsRes1_jmpDestMatch.get() ); + const uintptr_t jumpSource = reinterpret_cast(wsRes_jmpSrc.get( 6 + 2 )); + const uintptr_t jumpDestination = reinterpret_cast(wsRes1_jmpDest.get() ); const ptrdiff_t dist = jumpDestination - jumpSource; // Can only do a short jump if ( INT8_MIN <= dist && dist <= INT8_MAX ) { // jnl 00B19C33 - Patch( wsRes_jmpSrcMatch.get( 6 ), { 0x7D, static_cast(dist) } ); + Patch( wsRes_jmpSrc.get( 6 ), { 0x7D, static_cast(dist) } ); } } + TXN_CATCH(); - if ( wsRes2.size() == 1 ) + try { - auto wsRes2Match = wsRes2.get_one(); - Nop( wsRes2Match.get(), 4 ); - Patch( wsRes2Match.get( 4 ), { 0x7D, 0xD } ); - } + auto wsRes2 = pattern( "0F 8C ? ? ? ? 81 7D ? ? ? ? ? 0F 8C" ).get_one(); - if ( wsRes3.size() == 1 ) - { - Nop( wsRes3.get_first(), 2 ); + Nop( wsRes2.get(), 4 ); + Patch( wsRes2.get( 4 ), { 0x7D, 0xD } ); } + TXN_CATCH(); + + try + { + auto wsRes3 = get_pattern( "7A 4D EB 02" ); + Nop( wsRes3, 2 ); + } + TXN_CATCH(); } + // Default resolution to native resolution + try { - auto resolution = pattern( "BB 20 03 00 00" ).count(1); // Another instance could overwrite it so check first + auto resolution = pattern( "BB 20 03 00 00" ).get_one(); + void* cannotFindResMessage = get_pattern( "6A 00 68 ? ? ? ? 68 ? ? ? ? 6A 00", 7 + 1 ); - if ( resolution.size() == 1 ) - { - void* cannotFindResMessage = get_pattern( "6A 00 68 ? ? ? ? 68 ? ? ? ? 6A 00", 7 + 1 ); + RECT desktop; + GetWindowRect(GetDesktopWindow(), &desktop); + sprintf_s(aNoDesktopMode, "Cannot find %dx%dx32 video mode", desktop.right, desktop.bottom); - RECT desktop; - GetWindowRect(GetDesktopWindow(), &desktop); - sprintf_s(aNoDesktopMode, "Cannot find %dx%dx32 video mode", desktop.right, desktop.bottom); - - auto resolutionMatch = resolution.get_one(); - - Patch( resolutionMatch.get( 1 ), desktop.right ); - Patch( resolutionMatch.get( 5 + 1 ), desktop.bottom ); - Patch( cannotFindResMessage, aNoDesktopMode ); - } + Patch( resolution.get( 1 ), desktop.right ); + Patch( resolution.get( 5 + 1 ), desktop.bottom ); + Patch( cannotFindResMessage, aNoDesktopMode ); } + TXN_CATCH(); + // No DirectPlay dependency + try { auto getDXversion = pattern( "50 68 ? ? ? ? A3" ).get_one(); @@ -6237,38 +6242,55 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) Patch( getDXversion.get( -5 ), 0xB8 ); Patch( getDXversion.get( -5 + 1 ), 0x900 ); } + TXN_CATCH(); + // SHGetFolderPath on User Files + try { void* getDocumentsPath = get_pattern( "8D 45 FC 50 68 19 00 02 00", -6 ); InjectHook( getDocumentsPath, GetMyDocumentsPathSA, HookType::Jump ); } + TXN_CATCH(); + // Fixed muzzleflash not showing from last bullet + try { auto weaponStateCheck = pattern("83 BC 8E A4 05 00 00 01").get_one(); Nop(weaponStateCheck.get(-16), 22); Patch(weaponStateCheck.get(6), { 0x84, 0xC0, 0x74 }); } + TXN_CATCH(); + // Proper randomizations + try { - pattern( "C1 F8 06 99" ).count(2).for_each_result( []( pattern_match match ) { + auto pedsRand = pattern( "C1 F8 06 99" ).count(2); + void* prostitutesRand = get_pattern( "8B F8 32 C0", -5 ); + + pedsRand.for_each_result( []( pattern_match match ) { InjectHook( match.get( -5 ), Int32Rand ); // Missing ped paths }); - void* prostitutesRand = get_pattern( "8B F8 32 C0", -5 ); InjectHook( prostitutesRand, Int32Rand ); // Prostitutes } + TXN_CATCH(); + // Help boxes showing with big message // Game seems to assume they can show together + try { void* showingBigMessage = get_pattern( "38 1D ? ? ? ? 0F 85 ? ? ? ? 38 1D ? ? ? ? 0F 85 ? ? ? ? 38 1D", 6 ); Nop( showingBigMessage, 6 ); } + TXN_CATCH(); + // Fixed lens flare + try { auto coronasRenderEpilogue = pattern( "83 C7 3C FF 4D BC" ).get_one(); auto flushLensSwitchZ = pattern( "6A 01 6A 06 FF D0 83 C4 08" ).get_one(); @@ -6295,8 +6317,11 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) Patch( initBufferSwitchZ.get( -8 + 3 ), 0xB9 ); Patch( initBufferSwitchZ.get( -8 + 4 ), &InitBufferSwitchZ ); } + TXN_CATCH(); + // Y axis sensitivity fix + try { auto horizontalSens = pattern( "D9 05 ? ? ? ? D8 4D 0C D8 C9" ).get_one(); float* sens = *horizontalSens.get( 2 ); @@ -6308,15 +6333,20 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) float* vertSens = *horizontalSens.get( 0xE + 2 ); memcpy( bytes + 2, &vertSens, sizeof(vertSens) ); - pattern( {bytes, _countof(bytes)}, {mask, _countof(mask)} ).count(4).for_each_result( [sens]( pattern_match match ) { + auto mulVerticalSens1 = pattern( {bytes, _countof(bytes)}, {mask, _countof(mask)} ).count(4); + void* mulVerticalSens2 = get_pattern( "D8 0D ? ? ? ? D8 C9 D9 5D F4", 2 ); + + mulVerticalSens1.for_each_result( [sens]( pattern_match match ) { Patch( match.get( 2 ), sens ); } ); - void* mulVerticalSens = get_pattern( "D8 0D ? ? ? ? D8 C9 D9 5D F4", 2 ); - Patch( mulVerticalSens, sens ); + Patch( mulVerticalSens2, sens ); } + TXN_CATCH(); + // Don't lock mouse Y axis during fadeins + try { void* followPedWithMouse = get_pattern( "D9 5D 08 A0", -7 ); void* followPedWithMouse2 = get_pattern( "66 83 3D ? ? ? ? ? 0F 85 ? ? ? ? 80 3D", -6 ); @@ -6329,29 +6359,42 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) Patch( followPedWithMouse2, { 0x90, 0xE9 } ); InjectHook( followPedSA, folowPedSA_dest, HookType::Jump ); } + TXN_CATCH(); + // Fixed mirrors crash + try { // TODO: Change when short jumps are supported void* beforeMainRender = get_pattern( "8B 15 ? ? ? ? 83 C4 0C 52", 0xF ); Patch( beforeMainRender, { 0x85, 0xC0, 0x74, 0x34, 0x83, 0xC4, 0x04 } ); } + TXN_CATCH(); + // Mirrors depth fix & bumped quality + try { void* createBuffers = get_pattern( "7B 0A C7 05 ? ? ? ? 01 00 00 00", 0xC ); InjectHook( createBuffers, CreateMirrorBuffers ); } + TXN_CATCH(); + // Fixed MSAA options + try { using namespace MSAAFixes; - // TODO: Remove wildcards in patterns once transactional patching is implemented - auto func1 = pattern( "83 BE C8 00 00 00 04 ? ? E8" ).get_one(); - void* func2 = get_pattern( "05 A3 ? ? ? ? 59", -1 ); - void* func3 = get_pattern( "05 A3 ? ? ? ? 8B C7", -1 ); - void* func4 = get_pattern( "0F 8C ? ? ? ? 8B 44 24 0C", 0x18 ); + auto func1 = pattern("83 BE C8 00 00 00 04 7F 11 E8").get_one(); + void* func2 = get_pattern("76 05 A3 ? ? ? ? 59"); + void* func3 = get_pattern("76 05 A3 ? ? ? ? 8B C7"); + void* func4 = get_pattern("0F 8C ? ? ? ? 8B 44 24 0C", 0x18); + + auto getMaxMultisamplingLevels = pattern( "5F 89 86 C8 00 00 00 8A 45 FF" ).get_one(); + void* changeMultiSamplingLevels = get_pattern( "8B 8E D0 00 00 00 51", -5 ); + void* changeMultiSamplingLevels2 = get_pattern( "8B 96 D0 00 00 00 52", -5 ); + void* setMultiSamplingLevels = get_pattern( "83 C4 04 8B C7 5F 5E 5B 8B E5 5D C3 BB", -5 ); Patch( func1.get( 0x4A ), 0xEB ); // jmp Nop( func1.get( 7 ), 2 ); // nop a jmp @@ -6360,11 +6403,6 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) Patch(func3, 0xEB); // jmp Patch(func4, { 0x90, 0xE9 }); // jmp - auto getMaxMultisamplingLevels = pattern( "5F 89 86 C8 00 00 00 8A 45 FF" ).get_one(); - void* changeMultiSamplingLevels = get_pattern( "8B 8E D0 00 00 00 51", -5 ); - void* changeMultiSamplingLevels2 = get_pattern( "8B 96 D0 00 00 00 52", -5 ); - void* setMultiSamplingLevels = get_pattern( "83 C4 04 8B C7 5F 5E 5B 8B E5 5D C3 BB", -5 ); - std::array getMaxMultiSamplingLevels = { getMaxMultisamplingLevels.get( -5 ), func1.get( 7 + 2 ), @@ -6379,27 +6417,34 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) }; HookEach_SetOrChangeMultiSamplingLevels(setOrChangeMultiSamplingLevels, InterceptCall); - auto msaaText = pattern( "48 50 68 ? ? ? ? 53" ).count(1); // Only so newsteam r1 doesn't crash - if ( msaaText.size() == 1 ) // transactional patching will obsolete this + // Only so newsteam r1 doesn't crash + try { - auto msaaTextMatch = msaaText.get_one(); + auto msaaText = pattern( "48 50 68 ? ? ? ? 53" ).get_one(); // nop / mov edx, offset MSAAText - Patch( msaaTextMatch.get( -6 ), { 0x90, 0xBA } ); - Patch( msaaTextMatch.get( -6 + 2 ), MSAAText ); + Patch( msaaText.get( -6 ), { 0x90, 0xBA } ); + Patch( msaaText.get( -6 + 2 ), MSAAText ); } + TXN_CATCH(); } + TXN_CATCH(); + // Fixed car collisions - car you're hitting gets proper damage now + try { auto fixedCarDamage = pattern( "8B 7D 10 0F B6 47 21" ).get_one(); Nop( fixedCarDamage.get(), 2 ); InjectHook( fixedCarDamage.get( 2 ), FixedCarDamage_Newsteam, HookType::Call ); } + TXN_CATCH(); + // Car explosion crash with multimonitor // Unitialized collision data breaking stencil shadows + try { using namespace UnitializedCollisionDataFix; @@ -6412,12 +6457,15 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) InterceptCall(memMgrAlloc, orgMemMgrMalloc, CollisionData_MallocAndInit); HookEach_CollisionDataNew(newAlloc, InterceptCall); } + TXN_CATCH(); + // Crash when entering advanced display options on a dual monitor machine after: // - starting game on primary monitor in maximum resolution, exiting, // starting again in maximum resolution on secondary monitor. // Secondary monitor maximum resolution had to be greater than maximum resolution of primary monitor. // Not in 1.01 + try { void* storeVideoModes = get_pattern( "6A 00 8B F8 6A 04", -5 ); void* retrieveVideoModes = get_pattern( "57 E8 ? ? ? ? 83 3D", 1 ); @@ -6426,61 +6474,61 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) InjectHook( storeVideoModes, GetNumVideoModes_Store ); InjectHook( retrieveVideoModes, GetNumVideoModes_Retrieve ); } + TXN_CATCH(); + // Fixed escalators crash + try { orgEscalatorsUpdate = static_cast(get_pattern( "80 3D ? ? ? ? ? 74 23 56" )); - // TODO: Simplify when transactional patching is implemented - auto updateEscalators = pattern( "80 3D ? ? ? ? ? 74 22 56" ).count(1); - auto removeEscalatorsForEntity = pattern( "80 7E F5 00 74 56" ).count(1); + auto updateEscalators = get_pattern("80 3D ? ? ? ? ? 74 22 56"); + auto removeEscalatorsForEntity = pattern( "80 7E F5 00 74 56" ).get_one(); - if ( updateEscalators.size() == 1 && removeEscalatorsForEntity.size() == 1 ) - { - InjectHook( updateEscalators.get_first(), UpdateEscalators, HookType::Jump ); + InjectHook( updateEscalators, UpdateEscalators, HookType::Jump ); - // lea ecx, [esi-84] / call CEscalator::SwitchOffNoRemove / jmp loc_734C0A - auto removeEscalatorsMatch = removeEscalatorsForEntity.get_one(); - - // TODO: Change when short jmps are supported - Patch( removeEscalatorsMatch.get(), { 0x8D, 0x8E } ); - Patch( removeEscalatorsMatch.get( 2 ), -0x84 ); - InjectHook( removeEscalatorsMatch.get( 6 ), &CEscalator::SwitchOffNoRemove, HookType::Call ); - Patch( removeEscalatorsMatch.get( 6 + 5 ), { 0xEB, 0x4F } ); - } + // lea ecx, [esi-84] / call CEscalator::SwitchOffNoRemove / jmp loc_734C0A + // TODO: Change when short jmps are supported + Patch( removeEscalatorsForEntity.get(), { 0x8D, 0x8E } ); + Patch( removeEscalatorsForEntity.get( 2 ), -0x84 ); + InjectHook( removeEscalatorsForEntity.get( 6 ), &CEscalator::SwitchOffNoRemove, HookType::Call ); + Patch( removeEscalatorsForEntity.get( 6 + 5 ), { 0xEB, 0x4F } ); } + TXN_CATCH(); + // Don't allocate constant memory for stencil shadows every frame + try { - // TODO: Simplify when transactional patching is implemented - auto shadowAlloc = pattern( "83 C4 08 6A 00 68 00 60 00 00" ).count(1); - auto shadowFree = pattern( "A2 ? ? ? ? A1 ? ? ? ? 50 E8" ).count(1); - if ( shadowAlloc.size() == 1 && shadowFree.size() == 1 ) - { - auto allocMatch = shadowAlloc.get_one(); + auto shadowAlloc = pattern("83 C4 08 6A 00 68 00 60 00 00").get_one(); + auto shadowFree = get_pattern( "A2 ? ? ? ? A1 ? ? ? ? 50 E8", 5); - InjectHook( allocMatch.get( 3 ), StencilShadowAlloc, HookType::Call) ; - Patch( allocMatch.get( 3 + 5 ), { 0xEB, 0x2C } ); - Nop( allocMatch.get( 0x3B ), 3 ); - Patch( shadowFree.get_first( 5 ), { 0x5F, 0x5E, 0x5B, 0x5D, 0xC3 } ); // pop edi, pop esi, pop ebx, pop ebp, retn - } + InjectHook( shadowAlloc.get( 3 ), StencilShadowAlloc, HookType::Call) ; + Patch( shadowAlloc.get( 3 + 5 ), { 0xEB, 0x2C } ); + Nop( shadowAlloc.get( 0x3B ), 3 ); + Patch( shadowFree, { 0x5F, 0x5E, 0x5B, 0x5D, 0xC3 } ); // pop edi, pop esi, pop ebx, pop ebp, retn } + TXN_CATCH(); + // "Streaming memory bug" fix + try { void* animInterpolator = get_pattern( "83 C4 1C C7 03 00 30 00 00 5B", -5 ); InjectHook(animInterpolator, GTARtAnimInterpolatorSetCurrentAnim); } + TXN_CATCH(); + // Fixed ammo for melee weapons in cheats + try { - // TODO: Remove wildcards in patterns once transactional patching is implemented - void* knifeAmmo1 = get_pattern( "6A ? 6A 04 6A FF", 1 ); - void* knifeAmmo2 = get_pattern( "6A 01 6A ? 6A 04 6A 01", 2 + 1 ); - void* chainsawAmmo1 = get_pattern( "6A ? 6A 09 6A FF", 1 ); - void* chainsawAmmo2 = get_pattern( "6A ? 6A 09 6A 01", 1 ); - void* parachuteAmmo = get_pattern( "6A ? 6A 2E 6A FF", 1 ); - void* katanaAmmo = get_pattern( "83 C4 0C ? ? ? 6A 08 6A FF", 3 ); + void* knifeAmmo1 = get_pattern( "6A 00 6A 04 6A FF", 1 ); + void* knifeAmmo2 = get_pattern( "6A 01 6A 00 6A 04 6A 01", 2 + 1 ); + void* chainsawAmmo1 = get_pattern( "6A 00 6A 09 6A FF", 1 ); + void* chainsawAmmo2 = get_pattern( "6A 00 6A 09 6A 01", 1 ); + void* parachuteAmmo = get_pattern( "6A 00 6A 2E 6A FF", 1 ); + void* katanaAmmo = get_pattern( "83 C4 0C 6A 01 53 6A 08 6A FF", 3 ); Patch(knifeAmmo1, 1); // knife Patch(knifeAmmo2, 1); // knife @@ -6491,8 +6539,11 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) // push ebx / push 1 Patch( katanaAmmo, { 0x53, 0x6A, 0x01 } ); // katana } + TXN_CATCH(); + // Proper aspect ratios + try { auto calculateAr = pattern( "74 13 D9 05 ? ? ? ? D9 1D" ).get_one(); // 0x734247; has two matches but both from the same function @@ -6501,6 +6552,8 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) Patch(calculateAr.get( 0x1E + 2 ), &f54); Patch(calculateAr.get( 0x31 + 2 ), &f43); } + TXN_CATCH(); + // 6 extra directionals on Medium and higher // push dword ptr [CGame::currArea] @@ -6508,6 +6561,7 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) // add esp, 4 // mov ebx, eax // nop + try { auto maxdirs_addr = pattern( "83 3D ? ? ? ? 00 8D 5E 05 74 05 BB 06 00 00 00" ).get_one(); @@ -6516,15 +6570,21 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) Patch( maxdirs_addr.get(11), { 0x83, 0xC4, 0x04, 0x8B, 0xD8 } ); Nop( maxdirs_addr.get(16), 1 ); } + TXN_CATCH(); + // AI accuracy issue + try { auto match = pattern( "8B 82 8C 05 00 00 85 C0 74 09" ).get_one(); // 0x76DEA7 in newsteam r1 Nop(match.get(0), 1); InjectHook( match.get(1), WeaponRangeMult_VehicleCheck, HookType::Call ); } + TXN_CATCH(); + // Don't catch WM_SYSKEYDOWN and WM_SYSKEYUP (fixes Alt+F4) + try { auto patternie = pattern( "8B 75 10 8B ? 14 56" ).count(2); // 0x77C588 and 0x77C5CC in newsteam r2 auto defproc = get_pattern( "8B ? 14 8B ? 10 8B ? 08 ? ? 56" ); @@ -6539,12 +6599,26 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) Patch( match.get(0x2B + 2), -8 ); // use stack space for new lParam } ); } + TXN_CATCH(); // Reset variables on New Game + try { using namespace VariableResets; + // Variables to reset + { + auto timers_init = pattern( "89 45 FC DB 45 FC C6 05 ? ? ? ? 01" ).get_one(); + + GameVariablesToReset.emplace_back( *timers_init.get(-17 + 2) ); + GameVariablesToReset.emplace_back( *timers_init.get(-11 + 2) ); + GameVariablesToReset.emplace_back( *timers_init.get*>(0x41 + 2) ); + } + + GameVariablesToReset.emplace_back( *get_pattern( "A2 ? ? ? ? E9 ? ? ? ? 6A 01 8B CE", 1 ) ); // CGameLogic::bPenaltyForDeathApplies + GameVariablesToReset.emplace_back( *get_pattern( "88 0D ? ? ? ? E9 ? ? ? ? 6A 05", 2 ) ); // CGameLogic::bPenaltyForArrestApplies + { auto loadPickup = get_pattern("E8 ? ? ? ? EB 1B 6A 00"); auto loadCarGenerator = get_pattern("E8 ? ? ? ? 83 C4 08 EB 11"); @@ -6560,40 +6634,38 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) InterceptCall(loadCarGenerator, orgLoadCarGenerator, LoadCarGenerator_SaveLine); InterceptCall(loadStuntJump, orgLoadStuntJump, LoadStuntJump_SaveLine); } - - // Variables to reset - { - auto timers_init = pattern( "89 45 FC DB 45 FC C6 05 ? ? ? ? 01" ).get_one(); - - GameVariablesToReset.emplace_back( *timers_init.get(-17 + 2) ); - GameVariablesToReset.emplace_back( *timers_init.get(-11 + 2) ); - GameVariablesToReset.emplace_back( *timers_init.get*>(0x41 + 2) ); - } - - GameVariablesToReset.emplace_back( *get_pattern( "A2 ? ? ? ? E9 ? ? ? ? 6A 01 8B CE", 1 ) ); // CGameLogic::bPenaltyForDeathApplies - GameVariablesToReset.emplace_back( *get_pattern( "88 0D ? ? ? ? E9 ? ? ? ? 6A 05", 2 ) ); // CGameLogic::bPenaltyForArrestApplies } + TXN_CATCH(); + // FuckCarCompletely not fixing panels + try { void* panel_addr = get_pattern( "C6 46 04 FA 5E 5B", -3 ); Nop(panel_addr, 3); } + TXN_CATCH(); + // 014C cargen counter fix (by spaceeinstein) + try { auto do_processing = pattern( "B8 C3 2E 57 06 F7 EE C1 FA 06" ).get_one(); Patch( do_processing.get(27 + 1), 0xBF ); // movzx eax, word ptr [edi+1Ah] -> movsx eax, word ptr [edi+1Ah] Patch( do_processing.get(41), 0x74 ); // jge -> jz } + TXN_CATCH(); + // Linear filtering on script sprites + try { void* drawScriptSprites = get_pattern( "81 EC 94 01 00 00 53 56 57 50", 10 ); ReadCall( drawScriptSprites, orgDrawScriptSpritesAndRectangles ); InjectHook( drawScriptSprites, DrawScriptSpritesAndRectangles ); } + TXN_CATCH(); // Animated Phoenix hood scoop // TODO @@ -6609,25 +6681,44 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) // Make freeing temp objects more aggressive to fix vending crash - InjectHook( get_pattern( "57 8B 78 08 89 45 FC 85 FF 74 5B", -9 ), CObject::TryToFreeUpTempObjects_SilentPatch, HookType::Jump ); + try + { + auto match = get_pattern("57 8B 78 08 89 45 FC 85 FF 74 5B", -9); + InjectHook( match, CObject::TryToFreeUpTempObjects_SilentPatch, HookType::Jump ); + } + TXN_CATCH(); // Remove FILE_FLAG_NO_BUFFERING from CdStreams - Patch( get_pattern( "81 F9 00 08 00 00 ? 05", 6 ), 0xEB ); + try + { + auto match = get_pattern("81 F9 00 08 00 00 ? 05", 6); + Patch( match, 0xEB ); + } + TXN_CATCH(); // Proper metric-imperial conversion constants - static const double METERS_TO_FEET_DIV = 1.0 / 3.280839895; - Patch( get_pattern( "83 EC 08 DC 35 ? ? ? ? DD 1C 24", 3 + 2 ), &METERS_TO_FEET_DIV ); - Patch( get_pattern( "51 DC 35 ? ? ? ? DD 1C 24", 1 + 2 ), &METERS_TO_FEET_DIV ); + try + { + auto match1 = get_pattern( "83 EC 08 DC 35 ? ? ? ? DD 1C 24", 3 + 2 ); + auto match2 = get_pattern( "51 DC 35 ? ? ? ? DD 1C 24", 1 + 2 ); + + static const double METERS_TO_FEET_DIV = 1.0 / 3.280839895; + Patch( match1, &METERS_TO_FEET_DIV ); + Patch( match2, &METERS_TO_FEET_DIV ); + } + TXN_CATCH(); // Fixed impounding of random vehicles (because CVehicle::~CVehicle doesn't remove cars from apCarsToKeep) + try { void* recordVehicleDeleted = get_pattern( "E8 ? ? ? ? 33 C0 66 89 86" ); ReadCall( recordVehicleDeleted, orgRecordVehicleDeleted ); InjectHook( recordVehicleDeleted, RecordVehicleDeleted_AndRemoveFromVehicleList ); } + TXN_CATCH(); // Don't include an extra D3DLIGHT on vehicles since we fixed directional already @@ -6636,6 +6727,7 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) // Fixed CAEAudioUtility timers - not typecasting to float so we're not losing precision after X days of PC uptime // Also fixed integer division by zero + try { auto staticInitialize = pattern( "FF 15 ? ? ? ? 5F 5E 85 C0" ).get_one(); @@ -6643,13 +6735,20 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) InjectHook( staticInitialize.get( 0x1E ), AudioUtilsGetStartTime ); InjectHook( get_pattern( "50 FF 15 ? ? ? ? DF 6D F8", -9 ), AudioUtilsGetCurrentTimeInMs, HookType::Jump ); } + TXN_CATCH(); // Car generators placed in interiors visible everywhere - InjectHook( get_pattern( "E8 ? ? ? ? 0F B6 57 0A" ), &CEntity::SetPositionAndAreaCode ); + try + { + auto match = get_pattern("E8 ? ? ? ? 0F B6 57 0A"); + InjectHook( match, &CEntity::SetPositionAndAreaCode ); + } + TXN_CATCH(); // Fixed bomb ownership/bombs saving for bikes + try { std::array restoreCar = { get_pattern( "8D 4E EE E8", 3 ), @@ -6657,27 +6756,43 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) }; CStoredCar::HookEach_RestoreCar(restoreCar, InterceptCall); } + TXN_CATCH(); // unnamed CdStream semaphore + try { auto semaName = pattern( "52 6A 40 FF 15" ).get_one(); Patch( semaName.get( 9 ), { 0x6A, 0x00 } ); // push 0 \ nop Nop( semaName.get( 9 + 2 ), 3 ); } + TXN_CATCH(); // Correct streaming when using RC vehicles - InjectHook( get_pattern( "88 1D ? ? ? ? E8 ? ? ? ? 8B F0 83 C4 04 3B F3", 6 ), FindPlayerEntityWithRC ); - InjectHook( get_pattern( "E8 ? ? ? ? 83 C4 08 85 C0 74 07 C6 05" ), FindPlayerVehicle_RCWrap ); + try + { + auto findPlayerEntity = get_pattern("88 1D ? ? ? ? E8 ? ? ? ? 8B F0 83 C4 04 3B F3", 6); + auto findPlayerVehicle = get_pattern("E8 ? ? ? ? 83 C4 08 85 C0 74 07 C6 05"); + + InjectHook( findPlayerEntity, FindPlayerEntityWithRC ); + InjectHook( findPlayerVehicle, FindPlayerVehicle_RCWrap ); + } + TXN_CATCH(); // Fixed triangle above recruitable peds' heads - Patch( get_pattern( "83 BE 98 05 00 00 ? D9 45 DC", 6 ), 8 ); // GANG2 + try + { + auto match = get_pattern( "83 BE 98 05 00 00 ? D9 45 DC", 6 ); + Patch( match, 8 ); // GANG2 + } + TXN_CATCH(); // Credits =) + try { auto renderCredits = pattern( "83 C4 18 E8 ? ? ? ? 80 3D" ).get_one(); @@ -6685,17 +6800,22 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) ReadCall( renderCredits.get( -5 ), Credits::PrintCreditText_Hooked ); InjectHook( renderCredits.get( -5 ), Credits::PrintSPCredits ); } + TXN_CATCH(); + // Fixed ammo from SCM + try { void* giveWeapon = get_pattern( "8B CE E8 ? ? ? ? 8B CE 8B D8", 2 ); ReadCall( giveWeapon, CPed::orgGiveWeapon ); InjectHook( giveWeapon, &CPed::GiveWeapon_SP ); } + TXN_CATCH(); // Fixed bicycle on fire - instead of CJ being set on fire, bicycle's driver is + try { using namespace BicycleFire; @@ -6713,9 +6833,11 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) ReadCall( doStuffToGoOnFire.get( START_FIRE_OFFSET + 0x10 ), CFireManager::orgStartFire ); InjectHook( doStuffToGoOnFire.get( START_FIRE_OFFSET + 0x10 ), &CFireManager::StartFire_NullEntityCheck ); } + TXN_CATCH(); // Decreased keyboard input latency + try { using namespace KeyboardInputFix; @@ -6731,8 +6853,10 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) Nop( updatePads.get( 20 ), 2 ); Nop( updatePads.get( 37 ), 2 ); } + TXN_CATCH(); // Fixed handling.cfg name matching (names don't need unique prefixes anymore) + try { using namespace HandlingNameLoadFix; @@ -6741,8 +6865,10 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) InjectHook( findExactWord.get( -5 ), strncpy_Fix ); InjectHook( findExactWord.get( 9 ), strncmp_Fix ); } + TXN_CATCH(); // No censorships (not set nor loaded from savegame) + try { using namespace Localization; @@ -6773,17 +6899,22 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) InjectHook( setGermanGame, SetUncensoredGame, HookType::Jump ); InjectHook( setFrenchGame, SetUncensoredGame, HookType::Jump ); } + TXN_CATCH(); + // Default Steer with Mouse to disabled, like in older executables not based on xbox + try { // mov _ZN8CVehicle22m_bEnableMouseSteeringE, bl -> // mov _ZN8CVehicle22m_bEnableMouseSteeringE, al void* setDefaultPreferences = get_pattern( "89 86 AD 00 00 00 66 89 86 B1 00 00 00", -0xC ); Patch( setDefaultPreferences, { 0x90, 0xA2 } ); } + TXN_CATCH(); // Re-introduce corona rotation on PC, like it is in III/VC/SA PS2 + try { using namespace CoronaRotationFix; @@ -6796,9 +6927,11 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) ReadCall( renderOneXLUSprite, orgRenderOneXLUSprite_Rotate_Aspect ); InjectHook( renderOneXLUSprite, RenderOneXLUSprite_Rotate_Aspect_SilentPatch ); } + TXN_CATCH(); // Fixed static shadows not rendering under fire and pickups + try { using namespace StaticShadowAlphaFix; @@ -6809,9 +6942,11 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) ReadCall( renderStaticShadows.get( 1 + 5 + 5 + 5 ), orgRenderStoredShadows ); InjectHook( renderStaticShadows.get( 1 + 5 + 5 + 5 ), RenderStoredShadows_StateFix ); } + TXN_CATCH(); // Disable building pipeline for skinned objects (like parachute) + try { using namespace SkinBuildingPipelineFix; @@ -6819,27 +6954,33 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) InterceptCall(setupAtomic, orgCustomBuildingDNPipeline_CustomPipeAtomicSetup, CustomBuildingDNPipeline_CustomPipeAtomicSetup_Skinned); } + TXN_CATCH(); // Reset requested extras if created vehicle has no extras // Fixes eg. lightless taxis + try { auto resetComps = pattern( "6A 00 68 ? ? ? ? 57 E8 ? ? ? ? 83 C4 0C 8B C7" ).get_one(); InjectHook( resetComps.get( -9 ), CVehicleModelInfo::ResetCompsForNoExtras, HookType::Call ); Nop( resetComps.get( -9 + 5 ), 4 ); } + TXN_CATCH(); // Allow extra6 to be picked with component rule 4 (any) + try { void* extra6 = get_pattern( "6A 00 E8 ? ? ? ? 83 C4 08 5E", -2 + 1 ); Patch( extra6, 6 ); } + TXN_CATCH(); // Disallow moving cam up/down with mouse when looking back/left/right in vehicle + try { using namespace FollowCarMouseCamFix; @@ -6852,21 +6993,24 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) ReadCall( getPad, orgGetPad ); InjectHook( getPad, getPadAndSetFlag ); } + TXN_CATCH(); // Add wind animations when driving a Quadbike // By Wesser + try { auto isOpenTopCar = pattern("8B 11 8B 82 9C 00 00 00 FF D0").get_one(); InjectHook(isOpenTopCar.get(), &CVehicle::IsOpenTopCarOrQuadbike, HookType::Call); Nop(isOpenTopCar.get(5), 5); - } + TXN_CATCH(); // Tie handlebar movement to the stering animations on Quadbike, fixes odd animation interpolations at low speeds // By Wesser + try { auto processRiderAnims = pattern("DD 05 ? ? ? ? D9 05 ? ? ? ? E8 ? ? ? ? D9 5D F0 80 7D 0B 00").get_one(); // Compiler reordered variables compared to the older versions, so they need to be preserved @@ -6878,19 +7022,23 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) Nop(saveDriveByAnim.get(), 1); InjectHook(saveDriveByAnim.get(1), &QuadbikeHandlebarAnims::SaveDriveByAnim_Steam, HookType::Call); } + TXN_CATCH(); // Disable the radio station change anim on boats where CJ stands upright // By Wesser + try { using namespace UprightBoatRadioStationChange; auto blendAnimation = get_pattern("E8 ? ? ? ? 83 C4 10 85 C0 0F 85 ? ? ? ? D9 47 48"); InterceptCall(blendAnimation, orgAnimManagerBlendAnimation, AnimManagerBlendAnimation_SkipIfBoatDrive); } + TXN_CATCH(); // Fix a memory leak when taking photos + try { using namespace CameraMemoryLeakFix; @@ -6899,37 +7047,45 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) InjectHook(psGrabScreen.get(2), psGrabScreen_UnlockAndReleaseSurface_Steam, HookType::Jump); InjectHook(psGrabScreen.get(7 + 2), psGrabScreen_UnlockAndReleaseSurface_Steam, HookType::Jump); } + TXN_CATCH(); // Fix crosshair issues when sniper rifle is quipped and a photo is taken by a gang member // By Wesser + try { using namespace CameraCrosshairFix; auto getWeaponInfo = get_pattern("E8 ? ? ? ? 8B 40 0C 83 C4 08 85 C0"); InterceptCall(getWeaponInfo, orgGetWeaponInfo, GetWeaponInfo_OrCamera); } + TXN_CATCH(); // Cancel the Drive By task of biker cops when losing the wanted level + try { using namespace BikerCopsDriveByFix; auto backToCruisingIfNoWantedLevel = get_pattern("56 E8 ? ? ? ? 80 A6 ? ? ? ? ? 83 C4 04", 1); InterceptCall(backToCruisingIfNoWantedLevel, orgJoinCarWithRoadSystem, JoinCarWithRoadSystem_AbortDriveByTask); } + TXN_CATCH(); // Fix miscolored racing checkpoints if no other marker was drawn before them + try { using namespace RacingCheckpointsRender; auto clumpRender = get_pattern("E8 ? ? ? ? DD 05 ? ? ? ? 83 C4 14"); InterceptCall(clumpRender, orgRpClumpRender, RpClumpRender_SetLitFlag); } + TXN_CATCH(); // Delay destroying of cigarettes/bottles held by NPCs so it does not potentially corrupt the moving list + try { // CWorld::Process processes all entries in the moving list, calling ProcessControl on them. // CPlayerPed::ProcessControl handles the gang recruitment which in turn can result in homies dropping cigarettes or bottles. @@ -6945,10 +7101,12 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) Patch(dropEntity, { 0x81, 0x4E, 0x1C, 0x00, 0x08, 0x00, 0x00, 0xEB, 0x13 }); } + TXN_CATCH(); // Spawn lapdm1 (biker cop) correctly if the script requests one with PEDTYPE_COP // By Wesser + try { using namespace GetCorrectPedModel_Lapdm1; @@ -6960,9 +7118,11 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) Patch(jumpTablePtr+4, &BikerCop_Steam); } } + TXN_CATCH(); // Only allow impounding cars and bikes (and their subclasses), as impounding helicopters, planes, boats makes no sense + try { using namespace RestrictImpoundVehicleTypes; @@ -6973,11 +7133,13 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) }; HookEach_ShouldImpound(isThisVehicleInteresting, InterceptCall); } + TXN_CATCH(); // Fix PlayerPed replay crashes // 1. Crash when starting a mocap cutscene after playing a replay wearing different clothes to the ones CJ has currently // 2. Crash when playing back a replay with a different motion group anim (fat/muscular/normal) than the current one + try { using namespace ReplayPlayerPedCrashFixes; @@ -6987,19 +7149,23 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) InterceptCall(restoreStuffFromMem, orgRestoreStuffFromMem, RestoreStuffFromMem_RebuildPlayer); InterceptCall(rebuildPlayer, orgRebuildPlayer, RebuildPlayer_LoadAllMotionGroupAnims); } + TXN_CATCH(); // Fix planes spawning in places where they crash easily + try { using namespace FindPlaneCreationCoorsFix; auto findPlaneCreationCoors = get_pattern("E8 ? ? ? ? 83 C4 18 84 C0 74 09"); InterceptCall(findPlaneCreationCoors, orgCheckCameraCollisionBuildings, CheckCameraCollisionBuildings_FixParams_Steam); } + TXN_CATCH(); // Allow hovering on the Jetpack with Keyboard + Mouse controls // Does not modify any other controls, only hovering + try { using namespace JetpackKeyboardControlsHover; @@ -7013,10 +7179,12 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) InjectHook(processControl_CheckHover.get(6 + 1), &ProcessControlInput_HoverWithKeyboard_Steam, HookType::Jump); ReadCall(processControl_DoHover.get(), orgGetLookBehindForCar); } + TXN_CATCH(); // During riots, don't target the player group during missions // Fixes recruited homies panicking during Los Desperados and other riot-time missions + try { using namespace RiotDontTargetPlayerGroupDuringMissions; @@ -7027,19 +7195,23 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) SkipTargetting = skipTargetting; InjectHook(targettingCheck.get(), CheckIfInPlayerGroupAndOnAMission_Steam, HookType::Jump); } + TXN_CATCH(); // Rescale light switching randomness in CVehicle::GetVehicleLightsStatus for PC the randomness range // The original randomness was 50000 out of 65535, which is impossible to hit with PC's 32767 range + try { auto getVehicleLightsStatus = get_pattern("DC 35 ? ? ? ? D9 05 ? ? ? ? D8 D9", 2); static const double LightStatusRandomnessThreshold = 25000.0; Patch(getVehicleLightsStatus, &LightStatusRandomnessThreshold); } + TXN_CATCH(); // Fixed vehicles exploding twice if the driver leaves the car while it's exploding + try { using namespace RemoveDriverStatusFix; @@ -7057,9 +7229,11 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) Nop(removeThisPed, 3); Nop(taskSimpleCarSetPedOut, 3); } + TXN_CATCH(); // Fixed falling stars rendering black + try { using namespace ShootingStarsFix; @@ -7067,9 +7241,11 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) InterceptCall(rwIm3dTransform, orgRwIm3DTransform, RwIm3DTransform_UnsetTexture); } + TXN_CATCH(); // Enable directional lights on flying car components + try { using namespace LitFlyingComponents; @@ -7077,12 +7253,14 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) InterceptCall(worldAdd, orgWorldAdd, WorldAdd_SetLightObjectFlag); } + TXN_CATCH(); // Fix the logic behind exploding cars losing wheels // Right now, they lose one wheel at random according to the damage manager, but they always lose the front left wheel visually. // This change matches the visuals to the physics // Also make it possible for the rear right wheel to be randomly picked + try { auto automobileBlowUp = pattern("E8 ? ? ? ? 8B 8E ? ? ? ? 8D 45 08").get_one(); auto automobileBlowUpCutscene = pattern("E8 ? ? ? ? 80 7D 10 00 C7 45").get_one(); @@ -7106,9 +7284,11 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) static const double fRandomness = -4.0; Patch(wheelDetachRandomness, &fRandomness); } + TXN_CATCH(); // Make script randomness 16-bit, like on PS2 + try { using namespace Rand16bit; @@ -7119,6 +7299,7 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) HookEach_Rand(rands, InterceptCall); } + TXN_CATCH(); } diff --git a/SilentPatchSA/SilentPatchSA.vcxproj b/SilentPatchSA/SilentPatchSA.vcxproj index 8860681..3a98b0b 100644 --- a/SilentPatchSA/SilentPatchSA.vcxproj +++ b/SilentPatchSA/SilentPatchSA.vcxproj @@ -97,7 +97,6 @@ true false stdcpp17 - false Windows @@ -137,7 +136,6 @@ copy /y "$(TargetPath)" "H:\Rockstar Games\Grand Theft Auto San Andreas\SilentPa true false stdcpp17 - false true @@ -179,7 +177,6 @@ copy /y "$(TargetPath)" "H:\Rockstar Games\Grand Theft Auto San Andreas\SilentPa true false stdcpp17 - false true diff --git a/SilentPatchVC/SilentPatchVC.cpp b/SilentPatchVC/SilentPatchVC.cpp index f3132a5..38b21fd 100644 --- a/SilentPatchVC/SilentPatchVC.cpp +++ b/SilentPatchVC/SilentPatchVC.cpp @@ -717,7 +717,7 @@ namespace VariableResets void InjectDelayedPatches_VC_Common( bool bHasDebugMenu, const wchar_t* wcModulePath ) { using namespace Memory; - using namespace hook; + using namespace hook::txn; const ModuleList moduleList; @@ -749,139 +749,124 @@ void InjectDelayedPatches_VC_Common( bool bHasDebugMenu, const wchar_t* wcModule if ( GetPrivateProfileIntW(L"SilentPatch", L"EnableVehicleCoronaFixes", -1, wcModulePath) == 1 ) { // Other mods might be touching it, so only patch specific vehicles if their code has not been touched at all + try { - auto firetruck1 = pattern( "8D 8C 24 24 09 00 00 FF 35 ? ? ? ? FF 35 ? ? ? ? FF 35" ); - auto firetruck2 = pattern( "8D 8C 24 30 09 00 00 FF 35 ? ? ? ? FF 35 ? ? ? ? FF 35" ); + auto firetruck1 = pattern("8D 8C 24 24 09 00 00 FF 35 ? ? ? ? FF 35 ? ? ? ? FF 35").get_one(); + auto firetruck2 = pattern("8D 8C 24 30 09 00 00 FF 35 ? ? ? ? FF 35 ? ? ? ? FF 35").get_one(); - if ( firetruck1.count_hint(1).size() == 1 && firetruck2.count_hint(1).size() == 1 ) - { - static const CVector FIRETRUCK_SIREN_POS(0.95f, 3.2f, 1.4f); - static const float FIRETRUCK_SIREN_MINUS_X = -FIRETRUCK_SIREN_POS.x; + static const CVector FIRETRUCK_SIREN_POS(0.95f, 3.2f, 1.4f); + static const float FIRETRUCK_SIREN_MINUS_X = -FIRETRUCK_SIREN_POS.x; - auto match1 = firetruck1.get_one(); - auto match2 = firetruck2.get_one(); + Patch( firetruck1.get( 7 + 2 ), &FIRETRUCK_SIREN_POS.z ); + Patch( firetruck1.get( 7 + 2 + (6*1) ), &FIRETRUCK_SIREN_POS.y ); + Patch( firetruck1.get( 7 + 2 + (6*2) ), &FIRETRUCK_SIREN_POS.x ); - Patch( match1.get( 7 + 2 ), &FIRETRUCK_SIREN_POS.z ); - Patch( match1.get( 7 + 2 + (6*1) ), &FIRETRUCK_SIREN_POS.y ); - Patch( match1.get( 7 + 2 + (6*2) ), &FIRETRUCK_SIREN_POS.x ); - - Patch( match2.get( 7 + 2 ), &FIRETRUCK_SIREN_POS.z ); - Patch( match2.get( 7 + 2 + (6*1) ), &FIRETRUCK_SIREN_POS.y ); - Patch( match2.get( 7 + 2 + (6*2) ), &FIRETRUCK_SIREN_MINUS_X ); - } + Patch( firetruck2.get( 7 + 2 ), &FIRETRUCK_SIREN_POS.z ); + Patch( firetruck2.get( 7 + 2 + (6*1) ), &FIRETRUCK_SIREN_POS.y ); + Patch( firetruck2.get( 7 + 2 + (6*2) ), &FIRETRUCK_SIREN_MINUS_X ); } + TXN_CATCH(); + + try { - auto ambulan1 = pattern( "8D 8C 24 0C 09 00 00 FF 35 ? ? ? ? FF 35 ? ? ? ? FF 35" ); - auto ambulan2 = pattern( "8D 8C 24 18 09 00 00 FF 35 ? ? ? ? FF 35 ? ? ? ? FF 35" ); + auto ambulan1 = pattern("8D 8C 24 0C 09 00 00 FF 35 ? ? ? ? FF 35 ? ? ? ? FF 35").get_one(); + auto ambulan2 = pattern("8D 8C 24 18 09 00 00 FF 35 ? ? ? ? FF 35 ? ? ? ? FF 35").get_one(); - if ( ambulan1.count_hint(1).size() == 1 && ambulan2.count_hint(1).size() == 1 ) - { - static const CVector AMBULANCE_SIREN_POS(0.7f, 0.65f, 1.55f); - static const float AMBULANCE_SIREN_MINUS_X = -AMBULANCE_SIREN_POS.x; + static const CVector AMBULANCE_SIREN_POS(0.7f, 0.65f, 1.55f); + static const float AMBULANCE_SIREN_MINUS_X = -AMBULANCE_SIREN_POS.x; - auto match1 = ambulan1.get_one(); - auto match2 = ambulan2.get_one(); + Patch( ambulan1.get( 7 + 2 ), &AMBULANCE_SIREN_POS.z ); + Patch( ambulan1.get( 7 + 2 + (6*1) ), &AMBULANCE_SIREN_POS.y ); + Patch( ambulan1.get( 7 + 2 + (6*2) ), &AMBULANCE_SIREN_POS.x ); - Patch( match1.get( 7 + 2 ), &AMBULANCE_SIREN_POS.z ); - Patch( match1.get( 7 + 2 + (6*1) ), &AMBULANCE_SIREN_POS.y ); - Patch( match1.get( 7 + 2 + (6*2) ), &AMBULANCE_SIREN_POS.x ); - - Patch( match2.get( 7 + 2 ), &AMBULANCE_SIREN_POS.z ); - Patch( match2.get( 7 + 2 + (6*1) ), &AMBULANCE_SIREN_POS.y ); - Patch( match2.get( 7 + 2 + (6*2) ), &AMBULANCE_SIREN_MINUS_X ); - } + Patch( ambulan2.get( 7 + 2 ), &AMBULANCE_SIREN_POS.z ); + Patch( ambulan2.get( 7 + 2 + (6*1) ), &AMBULANCE_SIREN_POS.y ); + Patch( ambulan2.get( 7 + 2 + (6*2) ), &AMBULANCE_SIREN_MINUS_X ); } + TXN_CATCH(); + + try { - auto police1 = pattern( "8D 8C 24 DC 08 00 00 FF 35 ? ? ? ? FF 35 ? ? ? ? FF 35" ); - auto police2 = pattern( "8D 8C 24 E8 08 00 00 FF 35 ? ? ? ? FF 35 ? ? ? ? FF 35" ); + auto police1 = pattern("8D 8C 24 DC 08 00 00 FF 35 ? ? ? ? FF 35 ? ? ? ? FF 35").get_one(); + auto police2 = pattern("8D 8C 24 E8 08 00 00 FF 35 ? ? ? ? FF 35 ? ? ? ? FF 35").get_one(); - if ( police1.count_hint(1).size() == 1 && police2.count_hint(1).size() == 1 ) - { - static const CVector POLICE_SIREN_POS(0.55f, -0.4f, 0.95f); - static const float POLICE_SIREN_MINUS_X = -POLICE_SIREN_POS.x; + static const CVector POLICE_SIREN_POS(0.55f, -0.4f, 0.95f); + static const float POLICE_SIREN_MINUS_X = -POLICE_SIREN_POS.x; - auto match1 = police1.get_one(); - auto match2 = police2.get_one(); + Patch( police1.get( 7 + 2 ), &POLICE_SIREN_POS.z ); + Patch( police1.get( 7 + 2 + (6*1) ), &POLICE_SIREN_POS.y ); + Patch( police1.get( 7 + 2 + (6*2) ), &POLICE_SIREN_POS.x ); - Patch( match1.get( 7 + 2 ), &POLICE_SIREN_POS.z ); - Patch( match1.get( 7 + 2 + (6*1) ), &POLICE_SIREN_POS.y ); - Patch( match1.get( 7 + 2 + (6*2) ), &POLICE_SIREN_POS.x ); - - Patch( match2.get( 7 + 2 ), &POLICE_SIREN_POS.z ); - Patch( match2.get( 7 + 2 + (6*1) ), &POLICE_SIREN_POS.y ); - Patch( match2.get( 7 + 2 + (6*2) ), &POLICE_SIREN_MINUS_X ); - } + Patch( police2.get( 7 + 2 ), &POLICE_SIREN_POS.z ); + Patch( police2.get( 7 + 2 + (6*1) ), &POLICE_SIREN_POS.y ); + Patch( police2.get( 7 + 2 + (6*2) ), &POLICE_SIREN_MINUS_X ); } + TXN_CATCH(); + + try { - auto enforcer1 = pattern( "8D 8C 24 F4 08 00 00 FF 35 ? ? ? ? FF 35 ? ? ? ? FF 35" ); - auto enforcer2 = pattern( "8D 8C 24 00 09 00 00 FF 35 ? ? ? ? FF 35 ? ? ? ? FF 35" ); + auto enforcer1 = pattern("8D 8C 24 F4 08 00 00 FF 35 ? ? ? ? FF 35 ? ? ? ? FF 35").get_one(); + auto enforcer2 = pattern("8D 8C 24 00 09 00 00 FF 35 ? ? ? ? FF 35 ? ? ? ? FF 35").get_one(); - if ( enforcer1.count_hint(1).size() == 1 && enforcer2.count_hint(1).size() == 1 ) - { - static const CVector ENFORCER_SIREN_POS(0.6f, 1.05f, 1.4f); - static const float ENFORCER_SIREN_MINUS_X = -ENFORCER_SIREN_POS.x; + static const CVector ENFORCER_SIREN_POS(0.6f, 1.05f, 1.4f); + static const float ENFORCER_SIREN_MINUS_X = -ENFORCER_SIREN_POS.x; - auto match1 = enforcer1.get_one(); - auto match2 = enforcer2.get_one(); + Patch( enforcer1.get( 7 + 2 ), &ENFORCER_SIREN_POS.z ); + Patch( enforcer1.get( 7 + 2 + (6*1) ), &ENFORCER_SIREN_POS.y ); + Patch( enforcer1.get( 7 + 2 + (6*2) ), &ENFORCER_SIREN_POS.x ); - Patch( match1.get( 7 + 2 ), &ENFORCER_SIREN_POS.z ); - Patch( match1.get( 7 + 2 + (6*1) ), &ENFORCER_SIREN_POS.y ); - Patch( match1.get( 7 + 2 + (6*2) ), &ENFORCER_SIREN_POS.x ); - - Patch( match2.get( 7 + 2 ), &ENFORCER_SIREN_POS.z ); - Patch( match2.get( 7 + 2 + (6*1) ), &ENFORCER_SIREN_POS.y ); - Patch( match2.get( 7 + 2 + (6*2) ), &ENFORCER_SIREN_MINUS_X ); - } + Patch( enforcer2.get( 7 + 2 ), &ENFORCER_SIREN_POS.z ); + Patch( enforcer2.get( 7 + 2 + (6*1) ), &ENFORCER_SIREN_POS.y ); + Patch( enforcer2.get( 7 + 2 + (6*2) ), &ENFORCER_SIREN_MINUS_X ); } - { - auto chopper1 = pattern( "C7 44 24 44 00 00 E0 40 50 C7 44 24 4C 00 00 00 00" ); // Front light - auto chopper2 = pattern( "C7 44 24 6C 00 00 10 C1 8D 44 24 5C C7 44 24 70 00 00 00 00" ); // Tail light + TXN_CATCH(); - if ( chopper1.count_hint(1).size() == 1 ) + { + try { + auto chopper1 = pattern("C7 44 24 44 00 00 E0 40 50 C7 44 24 4C 00 00 00 00").get_one(); // Front light + constexpr CVector CHOPPER_SEARCH_LIGHT_POS(0.0f, 3.0f, -1.0f); // Same as in III Aircraft (not implemented there yet!) - auto match = chopper1.get_one(); - - Patch( match.get( 4 ), CHOPPER_SEARCH_LIGHT_POS.y ); - Patch( match.get( 9 + 4 ), CHOPPER_SEARCH_LIGHT_POS.z ); + Patch( chopper1.get( 4 ), CHOPPER_SEARCH_LIGHT_POS.y ); + Patch( chopper1.get( 9 + 4 ), CHOPPER_SEARCH_LIGHT_POS.z ); } + TXN_CATCH(); - if ( chopper2.count_hint(1).size() == 1 ) + try { + auto chopper2 = pattern("C7 44 24 6C 00 00 10 C1 8D 44 24 5C C7 44 24 70 00 00 00 00").get_one(); // Tail light + constexpr CVector CHOPPER_RED_LIGHT_POS(0.0f, -7.5f, 2.5f); // Same as in III Aircraft - auto match = chopper2.get_one(); - - Patch( match.get( 4 ), CHOPPER_RED_LIGHT_POS.y ); - Patch( match.get( 12 + 4 ), CHOPPER_RED_LIGHT_POS.z ); + Patch( chopper2.get( 4 ), CHOPPER_RED_LIGHT_POS.y ); + Patch( chopper2.get( 12 + 4 ), CHOPPER_RED_LIGHT_POS.z ); } + TXN_CATCH(); } + + try { using namespace FBISirenCoronaFix; - auto hasFBISiren = pattern( "83 E9 04 0F 84 87 0A 00 00 83 E9 10" ); // Predicate for showing FBI/Vice Squad siren - auto viceCheetah = pattern( "8D 8C 24 CC 09 00 00 FF 35 ? ? ? ? FF 35 ? ? ? ? FF 35 ? ? ? ? E8" ); // Siren pos + auto viceCheetah = pattern("8D 8C 24 CC 09 00 00 FF 35 ? ? ? ? FF 35 ? ? ? ? FF 35 ? ? ? ? E8").get_one(); // Siren pos - if ( viceCheetah.count_hint(1).size() == 1 ) + try { - auto match = viceCheetah.get_one(); + auto hasFBISiren = pattern("83 E9 04 0F 84 87 0A 00 00 83 E9 10").get_one(); // Predicate for showing FBI/Vice Squad siren - if ( hasFBISiren.count_hint(1).size() == 1 ) - { - auto matchSiren = hasFBISiren.get_one(); + Patch( hasFBISiren.get(), 0x55 ); // push ebp + InjectHook( hasFBISiren.get( 1 ), SetUpFBISiren, HookType::Call ); + Patch( hasFBISiren.get( 1 + 5 ), { 0x83, 0xC4, 0x04, 0x84, 0xC0, 0x90 } ); // add esp, 4 / test al, al / nop - Patch( matchSiren.get(), 0x55 ); // push ebp - InjectHook( matchSiren.get( 1 ), SetUpFBISiren, HookType::Call ); - Patch( matchSiren.get( 1 + 5 ), { 0x83, 0xC4, 0x04, 0x84, 0xC0, 0x90 } ); // add esp, 4 / test al, al / nop - - InjectHook( match.get( 0x19 ), SetUpVector ); - } - - static const float VICE_CHEETAH_SIREN_POS_Z = 0.25f; - Patch( match.get( 7 + 2 ), &VICE_CHEETAH_SIREN_POS_Z ); + InjectHook( viceCheetah.get( 0x19 ), SetUpVector ); } + TXN_CATCH(); + + static const float VICE_CHEETAH_SIREN_POS_Z = 0.25f; + Patch( viceCheetah.get( 7 + 2 ), &VICE_CHEETAH_SIREN_POS_Z ); } + TXN_CATCH(); } FLAUtils::Init(moduleList); @@ -1180,9 +1165,10 @@ void Patch_VC_JP() void Patch_VC_Common() { using namespace Memory; - using namespace hook; + using namespace hook::txn; // New timers fix + try { auto hookPoint = pattern( "83 E4 F8 89 44 24 08 C7 44 24 0C 00 00 00 00 DF 6C 24 08" ).get_one(); auto jmpPoint = get_pattern( "DD D8 E9 31 FF FF FF" ); @@ -1190,8 +1176,11 @@ void Patch_VC_Common() InjectHook( hookPoint.get( 0x21 ), CTimer::Update_SilentPatch, HookType::Call ); InjectHook( hookPoint.get( 0x21 + 5 ), jmpPoint, HookType::Jump ); } + TXN_CATCH(); + // Alt+F4 + try { auto addr = pattern( "59 59 31 C0 83 C4 70 5D 5F 5E 5B C2 10 00" ).count(2); auto dest = get_pattern( "53 55 56 FF B4 24 90 00 00 00 FF 15" ); @@ -1200,8 +1189,11 @@ void Patch_VC_Common() InjectHook( match.get( 2 ), dest, HookType::Jump ); }); } + TXN_CATCH(); + // Proper panels damage + try { auto addr = pattern( "C6 41 09 03 C6 41 0A 03 C6 41 0B 03" ).get_one(); @@ -1212,20 +1204,27 @@ void Patch_VC_Common() Nop( addr.get( 0x33 ), 7 ); } + TXN_CATCH(); + // Proper metric-imperial conversion constants + try { static const float METERS_TO_MILES = 0.0006213711922f; auto addr = pattern( "75 ? D9 05 ? ? ? ? D8 0D ? ? ? ? 6A 00 6A 00 D9 9C 24" ).count(6); + auto sum = get_pattern( "D9 9C 24 A8 00 00 00 8D 84 24 A8 00 00 00 50", -6 + 2 ); + addr.for_each_result( [&]( pattern_match match ) { Patch( match.get( 0x8 + 2 ), &METERS_TO_MILES ); }); - auto sum = get_pattern( "D9 9C 24 A8 00 00 00 8D 84 24 A8 00 00 00 50", -6 + 2 ); Patch( sum, &METERS_TO_MILES ); } + TXN_CATCH(); + // Improved pathfinding in PickNextNodeAccordingStrategy - PickNextNodeToChaseCar with XYZ coords + try { auto addr = pattern( "E8 ? ? ? ? 50 8D 44 24 10 50 E8" ).get_one(); ReadCall( addr.get( 0x25 ), orgPickNextNodeToChaseCar ); @@ -1258,25 +1257,31 @@ void Patch_VC_Common() InjectHook( addr.get( 0x46 ), PickNextNodeToChaseCarXYZ ); Patch( addr.get( 0x4B + 2 ), 0xC ); } + TXN_CATCH(); // No censorships + try { auto addr = get_pattern( "8B 43 50 85 C0 8B 53 50 74 2B 83 E8 01" ); Patch( addr, { 0x83, 0xC4, 0x08, 0x5B, 0xC3 } ); // add esp, 8 \ pop ebx \ retn } + TXN_CATCH(); // 014C cargen counter fix (by spaceeinstein) + try { auto do_processing = pattern( "0F B7 43 28 83 F8 FF 7D 04 66 FF 4B 28" ).get_one(); Patch( do_processing.get(1), 0xBF ); // movzx eax, word ptr [ebx+28h] -> movsx eax, word ptr [ebx+28h] Patch( do_processing.get(7), 0x74 ); // jge -> jz } + TXN_CATCH(); // Fixed ammo from SCM + try { using namespace ZeroAmmoFix; @@ -1286,16 +1291,20 @@ void Patch_VC_Common() }; HookEach_GiveWeapon(give_weapon, InterceptCall); } + TXN_CATCH(); // Extras working correctly on bikes + try { auto createInstance = get_pattern( "89 C1 8B 41 04" ); InjectHook( createInstance, CreateInstance_BikeFix, HookType::Call ); } + TXN_CATCH(); // Credits =) + try { auto renderCredits = pattern( "8D 44 24 28 83 C4 14 50 FF 35 ? ? ? ? E8 ? ? ? ? 8D 44 24 1C 59 59 50 FF 35 ? ? ? ? E8 ? ? ? ? 59 59" ).get_one(); @@ -1303,9 +1312,11 @@ void Patch_VC_Common() ReadCall( renderCredits.get( -5 ), Credits::PrintCreditText_Hooked ); InjectHook( renderCredits.get( -5 ), Credits::PrintSPCredits ); } + TXN_CATCH(); // Decreased keyboard input latency + try { using namespace KeyboardInputFix; @@ -1321,42 +1332,44 @@ void Patch_VC_Common() InjectHook( simButtonCheckers, ClearSimButtonPressCheckers ); InjectHook( updatePads.get( 9 ), jmpDest, HookType::Jump ); } + TXN_CATCH(); // Locale based metric/imperial system + try { using namespace Localization; void* updateCompareFlag = get_pattern( "89 D9 6A 00 E8 ? ? ? ? 30 C0 83 C4 70 5D 5F 5E 5B C2 04 00", 4 ); + auto constructStatLine = pattern( "85 C0 74 11 83 E8 01 83 F8 03" ).get_one(); ReadCall( updateCompareFlag, orgUpdateCompareFlag_IsMetric ); InjectHook( updateCompareFlag, UpdateCompareFlag_IsMetric ); // Stats - auto constructStatLine = pattern( "85 C0 74 11 83 E8 01 83 F8 03" ).get_one(); - Nop( constructStatLine.get( -11 ), 1 ); InjectHook( constructStatLine.get( -11 + 1 ), PrefsLanguage_IsMetric, HookType::Call ); Nop( constructStatLine.get( -2 ), 2 ); } + TXN_CATCH(); // Corrected FBI Washington sirens sound // Primary siren lower pitched like in FBI Rancher and secondary siren higher pitched + try { using namespace SirenSwitchingFix; // Other mods might be touching it, so only patch specific vehicles if their code has not been touched at all - auto sirenPitch = pattern( "83 F8 17 74 32" ).count_hint(1); - if ( sirenPitch.size() == 1 ) + auto sirenPitch = pattern( "83 F8 17 74 32" ).get_one(); + + InjectHook( sirenPitch.get( 5 ), IsFBIRanchOrFBICar, HookType::Call ); + Patch( sirenPitch.get( 5 + 5 ), { 0x84, 0xC0 } ); // test al, al + Nop( sirenPitch.get( 5 + 5 + 2 ), 4 ); + + // Pitch shift FBI Washington primary siren + try { - auto match = sirenPitch.get_one(); - - InjectHook( match.get( 5 ), IsFBIRanchOrFBICar, HookType::Call ); - Patch( match.get( 5 + 5 ), { 0x84, 0xC0 } ); // test al, al - Nop( match.get( 5 + 5 + 2 ), 4 ); - - // Pitch shift FBI Washington primary siren struct tVehicleSampleData { int m_nAccelerationSampleIndex; char m_bEngineSoundType; @@ -1375,20 +1388,25 @@ void Patch_VC_Common() dataTable[17].m_nSirenOrAlarmFrequency = dataTable[90].m_nSirenOrAlarmFrequency; } } + TXN_CATCH(); } + TXN_CATCH(); // Allow extra6 to be picked with component rule 4 (any) + try { void* extraMult6 = get_pattern( "D8 0D ? ? ? ? D9 7C 24 04 8B 44 24 04 80 4C 24 05 0C D9 6C 24 04 89 44 24 04 DB 5C 24 08 D9 6C 24 04 8B 44 24 08 83 C4 10 5D", 2 ); static const float MULT_6 = 6.0f; Patch( extraMult6, &MULT_6 ); } + TXN_CATCH(); // Make drive-by one shot sounds owned by the driver instead of the car // Fixes incorrect weapon sound being used for drive-by + try { auto getDriverOneShot = pattern( "FF 35 ? ? ? ? 6A 37 50 E8 ? ? ? ? 83 7E 08 00" ).get_one(); @@ -1398,9 +1416,11 @@ void Patch_VC_Common() Patch( getDriverOneShot.get( -8 ), { 0x90, 0x89, 0xD9 } ); InjectHook( getDriverOneShot.get( -5 ), &CVehicle::GetOneShotOwnerID_SilentPatch, HookType::Call ); } + TXN_CATCH(); // Fixed vehicles exploding twice if the driver leaves the car while it's exploding + try { using namespace RemoveDriverStatusFix; @@ -1419,9 +1439,11 @@ void Patch_VC_Common() Nop(removeThisPed, 3); Nop(pedSetOutCar, 3); } + TXN_CATCH(); // Apply the environment mapping on extra components + try { using namespace EnvMapsOnExtras; @@ -1431,17 +1453,21 @@ void Patch_VC_Common() Patch(forAllAtomics.get(), 0x53); InterceptCall(forAllAtomics.get(1), orgRpClumpForAllAtomics, RpClumpForAllAtomics_ExtraComps); } + TXN_CATCH(); // Fix probabilities in CVehicle::InflictDamage incorrectly assuming a random range from 0 to 100.000 + try { auto probability = get_pattern("66 81 7B 5A ? ? 73 50", 4); Patch(probability, 35000u / 2u); } + TXN_CATCH(); // Null terminate read lines in CPlane::LoadPath + try { using namespace NullTerminatedLines; @@ -1449,9 +1475,11 @@ void Patch_VC_Common() InterceptCall(loadPath, orgSscanf_LoadPath, sscanf1_LoadPath_Terminate); } + TXN_CATCH(); // Don't reset mouse sensitivity on New Game + try { using namespace MouseSensNewGame; @@ -1464,9 +1492,11 @@ void Patch_VC_Common() Nop(cameraInit.get(20), 10); InterceptCall(setDirMyDocuments, orgSetDirMyDocuments, SetDirMyDocuments_ResetMouse); } + TXN_CATCH(); // Fixed pickup effects + try { using namespace PickupEffectsFixes; @@ -1479,22 +1509,24 @@ void Patch_VC_Common() // Don't spawn the grenade together with the detonator in the pickup // FLA might be altering this due to the usage of 16-bit IDs? Just in case allow for graceful failure - auto pickupExtraObject = pattern("75 04 66 8B 70 58").count_hint(1); - if (pickupExtraObject.size() == 1) + try { - auto match = pickupExtraObject.get_one(); + auto pickupExtraObject = pattern("75 04 66 8B 70 58").get_one(); - Nop(match.get(), 1); - InjectHook(match.get(1), &PickUpEffects_GiveUsAnObject, HookType::Call); + Nop(pickupExtraObject.get(), 1); + InjectHook(pickupExtraObject.get(1), &PickUpEffects_GiveUsAnObject, HookType::Call); } + TXN_CATCH(); InjectHook(bigDollarColor, &PickUpEffects_BigDollarColor, HookType::Call); InjectHook(minigun2Glow, &PickUpEffects_Minigun2Glow, HookType::Call); } + TXN_CATCH(); // Fixed the muzzle flash facing the wrong direction // By Wesser + try { auto fireInstantHit = pattern("D9 44 24 50 D8 44 24 44").get_one(); @@ -1503,11 +1535,13 @@ void Patch_VC_Common() Patch(fireInstantHit.get(15), { 0xD9, 0xEE, 0x90, 0x90 }); Patch(fireInstantHit.get(30), { 0xD9, 0xEE, 0x90, 0x90 }); } + TXN_CATCH(); // Fixed IS_PLAYER_TARGETTING_CHAR incorrectly detecting targetting in Classic controls // when the player is not aiming // By Wesser + try { using namespace IsPlayerTargettingCharFix; @@ -1525,17 +1559,21 @@ void Patch_VC_Common() memmove(isPlayerTargettingChar.get(), isPlayerTargettingChar.get(5), 5); InjectHook(isPlayerTargettingChar.get(5), IsPlayerTargettingChar_ExtraChecks, HookType::Call); } + TXN_CATCH(); // Use PS2 randomness for Rosenberg audio to hopefully bring the odds closer to PS2 // The functionality was never broken on PC - but the random distribution seemingly made it looks as if it was + try { auto busted_audio_rand = get_pattern("80 BB 48 01 00 00 00 0F 85 ? ? ? ? E8 ? ? ? ? 25 FF FF 00 00", 13); InjectHook(busted_audio_rand, rand15_ps2); } + TXN_CATCH(); // Reset variables on New Game + try { using namespace VariableResets; @@ -1553,30 +1591,28 @@ void Patch_VC_Common() GameVariablesToReset.emplace_back(*get_pattern("7D 78 A1 ? ? ? ? 05", 2 + 1)); // LastTimeAmbulanceCreated GameVariablesToReset.emplace_back(*get_pattern("A1 ? ? ? ? 05 ? ? ? ? 39 05 ? ? ? ? 0F 86 ? ? ? ? 8B 15", 1)); // LastTimeFireTruckCreated } + TXN_CATCH(); // Ped speech fix // Based off Sergenaur's fix + try { // Remove the artificial 6s delay between any ped speech samples - auto delay_check = pattern("80 BE ? ? ? ? ? 0F 85 ? ? ? ? B9"); - auto comment_delay_id1 = pattern("0F B7 C2 DD D8 C1 E0 04"); - auto comment_delay_id2 = pattern("0F B7 95 DA 05 00 00 D9 6C 24 04"); + auto delay_check = get_pattern("80 BE ? ? ? ? ? 0F 85 ? ? ? ? B9", 7); + auto comment_delay_id1 = get_pattern("0F B7 C2 DD D8 C1 E0 04"); + auto comment_delay_id2 = pattern("0F B7 95 DA 05 00 00 D9 6C 24 04").get_one(); - // Make sure we don't conflict with Sergenaur's fix - if (delay_check.count_hint(1).size() == 1 && comment_delay_id1.count_hint(1).size() == 1 && comment_delay_id2.count_hint(1).size() == 1) - { - Nop(delay_check.get_first(7), 6); + Nop(delay_check, 6); - // movzx eax, dx -> movzx eax, bx - Patch(comment_delay_id1.get_first(), { 0x0F, 0xB7, 0xC3 }); + // movzx eax, dx -> movzx eax, bx + Patch(comment_delay_id1, { 0x0F, 0xB7, 0xC3 }); - // movzx edx, word ptr [ebp+5DAh] -> movzx edx, bx \ nop - auto delay_id2 = comment_delay_id2.get_one(); - Patch(delay_id2.get(), { 0x0F, 0xB7, 0xD3 }); - Nop(delay_id2.get(3), 4); - } + // movzx edx, word ptr [ebp+5DAh] -> movzx edx, bx \ nop + Patch(comment_delay_id2.get(), { 0x0F, 0xB7, 0xD3 }); + Nop(comment_delay_id2.get(3), 4); } + TXN_CATCH(); } BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) diff --git a/SilentPatchVC/SilentPatchVC.vcxproj b/SilentPatchVC/SilentPatchVC.vcxproj index 4ad056c..eda5695 100644 --- a/SilentPatchVC/SilentPatchVC.vcxproj +++ b/SilentPatchVC/SilentPatchVC.vcxproj @@ -82,7 +82,6 @@ NoExtensions /Zc:threadSafeInit- /Zc:strictStrings %(AdditionalOptions) true - false true false stdcpp17 @@ -114,7 +113,6 @@ NoExtensions /Zc:threadSafeInit- /Zc:strictStrings %(AdditionalOptions) true - false true false stdcpp17 @@ -148,7 +146,6 @@ NoExtensions /Zc:threadSafeInit- /Zc:strictStrings %(AdditionalOptions) true - false true false stdcpp17