From fe6824e94a3632de9160092f12614a5043e12a1d Mon Sep 17 00:00:00 2001 From: Batuhan Tonga <76632145+QueryOfficial@users.noreply.github.com> Date: Sun, 5 Jul 2026 19:44:50 +0300 Subject: [PATCH] Add script rotation handling for peds in game logic - Implemented `ReapplyScriptRotations` in `CClientPedManager` to update ped rotations when the game is loaded. - Added `SetScriptRotationOverride` and `ReapplyScriptRotationIfNeeded` methods in `CClientPed` to manage script rotation states. - Updated `CClientGame` to call `ReapplyScriptRotations` during post-world processing. - Ensured script rotation overrides are cleared when a ped enters a vehicle. This change enhances the accuracy of ped rotations in the game environment, addressing potential desynchronization issues. --- Client/mods/deathmatch/logic/CClientGame.cpp | 6 +++++ Client/mods/deathmatch/logic/CClientPed.cpp | 22 ++++++++++++++++ Client/mods/deathmatch/logic/CClientPed.h | 8 ++++++ .../deathmatch/logic/CClientPedManager.cpp | 6 +++++ .../mods/deathmatch/logic/CClientPedManager.h | 2 ++ .../mods/deathmatch/logic/CClientVehicle.cpp | 1 + Client/mods/deathmatch/logic/CNetAPI.cpp | 2 ++ .../logic/CStaticFunctionDefinitions.cpp | 26 +++++++++---------- Client/mods/deathmatch/logic/rpc/CPedRPCs.cpp | 2 ++ 9 files changed, 62 insertions(+), 13 deletions(-) diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index 69edcc4337b..c34a0506972 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -3942,6 +3942,9 @@ void CClientGame::PreWorldProcessHandler() void CClientGame::PostWorldProcessHandler() { + if (m_pManager->IsGameLoaded()) + m_pManager->GetPedManager()->ReapplyScriptRotations(); + m_pManager->GetMarkerManager()->DoPulse(); m_pManager->GetPointLightsManager()->DoPulse(); m_pManager->GetObjectManager()->DoPulse(); @@ -3958,6 +3961,9 @@ void CClientGame::PostWorldProcessHandler() void CClientGame::PostWorldProcessPedsAfterPreRenderHandler() { + if (m_pManager->IsGameLoaded()) + m_pManager->GetPedManager()->ReapplyScriptRotations(); + CLuaArguments Arguments; m_pRootEntity->CallEvent("onClientPedsProcessed", Arguments, false); } diff --git a/Client/mods/deathmatch/logic/CClientPed.cpp b/Client/mods/deathmatch/logic/CClientPed.cpp index bfb2cb271cf..44420dfb971 100644 --- a/Client/mods/deathmatch/logic/CClientPed.cpp +++ b/Client/mods/deathmatch/logic/CClientPed.cpp @@ -738,6 +738,27 @@ void CClientPed::SetCurrentRotationNew(float fRotation) SetRotationRadiansNew(CVector(0, 0, fRotation)); } +void CClientPed::SetScriptRotationOverride(const CVector& vecRotationRadians, bool bNewWay) +{ + m_bHasScriptRotationOverride = true; + m_bScriptRotationNewWay = bNewWay; + m_vecScriptRotation = vecRotationRadians; +} + +void CClientPed::ReapplyScriptRotationIfNeeded() +{ + if (!m_bHasScriptRotationOverride || !m_pPlayerPed) + return; + + if (GetRealOccupiedVehicle()) + return; + + if (m_bScriptRotationNewWay) + SetRotationRadiansNew(m_vecScriptRotation); + else + SetRotationRadians(m_vecScriptRotation); +} + void CClientPed::Spawn(const CVector& vecPosition, float fRotation, unsigned short usModel, unsigned char ucInterior) { // Remove us from our car @@ -779,6 +800,7 @@ void CClientPed::Spawn(const CVector& vecPosition, float fRotation, unsigned sho // Set some states SetFrozen(false); + ClearScriptRotationOverride(); Teleport(vecPosition); SetCurrentRotationNew(fRotation); SetHealth(GetMaxHealth()); diff --git a/Client/mods/deathmatch/logic/CClientPed.h b/Client/mods/deathmatch/logic/CClientPed.h index e950a111c57..40fad19ff6e 100644 --- a/Client/mods/deathmatch/logic/CClientPed.h +++ b/Client/mods/deathmatch/logic/CClientPed.h @@ -202,6 +202,11 @@ class CClientPed : public CClientStreamElement, public CAntiCheatModule void SetRotationRadiansNew(const CVector& vecRotation); void SetCurrentRotationNew(float fRotation); + void SetScriptRotationOverride(const CVector& vecRotationRadians, bool bNewWay); + void ClearScriptRotationOverride() noexcept { m_bHasScriptRotationOverride = false; } + void ReapplyScriptRotationIfNeeded(); + bool HasScriptRotationOverride() const noexcept { return m_bHasScriptRotationOverride; } + void Teleport(const CVector& vecPosition); // This function spawns/respawns this ped in any location. This will force a recreation @@ -748,6 +753,9 @@ class CClientPed : public CClientStreamElement, public CAntiCheatModule uint m_uiFrameLastRebuildPlayer; bool m_bIsSyncing; bool m_shouldRecreate{false}; + bool m_bHasScriptRotationOverride{}; + bool m_bScriptRotationNewWay{}; + CVector m_vecScriptRotation{}; bool m_bBulletImpactData; CClientEntityPtr m_pBulletImpactEntity; diff --git a/Client/mods/deathmatch/logic/CClientPedManager.cpp b/Client/mods/deathmatch/logic/CClientPedManager.cpp index 2f1c5fd5f7a..b5d4e08896c 100644 --- a/Client/mods/deathmatch/logic/CClientPedManager.cpp +++ b/Client/mods/deathmatch/logic/CClientPedManager.cpp @@ -75,6 +75,12 @@ bool CClientPedManager::Exists(CClientPed* pPed) return false; } +void CClientPedManager::ReapplyScriptRotations() +{ + for (uint i = 0; i < m_StreamedIn.size(); i++) + m_StreamedIn[i]->ReapplyScriptRotationIfNeeded(); +} + void CClientPedManager::RemoveFromList(CClientPed* pPed) { if (m_bRemoveFromList) diff --git a/Client/mods/deathmatch/logic/CClientPedManager.h b/Client/mods/deathmatch/logic/CClientPedManager.h index cba3458c87c..14aa4cfca2e 100644 --- a/Client/mods/deathmatch/logic/CClientPedManager.h +++ b/Client/mods/deathmatch/logic/CClientPedManager.h @@ -42,6 +42,8 @@ class CClientPedManager void RestreamAllPeds(); void RestreamWeapon(unsigned short usModel); + void ReapplyScriptRotations(); + protected: CClientPedManager(class CClientManager* pManager); ~CClientPedManager(); diff --git a/Client/mods/deathmatch/logic/CClientVehicle.cpp b/Client/mods/deathmatch/logic/CClientVehicle.cpp index af916f2f00c..a6275779e75 100644 --- a/Client/mods/deathmatch/logic/CClientVehicle.cpp +++ b/Client/mods/deathmatch/logic/CClientVehicle.cpp @@ -4187,6 +4187,7 @@ void CClientVehicle::SetPedOccupiedVehicle(CClientPed* pClientPed, CClientVehicl // Ped vars pClientPed->m_pOccupiedVehicle = pVehicle; pClientPed->m_uiOccupiedVehicleSeat = uiSeat; + pClientPed->ClearScriptRotationOverride(); if (ucDoor != 0xFF) pVehicle->AllowDoorRatioSetting(ucDoor, true); diff --git a/Client/mods/deathmatch/logic/CNetAPI.cpp b/Client/mods/deathmatch/logic/CNetAPI.cpp index cebb2feae34..fc5bfdc2183 100644 --- a/Client/mods/deathmatch/logic/CNetAPI.cpp +++ b/Client/mods/deathmatch/logic/CNetAPI.cpp @@ -737,6 +737,7 @@ void CNetAPI::WriteKeysync(CClientPed* pPlayerModel, NetBitStreamInterface& BitS WriteSmallKeysync(ControllerState, BitStream); // Write the rotations + pPlayerModel->ReapplyScriptRotationIfNeeded(); SKeysyncRotation rotation; rotation.data.fPlayerRotation = pPlayerModel->GetCurrentRotation(); rotation.data.fCameraRotation = pPlayerModel->GetCameraRotation(); @@ -1187,6 +1188,7 @@ void CNetAPI::WritePlayerPuresync(CClientPlayer* pPlayerModel, NetBitStreamInter BitStream.Write(&position); // Player rotation + pPlayerModel->ReapplyScriptRotationIfNeeded(); SPedRotationSync rotation; rotation.data.fRotation = pPlayerModel->GetCurrentRotation(); BitStream.Write(&rotation); diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index dcd11a4e984..6b0ed4fd448 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -1092,20 +1092,18 @@ bool CStaticFunctionDefinitions::SetElementRotation(CClientEntity& Entity, const case CCLIENTPLAYER: { CClientPed& Ped = static_cast(Entity); - if (argumentRotOrder == EULER_DEFAULT || argumentRotOrder == EULER_MINUS_ZYX) - { - if (bNewWay) - Ped.SetRotationDegreesNew(vecRotation); - else - Ped.SetRotationDegrees(vecRotation); - } + CVector vecUseRotation = vecRotation; + if (argumentRotOrder != EULER_DEFAULT && argumentRotOrder != EULER_MINUS_ZYX) + vecUseRotation = ConvertEulerRotationOrder(vecRotation, argumentRotOrder, EULER_MINUS_ZYX); + + if (bNewWay) + Ped.SetRotationDegreesNew(vecUseRotation); else - { - if (bNewWay) - Ped.SetRotationDegreesNew(ConvertEulerRotationOrder(vecRotation, argumentRotOrder, EULER_MINUS_ZYX)); - else - Ped.SetRotationDegrees(ConvertEulerRotationOrder(vecRotation, argumentRotOrder, EULER_MINUS_ZYX)); - } + Ped.SetRotationDegrees(vecUseRotation); + + CVector vecRotationRadians = vecUseRotation; + ConvertDegreesToRadiansNoWrap(vecRotationRadians); + Ped.SetScriptRotationOverride(vecRotationRadians, bNewWay); break; } case CCLIENTVEHICLE: @@ -2225,6 +2223,8 @@ bool CStaticFunctionDefinitions::SetPedRotation(CClientEntity& Entity, float fRo if (!IS_PLAYER(&Entity)) Ped.SetCameraRotation(-fRadians); + + Ped.SetScriptRotationOverride(CVector(0.0f, 0.0f, fRadians), bNewWay); return true; } diff --git a/Client/mods/deathmatch/logic/rpc/CPedRPCs.cpp b/Client/mods/deathmatch/logic/rpc/CPedRPCs.cpp index 7b4b1af19e9..df1c879c107 100644 --- a/Client/mods/deathmatch/logic/rpc/CPedRPCs.cpp +++ b/Client/mods/deathmatch/logic/rpc/CPedRPCs.cpp @@ -79,6 +79,8 @@ void CPedRPCs::SetPedRotation(CClientEntity* pSource, NetBitStreamInterface& bit if (!IS_PLAYER(pPed)) pPed->SetCameraRotation(rotation.data.fRotation); + + pPed->SetScriptRotationOverride(CVector(0.0f, 0.0f, rotation.data.fRotation), ucNewWay == 1); pPed->SetSyncTimeContext(ucTimeContext); } }