From fe363932c7897652cc546b53892ac20da922931b Mon Sep 17 00:00:00 2001 From: Silent Date: Mon, 19 Feb 2024 22:47:35 +0100 Subject: [PATCH] Fix PlayerPed replay crashes: * Crash when starting a mocap cutscene after playing a replay wearing different clothes to the ones CJ has currently * Crash when playing back a replay with a different motion group anim (fat/muscular/normal) than the current one Fixes #7 --- SilentPatchSA/PedSA.cpp | 2 + SilentPatchSA/PedSA.h | 6 +++ SilentPatchSA/SilentPatchSA.cpp | 76 +++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) diff --git a/SilentPatchSA/PedSA.cpp b/SilentPatchSA/PedSA.cpp index e1c6239..ece35c5 100644 --- a/SilentPatchSA/PedSA.cpp +++ b/SilentPatchSA/PedSA.cpp @@ -19,6 +19,8 @@ WRAPPER void CTaskSimpleJetPack::RenderJetPack(CPed* pPed) { WRAPARG(pPed); VARJ void (CPed::*CPed::orgGiveWeapon)(uint32_t weapon, uint32_t ammo, bool flag); void (CPlayerPed::*CPlayerPed::orgDoStuffToGoOnFire)(); +void (*CClothes::RebuildPlayer)(CPlayerPed* ped, bool bForReplay) = AddressByVersion(0x5A82C0, { "8B 8E ? ? ? ? 83 C4 04 6A 05", -0x11 }); + RwObject* GetFirstObject(RwFrame* pFrame) { RwObject* pObject = nullptr; diff --git a/SilentPatchSA/PedSA.h b/SilentPatchSA/PedSA.h index 64ee57e..9859592 100644 --- a/SilentPatchSA/PedSA.h +++ b/SilentPatchSA/PedSA.h @@ -421,5 +421,11 @@ public: static_assert(sizeof(CPed) == 0x79C, "Wrong size: CPed"); static_assert(sizeof(CPlayerPed) == 0x7A4, "Wrong size: CPlayerPed"); +class CClothes +{ +public: + static void (*RebuildPlayer)(CPlayerPed* ped, bool bForReplay); +}; + #endif \ No newline at end of file diff --git a/SilentPatchSA/SilentPatchSA.cpp b/SilentPatchSA/SilentPatchSA.cpp index fdaf4ab..ac14a33 100644 --- a/SilentPatchSA/SilentPatchSA.cpp +++ b/SilentPatchSA/SilentPatchSA.cpp @@ -316,6 +316,9 @@ const char* (*GetFrameNodeName)(RwFrame*) = AddressByVersion(0x734A40, 0x735270, 0x7671B0); auto InitializeUtrax = AddressByVersion(0x4F35B0, 0x4F3A10, 0x4FFA80); auto RpAnimBlendClumpGetAssociation = AddressByVersion(0x4D68B0, { "8B 0D ? ? ? ? 8B 14 01 8B 02 85 C0 74 11 8B 4D 0C", -6 }); +auto GetAnimationBlockIndex = AddressByVersion(0x4D3990, { "83 C4 04 85 C0 75 05", -0xC }); +auto RequestModel = AddressByVersion(0x4087E0, { "57 8D 3C 9B", -0x8 }); +auto LoadAllRequestedModels = AddressByVersion(0x40EA10, { "A1 ? ? ? ? 03 C0", -0x20 }); static void (__thiscall* SetVolume)(void*,float); static BOOL (*IsAlreadyRunning)(); @@ -2133,6 +2136,38 @@ namespace RestrictImpoundVehicleTypes } +// ============= 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 +namespace ReplayPlayerPedCrashFixes +{ + static void (*orgRestoreStuffFromMem)(); + static void RestoreStuffFromMem_RebuildPlayer() + { + orgRestoreStuffFromMem(); + CClothes::RebuildPlayer(FindPlayerPed(), false); + } + + static void LoadAllMotionGroupAnims() + { + // FLA compatibility + static const int32_t animGroupIDOffset = *AddressByVersion(0x5A814C + 2, { "81 C7 ? ? ? ? 57 E8 ? ? ? ? 83 C4 0C", 2 }); + + RequestModel(GetAnimationBlockIndex("fat") + animGroupIDOffset, 18); + RequestModel(GetAnimationBlockIndex("muscular") + animGroupIDOffset, 18); + + LoadAllRequestedModels(true); + } + + static void (*orgRebuildPlayer)(CPlayerPed*, bool); + static void RebuildPlayer_LoadAllMotionGroupAnims(CPlayerPed* ped, bool bForReplay) + { + orgRebuildPlayer(ped, bForReplay); + LoadAllMotionGroupAnims(); + } +} + + // ============= LS-RP Mode stuff ============= namespace LSRPMode { @@ -4820,6 +4855,33 @@ void Patch_SA_10(HINSTANCE hInstance) HookEach_ShouldImpound(isThisVehicleInteresting, InterceptCall); } + + // 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 + { + using namespace ReplayPlayerPedCrashFixes; + + InterceptCall(0x45F060, orgRestoreStuffFromMem, RestoreStuffFromMem_RebuildPlayer); + + bool HoodlumPatched = false; + if (*reinterpret_cast(0x45CEA0) == 0xE9) + { + uintptr_t DealWithNewPedPacket_Obfuscated; + ReadCall(0x45CEA0, DealWithNewPedPacket_Obfuscated); + if (ModCompat::Utils::GetModuleHandleFromAddress(DealWithNewPedPacket_Obfuscated) == hInstance) + { + InterceptCall(DealWithNewPedPacket_Obfuscated + 0xF8, orgRebuildPlayer, RebuildPlayer_LoadAllMotionGroupAnims); + HoodlumPatched = true; + } + } + + if (!HoodlumPatched) + { + InterceptCall(0x45CF87, orgRebuildPlayer, RebuildPlayer_LoadAllMotionGroupAnims); + } + } + #if FULL_PRECISION_D3D // Test - full precision D3D device Patch( 0x7F672B+1, *(uint8_t*)(0x7F672B+1) | D3DCREATE_FPU_PRESERVE ); @@ -6454,6 +6516,20 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) }; HookEach_ShouldImpound(isThisVehicleInteresting, InterceptCall); } + + + // 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 + { + using namespace ReplayPlayerPedCrashFixes; + + auto restoreStuffFromMem = get_pattern("E8 ? ? ? ? 80 3D ? ? ? ? ? C6 05 ? ? ? ? ? 74 3A D9 05"); + auto rebuildPlayer = get_pattern("E8 ? ? ? ? 6A 01 56 E8 ? ? ? ? 83 C4 10 EB 53", 8); + + InterceptCall(restoreStuffFromMem, orgRestoreStuffFromMem, RestoreStuffFromMem_RebuildPlayer); + InterceptCall(rebuildPlayer, orgRebuildPlayer, RebuildPlayer_LoadAllMotionGroupAnims); + } }