From b76637d3917047d46d3c036db87e0798e292e6e9 Mon Sep 17 00:00:00 2001 From: Silent Date: Tue, 21 May 2024 18:34:44 +0200 Subject: [PATCH] Unify randomness fixes to use PS2-like 31-bit rand --- SilentPatch/Common.cpp | 33 ++++--------- SilentPatch/Random.h | 27 +++++++++++ SilentPatchIII/SilentPatchIII.vcxproj | 1 + SilentPatchIII/SilentPatchIII.vcxproj.filters | 3 ++ SilentPatchSA/SilentPatchSA.cpp | 48 +++++++++++-------- SilentPatchSA/SilentPatchSA.vcxproj | 1 + SilentPatchSA/SilentPatchSA.vcxproj.filters | 3 ++ SilentPatchSA/StdAfxSA.h | 1 - SilentPatchSA/VehicleSA.cpp | 3 +- SilentPatchVC/SilentPatchVC.cpp | 19 ++------ SilentPatchVC/SilentPatchVC.vcxproj | 1 + SilentPatchVC/SilentPatchVC.vcxproj.filters | 3 ++ 12 files changed, 82 insertions(+), 61 deletions(-) create mode 100644 SilentPatch/Random.h diff --git a/SilentPatch/Common.cpp b/SilentPatch/Common.cpp index 875eea2..836f356 100644 --- a/SilentPatch/Common.cpp +++ b/SilentPatch/Common.cpp @@ -6,6 +6,7 @@ #include "StoredCar.h" #include "SVF.h" #include "ParseUtils.hpp" +#include "Random.h" #include "Utils/DelimStringReader.h" @@ -151,26 +152,6 @@ namespace ExtraCompSpecularity } } - -// ============= Make script randomness 16-bit, like on PS2 ============= -namespace Rand16bit -{ - template - static int (*orgRand)(); - - template - static int rand16bit() - { - const int bottomBits = orgRand(); - const int topBit = (orgRand() & 1) << 15; - return bottomBits | topBit; - } - - HOOK_EACH_FUNC_CTR(Rand_Script, 0, orgRand, rand16bit); - HOOK_EACH_FUNC_CTR(Rand_PedChat, 1, orgRand, rand16bit); -} - - // ============= Delayed patches ============= namespace DelayedPatches { @@ -336,7 +317,7 @@ namespace Common { // Fix various randomness factors expecting 16-bit rand() { // Treat each instance separately - using namespace Rand16bit; + using namespace ConsoleRandomness; // Script randomness try @@ -346,7 +327,10 @@ namespace Common { get_pattern("E8 ? ? ? ? 25 FF FF 00 00 89 84 24 ? ? ? ? 30 C0"), }; - HookEach_Rand_Script(rands, InterceptCall); + for (void* rand : rands) + { + InjectHook(rand, rand16); + } } TXN_CATCH(); @@ -358,7 +342,10 @@ namespace Common { get_pattern("E8 ? ? ? ? 66 83 F8 14"), }; - HookEach_Rand_PedChat(rands, InterceptCall); + for (void* rand : rands) + { + InjectHook(rand, rand16); + } } TXN_CATCH(); } diff --git a/SilentPatch/Random.h b/SilentPatch/Random.h new file mode 100644 index 0000000..909e340 --- /dev/null +++ b/SilentPatch/Random.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +namespace ConsoleRandomness +{ + // PS2 implementation of rand() + inline uint64_t seed_rand_ps2 = std::time(nullptr); + inline int rand31() + { + seed_rand_ps2 = 0x5851F42D4C957F2D * seed_rand_ps2 + 1; + return ((seed_rand_ps2 >> 32) & 0x7FFFFFFF); + } + + // PS2 rand, but returning a 16-bit value + inline int rand16() + { + return rand31() & 0xFFFF; + } + + // PS2 rand, but matching PC's RAND_MAX + inline int rand15() + { + return rand31() & 0x7FFF; + } +} diff --git a/SilentPatchIII/SilentPatchIII.vcxproj b/SilentPatchIII/SilentPatchIII.vcxproj index 5c5df47..3b3ebde 100644 --- a/SilentPatchIII/SilentPatchIII.vcxproj +++ b/SilentPatchIII/SilentPatchIII.vcxproj @@ -72,6 +72,7 @@ + diff --git a/SilentPatchIII/SilentPatchIII.vcxproj.filters b/SilentPatchIII/SilentPatchIII.vcxproj.filters index 2bbb958..c630dbd 100644 --- a/SilentPatchIII/SilentPatchIII.vcxproj.filters +++ b/SilentPatchIII/SilentPatchIII.vcxproj.filters @@ -110,6 +110,9 @@ Header Files + + Header Files + diff --git a/SilentPatchSA/SilentPatchSA.cpp b/SilentPatchSA/SilentPatchSA.cpp index 781eb1e..88d4d27 100644 --- a/SilentPatchSA/SilentPatchSA.cpp +++ b/SilentPatchSA/SilentPatchSA.cpp @@ -18,6 +18,7 @@ #include "PNGFile.h" #include "PlayerInfoSA.h" #include "FireManagerSA.h" +#include "Random.h" #include "WaveDecoderSA.h" #include "FLACDecoderSA.h" @@ -894,15 +895,6 @@ int NewFrameRender(int nEvent, void* pParam) return RsEventHandler(nEvent, pParam); } -#include -#include - -static std::ranlux48 generator (time(nullptr)); -int32_t Int32Rand() -{ - return generator() & INT32_MAX; -} - auto FlushSpriteBuffer = AddressByVersion(0x70CF20, 0x70D750, 0x7591E0, { "85 C0 0F 8E ? ? ? ? 83 3D", -5 }); void FlushLensSwitchZ( RwRenderState rwa, void* rwb ) { @@ -1630,7 +1622,7 @@ namespace VariableResets T m_timer; TimeNextMadDriverChaseCreated_t() - : m_timer( (static_cast(Int32Rand()) / INT32_MAX) * 600.0f + 600.0f ) + : m_timer( (static_cast(ConsoleRandomness::rand31()) / INT32_MAX) * 600.0f + 600.0f ) { } }; @@ -4628,9 +4620,13 @@ void Patch_SA_10(HINSTANCE hInstance) Patch(0x61ECE2, { 0x84, 0xC0, 0x74 }); // Proper randomizations - InjectHook(0x44E82E, Int32Rand); // Missing ped paths - InjectHook(0x44ECEE, Int32Rand); // Missing ped paths - InjectHook(0x666EA0, Int32Rand); // Prostitutes + { + using namespace ConsoleRandomness; + + InjectHook(0x44E82E, rand31); // Missing ped paths + InjectHook(0x44ECEE, rand31); // Missing ped paths + InjectHook(0x666EA0, rand31); // Prostitutes + } // Help boxes showing with big message // Game seems to assume they can show together @@ -5624,9 +5620,13 @@ void Patch_SA_11() Patch(0x61F502, { 0x84, 0xC0, 0x74 }); // Proper randomizations - InjectHook(0x44E8AE, Int32Rand); // Missing ped paths - InjectHook(0x44ED6E, Int32Rand); // Missing ped paths - InjectHook(0x6676C0, Int32Rand); // Prostitutes + { + using namespace ConsoleRandomness; + + InjectHook(0x44E8AE, rand31); // Missing ped paths + InjectHook(0x44ED6E, rand31); // Missing ped paths + InjectHook(0x6676C0, rand31); // Prostitutes + } // Help boxes showing with big message // Game seems to assume they can show together @@ -5937,9 +5937,13 @@ void Patch_SA_Steam() // REMOVED - the fix pointed at some unrelated instruction anyway? I think it never worked // Proper randomizations - InjectHook(0x452CCF, Int32Rand); // Missing ped paths - InjectHook(0x45322C, Int32Rand); // Missing ped paths - InjectHook(0x690263, Int32Rand); // Prostitutes + { + using namespace ConsoleRandomness; + + InjectHook(0x452CCF, rand31); // Missing ped paths + InjectHook(0x45322C, rand31); // Missing ped paths + InjectHook(0x690263, rand31); // Prostitutes + } // Help boxes showing with big message // Game seems to assume they can show together @@ -6288,14 +6292,16 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) // Proper randomizations try { + using namespace ConsoleRandomness; + 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 + InjectHook( match.get( -5 ), rand31 ); // Missing ped paths }); - InjectHook( prostitutesRand, Int32Rand ); // Prostitutes + InjectHook( prostitutesRand, rand31 ); // Prostitutes } TXN_CATCH(); diff --git a/SilentPatchSA/SilentPatchSA.vcxproj b/SilentPatchSA/SilentPatchSA.vcxproj index d83ffda..2ce16f6 100644 --- a/SilentPatchSA/SilentPatchSA.vcxproj +++ b/SilentPatchSA/SilentPatchSA.vcxproj @@ -252,6 +252,7 @@ copy /y "$(TargetPath)" "H:\Rockstar Games\Grand Theft Auto San Andreas\SilentPa + diff --git a/SilentPatchSA/SilentPatchSA.vcxproj.filters b/SilentPatchSA/SilentPatchSA.vcxproj.filters index 5aea32f..3ccaeb8 100644 --- a/SilentPatchSA/SilentPatchSA.vcxproj.filters +++ b/SilentPatchSA/SilentPatchSA.vcxproj.filters @@ -170,6 +170,9 @@ Header Files + + Header Files + diff --git a/SilentPatchSA/StdAfxSA.h b/SilentPatchSA/StdAfxSA.h index c7d9948..c588513 100644 --- a/SilentPatchSA/StdAfxSA.h +++ b/SilentPatchSA/StdAfxSA.h @@ -28,7 +28,6 @@ extern void (*GTAdelete)(void* data); extern const char* (*GetFrameNodeName)(RwFrame*); extern RpHAnimHierarchy* (*GetAnimHierarchyFromSkinClump)(RpClump*); -int32_t Int32Rand(); RwObject* GetFirstObject(RwFrame* pFrame); extern unsigned char& nGameClockDays; diff --git a/SilentPatchSA/VehicleSA.cpp b/SilentPatchSA/VehicleSA.cpp index bdf799a..1ab5632 100644 --- a/SilentPatchSA/VehicleSA.cpp +++ b/SilentPatchSA/VehicleSA.cpp @@ -7,6 +7,7 @@ #include "Utils/DelimStringReader.h" #include "PlayerInfoSA.h" #include "ParseUtils.hpp" +#include "Random.h" #include "SVF.h" @@ -122,7 +123,7 @@ void (CPlane::*CPlane::orgPlanePreRender)(); static int32_t random(int32_t from, int32_t to) { - return from + ( Int32Rand() % (to-from) ); + return from + ( ConsoleRandomness::rand31() % (to-from) ); } static RwObject* GetCurrentAtomicObject( RwFrame* frame ) diff --git a/SilentPatchVC/SilentPatchVC.cpp b/SilentPatchVC/SilentPatchVC.cpp index 2d48e29..cfbd0f5 100644 --- a/SilentPatchVC/SilentPatchVC.cpp +++ b/SilentPatchVC/SilentPatchVC.cpp @@ -11,6 +11,7 @@ #include "RWUtils.hpp" #include "TheFLAUtils.h" #include "ParseUtils.hpp" +#include "Random.h" #include #include @@ -272,20 +273,6 @@ void __declspec(naked) AutoPilotTimerFix_VC() } -// PS2 implementation of rand() -static uint64_t seed_rand_ps2 = time(nullptr); -static int rand_ps2() -{ - seed_rand_ps2 = 0x5851F42D4C957F2D * seed_rand_ps2 + 1; - return ((seed_rand_ps2 >> 32) & 0x7FFFFFFF); -} - -// PS2 rand, but matching PC's RAND_MAX -static int rand15_ps2() -{ - return rand_ps2() & 0x7FFF; -} - namespace ZeroAmmoFix { @@ -1718,8 +1705,10 @@ void Patch_VC_Common() // The functionality was never broken on PC - but the random distribution seemingly made it looks as if it was try { + using namespace ConsoleRandomness; + 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); + InjectHook(busted_audio_rand, rand15); } TXN_CATCH(); diff --git a/SilentPatchVC/SilentPatchVC.vcxproj b/SilentPatchVC/SilentPatchVC.vcxproj index 0677286..6d7a97b 100644 --- a/SilentPatchVC/SilentPatchVC.vcxproj +++ b/SilentPatchVC/SilentPatchVC.vcxproj @@ -171,6 +171,7 @@ + diff --git a/SilentPatchVC/SilentPatchVC.vcxproj.filters b/SilentPatchVC/SilentPatchVC.vcxproj.filters index 58bcbb4..187c456 100644 --- a/SilentPatchVC/SilentPatchVC.vcxproj.filters +++ b/SilentPatchVC/SilentPatchVC.vcxproj.filters @@ -69,6 +69,9 @@ Header Files + + Header Files +