From c901c3f7e54a7c6776e252e43ee3ae3971c5c5f8 Mon Sep 17 00:00:00 2001 From: ricardoofnl Date: Thu, 3 Sep 2026 04:36:40 +0700 Subject: [PATCH] Write the `ScrUnk4B` attach-object body; frame is 4 bytes short of 0x1001C6A0 --- saco/game/scripting.h | 1 + saco/net/scriptrpc.cpp | 43 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/saco/game/scripting.h b/saco/game/scripting.h index 022fe5a..04775b3 100644 --- a/saco/game/scripting.h +++ b/saco/game/scripting.h @@ -168,6 +168,7 @@ const SCRIPT_COMMAND is_line_of_sight_clear = { 0x06BD, "ffffffiiiii" }; const SCRIPT_COMMAND set_widescreen = { 0x02A3, "i" }; // the fifth argument is declared "i" but samp passes a float const SCRIPT_COMMAND script_command_0948 = { 0x0948, "fffii" }; +const SCRIPT_COMMAND attach_object_to_player = { 0x069B, "iiffffff" }; // object, char, offset xyz, rot xyz diff --git a/saco/net/scriptrpc.cpp b/saco/net/scriptrpc.cpp index cf0fad4..dba8fe2 100644 --- a/saco/net/scriptrpc.cpp +++ b/saco/net/scriptrpc.cpp @@ -98,7 +98,48 @@ void ScrUnk7D(RPCParameters *rpcParams) void ScrUnk7E(RPCParameters *rpcParams) {} void ScrUnk7F(RPCParameters *rpcParams) {} void ScrUnk39(RPCParameters *rpcParams) {} -void ScrUnk4B(RPCParameters *rpcParams) {} +void ScrUnk4B(RPCParameters *rpcParams) +{ + PCHAR Data = reinterpret_cast(rpcParams->input); + int iBitLength = rpcParams->numberOfBitsOfData; + PlayerID sender = rpcParams->sender; + + WORD objectId; + PLAYERID playerId; + float fOffsetX, fOffsetY, fOffsetZ, fRotX, fRotY, fRotZ; + CPlayerPed *pPlayerPed; + + RakNet::BitStream bsData(Data,(iBitLength/8)+1,false); + + bsData.Read(objectId); + bsData.Read(playerId); + bsData.Read(fOffsetX); + bsData.Read(fOffsetY); + bsData.Read(fOffsetZ); + bsData.Read(fRotX); + bsData.Read(fRotY); + bsData.Read(fRotZ); + + CObjectPool *pObjectPool = pNetGame->FUNC_10002E10(); + if(objectId > MAX_OBJECTS) return; + if(!pObjectPool->field_4[objectId]) return; + CObject *pObject = (CObject *)pObjectPool->field_FA4[objectId]; + if(!pObject) return; + + CPlayerPool *pPlayerPool = pNetGame->GetPlayerPool(); + + if(playerId == pPlayerPool->GetLocalPlayerID()) { + pPlayerPed = pPlayerPool->GetLocalPlayer()->GetPlayerPed(); + } else { + if(playerId > MAX_PLAYERS) return; + if(!pPlayerPool->m_pPlayers[playerId]) return; + if(!pPlayerPool->m_pPlayers[playerId]->m_pRemotePlayer) return; + pPlayerPed = pPlayerPool->m_pPlayers[playerId]->m_pRemotePlayer->m_pPlayerPed; + } + + ScriptCommand(&attach_object_to_player, pObject->field_44, pPlayerPed->m_dwGTAId, + fOffsetX, fOffsetY, fOffsetZ, fRotX, fRotY, fRotZ); +} void ScrUnk85(RPCParameters *rpcParams) {} void ScrUnk86(RPCParameters *rpcParams) {} void ScrUnk87(RPCParameters *rpcParams) {}