Migrate to transactional patterns

This commit is contained in:
Silent 2024-05-16 23:43:48 +02:00
parent 6ee676400b
commit d4374df50a
No known key found for this signature in database
GPG Key ID: AE53149BB0C45AF1
9 changed files with 706 additions and 439 deletions

View File

@ -75,7 +75,6 @@
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\SilentPatch;..\DDraw;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>false</ExceptionHandling>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<EnforceTypeConversionRules>true</EnforceTypeConversionRules>
@ -107,7 +106,6 @@ copy /y "$(TargetPath)" "D:\Steam\steamapps\common\Grand Theft Auto Vice City\dd
<AdditionalIncludeDirectories>..\SilentPatch;..\DDraw;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>false</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<EnforceTypeConversionRules>true</EnforceTypeConversionRules>
@ -141,7 +139,6 @@ copy /y "$(TargetPath)" "D:\Steam\steamapps\common\Grand Theft Auto Vice City\dd
<AdditionalIncludeDirectories>..\SilentPatch;..\DDraw;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_HAS_EXCEPTIONS=0;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<ExceptionHandling>false</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<EnforceTypeConversionRules>true</EnforceTypeConversionRules>

View File

@ -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<decltype(OldSetPreference)*>(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<void>( -5 ), strncpy_Fix );
InjectHook( findExactWord.get<void>( 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<void>( -14 ), ResetCompsForNoExtras, HookType::Call );
Nop( resetComps.get<void>( -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<const void*>(match.get<void>(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<uint8_t>( match.get<void>( -15 ), 0x55 ); // push eax -> push ebp
InjectHook( match.get<void>(), GetTransformedCoronaPos );
}
}
Patch<uint8_t>( getTaxiLightPos.get<void>( -15 ), 0x55 ); // push eax -> push ebp
InjectHook( getTaxiLightPos.get<void>(), GetTransformedCoronaPos );
}
TXN_CATCH();
}
}
}

View File

@ -39,23 +39,35 @@ 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<uintptr_t>(GetModuleHandle(nullptr));
PIMAGE_DOS_HEADER dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(module);
PIMAGE_NT_HEADERS ntHeader = reinterpret_cast<PIMAGE_NT_HEADERS>(module + dosHeader->e_lfanew);
if ( begin.count_hint(1).size() == 1 && end.count_hint(1).size() == 1 )
{
const ptrdiff_t size = (intptr_t)end.get_first( 24 ) - (intptr_t)begin.get_first();
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<void>();
auto end = make_range_pattern(moduleBegin, moduleEnd, "9B D9 3D ? ? ? ? 81 25 ? ? ? ? FF FC FF FF 83 0D ? ? ? ? 3F").get_first<void>(31);
const ptrdiff_t size = reinterpret_cast<uintptr_t>(end) - reinterpret_cast<uintptr_t>(begin);
if ( size > 0 )
{
DWORD dwProtect;
VirtualProtect( begin.get_first(), size, PAGE_EXECUTE_READ, &dwProtect );
VirtualProtect( begin, size, PAGE_EXECUTE_READ, &dwProtect );
return true;
}
return false;
}
catch (const hook::txn_exception&)
{
return false;
}
@ -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<uint8_t>( mem.get_first( 0x12 ), 0xEB );
}
auto mem = get_pattern("81 7C 24 04 00 08 00 00", 0x12);
Patch<uint8_t>( 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<void>( 0x25 ), { 0x6A, 0x00 } ); // push 0 \ nop
Nop( mem.get<void>( 0x25 + 2 ), 3 );
}
TXN_CATCH();
}
}
}

View File

@ -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<int8_t>( canPickBlista.get_first<void>( 2 ), 127 ); // coach
}
auto canPickBlista = get_pattern("83 FA 66 74", 2);
Patch<int8_t>( 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);
Patch<float>( firetruckX1.get_first( 7 ), FIRETRUCK_SIREN_POS.x );
Patch<float>( firetruckY1.get_first( 7 ), FIRETRUCK_SIREN_POS.y );
Patch<float>( firetruckZ1.get_first( 7 ), FIRETRUCK_SIREN_POS.z );
Patch<float>( firetruckX1, FIRETRUCK_SIREN_POS.x );
Patch<float>( firetruckY1, FIRETRUCK_SIREN_POS.y );
Patch<float>( firetruckZ1, FIRETRUCK_SIREN_POS.z );
Patch<float>( firetruckX2.get_first( 7 ), -FIRETRUCK_SIREN_POS.x );
Patch<float>( firetruckY2.get_first( 7 ), FIRETRUCK_SIREN_POS.y );
Patch<float>( firetruckZ2.get_first( 7 ), FIRETRUCK_SIREN_POS.z );
Patch<float>( firetruckX2, -FIRETRUCK_SIREN_POS.x );
Patch<float>( firetruckY2, FIRETRUCK_SIREN_POS.y );
Patch<float>( firetruckZ2, FIRETRUCK_SIREN_POS.z );
}
}
{
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" );
TXN_CATCH();
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" );
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 )
try
{
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 = 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);
constexpr CVector AMBULANCE_SIREN_POS(0.7f, 0.65f, 1.55f);
Patch<float>( ambulanceX1.get_first( 7 ), AMBULANCE_SIREN_POS.x );
Patch<float>( ambulanceY1.get_first( 7 ), AMBULANCE_SIREN_POS.y );
Patch<float>( ambulanceZ1.get_first( 7 ), AMBULANCE_SIREN_POS.z );
Patch<float>( ambulanceX1, AMBULANCE_SIREN_POS.x );
Patch<float>( ambulanceY1, AMBULANCE_SIREN_POS.y );
Patch<float>( ambulanceZ1, AMBULANCE_SIREN_POS.z );
Patch<float>( ambulanceX2.get_first( 7 ), -AMBULANCE_SIREN_POS.x );
Patch<float>( ambulanceY2.get_first( 7 ), AMBULANCE_SIREN_POS.y );
Patch<float>( ambulanceZ2.get_first( 7 ), AMBULANCE_SIREN_POS.z );
Patch<float>( ambulanceX2, -AMBULANCE_SIREN_POS.x );
Patch<float>( ambulanceY2, AMBULANCE_SIREN_POS.y );
Patch<float>( ambulanceZ2, AMBULANCE_SIREN_POS.z );
}
}
{
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" );
TXN_CATCH();
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" );
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 )
try
{
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 = 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);
constexpr CVector ENFORCER_SIREN_POS(0.6f, 1.05f, 1.4f);
Patch<float>( enforcerX1.get_first( 7 ), ENFORCER_SIREN_POS.x );
Patch<float>( enforcerY1.get_first( 7 ), ENFORCER_SIREN_POS.y );
Patch<float>( enforcerZ1.get_first( 7 ), ENFORCER_SIREN_POS.z );
Patch<float>( enforcerX1, ENFORCER_SIREN_POS.x );
Patch<float>( enforcerY1, ENFORCER_SIREN_POS.y );
Patch<float>( enforcerZ1, ENFORCER_SIREN_POS.z );
Patch<float>( enforcerX2.get_first( 7 ), -ENFORCER_SIREN_POS.x );
Patch<float>( enforcerY2.get_first( 7 ), ENFORCER_SIREN_POS.y );
Patch<float>( enforcerZ2.get_first( 7 ), ENFORCER_SIREN_POS.z );
Patch<float>( enforcerX2, -ENFORCER_SIREN_POS.x );
Patch<float>( enforcerY2, ENFORCER_SIREN_POS.y );
Patch<float>( enforcerZ2, ENFORCER_SIREN_POS.z );
}
}
{
auto chopper1 = pattern( "C7 44 24 44 00 00 E0 40 50 C7 44 24 4C 00 00 00 00" ); // Front 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.25f);
auto match = chopper1.get_one();
Patch( match.get<float>( 4 ), CHOPPER_SEARCH_LIGHT_POS.y );
Patch( match.get<float>( 9 + 4 ), CHOPPER_SEARCH_LIGHT_POS.z );
}
Patch( chopper1.get<float>( 4 ), CHOPPER_SEARCH_LIGHT_POS.y );
Patch( chopper1.get<float>( 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<void>(), orgUsesSirenSwitching );
InjectHook( match.get<void>(), UsesSirenSwitching_FbiCar );
}
auto usesSirenSwitching = pattern("E8 ? ? ? ? 84 C0 74 12 83 C4 08").get_one();
InterceptCall(usesSirenSwitching.get<void>(), 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<void>(), { 0x89, 0xD9 } );
InjectHook( match.get<void>( 2 ), &CSimpleModelInfo::SetNearDistanceForLOD_SilentPatch, HookType::Call );
}
Patch( setupMinDist.get<void>(), { 0x89, 0xD9 } );
InjectHook( setupMinDist.get<void>( 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<void>( 0x21 ), CTimer::Update_SilentPatch, HookType::Call );
InjectHook( hookPoint.get<void>( 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<void>( 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<uint8_t>( addr.get<void>( 0x23 + 1 ), 6 );
Nop( addr.get<void>( 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<const void*>( addr.get(2).get<void>( 2 ), &METERS_TO_FEET );
Patch<const void*>( addr.get(3).get<void>( 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<void>( 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<uint8_t>( do_processing.get<uint8_t*>(1), 0xBF ); // movzx eax, word ptr [ebx+28h] -> movsx eax, word ptr [ebx+28h]
Patch<uint8_t>( do_processing.get<uint8_t*>(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<void>( -5 ), Credits::PrintCreditText_Hooked );
InjectHook( renderCredits.get<void>( -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<void>( 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<void>( -0xF + 7 ), { 0x0F, 0xB6, 0xD8, 0x5A, 0x58 } );
Nop( constructStatLine.get<void>( -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<uintptr_t*>( "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<void>( 0 ), operatorNew );
InjectHook( processCommands300.get<void>( 0 ), operatorNew_InitializedCheck );
Patch<int8_t>( processCommands300.get<void>( 8 + 1 ), 0x440B62 - 0x440B24 );
auto processCommands300_2 = pattern( "6A 14 E8 ? ? ? ? 89 C3 59 85 DB 74" ).get_one();
InjectHook( processCommands300_2.get<void>( 2 ), operatorNew_InitializedCheck );
Patch<int8_t>( processCommands300_2.get<void>( 0xC + 1 ), 0x440BD7 - 0x440B8B );
// We need to patch switch cases 0, 3, 4
auto bulletInfoUpdate_Switch = *get_pattern<uintptr_t*>( "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<int8_t>( 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<void>( 2 ), operatorNew_InitializedCheck );
Patch<int8_t>( playlayOneShotScriptObject.get<void>( 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 )
{
auto initHelis = pattern( "C6 40 2C 00 A1" ).get_one();
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 = initHelisPattern.get_one();
Patch( initHelis.get<void>( -7 + 3 ), &colModelChopper );
Patch( initHelis.get<void>( 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<uint8_t>(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<void>(), 1);
InjectHook(setEvasiveDive.get<void>(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<uint16_t>(probability_do_nothing, 35000u * 32767u / 100000u);
Patch<uint32_t>(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<void>(), 2);
InjectHook(readTrackFile2.get<void>(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 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<void>(), orgConstructStatLine, ConstructStatLine_SetFontStyle);
}
InterceptCall(constructStatLine.get<void>(), 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<int*>("7D 72 A1 ? ? ? ? 05", 2 + 1)); // LastTimeAmbulanceCreated
GameVariablesToReset.emplace_back(*get_pattern<int*>("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<void*>(7 + 2);
InterceptCall(give_us_a_pick_up_object.get<void>(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<void>(), { 0x31, 0xC0 });
Nop(match.get<void>(2), 3);
}
Patch(reflection.get<void>(), { 0x31, 0xC0 });
Nop(reflection.get<void>(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<uint8_t>(spawn_one_car, 0xEB);
}
TXN_CATCH();
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)

View File

@ -152,7 +152,6 @@
<LanguageStandard>stdcpp17</LanguageStandard>
<EnforceTypeConversionRules>true</EnforceTypeConversionRules>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<ExceptionHandling>false</ExceptionHandling>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -186,7 +185,6 @@
<LanguageStandard>stdcpp17</LanguageStandard>
<EnforceTypeConversionRules>true</EnforceTypeConversionRules>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<ExceptionHandling>false</ExceptionHandling>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
@ -222,7 +220,6 @@
<LanguageStandard>stdcpp17</LanguageStandard>
<EnforceTypeConversionRules>true</EnforceTypeConversionRules>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<ExceptionHandling>false</ExceptionHandling>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>

File diff suppressed because it is too large Load Diff

View File

@ -97,7 +97,6 @@
<EnforceTypeConversionRules>true</EnforceTypeConversionRules>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<LanguageStandard>stdcpp17</LanguageStandard>
<ExceptionHandling>false</ExceptionHandling>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -137,7 +136,6 @@ copy /y "$(TargetPath)" "H:\Rockstar Games\Grand Theft Auto San Andreas\SilentPa
<EnforceTypeConversionRules>true</EnforceTypeConversionRules>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<LanguageStandard>stdcpp17</LanguageStandard>
<ExceptionHandling>false</ExceptionHandling>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
@ -179,7 +177,6 @@ copy /y "$(TargetPath)" "H:\Rockstar Games\Grand Theft Auto San Andreas\SilentPa
<EnforceTypeConversionRules>true</EnforceTypeConversionRules>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<LanguageStandard>stdcpp17</LanguageStandard>
<ExceptionHandling>false</ExceptionHandling>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>

View File

@ -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;
auto match1 = firetruck1.get_one();
auto match2 = firetruck2.get_one();
Patch( firetruck1.get<float*>( 7 + 2 ), &FIRETRUCK_SIREN_POS.z );
Patch( firetruck1.get<float*>( 7 + 2 + (6*1) ), &FIRETRUCK_SIREN_POS.y );
Patch( firetruck1.get<float*>( 7 + 2 + (6*2) ), &FIRETRUCK_SIREN_POS.x );
Patch( match1.get<float*>( 7 + 2 ), &FIRETRUCK_SIREN_POS.z );
Patch( match1.get<float*>( 7 + 2 + (6*1) ), &FIRETRUCK_SIREN_POS.y );
Patch( match1.get<float*>( 7 + 2 + (6*2) ), &FIRETRUCK_SIREN_POS.x );
Patch( match2.get<float*>( 7 + 2 ), &FIRETRUCK_SIREN_POS.z );
Patch( match2.get<float*>( 7 + 2 + (6*1) ), &FIRETRUCK_SIREN_POS.y );
Patch( match2.get<float*>( 7 + 2 + (6*2) ), &FIRETRUCK_SIREN_MINUS_X );
Patch( firetruck2.get<float*>( 7 + 2 ), &FIRETRUCK_SIREN_POS.z );
Patch( firetruck2.get<float*>( 7 + 2 + (6*1) ), &FIRETRUCK_SIREN_POS.y );
Patch( firetruck2.get<float*>( 7 + 2 + (6*2) ), &FIRETRUCK_SIREN_MINUS_X );
}
}
{
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" );
TXN_CATCH();
if ( ambulan1.count_hint(1).size() == 1 && ambulan2.count_hint(1).size() == 1 )
try
{
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();
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<float*>( 7 + 2 ), &AMBULANCE_SIREN_POS.z );
Patch( ambulan1.get<float*>( 7 + 2 + (6*1) ), &AMBULANCE_SIREN_POS.y );
Patch( ambulan1.get<float*>( 7 + 2 + (6*2) ), &AMBULANCE_SIREN_POS.x );
Patch( match1.get<float*>( 7 + 2 ), &AMBULANCE_SIREN_POS.z );
Patch( match1.get<float*>( 7 + 2 + (6*1) ), &AMBULANCE_SIREN_POS.y );
Patch( match1.get<float*>( 7 + 2 + (6*2) ), &AMBULANCE_SIREN_POS.x );
Patch( match2.get<float*>( 7 + 2 ), &AMBULANCE_SIREN_POS.z );
Patch( match2.get<float*>( 7 + 2 + (6*1) ), &AMBULANCE_SIREN_POS.y );
Patch( match2.get<float*>( 7 + 2 + (6*2) ), &AMBULANCE_SIREN_MINUS_X );
Patch( ambulan2.get<float*>( 7 + 2 ), &AMBULANCE_SIREN_POS.z );
Patch( ambulan2.get<float*>( 7 + 2 + (6*1) ), &AMBULANCE_SIREN_POS.y );
Patch( ambulan2.get<float*>( 7 + 2 + (6*2) ), &AMBULANCE_SIREN_MINUS_X );
}
}
{
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" );
TXN_CATCH();
if ( police1.count_hint(1).size() == 1 && police2.count_hint(1).size() == 1 )
try
{
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();
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<float*>( 7 + 2 ), &POLICE_SIREN_POS.z );
Patch( police1.get<float*>( 7 + 2 + (6*1) ), &POLICE_SIREN_POS.y );
Patch( police1.get<float*>( 7 + 2 + (6*2) ), &POLICE_SIREN_POS.x );
Patch( match1.get<float*>( 7 + 2 ), &POLICE_SIREN_POS.z );
Patch( match1.get<float*>( 7 + 2 + (6*1) ), &POLICE_SIREN_POS.y );
Patch( match1.get<float*>( 7 + 2 + (6*2) ), &POLICE_SIREN_POS.x );
Patch( match2.get<float*>( 7 + 2 ), &POLICE_SIREN_POS.z );
Patch( match2.get<float*>( 7 + 2 + (6*1) ), &POLICE_SIREN_POS.y );
Patch( match2.get<float*>( 7 + 2 + (6*2) ), &POLICE_SIREN_MINUS_X );
Patch( police2.get<float*>( 7 + 2 ), &POLICE_SIREN_POS.z );
Patch( police2.get<float*>( 7 + 2 + (6*1) ), &POLICE_SIREN_POS.y );
Patch( police2.get<float*>( 7 + 2 + (6*2) ), &POLICE_SIREN_MINUS_X );
}
}
{
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" );
TXN_CATCH();
if ( enforcer1.count_hint(1).size() == 1 && enforcer2.count_hint(1).size() == 1 )
try
{
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();
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<float*>( 7 + 2 ), &ENFORCER_SIREN_POS.z );
Patch( enforcer1.get<float*>( 7 + 2 + (6*1) ), &ENFORCER_SIREN_POS.y );
Patch( enforcer1.get<float*>( 7 + 2 + (6*2) ), &ENFORCER_SIREN_POS.x );
Patch( match1.get<float*>( 7 + 2 ), &ENFORCER_SIREN_POS.z );
Patch( match1.get<float*>( 7 + 2 + (6*1) ), &ENFORCER_SIREN_POS.y );
Patch( match1.get<float*>( 7 + 2 + (6*2) ), &ENFORCER_SIREN_POS.x );
Patch( match2.get<float*>( 7 + 2 ), &ENFORCER_SIREN_POS.z );
Patch( match2.get<float*>( 7 + 2 + (6*1) ), &ENFORCER_SIREN_POS.y );
Patch( match2.get<float*>( 7 + 2 + (6*2) ), &ENFORCER_SIREN_MINUS_X );
Patch( enforcer2.get<float*>( 7 + 2 ), &ENFORCER_SIREN_POS.z );
Patch( enforcer2.get<float*>( 7 + 2 + (6*1) ), &ENFORCER_SIREN_POS.y );
Patch( enforcer2.get<float*>( 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<float>( 4 ), CHOPPER_SEARCH_LIGHT_POS.y );
Patch( match.get<float>( 9 + 4 ), CHOPPER_SEARCH_LIGHT_POS.z );
Patch( chopper1.get<float>( 4 ), CHOPPER_SEARCH_LIGHT_POS.y );
Patch( chopper1.get<float>( 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( chopper2.get<float>( 4 ), CHOPPER_RED_LIGHT_POS.y );
Patch( chopper2.get<float>( 12 + 4 ), CHOPPER_RED_LIGHT_POS.z );
}
TXN_CATCH();
}
Patch( match.get<float>( 4 ), CHOPPER_RED_LIGHT_POS.y );
Patch( match.get<float>( 12 + 4 ), CHOPPER_RED_LIGHT_POS.z );
}
}
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<uint8_t>( hasFBISiren.get<void>(), 0x55 ); // push ebp
InjectHook( hasFBISiren.get<void>( 1 ), SetUpFBISiren, HookType::Call );
Patch( hasFBISiren.get<void>( 1 + 5 ), { 0x83, 0xC4, 0x04, 0x84, 0xC0, 0x90 } ); // add esp, 4 / test al, al / nop
Patch<uint8_t>( matchSiren.get<void>(), 0x55 ); // push ebp
InjectHook( matchSiren.get<void>( 1 ), SetUpFBISiren, HookType::Call );
Patch( matchSiren.get<void>( 1 + 5 ), { 0x83, 0xC4, 0x04, 0x84, 0xC0, 0x90 } ); // add esp, 4 / test al, al / nop
InjectHook( match.get<void>( 0x19 ), SetUpVector );
InjectHook( viceCheetah.get<void>( 0x19 ), SetUpVector );
}
TXN_CATCH();
static const float VICE_CHEETAH_SIREN_POS_Z = 0.25f;
Patch( match.get<float*>( 7 + 2 ), &VICE_CHEETAH_SIREN_POS_Z );
}
Patch( viceCheetah.get<float*>( 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<void>( 0x21 ), CTimer::Update_SilentPatch, HookType::Call );
InjectHook( hookPoint.get<void>( 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<void>( 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<void>( 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<const void*>( match.get<void>( 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<const void*>( 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<void>( 0x25 ), orgPickNextNodeToChaseCar );
@ -1258,25 +1257,31 @@ void Patch_VC_Common()
InjectHook( addr.get<void>( 0x46 ), PickNextNodeToChaseCarXYZ );
Patch<uint8_t>( addr.get<void>( 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<uint8_t>( do_processing.get<uint8_t*>(1), 0xBF ); // movzx eax, word ptr [ebx+28h] -> movsx eax, word ptr [ebx+28h]
Patch<uint8_t>( do_processing.get<uint8_t*>(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<void>( -5 ), Credits::PrintCreditText_Hooked );
InjectHook( renderCredits.get<void>( -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<void>( 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<void>( -11 ), 1 );
InjectHook( constructStatLine.get<void>( -11 + 1 ), PrefsLanguage_IsMetric, HookType::Call );
Nop( constructStatLine.get<void>( -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 match = sirenPitch.get_one();
auto sirenPitch = pattern( "83 F8 17 74 32" ).get_one();
InjectHook( match.get<void>( 5 ), IsFBIRanchOrFBICar, HookType::Call );
Patch( match.get<void>( 5 + 5 ), { 0x84, 0xC0 } ); // test al, al
Nop( match.get<void>( 5 + 5 + 2 ), 4 );
InjectHook( sirenPitch.get<void>( 5 ), IsFBIRanchOrFBICar, HookType::Call );
Patch( sirenPitch.get<void>( 5 + 5 ), { 0x84, 0xC0 } ); // test al, al
Nop( sirenPitch.get<void>( 5 + 5 + 2 ), 4 );
// Pitch shift FBI Washington primary siren
try
{
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<void>( -8 ), { 0x90, 0x89, 0xD9 } );
InjectHook( getDriverOneShot.get<void>( -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<uint8_t>(forAllAtomics.get<void>(), 0x53);
InterceptCall(forAllAtomics.get<void>(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<uint16_t>(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<void>(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<void>(), 1);
InjectHook(match.get<void>(1), &PickUpEffects_GiveUsAnObject, HookType::Call);
Nop(pickupExtraObject.get<void>(), 1);
InjectHook(pickupExtraObject.get<void>(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<void>(15), { 0xD9, 0xEE, 0x90, 0x90 });
Patch(fireInstantHit.get<void>(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<void>(), isPlayerTargettingChar.get<void>(5), 5);
InjectHook(isPlayerTargettingChar.get<void>(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<int*>("7D 78 A1 ? ? ? ? 05", 2 + 1)); // LastTimeAmbulanceCreated
GameVariablesToReset.emplace_back(*get_pattern<int*>("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<void>(7), 6);
Nop(delay_check, 6);
// movzx eax, dx -> movzx eax, bx
Patch(comment_delay_id1.get_first<void>(), { 0x0F, 0xB7, 0xC3 });
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<void>(), { 0x0F, 0xB7, 0xD3 });
Nop(delay_id2.get<void>(3), 4);
}
Patch(comment_delay_id2.get<void>(), { 0x0F, 0xB7, 0xD3 });
Nop(comment_delay_id2.get<void>(3), 4);
}
TXN_CATCH();
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)

View File

@ -82,7 +82,6 @@
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<AdditionalOptions>/Zc:threadSafeInit- /Zc:strictStrings %(AdditionalOptions)</AdditionalOptions>
<SDLCheck>true</SDLCheck>
<ExceptionHandling>false</ExceptionHandling>
<EnforceTypeConversionRules>true</EnforceTypeConversionRules>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<LanguageStandard>stdcpp17</LanguageStandard>
@ -114,7 +113,6 @@
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<AdditionalOptions>/Zc:threadSafeInit- /Zc:strictStrings %(AdditionalOptions)</AdditionalOptions>
<SDLCheck>true</SDLCheck>
<ExceptionHandling>false</ExceptionHandling>
<EnforceTypeConversionRules>true</EnforceTypeConversionRules>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<LanguageStandard>stdcpp17</LanguageStandard>
@ -148,7 +146,6 @@
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<AdditionalOptions>/Zc:threadSafeInit- /Zc:strictStrings %(AdditionalOptions)</AdditionalOptions>
<SDLCheck>true</SDLCheck>
<ExceptionHandling>false</ExceptionHandling>
<EnforceTypeConversionRules>true</EnforceTypeConversionRules>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<LanguageStandard>stdcpp17</LanguageStandard>