From 8e9614dfccd515be5edbfa04d07af19aefddc560 Mon Sep 17 00:00:00 2001 From: ricardoofnl Date: Sun, 30 Aug 2026 13:42:28 +0700 Subject: [PATCH] [saco] Implement/match `CPlayerPed_ProcessControl_Hook` --- saco/game/hooks.cpp | 120 ++++++++++++++++++++++++++++++++++++++++- saco/net/localplayer.h | 2 + saco/net/netgame.h | 7 ++- 3 files changed, 127 insertions(+), 2 deletions(-) diff --git a/saco/game/hooks.cpp b/saco/game/hooks.cpp index cb02919..8148cf5 100644 --- a/saco/game/hooks.cpp +++ b/saco/game/hooks.cpp @@ -32,6 +32,7 @@ BYTE byteSavedCameraMode; DWORD dwCurPlayerActor=0; BYTE *pbyteCameraMode = (BYTE *)0xB6F1A8; BYTE *pbyteCurrentPlayer = (BYTE *)0xB7CD74; +WORD *wCameraMode2 = (WORD *)0xB6F858; PED_TYPE pedCrimeReportTemp; // pay attention! used in 0x100A1790 ; void __thiscall CGame::PlayCrimeReport as pedCrimeReportTemp 0x10150D00 @@ -367,9 +368,126 @@ NUDE CAnimManager__BlendAnimation_Hook() //----------------------------------------------------------- +DWORD dwProcessControlPed; +PED_TYPE *_pProcessControlPed; +BYTE byteSavedCurrentPlayer; +BYTE byteProcessControlPlayerID; +WORD wSavedCameraMode2; +DWORD dwSavedPedHealth; +GTA_CONTROLSET *pProcessControlKeys; + +// `fst [esi+0x55C]` heading writes at 0x6884C4 and 0x688200, only enabled for the local player +BYTE PedHeadingCode1[] = {0xD9,0x96,0x5C,0x05,0x00,0x00}; +BYTE PedHeadingCode2[] = {0xD9,0x96,0x5C,0x05,0x00,0x00}; +// `call 0x5E1B10` at 0x5E92F4, nopped out while a remote ped processes +BYTE RemotePedProcessCode[] = {0xE8,0x17,0x88,0xFF,0xFF}; + +// runs the original CPlayerPed::ProcessControl for a remote ped under SEH +void ProcessControlRemotePed(); // .text:100A27C0 + NUDE CPlayerPed_ProcessControl_Hook() { - // TODO: CPlayerPed_ProcessControl_Hook + _asm mov dwProcessControlPed, ecx + _asm pushad + + _pProcessControlPed = (PED_TYPE *)dwProcessControlPed; + byteSavedCurrentPlayer = *pbyteCurrentPlayer; + byteProcessControlPlayerID = FindPlayerNumFromPedPtr(dwProcessControlPed); + + if(dwProcessControlPed && byteProcessControlPlayerID && !byteSavedCurrentPlayer) + { + GameStoreLocalPlayerKeys(); + GameSetRemotePlayerKeys(byteProcessControlPlayerID); + + byteSavedCameraMode = *pbyteCameraMode; + *pbyteCameraMode = GameGetPlayerCameraMode(byteProcessControlPlayerID); + wSavedCameraMode2 = *wCameraMode2; + *wCameraMode2 = GameGetPlayerCameraMode(byteProcessControlPlayerID); + if(*wCameraMode2 == 4) *wCameraMode2 = 0; + + GameStoreLocalPlayerCameraExtZoom(); + GameSetRemotePlayerCameraExtZoom(byteProcessControlPlayerID); + GameStoreLocalPlayerAim(); + GameSetRemotePlayerAim(byteProcessControlPlayerID); + GameStoreLocalPlayerWeaponSkills(); + GameSetRemotePlayerWeaponSkills(byteProcessControlPlayerID); + + *pbyteCurrentPlayer = byteProcessControlPlayerID; + dwSavedPedHealth = *(DWORD *)&_pProcessControlPed->fHealth; + + UnFuck(0x5E92F4, 5); + memset((void *)0x5E92F4, 0x90, 5); + ProcessControlRemotePed(); + memcpy((void *)0x5E92F4, RemotePedProcessCode, 5); + + GameSetLocalPlayerWeaponSkills(); + *pbyteCameraMode = byteSavedCameraMode; + *wCameraMode2 = wSavedCameraMode2; + GameSetLocalPlayerCameraExtZoom(); + *pbyteCurrentPlayer = 0; + GameSetLocalPlayerKeys(); + GameSetLocalPlayerAim(); + } + else + { + if(pNetGame && pNetGame->GetPlayerPool()->GetLocalPlayer()->GetField_F0()) + { + struc_41 *pSettings = pNetGame->GetSettings(); + + if(pGame->FindPlayerPed()->HasExceededWorldBoundries(pSettings->fWorldBoundryPX, + pSettings->fWorldBoundryZX, pSettings->fWorldBoundryPY, pSettings->fWorldBoundryNY)) + { + if(!pGame->GetActiveInterior()) + { + DWORD dwStateFlags = _pProcessControlPed->dwStateFlags; + + if(!(dwStateFlags & 0x100) && (dwStateFlags & 3)) + { + pProcessControlKeys = GameGetInternalKeys(); + pProcessControlKeys->wKeys1[14] = 255; + pProcessControlKeys->wKeys2[14] = 0; + } + } + } + } + + if(pGame->FindPlayerPed()) + { + if(pGame->FindPlayerPed()->field_2F7) + { + pProcessControlKeys = GameGetInternalKeys(); + pProcessControlKeys->wKeys1[18] = 0; + pProcessControlKeys->wKeys2[18] = 0; + } + + if(pGame->FindPlayerPed()->field_2F6) + { + pProcessControlKeys = GameGetInternalKeys(); + pProcessControlKeys->wKeys1[14] = 0; + pProcessControlKeys->wKeys2[14] = 0; + } + + if(pGame->FindPlayerPed()->field_2F8) + { + pProcessControlKeys = GameGetInternalKeys(); + pProcessControlKeys->wKeys1[16] = 0; + pProcessControlKeys->wKeys2[16] = 0; + } + } + + memcpy((void *)0x6884C4, PedHeadingCode1, 6); + memcpy((void *)0x688200, PedHeadingCode2, 6); + + _asm mov ecx, dwProcessControlPed + _asm mov edx, 0x60EA90 + _asm call edx + + memset((void *)0x6884C4, 0x90, 6); + memset((void *)0x688200, 0x90, 6); + } + + _asm popad + _asm retn } //----------------------------------------------------------- diff --git a/saco/net/localplayer.h b/saco/net/localplayer.h index 233bb91..84643e7 100644 --- a/saco/net/localplayer.h +++ b/saco/net/localplayer.h @@ -108,6 +108,8 @@ public: BOOL IsInRCMode() { return m_bInRCMode; }; void FUNC_10005BF0(WORD a1); // .text:10005BF0 + + DWORD GetField_F0() { return field_F0; }; }; //---------------------------------------------------------- diff --git a/saco/net/netgame.h b/saco/net/netgame.h index cccf860..2a281cf 100644 --- a/saco/net/netgame.h +++ b/saco/net/netgame.h @@ -9,7 +9,11 @@ struct struc_41 { bool bUseCJWalk; int field_1; - char _gap5[17]; + float fWorldBoundryPX; + float fWorldBoundryZX; + float fWorldBoundryPY; + float fWorldBoundryNY; + char _gap15; float field_16; char field_1A; char _gap1B[4]; @@ -74,6 +78,7 @@ public: DWORD GetTime(); int GetGameState() { return m_iGameState; }; BOOL GetWalkStyle() { return field_3D5->bUseCJWalk; }; + struc_41 * GetSettings() { return field_3D5; }; CVehiclePool * GetVehiclePool() { return m_pPools->pVehiclePool; }; CPlayerPool * GetPlayerPool() { return m_pPools->pPlayerPool; };