From 10dddab97e175e1409e1da2a3bef7fc61383d061 Mon Sep 17 00:00:00 2001 From: ricardoofnl Date: Sat, 5 Sep 2026 09:24:38 +0700 Subject: [PATCH] [saco] Implement/match `FUNC_10016370`, the bullet sync handler; per-component float assignments keep the direct displacements a `VECTOR` copy would hide behind a `lea` --- saco/game/hooks.cpp | 10 ------ saco/game/playerped.h | 10 ++++++ saco/net/remoteplayer.cpp | 64 +++++++++++++++++++++++++++++++++++++++ saco/net/remoteplayer.h | 12 ++++++++ 4 files changed, 86 insertions(+), 10 deletions(-) diff --git a/saco/game/hooks.cpp b/saco/game/hooks.cpp index 1eb1732..d184272 100644 --- a/saco/game/hooks.cpp +++ b/saco/game/hooks.cpp @@ -2823,16 +2823,6 @@ NUDE CWeapon__FireInstantHit_Hook() extern DWORD unnamed_10118990; // 0x10118990, lives in another translation unit -// where a synced shot came from, snapshotted by CPlayerPed::FUNC_100AFA70 -struct SHOT_SYNC_DATA -{ - DWORD field_0; - VECTOR vecOrigin; - VECTOR vecColPoint; - VECTOR vecOffset; - ENTITY_TYPE *pAttachedTo; -}; - // todo: implement sub_100A5410 void __stdcall sub_100A5410(VECTOR *vecOrigin, VECTOR *vecLine, VECTOR *colPoint, DWORD *pHitEntity); diff --git a/saco/game/playerped.h b/saco/game/playerped.h index b4797d5..1d480c2 100644 --- a/saco/game/playerped.h +++ b/saco/game/playerped.h @@ -7,6 +7,16 @@ struct struc_13; +// where a synced shot came from, snapshotted by CPlayerPed::FUNC_100AFA70 +struct SHOT_SYNC_DATA +{ + DWORD field_0; + VECTOR vecOrigin; + VECTOR vecColPoint; + VECTOR vecOffset; + ENTITY_TYPE *pAttachedTo; +}; + DWORD __stdcall GamePool_Vehicle_GetIndex(VEHICLE_TYPE *pVehicle); void FUNC_100AE520(); // .text:100AE520 diff --git a/saco/net/remoteplayer.cpp b/saco/net/remoteplayer.cpp index 8cc6983..c9a75a6 100644 --- a/saco/net/remoteplayer.cpp +++ b/saco/net/remoteplayer.cpp @@ -39,6 +39,8 @@ typedef char CRemotePlayer_offsets[( offsetof(CRemotePlayer, field_1F9) == 0x1F9) ? 1 : -1]; typedef char CNetPlayer_offsets[(offsetof(CNetPlayer, m_PlayerName) == 0x14) ? 1 : -1]; +typedef char BULLET_SYNC_offsets[(offsetof(BULLET_SYNC_DATA, byteWeaponID) == 0x27 && + sizeof(BULLET_SYNC_DATA) == 0x28) ? 1 : -1]; typedef char struc_41_offsets[(offsetof(struc_41, field_30) == 0x30) ? 1 : -1]; typedef char WEAPON_SLOT_offsets[(offsetof(WEAPON_SLOT_TYPE, field_8) == 8 && sizeof(WEAPON_SLOT_TYPE) == 28) ? 1 : -1]; @@ -411,6 +413,68 @@ void CRemotePlayer::FUNC_10017260(BYTE *pSync, int iTime) //---------------------------------------------------- +void CRemotePlayer::FUNC_10016370(BULLET_SYNC_DATA *pSync) +{ + if(!m_pPlayerPed) return; + if(!m_pPlayerPed->IsAdded()) return; + + SHOT_SYNC_DATA shotSync; + + memset(&shotSync, 0, sizeof(shotSync)); + shotSync.vecOrigin.X = pSync->vecHitOrigin.X; + shotSync.vecOrigin.Y = pSync->vecHitOrigin.Y; + shotSync.vecOrigin.Z = pSync->vecHitOrigin.Z; + shotSync.vecColPoint.X = pSync->vecHitTarget.X; + shotSync.vecColPoint.Y = pSync->vecHitTarget.Y; + shotSync.vecColPoint.Z = pSync->vecHitTarget.Z; + shotSync.vecOffset.X = pSync->vecCenterOfHit.X; + shotSync.vecOffset.Y = pSync->vecCenterOfHit.Y; + shotSync.vecOffset.Z = pSync->vecCenterOfHit.Z; + + if(pSync->byteHitType) { + if(shotSync.vecOffset.X > 300.0f || shotSync.vecOffset.X < -300.0f || + shotSync.vecOffset.Y > 300.0f || shotSync.vecOffset.Y < -300.0f || + shotSync.vecOffset.Z > 300.0f || shotSync.vecOffset.Z < -300.0f) return; + + if(pSync->byteHitType == 1) { + CPlayerPool *pPlayerPool = pNetGame->GetPlayerPool(); + if(pPlayerPool) { + PLAYERID playerId = pSync->wHitID; + if(playerId == pPlayerPool->m_LocalPlayerID) { + shotSync.pAttachedTo = (ENTITY_TYPE *)pGame->FindPlayerPed()->m_pPed; + } else if(playerId == m_PlayerID) return; + else if(pPlayerPool->GetSlotState(playerId)) { + CPlayerPed *pPlayerPed = pPlayerPool->GetAt(playerId)->m_pPlayerPed; + if(pPlayerPed) shotSync.pAttachedTo = (ENTITY_TYPE *)pPlayerPed->m_pPed; + } + } + } else if(pSync->byteHitType == 2) { + CVehiclePool *pVehiclePool = pNetGame->GetVehiclePool(); + if(pVehiclePool) { + VEHICLEID VehicleID = pSync->wHitID; + if(pVehiclePool->GetSlotState(VehicleID)) + shotSync.pAttachedTo = + (ENTITY_TYPE *)((CVehicle *)pVehiclePool->GetAt(VehicleID))->m_pVehicle; + } + } + } + + if(m_pPlayerPed->IsAdded()) { + if(m_pPlayerPed->GetCurrentWeapon() != pSync->byteWeaponID) { + m_pPlayerPed->SetArmedWeapon(pSync->byteWeaponID, true); + if(m_pPlayerPed->GetCurrentWeapon() != pSync->byteWeaponID) { + m_pPlayerPed->GiveWeapon(pSync->byteWeaponID, 9999); + m_pPlayerPed->SetArmedWeapon(pSync->byteWeaponID, true); + } + } + } + + m_pPlayerPed->FUNC_100AF280(&shotSync); + m_pPlayerPed->FUNC_100AFA70(); +} + +//---------------------------------------------------- + void CRemotePlayer::FUNC_10014C40() { if(!m_pPlayerPed) return; diff --git a/saco/net/remoteplayer.h b/saco/net/remoteplayer.h index 19de6a6..fd1d131 100644 --- a/saco/net/remoteplayer.h +++ b/saco/net/remoteplayer.h @@ -3,6 +3,17 @@ //---------------------------------------------------- +// the bullet sync payload, 0x28 bytes on the wire +struct BULLET_SYNC_DATA +{ + BYTE byteHitType; + WORD wHitID; + VECTOR vecHitOrigin; + VECTOR vecHitTarget; + VECTOR vecCenterOfHit; + BYTE byteWeaponID; +}; + #pragma pack(1) class CRemotePlayer { @@ -95,6 +106,7 @@ public: void FUNC_10014FF0(); // .text:10014FF0 void FUNC_10017260(BYTE *pSync, int iTime); // .text:10017260 void FUNC_10014C40(); // .text:10014C40 + void FUNC_10016370(BULLET_SYNC_DATA *pSync); // .text:10016370 void FUNC_10014E60(); // .text:10014E60 void FUNC_10015460(); // .text:10015460 void FUNC_10015760(BYTE *pAim); // .text:10015760