diff --git a/Client/mods/deathmatch/logic/CClientCommon.h b/Client/mods/deathmatch/logic/CClientCommon.h index a01416ac1d..74835677c1 100644 --- a/Client/mods/deathmatch/logic/CClientCommon.h +++ b/Client/mods/deathmatch/logic/CClientCommon.h @@ -41,6 +41,8 @@ // Defines the maximum size for a HTTP Download URL (with file / directory information appended) #define MAX_HTTP_DOWNLOAD_URL_WITH_FILE 768 +#define WITH_OBJECT_SYNC 1 + enum eHTTPDownloadType { HTTP_DOWNLOAD_DISABLED = 0, diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index bc20947eac..bf336b66ab 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -4783,7 +4783,13 @@ bool CClientGame::ObjectDamageHandler(CObjectSAInterface* pObjectInterface, floa else Arguments.PushNil(); - return pClientObject->CallEvent("onClientObjectDamage", Arguments, true); + bool bContinue = pClientObject->CallEvent("onClientObjectDamage", Arguments, true); + if (bContinue && !pClientObject->IsLocalEntity() && pClientAttacker) + { + pClientObject->SetAttackerID(pClientAttacker->GetID()); + } + + return bContinue; } } return true; diff --git a/Client/mods/deathmatch/logic/CClientObject.cpp b/Client/mods/deathmatch/logic/CClientObject.cpp index 7d34045f1b..7955843a10 100644 --- a/Client/mods/deathmatch/logic/CClientObject.cpp +++ b/Client/mods/deathmatch/logic/CClientObject.cpp @@ -14,7 +14,7 @@ #define CCLIENTOBJECT_MAX 250 #ifndef M_PI -#define M_PI 3.14159265358979323846 + #define M_PI 3.14159265358979323846 #endif CClientObject::CClientObject(CClientManager* pManager, ElementID ID, unsigned short usModel, bool bLowLod) @@ -25,12 +25,11 @@ CClientObject::CClientObject(CClientManager* pManager, ElementID ID, unsigned sh m_pObjectManager = pManager->GetObjectManager(); m_pModelRequester = pManager->GetModelRequestManager(); - m_pObject = NULL; + m_pObject = nullptr; m_usModel = usModel; SetTypeName("object"); - m_usModel = usModel; m_bIsVisible = true; m_bIsFrozen = false; m_bUsesCollision = true; @@ -45,6 +44,7 @@ CClientObject::CClientObject(CClientManager* pManager, ElementID ID, unsigned sh m_fElasticity = -1.0f; m_fBuoyancyConstant = -1.0f; m_vecCenterOfMass = CVector(0.0f, 0.0f, 0.0f); + m_bIsStatic = true; m_pModelInfo = g_pGame->GetModelInfo(usModel); @@ -53,6 +53,7 @@ CClientObject::CClientObject(CClientManager* pManager, ElementID ID, unsigned sh if (m_bIsLowLod) m_pManager->OnLowLODElementCreated(); + m_clientModel = pManager->GetModelManager()->FindModelByID(usModel); } @@ -62,7 +63,7 @@ CClientObject::~CClientObject() m_pModelRequester->Cancel(this, false); // Detach us from anything - AttachTo(NULL); + AttachTo(nullptr); // Destroy the object Destroy(); @@ -72,6 +73,7 @@ CClientObject::~CClientObject() if (m_bIsLowLod) m_pManager->OnLowLODElementDestroyed(); + m_clientModel = nullptr; } @@ -81,9 +83,9 @@ void CClientObject::Unlink() g_pClientGame->GetObjectRespawner()->Unreference(this); // Remove LowLod refs in others - SetLowLodObject(NULL); + SetLowLodObject(nullptr); while (!m_HighLodObjectList.empty()) - m_HighLodObjectList[0]->SetLowLodObject(NULL); + m_HighLodObjectList[0]->SetLowLodObject(nullptr); } void CClientObject::GetPosition(CVector& vecPosition) const @@ -136,18 +138,17 @@ void CClientObject::GetRotationDegrees(CVector& vecRotation) const void CClientObject::GetRotationRadians(CVector& vecRotation) const { - if (m_pObject && m_pAttachedToEntity) // Temp fix for static objects-> - { - // We've been returning the rotation that got set last so far (::m_vecRotation).. - // but we need to get the real rotation for when the game moves the objects.. - CMatrix matTemp; - m_pObject->GetMatrix(&matTemp); - vecRotation = matTemp.GetRotation(); - } - else + if (m_pObject && (!IsStatic() || m_pAttachedToEntity)) { - vecRotation = m_vecRotation; + // Get the real rotation (game can moves the non-static objects) + CMatrix matrix; + m_pObject->GetMatrix(&matrix); + vecRotation = matrix.GetRotation(); + + return; } + + vecRotation = m_vecRotation; } void CClientObject::SetRotationDegrees(const CVector& vecRotation) @@ -228,14 +229,7 @@ void CClientObject::ModelRequestCallback(CModelInfo* pModelInfo) float CClientObject::GetDistanceFromCentreOfMassToBaseOfModel() { - if (m_pObject) - { - return m_pObject->GetDistanceFromCentreOfMassToBaseOfModel(); - } - else - { - return 0; - } + return (m_pObject ? m_pObject->GetDistanceFromCentreOfMassToBaseOfModel() : 0.0); } void CClientObject::SetVisible(bool bVisible) @@ -247,10 +241,10 @@ void CClientObject::SetVisible(bool bVisible) // Call this when m_bIsVisible, m_IsHiddenLowLod or m_pObject is changed void CClientObject::UpdateVisibility() { - if (m_pObject) - { - m_pObject->SetVisible(m_bIsVisible && !m_IsHiddenLowLod); - } + if (!m_pObject) + return; + + m_pObject->SetVisible(m_bIsVisible && !m_IsHiddenLowLod); } void CClientObject::SetModel(unsigned short usModel) @@ -265,6 +259,7 @@ void CClientObject::SetModel(unsigned short usModel) m_usModel = usModel; if (m_clientModel && m_clientModel->GetModelID() != m_usModel) m_clientModel = nullptr; + m_pModelInfo = g_pGame->GetModelInfo(usModel); UpdateSpatialData(); @@ -280,11 +275,6 @@ void CClientObject::SetModel(unsigned short usModel) } } -bool CClientObject::IsLowLod() -{ - return m_bIsLowLod; -} - bool CClientObject::SetLowLodObject(CClientObject* pNewLowLodObject) { // This object has to be high lod @@ -303,7 +293,7 @@ bool CClientObject::SetLowLodObject(CClientObject* pNewLowLodObject) // Clear there and here ListRemove(m_pLowLodObject->m_HighLodObjectList, this); - m_pLowLodObject = NULL; + m_pLowLodObject = nullptr; return true; } else @@ -313,7 +303,7 @@ bool CClientObject::SetLowLodObject(CClientObject* pNewLowLodObject) return false; // Remove any previous link - SetLowLodObject(NULL); + SetLowLodObject(nullptr); // Make new link m_pLowLodObject = pNewLowLodObject; @@ -324,17 +314,13 @@ bool CClientObject::SetLowLodObject(CClientObject* pNewLowLodObject) CClientObject* CClientObject::GetLowLodObject() { - if (m_bIsLowLod) - return NULL; - return m_pLowLodObject; + return (m_bIsLowLod ? nullptr : m_pLowLodObject); } void CClientObject::Render() { if (m_pObject) - { m_pObject->Render(); - } } void CClientObject::SetFrozen(bool bFrozen) @@ -342,9 +328,7 @@ void CClientObject::SetFrozen(bool bFrozen) m_bIsFrozen = bFrozen; if (m_pObject) - { m_pObject->SetFrozen(bFrozen); - } // Reset speed if we frozing object if (bFrozen) @@ -355,45 +339,32 @@ void CClientObject::SetFrozen(bool bFrozen) GetMoveSpeed(vecSpeed); if (vecZero != vecSpeed) - { SetMoveSpeed(vecZero); - } GetTurnSpeed(vecSpeed); if (vecZero != vecSpeed) - { SetTurnSpeed(vecZero); - } } } void CClientObject::SetAlpha(unsigned char ucAlpha) { if (m_pObject) - { m_pObject->SetAlpha(ucAlpha); - } + m_ucAlpha = ucAlpha; } void CClientObject::GetScale(CVector& vecScale) const { - if (m_pObject) - { - vecScale = *m_pObject->GetScale(); - } - else - { - vecScale = m_vecScale; - } + vecScale = (m_pObject ? *m_pObject->GetScale() : m_vecScale); } void CClientObject::SetScale(const CVector& vecScale) { if (m_pObject) - { m_pObject->SetScale(vecScale.fX, vecScale.fY, vecScale.fZ); - } + m_vecScale = vecScale; } @@ -411,20 +382,13 @@ void CClientObject::SetCollisionEnabled(bool bCollisionEnabled) float CClientObject::GetHealth() { - if (m_pObject) - { - return m_pObject->GetHealth(); - } - - return m_fHealth; + return (m_pObject ? m_pObject->GetHealth() : m_fHealth); } void CClientObject::SetHealth(float fHealth) { if (m_pObject) - { m_pObject->SetHealth(fHealth); - } m_fHealth = fHealth; } @@ -440,10 +404,8 @@ void CClientObject::StreamIn(bool bInstantly) { // Request the model blocking if (m_pModelRequester->RequestBlocking(m_usModel, "CClientObject::StreamIn - bInstantly")) - { // Create us Create(); - } else NotifyUnableToCreate(); } @@ -451,10 +413,8 @@ void CClientObject::StreamIn(bool bInstantly) { // Request the model async if (m_pModelRequester->Request(m_usModel, this)) - { // Create us now if we already had it loaded Create(); - } else NotifyUnableToCreate(); } @@ -519,9 +479,9 @@ void CClientObject::Create() // Apply our data to the object m_pObject->Teleport(m_vecPosition.fX, m_vecPosition.fY, m_vecPosition.fZ); m_pObject->SetOrientation(m_vecRotation.fX, m_vecRotation.fY, m_vecRotation.fZ); - #ifndef MTA_BUILDINGS +#ifndef MTA_BUILDINGS m_pObject->ProcessCollision(); - #endif +#endif m_pObject->SetupLighting(); m_pObject->SetFrozen(m_bIsFrozen); @@ -574,21 +534,20 @@ void CClientObject::Create() void CClientObject::Destroy() { - // If the object exists - if (m_pObject) - { - // Invalidate - m_pManager->InvalidateEntity(this); + if (!m_pObject) + return; + + // Invalidate + m_pManager->InvalidateEntity(this); - // Destroy the object - g_pGame->GetPools()->RemoveObject(m_pObject); - m_pObject = NULL; + // Destroy the object + g_pGame->GetPools()->RemoveObject(m_pObject); + m_pObject = nullptr; - // Remove our reference to its model - m_pModelInfo->RemoveRef(); + // Remove our reference to its model + m_pModelInfo->RemoveRef(); - NotifyDestroy(); - } + NotifyDestroy(); } void CClientObject::NotifyCreate() @@ -630,9 +589,7 @@ void CClientObject::StreamedInPulse() { // Fixed attachment bug #9339 where [object1] -> [object2] -> [vehicle] causes positional lag for [object1] if (m_pAttachedToEntity && m_pAttachedToEntity->GetAttachedTo()) - { DoAttaching(); - } } // Are we not frozen @@ -655,43 +612,36 @@ void CClientObject::StreamedInPulse() void CClientObject::GetMoveSpeed(CVector& vecMoveSpeed) const { if (m_pObject) - { m_pObject->GetMoveSpeed(&vecMoveSpeed); - } else - { vecMoveSpeed = m_vecMoveSpeed; - } } void CClientObject::SetMoveSpeed(const CVector& vecMoveSpeed) { if (m_pObject) - { m_pObject->SetMoveSpeed(const_cast(&vecMoveSpeed)); - } + m_vecMoveSpeed = vecMoveSpeed; + SetStatic(false); } void CClientObject::GetTurnSpeed(CVector& vecTurnSpeed) const { if (m_pObject) - { m_pObject->GetTurnSpeed(&vecTurnSpeed); - } else - { vecTurnSpeed = m_vecTurnSpeed; - } } void CClientObject::SetTurnSpeed(const CVector& vecTurnSpeed) { if (m_pObject) - { m_pObject->SetTurnSpeed(const_cast(&vecTurnSpeed)); - } + m_vecTurnSpeed = vecTurnSpeed; + + SetStatic(false); } CSphere CClientObject::GetWorldBoundingSphere() @@ -735,21 +685,16 @@ bool CClientObject::SetBreakable(bool bBreakable) bool CClientObject::Break() { - // Are we breakable? - if (m_pObject && CClientObjectManager::IsBreakableModel(m_usModel) && !m_bBreakingDisabled) - { - m_pObject->Break(); - return true; - } - return false; + if (!m_pObject || m_bBreakingDisabled || !CClientObjectManager::IsBreakableModel(m_usModel)) + return false; + + m_pObject->Break(); + return true; } float CClientObject::GetMass() { - if (m_pObject) - return m_pObject->GetMass(); - - return m_fMass; + return (m_pObject ? m_pObject->GetMass() : m_fMass); } void CClientObject::SetMass(float fMass) @@ -762,10 +707,7 @@ void CClientObject::SetMass(float fMass) float CClientObject::GetTurnMass() { - if (m_pObject) - return m_pObject->GetTurnMass(); - - return m_fTurnMass; + return (m_pObject ? m_pObject->GetTurnMass() : m_fTurnMass); } void CClientObject::SetTurnMass(float fTurnMass) @@ -778,10 +720,7 @@ void CClientObject::SetTurnMass(float fTurnMass) float CClientObject::GetAirResistance() { - if (m_pObject) - return m_pObject->GetAirResistance(); - - return m_fAirResistance; + return (m_pObject ? m_pObject->GetAirResistance() : m_fAirResistance); } void CClientObject::SetAirResistance(float fAirResistance) @@ -794,10 +733,7 @@ void CClientObject::SetAirResistance(float fAirResistance) float CClientObject::GetElasticity() { - if (m_pObject) - return m_pObject->GetElasticity(); - - return m_fElasticity; + return (m_pObject ? m_pObject->GetElasticity() : m_fElasticity); } void CClientObject::SetElasticity(float fElasticity) @@ -810,10 +746,7 @@ void CClientObject::SetElasticity(float fElasticity) float CClientObject::GetBuoyancyConstant() { - if (m_pObject) - return m_pObject->GetBuoyancyConstant(); - - return m_fBuoyancyConstant; + return (m_pObject ? m_pObject->GetBuoyancyConstant() : m_fBuoyancyConstant); } void CClientObject::SetBuoyancyConstant(float fBuoyancyConstant) @@ -848,12 +781,34 @@ void CClientObject::SetVisibleInAllDimensions(bool bVisible, unsigned short usNe if (bVisible) { if (g_pClientGame->GetLocalPlayer()) - { SetDimension(g_pClientGame->GetLocalPlayer()->GetDimension()); - } } else - { SetDimension(usNewDimension); - } +} + +bool CClientObject::IsInWater() +{ + if (!m_pModelInfo) + return false; + + // Get object bounding box + CBoundingBox* pBoundingBox = m_pModelInfo->GetBoundingBox(); + if (!pBoundingBox) + return false; + + // Get bounding box min. Z position + CVector vecMin = pBoundingBox->vecBoundMin; + vecMin.fZ += pBoundingBox->vecBoundOffset.fZ; + + CVector vecPosition, vecUnknown; + GetPosition(vecPosition); + + // Get water level + float fWaterLevel; + if (!g_pGame->GetWaterManager()->GetWaterLevel(vecPosition, &fWaterLevel, true, &vecUnknown)) + return false; + + // Check if min. Z is in the water + return (vecPosition.fZ + vecMin.fZ <= fWaterLevel); } diff --git a/Client/mods/deathmatch/logic/CClientObject.h b/Client/mods/deathmatch/logic/CClientObject.h index a016facd5c..77f9b7e4eb 100644 --- a/Client/mods/deathmatch/logic/CClientObject.h +++ b/Client/mods/deathmatch/logic/CClientObject.h @@ -20,7 +20,11 @@ struct SLastSyncedObjectData { CVector vecPosition; CVector vecRotation; + CVector vecVelocity; + CVector vecTurnVelocity; float fHealth; + bool bIsInWater; + CVector vecCenterOfMass; }; class CClientObject : public CClientStreamElement @@ -35,11 +39,11 @@ class CClientObject : public CClientStreamElement void Unlink(); - eClientEntityType GetType() const { return CCLIENTOBJECT; }; + eClientEntityType GetType() const { return CCLIENTOBJECT; } - CObject* GetGameObject() { return m_pObject; } - CEntity* GetGameEntity() { return m_pObject; } - const CEntity* GetGameEntity() const { return m_pObject; } + CObject* GetGameObject() const noexcept { return m_pObject; } + CEntity* GetGameEntity() noexcept { return m_pObject; } + const CEntity* GetGameEntity() const noexcept { return m_pObject; } void GetPosition(CVector& vecPosition) const; void SetPosition(const CVector& vecPosition); @@ -65,22 +69,22 @@ class CClientObject : public CClientStreamElement float GetDistanceFromCentreOfMassToBaseOfModel(); - bool IsVisible() { return m_bIsVisible; }; + bool IsVisible() const { return m_bIsVisible; }; void SetVisible(bool bVisible); - unsigned short GetModel() const { return m_usModel; }; + unsigned short GetModel() const const { return m_usModel; }; void SetModel(unsigned short usModel); - bool IsLowLod(); + bool IsLowLod() const { return m_bIsLowLod; } bool SetLowLodObject(CClientObject* pLowLodObject); CClientObject* GetLowLodObject(); void Render(); - bool IsFrozen() { return m_bIsFrozen; } + bool IsFrozen() const { return m_bIsFrozen; } void SetFrozen(bool bFrozen); - unsigned char GetAlpha() { return m_ucAlpha; } + unsigned char GetAlpha() const { return m_ucAlpha; } void SetAlpha(unsigned char ucAlpha); void GetScale(CVector& vecScale) const; void SetScale(const CVector& vecScale); @@ -104,21 +108,28 @@ class CClientObject : public CClientStreamElement bool IsBreakable(bool bCheckModelList = true); bool SetBreakable(bool bBreakable); bool Break(); - bool IsRespawnEnabled() { return m_bRespawnEnabled; }; + bool IsRespawnEnabled() const { return m_bRespawnEnabled; }; void SetRespawnEnabled(bool bRespawnEnabled) { m_bRespawnEnabled = bRespawnEnabled; }; float GetMass(); void SetMass(float fMass); - bool IsVisibleInAllDimensions() { return m_bVisibleInAllDimensions; }; + bool IsVisibleInAllDimensions() const { return m_bVisibleInAllDimensions; }; void SetVisibleInAllDimensions(bool bVisible, unsigned short usNewDimension = 0); void ReCreate(); void UpdateVisibility(); - bool IsBeingRespawned() { return m_bBeingRespawned; }; + bool IsBeingRespawned() const { return m_bBeingRespawned; }; void SetBeingRespawned(bool bBeingRespawned) { m_bBeingRespawned = bBeingRespawned; }; + bool IsInWater(); + + bool IsStatic() const { return m_bIsStatic; } + void SetStatic(bool isStatic) { m_bIsStatic = isStatic; } + + ElementID GetAttackerID() const { return m_AttackerID; } + void SetAttackerID(ElementID attackerID) { m_AttackerID = attackerID; } protected: void StreamIn(bool bInstantly); void StreamOut(); @@ -154,10 +165,13 @@ class CClientObject : public CClientStreamElement float m_fBuoyancyConstant; CVector m_vecCenterOfMass; bool m_bVisibleInAllDimensions = false; + bool m_bIsStatic; // true if the object never moved using setElementVelocity/setElementAngularVelocity CVector m_vecMoveSpeed; CVector m_vecTurnSpeed; + ElementID m_AttackerID = INVALID_ELEMENT_ID; + const bool m_bIsLowLod; // true if this object is low LOD CClientObject* m_pLowLodObject; // Pointer to low LOD version of this object std::vector m_HighLodObjectList; // List of objects that use this object as a low LOD version diff --git a/Client/mods/deathmatch/logic/CDeathmatchObject.cpp b/Client/mods/deathmatch/logic/CDeathmatchObject.cpp index c1712246fb..7729cebbb9 100644 --- a/Client/mods/deathmatch/logic/CDeathmatchObject.cpp +++ b/Client/mods/deathmatch/logic/CDeathmatchObject.cpp @@ -18,7 +18,7 @@ extern CClientGame* g_pClientGame; #ifdef WITH_OBJECT_SYNC CDeathmatchObject::CDeathmatchObject(CClientManager* pManager, CMovingObjectsManager* pMovingObjectsManager, CObjectSync* pObjectSync, ElementID ID, unsigned short usModel) - : ClassInit(this), CClientObject(pManager, ID, usModel) + : ClassInit(this), CClientObject(pManager, ID, usModel, false) { m_pMovingObjectsManager = pMovingObjectsManager; m_pObjectSync = pObjectSync; diff --git a/Client/mods/deathmatch/logic/CObjectSync.cpp b/Client/mods/deathmatch/logic/CObjectSync.cpp index 9ec862c148..4ac4b63a79 100644 --- a/Client/mods/deathmatch/logic/CObjectSync.cpp +++ b/Client/mods/deathmatch/logic/CObjectSync.cpp @@ -10,39 +10,35 @@ *****************************************************************************/ #include "StdInc.h" -#include "net/SyncStructures.h" - -#ifdef WITH_OBJECT_SYNC using std::list; +extern CClientGame* g_pClientGame; -#define OBJECT_SYNC_RATE ( g_TickRateSettings.iObjectSync ) +#define OBJECT_SYNC_RATE (g_TickRateSettings.iObjectSync) -CObjectSync::CObjectSync(CClientObjectManager* pObjectManager) +CObjectSync::CObjectSync(CClientObjectManager* pObjectManager) : m_pObjectManager(pObjectManager), m_ulLastSyncTime(0) { - m_pObjectManager = pObjectManager; - m_ulLastSyncTime = 0; } -bool CObjectSync::ProcessPacket(unsigned char ucPacketID, NetBitStreamInterface& BitStream) +bool CObjectSync::ProcessPacket(unsigned char ucPacketID, NetBitStreamInterface& bitStream) { switch (ucPacketID) { case PACKET_ID_OBJECT_STARTSYNC: { - Packet_ObjectStartSync(BitStream); + Packet_ObjectStartSync(bitStream); return true; } case PACKET_ID_OBJECT_STOPSYNC: { - Packet_ObjectStopSync(BitStream); + Packet_ObjectStopSync(bitStream); return true; } case PACKET_ID_OBJECT_SYNC: { - Packet_ObjectSync(BitStream); + Packet_ObjectSync(bitStream); return true; } } @@ -52,11 +48,10 @@ bool CObjectSync::ProcessPacket(unsigned char ucPacketID, NetBitStreamInterface& void CObjectSync::DoPulse() { - // Has it been long enough since our last state's sync? unsigned long ulCurrentTime = CClientTime::GetTime(); if (ulCurrentTime >= m_ulLastSyncTime + OBJECT_SYNC_RATE) { - Sync(); + Update(); m_ulLastSyncTime = ulCurrentTime; } } @@ -72,199 +67,257 @@ void CObjectSync::RemoveObject(CDeathmatchObject* pObject) m_List.remove(pObject); } -void CObjectSync::ClearObjects() -{ - m_List.clear(); -} - bool CObjectSync::Exists(CDeathmatchObject* pObject) { return m_List.Contains(pObject); } -void CObjectSync::Packet_ObjectStartSync(NetBitStreamInterface& BitStream) +void CObjectSync::Packet_ObjectStartSync(NetBitStreamInterface& bitStream) { - // Read out the ID + // Read out the element ID ElementID ID; - if (BitStream.Read(ID)) - { - // Grab the object - CDeathmatchObject* pObject = static_cast(m_pObjectManager->Get(ID)); - if (pObject) - { - // Read out the position and rotation - SPositionSync position; - SRotationRadiansSync rotation; - if (BitStream.Read(&position) && BitStream.Read(&rotation)) - { - // Disabled due to problem when attached in the editor - issue #5886 - #if 0 - pObject->SetOrientation ( position.data.vecPosition, rotation.data.vecRotation ); - #endif - } - // No velocity due to issue #3522 - - // Read out the health - SObjectHealthSync health; - if (BitStream.Read(&health)) - { - pObject->SetHealth(health.data.fValue); - } - - AddObject(pObject); - } - } + if (!bitStream.Read(ID)) + return; + + // Grab the object + auto pObject = static_cast(m_pObjectManager->Get(ID)); + if (!pObject) + return; + + // Read out the data + SPositionSync position; + SRotationRadiansSync rotation; + SVelocitySync velocity; + SVelocitySync angularVelocity; + SObjectHealthSync health; + + if (!bitStream.Read(&position) || !bitStream.Read(&rotation) || !bitStream.Read(&velocity) || !bitStream.Read(&angularVelocity) || !bitStream.Read(&health)) + return; + + // Set data from the server + pObject->SetOrientation(position.data.vecPosition, rotation.data.vecRotation); + pObject->SetHealth(health.data.fValue); + pObject->SetMoveSpeed(velocity.data.vecVelocity); + pObject->SetTurnSpeed(angularVelocity.data.vecVelocity); + + // Add object to the sync list + AddObject(pObject); } -void CObjectSync::Packet_ObjectStopSync(NetBitStreamInterface& BitStream) +void CObjectSync::Packet_ObjectStopSync(NetBitStreamInterface& bitStream) { - // Read out the ID + // Read out the element ID ElementID ID; - if (BitStream.Read(ID)) - { - // Grab the object - CDeathmatchObject* pObject = static_cast(m_pObjectManager->Get(ID)); - if (pObject) - { - RemoveObject(pObject); - } - } + if (!bitStream.Read(ID)) + return; + + // Grab the object + auto* pObject = static_cast(m_pObjectManager->Get(ID)); + if (!pObject) + return; + + // Remove object from the sync list + RemoveObject(pObject); } -void CObjectSync::Packet_ObjectSync(NetBitStreamInterface& BitStream) +void CObjectSync::Packet_ObjectSync(NetBitStreamInterface& bitStream) { // While we're not out of bytes - while (BitStream.GetNumberOfUnreadBits() > 8) + while (bitStream.GetNumberOfUnreadBits() > 8) { - // Read out the ID + // Read out the element ID ElementID ID; - if (!BitStream.Read(ID)) + if (!bitStream.Read(ID)) return; - // Read out the sync time context. See CClientEntity for documentation on that. + // Read out the sync time context unsigned char ucSyncTimeContext; - if (!BitStream.Read(ucSyncTimeContext)) + if (!bitStream.Read(ucSyncTimeContext)) return; - // Read out flags - SIntegerSync flags(0); - if (!BitStream.Read(&flags)) + // Read out the flags + SIntegerSync ucFlags(0); + if (!bitStream.Read(&ucFlags)) return; - // Read out the position if we need + // Read out the position SPositionSync position; - if (flags & 0x1) + if (ucFlags & 0x1) { - if (!BitStream.Read(&position)) + if (!bitStream.Read(&position)) return; } // Read out the rotation SRotationRadiansSync rotation; - if (flags & 0x2) + if (ucFlags & 0x2) + { + if (!bitStream.Read(&rotation)) + return; + } + + // Read out the velocity + SVelocitySync velocity; + if (ucFlags & 0x4) + { + if (!bitStream.Read(&velocity)) + return; + } + + // Read out the angular velocity + SVelocitySync angularVelocity; + if (ucFlags & 0x8) { - if (!BitStream.Read(&rotation)) + if (!bitStream.Read(&angularVelocity)) return; } // Read out the health SObjectHealthSync health; - if (flags & 0x4) + if (ucFlags & 0x10) { - if (!BitStream.Read(&health)) + if (!bitStream.Read(&health)) return; } - // Grab the object - CDeathmatchObject* pObject = static_cast(m_pObjectManager->Get(ID)); + // Grab the object. + auto* pObject = static_cast(m_pObjectManager->Get(ID)); + // Only update the sync if this packet is from the same context - if (pObject && pObject->CanUpdateSync(ucSyncTimeContext)) - { - if (flags & 0x1) - pObject->SetPosition(position.data.vecPosition); - if (flags & 0x2) - pObject->SetRotationRadians(rotation.data.vecRotation); - if (flags & 0x4) - pObject->SetHealth(health.data.fValue); - } + if (!pObject || !pObject->CanUpdateSync(ucSyncTimeContext)) + return; + + // Set data + if (ucFlags & 0x1) + pObject->SetPosition(position.data.vecPosition); + if (ucFlags & 0x2) + pObject->SetRotationRadians(rotation.data.vecRotation); + if (ucFlags & 0x4) + pObject->SetMoveSpeed(velocity.data.vecVelocity); + if (ucFlags & 0x8) + pObject->SetTurnSpeed(angularVelocity.data.vecVelocity); + if (ucFlags & 0x10) + pObject->SetHealth(health.data.fValue); } } -void CObjectSync::Sync() +void CObjectSync::Update() { - // Got any items? + // Got any objects to sync? if (m_List.size() > 0) { - // Write each object to packet - CBitStream bitStream; + // Create packet + NetBitStreamInterface* pBitStream = g_pNet->AllocateNetBitStream(); + if (!pBitStream) + return; + + // Write object information list::const_iterator iter = m_List.begin(); for (; iter != m_List.end(); iter++) { - WriteObjectInformation(bitStream.pBitStream, *iter); + WriteObjectInformation(pBitStream, *iter); } - // Send the packet - g_pNet->SendPacket(PACKET_ID_OBJECT_SYNC, bitStream.pBitStream, PACKET_PRIORITY_MEDIUM, PACKET_RELIABILITY_UNRELIABLE_SEQUENCED); + // Send and destroy the packet + g_pNet->SendPacket(PACKET_ID_OBJECT_SYNC, pBitStream, PACKET_PRIORITY_MEDIUM, PACKET_RELIABILITY_UNRELIABLE_SEQUENCED); + g_pNet->DeallocateNetBitStream(pBitStream); } } void CObjectSync::WriteObjectInformation(NetBitStreamInterface* pBitStream, CDeathmatchObject* pObject) { - unsigned char ucFlags = 0; - - // What's changed? - CVector vecPosition, vecRotation; + CVector vecPosition, vecRotation, vecVelocity, vecAngularVelocity; pObject->GetPosition(vecPosition); pObject->GetRotationRadians(vecRotation); + pObject->GetMoveSpeed(vecVelocity); + pObject->GetTurnSpeed(vecAngularVelocity); + + unsigned int ucFlags = 0; if (vecPosition != pObject->m_LastSyncedData.vecPosition) ucFlags |= 0x1; if (vecRotation != pObject->m_LastSyncedData.vecRotation) ucFlags |= 0x2; - if (pObject->GetHealth() != pObject->m_LastSyncedData.fHealth) + if (vecVelocity != pObject->m_LastSyncedData.vecVelocity) ucFlags |= 0x4; + if (vecAngularVelocity != pObject->m_LastSyncedData.vecTurnVelocity) + ucFlags |= 0x8; + if (pObject->GetHealth() != pObject->m_LastSyncedData.fHealth) + ucFlags |= 0x10; + if (pObject->IsInWater() != pObject->m_LastSyncedData.bIsInWater) + ucFlags |= 0x20; // Don't sync if nothing changed if (ucFlags == 0) return; - // Write the ID + // Write the object ID pBitStream->Write(pObject->GetID()); // Write the sync time context pBitStream->Write(pObject->GetSyncTimeContext()); // Write flags - SIntegerSync flags(ucFlags); - pBitStream->Write(&flags); + //SIntegerSync flags(ucFlags); + pBitStream->Write(ucFlags); - // Write changed stuff - // Position + // Write position if (ucFlags & 0x1) { - SPositionSync position; + SPositionSync position(false); pObject->GetPosition(position.data.vecPosition); pBitStream->Write(&position); + pObject->m_LastSyncedData.vecPosition = position.data.vecPosition; } - // Rotation + // Write rotation if (ucFlags & 0x2) { SRotationRadiansSync rotation; pObject->GetRotationRadians(rotation.data.vecRotation); pBitStream->Write(&rotation); + pObject->m_LastSyncedData.vecRotation = rotation.data.vecRotation; } - // Health + // Write velocity if (ucFlags & 0x4) + { + SVelocitySync velocity; + pObject->GetMoveSpeed(velocity.data.vecVelocity); + pBitStream->Write(&velocity); + + pObject->m_LastSyncedData.vecVelocity = velocity.data.vecVelocity; + } + + // Write angular velocity + if (ucFlags & 0x8) + { + SVelocitySync angularVelocity; + pObject->GetTurnSpeed(angularVelocity.data.vecVelocity); + pBitStream->Write(&angularVelocity); + + pObject->m_LastSyncedData.vecTurnVelocity = angularVelocity.data.vecVelocity; + } + + // Write health & attacker + if (ucFlags & 0x10) { SObjectHealthSync health; health.data.fValue = pObject->GetHealth(); pBitStream->Write(&health); + pBitStream->Write(pObject->GetAttackerID()); + pObject->m_LastSyncedData.fHealth = health.data.fValue; } -} -#endif \ No newline at end of file + // Write inWater state + if (ucFlags & 0x20) + { + bool bIsInWater = pObject->IsInWater(); + pBitStream->WriteBit(bIsInWater); + + pObject->m_LastSyncedData.bIsInWater = bIsInWater; + } +} diff --git a/Client/mods/deathmatch/logic/CObjectSync.h b/Client/mods/deathmatch/logic/CObjectSync.h index 73fa400a8b..d987791aef 100644 --- a/Client/mods/deathmatch/logic/CObjectSync.h +++ b/Client/mods/deathmatch/logic/CObjectSync.h @@ -26,7 +26,6 @@ class CObjectSync void AddObject(CDeathmatchObject* pObject); void RemoveObject(CDeathmatchObject* pObject); - void ClearObjects(); std::list::const_iterator IterBegin() { return m_List.begin(); }; std::list::const_iterator IterEnd() { return m_List.end(); }; @@ -38,7 +37,7 @@ class CObjectSync void Packet_ObjectStopSync(NetBitStreamInterface& BitStream); void Packet_ObjectSync(NetBitStreamInterface& BitStream); - void Sync(); + void Update(); void WriteObjectInformation(NetBitStreamInterface* pBitStream, CDeathmatchObject* pObject); CClientObjectManager* m_pObjectManager; diff --git a/Client/mods/deathmatch/logic/CPacketHandler.cpp b/Client/mods/deathmatch/logic/CPacketHandler.cpp index ebf2ba5140..4996e3835c 100644 --- a/Client/mods/deathmatch/logic/CPacketHandler.cpp +++ b/Client/mods/deathmatch/logic/CPacketHandler.cpp @@ -2716,15 +2716,23 @@ void CPacketHandler::Packet_EntityAdd(NetBitStreamInterface& bitStream) // ??? (?) - custom data // Objects: - // CVector (12) - position - // CVector (12) - rotation - // unsigned short (2) - object model id - // unsigned char (1) - alpha - // CVector (12) - scale - // bool (1) - static - // SObjectHealthSync (?) - health - // bool (1) - is break - // bool (1) - respawnable + // CVector (12) - position + // CVector (12) - rotation + // unsigned short (2) - object model id + // unsigned char (1) - alpha + // bool (1) - is low lod + // ElementID (2) - low lod object id + // bool (1) - doublesided + // bool (1) - breakable + // bool (1) - visible in all dimensions + // bool (1) - moving + // CPositionRotationAnimation (?) - Moving animation data + // CVector (12) - scale + // bool (1) - frozen + // SObjectHealthSync (?) - health + // bool (1) - is break + // bool (1) - respawnable + // bool (1) - static flag // Pickups: // CVector (12) - position @@ -3090,9 +3098,15 @@ void CPacketHandler::Packet_EntityAdd(NetBitStreamInterface& bitStream) if (bitStream.ReadBit()) pObject->Break(); } - + if (bitStream.Can(eBitStreamVersion::RespawnObject_Serverside)) pObject->SetRespawnEnabled(bitStream.ReadBit()); + + // Set static flag + if (bitStream.Can(eBitStreamVersion::ObjectSync_FixAndUpdate)) + { + pObject->SetStatic(bitStream.ReadBit()); + } pObject->SetCollisionEnabled(bCollisonsEnabled); if (ucEntityTypeID == CClientGame::WEAPON) diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index da92891265..31d64bb9ae 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -823,6 +823,13 @@ bool CStaticFunctionDefinitions::IsElementInWater(CClientEntity& Entity, bool& b bInWater = Vehicle.IsInWater(); break; } + case CCLIENTOBJECT: + case CCLIENTWEAPON: + { + CClientObject& Object = static_cast(Entity); + bInWater = Object.IsInWater(); + break; + } default: return false; } diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp index 64708dea0c..565ce18fdc 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp @@ -372,16 +372,6 @@ ADD_ENUM(VEHICLE_COMPONENT_EXTRA_1, "extra_1") ADD_ENUM(VEHICLE_COMPONENT_EXTRA_2, "extra_2") IMPLEMENT_ENUM_END("vehicle-component") -IMPLEMENT_ENUM_BEGIN(eObjectProperty) -ADD_ENUM(OBJECT_PROPERTY_ALL, "all") -ADD_ENUM(OBJECT_PROPERTY_MASS, "mass") -ADD_ENUM(OBJECT_PROPERTY_TURNMASS, "turn_mass") -ADD_ENUM(OBJECT_PROPERTY_AIRRESISTANCE, "air_resistance") -ADD_ENUM(OBJECT_PROPERTY_ELASTICITY, "elasticity") -ADD_ENUM(OBJECT_PROPERTY_CENTEROFMASS, "center_of_mass") -ADD_ENUM(OBJECT_PROPERTY_BUOYANCY, "buoyancy") -IMPLEMENT_ENUM_END("object-property") - IMPLEMENT_ENUM_BEGIN(eObjectGroup::Modifiable) ADD_ENUM(eObjectGroup::Modifiable::MASS, "mass") ADD_ENUM(eObjectGroup::Modifiable::TURNMASS, "turn_mass") diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h index e134a73bea..460e2da41e 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h @@ -43,7 +43,6 @@ DECLARE_ENUM(EEntityTypeMask); DECLARE_ENUM(eWeaponState); DECLARE_ENUM(eWeaponFlags); DECLARE_ENUM(eVehicleComponent); -DECLARE_ENUM(eObjectProperty); DECLARE_ENUM(eObjectGroup::Modifiable); DECLARE_ENUM(eObjectGroup::DamageEffect); DECLARE_ENUM(eObjectGroup::CollisionResponse); diff --git a/Client/sdk/game/Common.h b/Client/sdk/game/Common.h index 11e5a31554..47161fde67 100644 --- a/Client/sdk/game/Common.h +++ b/Client/sdk/game/Common.h @@ -1431,18 +1431,6 @@ enum class eResizableVehicleWheelGroup ALL_WHEELS = 0xFF, }; -enum eObjectProperty -{ - OBJECT_PROPERTY_ALL, - OBJECT_PROPERTY_MASS, - OBJECT_PROPERTY_TURNMASS, - OBJECT_PROPERTY_AIRRESISTANCE, - OBJECT_PROPERTY_ELASTICITY, - OBJECT_PROPERTY_CENTEROFMASS, - OBJECT_PROPERTY_BUOYANCY, - OBJECT_PROPERTY_MAX, -}; - namespace eObjectGroup { enum Modifiable diff --git a/Server/mods/deathmatch/logic/CCommon.h b/Server/mods/deathmatch/logic/CCommon.h index 2138fadbf7..221a678fc4 100644 --- a/Server/mods/deathmatch/logic/CCommon.h +++ b/Server/mods/deathmatch/logic/CCommon.h @@ -798,3 +798,5 @@ DECLARE_ENUM(eJSONPrettyType); #define WEAPONTYPE_RANDOM_SPEED (0x020000) // #define WEAPONTYPE_FORCE_FINISH_ANIM (0x040000) // force the anim to finish player after aim/fire rather than blending out #define WEAPONTYPE_EXPANDS (0x080000) // + +#define WITH_OBJECT_SYNC 1 diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp index 58989394ec..3379e65e54 100644 --- a/Server/mods/deathmatch/logic/CGame.cpp +++ b/Server/mods/deathmatch/logic/CGame.cpp @@ -28,6 +28,7 @@ #include "lua/CLuaCallback.h" #include "CWeaponStatManager.h" #include "CPedSync.h" +#include "CObjectSync.h" #include "CHTTPD.h" #include "CBan.h" #include "CPlayerCamera.h" @@ -1561,6 +1562,10 @@ void CGame::AddBuiltInEvents() m_Events.AddEvent("onPlayerVoiceStop", "", NULL, false); // Object events + m_Events.AddEvent("onObjectDamage", "loss, attacker", nullptr, false); + m_Events.AddEvent("onObjectBreak", "attacker", nullptr, false); + m_Events.AddEvent("onObjectMoveStart", "", nullptr, false); + m_Events.AddEvent("onObjectMoveStop", "", nullptr, false); // Pickup events m_Events.AddEvent("onPickupHit", "player", NULL, false); diff --git a/Server/mods/deathmatch/logic/CObject.cpp b/Server/mods/deathmatch/logic/CObject.cpp index 31aa8b2113..6a41e89709 100644 --- a/Server/mods/deathmatch/logic/CObject.cpp +++ b/Server/mods/deathmatch/logic/CObject.cpp @@ -16,7 +16,7 @@ extern CGame* g_pGame; -CObject::CObject(CElement* pParent, CObjectManager* pObjectManager, bool bIsLowLod) : CElement(pParent), m_bIsLowLod(bIsLowLod), m_pLowLodObject(NULL) +CObject::CObject(CElement* pParent, CObjectManager* pObjectManager, bool bIsLowLod) : CElement(pParent), m_bIsLowLod(bIsLowLod), m_pLowLodObject(nullptr) { // Init m_iType = CElement::OBJECT; @@ -24,16 +24,19 @@ CObject::CObject(CElement* pParent, CObjectManager* pObjectManager, bool bIsLowL m_pObjectManager = pObjectManager; m_usModel = 0xFFFF; - m_pMoveAnimation = NULL; + m_pMoveAnimation = nullptr; m_ucAlpha = 255; m_vecScale = CVector(1.0f, 1.0f, 1.0f); m_fHealth = 1000.0f; m_bSyncable = true; - m_pSyncer = NULL; + m_pSyncer = nullptr; m_bIsFrozen = false; m_bDoubleSided = false; m_bBreakable = false; m_bRespawnable = false; + m_bInWater = false; + m_bIsStatic = true; + m_bIsMoving = false; m_bCollisionsEnabled = true; @@ -60,11 +63,14 @@ CObject::CObject(const CObject& Copy) : CElement(Copy.m_pParent), m_bIsLowLod(Co m_vecPosition = Copy.m_vecPosition; m_vecRotation = Copy.m_vecRotation; m_bRespawnable = Copy.m_bRespawnable; + m_bInWater = Copy.m_bInWater; + m_bIsStatic = Copy.m_bIsStatic; - m_pMoveAnimation = NULL; - if (Copy.m_pMoveAnimation != NULL) + m_pMoveAnimation = nullptr; + if (Copy.m_pMoveAnimation != nullptr) { m_pMoveAnimation = new CPositionRotationAnimation(*Copy.m_pMoveAnimation); + m_bIsMoving = true; } m_bCollisionsEnabled = Copy.m_bCollisionsEnabled; @@ -76,14 +82,14 @@ CObject::CObject(const CObject& Copy) : CElement(Copy.m_pParent), m_bIsLowLod(Co CObject::~CObject() { - if (m_pMoveAnimation != NULL) + if (m_pMoveAnimation != nullptr) { delete m_pMoveAnimation; - m_pMoveAnimation = NULL; + m_pMoveAnimation = nullptr; } // Remove syncer - SetSyncer(NULL); + SetSyncer(nullptr); // Unlink us from manager Unlink(); @@ -100,9 +106,9 @@ void CObject::Unlink() m_pObjectManager->RemoveFromList(this); // Remove LowLod refs in others - SetLowLodObject(NULL); + SetLowLodObject(nullptr); while (!m_HighLodObjectList.empty()) - m_HighLodObjectList[0]->SetLowLodObject(NULL); + m_HighLodObjectList[0]->SetLowLodObject(nullptr); } bool CObject::ReadSpecialData(const int iLine) @@ -231,17 +237,15 @@ const CVector& CObject::GetPosition() // Are we attached to something? if (m_pAttachedTo) GetAttachedPosition(m_vecPosition); - // Are we moving? else if (IsMoving()) { SPositionRotation positionRotation; bool bStillRunning = m_pMoveAnimation->GetValue(positionRotation); m_vecPosition = positionRotation.m_vecPosition; + if (!bStillRunning) - { StopMoving(); - } } if (vecOldPosition != m_vecPosition) @@ -276,17 +280,16 @@ void CObject::GetRotation(CVector& vecRotation) // Are we attached to something? if (m_pAttachedTo) GetAttachedRotation(vecRotation); - // Are we moving? else if (IsMoving()) { SPositionRotation positionRotation; bool bStillRunning = m_pMoveAnimation->GetValue(positionRotation); m_vecRotation = positionRotation.m_vecRotation; + if (!bStillRunning) - { StopMoving(); - } + vecRotation = m_vecRotation; } } @@ -303,36 +306,31 @@ void CObject::SetRotation(const CVector& vecRotation) // Different rotation? if (m_vecRotation != vecRotation) - { // Set the new rotation m_vecRotation = vecRotation; - } } bool CObject::IsMoving() { // Are we currently moving? - if (m_pMoveAnimation != NULL) + if (m_pMoveAnimation != nullptr) { // Should we have stopped moving by now? if (!m_pMoveAnimation->IsRunning()) - { // Stop our movement StopMoving(); - } } + // Are we still moving after the above check? - return (m_pMoveAnimation != NULL); + return (m_pMoveAnimation != nullptr); } void CObject::Move(const CPositionRotationAnimation& a_rMoveAnimation) { // Are we already moving? if (IsMoving()) - { // Stop our current movement StopMoving(); - } if (a_rMoveAnimation.IsRunning()) { @@ -348,35 +346,35 @@ void CObject::Move(const CPositionRotationAnimation& a_rMoveAnimation) SetPosition(positionRotation.m_vecPosition); SetRotation(positionRotation.m_vecRotation); } + + // Mark object as moving + m_bIsMoving = true; + + CLuaArguments Arguments; + CallEvent("onObjectMoveStart", Arguments); } void CObject::StopMoving() { + if (!m_pMoveAnimation) + return; + // Were we moving in the first place - if (m_pMoveAnimation != NULL) - { - SPositionRotation positionRotation; - m_pMoveAnimation->GetValue(positionRotation); - m_vecPosition = positionRotation.m_vecPosition; - m_vecRotation = positionRotation.m_vecRotation; + SPositionRotation positionRotation; + m_pMoveAnimation->GetValue(positionRotation); + m_vecPosition = positionRotation.m_vecPosition; + m_vecRotation = positionRotation.m_vecRotation; - delete m_pMoveAnimation; - m_pMoveAnimation = NULL; + delete m_pMoveAnimation; + m_pMoveAnimation = nullptr; - UpdateSpatialData(); - } + UpdateSpatialData(); } const CPositionRotationAnimation* CObject::GetMoveAnimation() { - if (IsMoving()) // Call IsMoving since it will make sure the anim is stopped if it's finished - { - return m_pMoveAnimation; - } - else - { - return NULL; - } + // Call IsMoving since it will make sure the anim is stopped if it's finished + return (IsMoving() ? m_pMoveAnimation : nullptr); } void CObject::SetSyncer(CPlayer* pPlayer) @@ -388,15 +386,12 @@ void CObject::SetSyncer(CPlayer* pPlayer) // Update the last player if any bAlreadyIn = true; if (m_pSyncer) - { m_pSyncer->RemoveSyncingObject(this); - } // Update the new player if (pPlayer) - { pPlayer->AddSyncingObject(this); - } + bAlreadyIn = false; // Set it @@ -427,7 +422,7 @@ bool CObject::SetLowLodObject(CObject* pNewLowLodObject) // Clear there and here ListRemove(m_pLowLodObject->m_HighLodObjectList, this); - m_pLowLodObject = NULL; + m_pLowLodObject = nullptr; return true; } else @@ -437,7 +432,7 @@ bool CObject::SetLowLodObject(CObject* pNewLowLodObject) return false; // Remove any previous link - SetLowLodObject(NULL); + SetLowLodObject(nullptr); // Make new link m_pLowLodObject = pNewLowLodObject; @@ -448,7 +443,21 @@ bool CObject::SetLowLodObject(CObject* pNewLowLodObject) CObject* CObject::GetLowLodObject() { - if (m_bIsLowLod) - return NULL; - return m_pLowLodObject; + return (m_bIsLowLod ? nullptr : m_pLowLodObject); +} + +void CObject::SetMoveSpeed(CVector vecMoveSpeed) +{ + m_vecMoveSpeed = vecMoveSpeed; + + // Mark an object as non-static + SetStatic(false); +} + +void CObject::SetTurnSpeed(CVector vecTurnSpeed) +{ + m_vecTurnSpeed = vecTurnSpeed; + + // Mark an object as non-static + SetStatic(false); } diff --git a/Server/mods/deathmatch/logic/CObject.h b/Server/mods/deathmatch/logic/CObject.h index e5032b91ce..85f10a6f04 100644 --- a/Server/mods/deathmatch/logic/CObject.h +++ b/Server/mods/deathmatch/logic/CObject.h @@ -47,43 +47,55 @@ class CObject : public CElement void StopMoving(); const CPositionRotationAnimation* GetMoveAnimation(); - unsigned char GetAlpha() { return m_ucAlpha; } + unsigned char GetAlpha() const { return m_ucAlpha; } void SetAlpha(unsigned char ucAlpha) { m_ucAlpha = ucAlpha; } - unsigned short GetModel() { return m_usModel; } + unsigned short GetModel() const { return m_usModel; } void SetModel(unsigned short usModel) { m_usModel = usModel; } - const CVector& GetScale() { return m_vecScale; } + const CVector& GetScale() const { return m_vecScale; } void SetScale(const CVector& vecScale) { m_vecScale = vecScale; } - bool GetCollisionEnabled() { return m_bCollisionsEnabled; } + bool GetCollisionEnabled() const { return m_bCollisionsEnabled; } void SetCollisionEnabled(bool bCollisionEnabled) { m_bCollisionsEnabled = bCollisionEnabled; } - bool IsFrozen() { return m_bIsFrozen; } + bool IsFrozen() const { return m_bIsFrozen; } void SetFrozen(bool bFrozen) { m_bIsFrozen = bFrozen; } - float GetHealth() { return m_fHealth; } + float GetHealth() const { return m_fHealth; } void SetHealth(float fHealth) { m_fHealth = fHealth; } - bool IsSyncable() { return m_bSyncable; } + bool IsSyncable() const { return m_bSyncable; } void SetSyncable(bool bSyncable) { m_bSyncable = bSyncable; } - CPlayer* GetSyncer() { return m_pSyncer; } + CPlayer* GetSyncer() const { return m_pSyncer; } void SetSyncer(CPlayer* pPlayer); bool IsLowLod(); bool SetLowLodObject(CObject* pLowLodObject); CObject* GetLowLodObject(); - bool IsVisibleInAllDimensions() { return m_bVisibleInAllDimensions; }; + bool IsVisibleInAllDimensions() const { return m_bVisibleInAllDimensions; }; void SetVisibleInAllDimensions(bool bVisible) { m_bVisibleInAllDimensions = bVisible; }; - bool IsBreakable() { return m_bBreakable; } + bool IsBreakable() const { return m_bBreakable; } void SetBreakable(bool bBreakable) { m_bBreakable = bBreakable; } bool IsRespawnEnabled() const noexcept { return m_bRespawnable; } void SetRespawnEnabled(bool bRespawn) noexcept { m_bRespawnable = bRespawn; } + CVector GetMoveSpeed() const { return m_vecMoveSpeed; } + void SetMoveSpeed(CVector vecMoveSpeed); + + CVector GetTurnSpeed() const { return m_vecTurnSpeed; } + void SetTurnSpeed(CVector vecTurnSpeed); + + bool IsStatic() const { return m_bIsStatic; } + void SetStatic(bool bStatic) { m_bIsStatic = bStatic; } + + bool IsInWater() const { return m_bInWater; } + void SetInWater(bool bInWater) { m_bInWater = bInWater; } + protected: bool ReadSpecialData(const int iLine) override; @@ -100,6 +112,10 @@ class CObject : public CElement CPlayer* m_pSyncer; bool m_bVisibleInAllDimensions = false; bool m_bRespawnable; + CVector m_vecMoveSpeed; + CVector m_vecTurnSpeed; + bool m_bInWater; + bool m_bIsStatic; // true if the object never moved using setElementVelocity/setElementAngularVelocity protected: bool m_bCollisionsEnabled; @@ -110,4 +126,5 @@ class CObject : public CElement public: CPositionRotationAnimation* m_pMoveAnimation; + bool m_bIsMoving; // Variable for onObjectMoveStop event }; diff --git a/Server/mods/deathmatch/logic/CObjectManager.h b/Server/mods/deathmatch/logic/CObjectManager.h index 1f975cf26f..8654eb3018 100644 --- a/Server/mods/deathmatch/logic/CObjectManager.h +++ b/Server/mods/deathmatch/logic/CObjectManager.h @@ -14,6 +14,8 @@ #include "CObject.h" #include +#define WITH_OBJECT_SYNC 1 + using std::list; class CObject; diff --git a/Server/mods/deathmatch/logic/CObjectSync.cpp b/Server/mods/deathmatch/logic/CObjectSync.cpp index f17f640675..6b6813b841 100644 --- a/Server/mods/deathmatch/logic/CObjectSync.cpp +++ b/Server/mods/deathmatch/logic/CObjectSync.cpp @@ -11,16 +11,20 @@ #include "StdInc.h" #include "CObjectSync.h" +#include +#include "CElementIDs.h" +#include "packets/CObjectStartSyncPacket.h" +#include "packets/CObjectStopSyncPacket.h" +#include "CGame.h" +#include "CColManager.h" #ifdef WITH_OBJECT_SYNC -#define SYNC_RATE 500 -#define MAX_PLAYER_SYNC_DISTANCE 100.0f + #define SYNC_RATE 500 + #define MAX_PLAYER_SYNC_DISTANCE 100.0f -CObjectSync::CObjectSync(CPlayerManager* pPlayerManager, CObjectManager* pObjectManager) +CObjectSync::CObjectSync(CPlayerManager* pPlayerManager, CObjectManager* pObjectManager) : m_pPlayerManager(pPlayerManager), m_pObjectManager(pObjectManager) { - m_pPlayerManager = pPlayerManager; - m_pObjectManager = pObjectManager; } void CObjectSync::DoPulse() @@ -53,9 +57,7 @@ void CObjectSync::OverrideSyncer(CObject* pObject, CPlayer* pPlayer, bool bPersi if (pSyncer == pPlayer) { if (bPersist == false) - { SetSyncerAsPersistent(false); - } return; } @@ -73,7 +75,7 @@ void CObjectSync::OverrideSyncer(CObject* pObject, CPlayer* pPlayer, bool bPersi void CObjectSync::Update() { // Update all objects - list::const_iterator iter = m_pObjectManager->IterBegin(); + CFastList::const_iterator iter = m_pObjectManager->IterBegin(); for (; iter != m_pObjectManager->IterEnd(); iter++) { UpdateObject(*iter); @@ -85,14 +87,13 @@ void CObjectSync::UpdateObject(CObject* pObject) CPlayer* pSyncer = pObject->GetSyncer(); // Does the object need to be synced? - // We have no reason to sync static and unbreakable objects - if (!pObject->IsSyncable() || (pObject->IsStatic() && !pObject->IsBreakable())) + // We have no reason to sync frozen and unbreakable objects + if (!pObject->IsSyncable() || (pObject->IsFrozen() && !pObject->IsBreakable())) { if (pSyncer) - { // Tell the syncer to stop syncing StopSync(pObject); - } + return; } @@ -101,7 +102,7 @@ void CObjectSync::UpdateObject(CObject* pObject) { // Does the syncer still near the object? if (!IsSyncerPersistent() && !IsPointNearPoint3D(pSyncer->GetPosition(), pObject->GetPosition(), MAX_PLAYER_SYNC_DISTANCE) || - (pObject->GetDimension() != pSyncer->GetDimension())) + (pObject->GetDimension() != pSyncer->GetDimension()) || (pObject->GetInterior() != pSyncer->GetInterior())) { // Stop him from syncing it StopSync(pObject); @@ -111,9 +112,16 @@ void CObjectSync::UpdateObject(CObject* pObject) } } else - { // Try to find a syncer FindSyncer(pObject); + + // If an object is marked as moving, is it really still moving? + if (pObject->m_bIsMoving && !pObject->IsMoving()) + { + pObject->m_bIsMoving = false; + + CLuaArguments Arguments; + pObject->CallEvent("onObjectMoveStop", Arguments); } } @@ -121,11 +129,11 @@ void CObjectSync::FindSyncer(CObject* pObject) { // Find a player close enough to it CPlayer* pPlayer = FindPlayerCloseToObject(pObject, MAX_PLAYER_SYNC_DISTANCE); - if (pPlayer) - { - // Tell him to start syncing it - StartSync(pPlayer, pObject); - } + if (!pPlayer) + return; + + // Tell him to start syncing it + StartSync(pPlayer, pObject); } void CObjectSync::StartSync(CPlayer* pPlayer, CObject* pObject) @@ -152,7 +160,7 @@ void CObjectSync::StopSync(CObject* pObject) pSyncer->Send(CObjectStopSyncPacket(pObject)); // Unmark him as the syncing player - pObject->SetSyncer(NULL); + pObject->SetSyncer(nullptr); SetSyncerAsPersistent(false); @@ -168,7 +176,7 @@ CPlayer* CObjectSync::FindPlayerCloseToObject(CObject* pObject, float fMaxDistan CVector vecPosition = pObject->GetPosition(); // See if any players are close enough - CPlayer* pSyncer = NULL; + CPlayer* pSyncer = nullptr; list::const_iterator iter = m_pPlayerManager->IterBegin(); for (; iter != m_pPlayerManager->IterEnd(); iter++) { @@ -181,9 +189,7 @@ CPlayer* CObjectSync::FindPlayerCloseToObject(CObject* pObject, float fMaxDistan { // Prefer a player that syncs less objects if (!pSyncer || pPlayer->CountSyncingObjects() < pSyncer->CountSyncingObjects()) - { pSyncer = pPlayer; - } } } } @@ -196,43 +202,84 @@ void CObjectSync::Packet_ObjectSync(CObjectSyncPacket& Packet) { // Grab the player CPlayer* pPlayer = Packet.GetSourcePlayer(); - if (pPlayer && pPlayer->IsJoined()) + if (!pPlayer || !pPlayer->IsJoined()) + return; + + // Apply the data for each object in the packet + std::vector::const_iterator iter = Packet.IterBegin(); + for (; iter != Packet.IterEnd(); iter++) { - // Apply the data for each object in the packet - vector::const_iterator iter = Packet.IterBegin(); - for (; iter != Packet.IterEnd(); iter++) + CObjectSyncPacket::SyncData* pData = *iter; + + // Grab the element + CElement* pElement = CElementIDs::GetElement(pData->ID); + if (!pElement || !IS_OBJECT(pElement)) + continue; + + // Is the player syncing this object? + CObject* pObject = static_cast(pElement); + if (!pObject || pObject->GetSyncer() != pPlayer || !pObject->CanUpdateSync(pData->ucSyncTimeContext)) + continue; + + // Apply the data to the object + if (pData->ucFlags & 0x1) { - CObjectSyncPacket::SyncData* pData = *iter; + pObject->SetPosition(pData->vecPosition); + g_pGame->GetColManager()->DoHitDetection(pObject->GetPosition(), pObject); + } + if (pData->ucFlags & 0x2) + pObject->SetRotation(pData->vecRotation); + if (pData->ucFlags & 0x4) + pObject->SetMoveSpeed(pData->vecVelocity); // Sync velocity from client + if (pData->ucFlags & 0x8) + pObject->SetTurnSpeed(pData->vecTurnVelocity); // Sync angular velocity from client + if (pData->ucFlags & 0x10) + { + float fPreviousHealth = pObject->GetHealth(); + pObject->SetHealth(pData->fHealth); - // Grab the element - CElement* pElement = CElementIDs::GetElement(pData->ID); - if (pElement && IS_OBJECT(pElement)) + if (pData->fHealth < fPreviousHealth) { - CObject* pObject = static_cast(pElement); + CElement* pAttacker = CElementIDs::GetElement(pData->attackerID); - // Is the player syncing this object? - if ((pObject->GetSyncer() == pPlayer) && pObject->CanUpdateSync(pData->ucSyncTimeContext)) + if (pData->fHealth > 0) { - // Apply the data to the object - if (pData->ucFlags & 0x1) + float fLoss = fPreviousHealth - pData->fHealth; + + if (fLoss > 0) { - pObject->SetPosition(pData->vecPosition); - g_pGame->GetColManager()->DoHitDetection(pObject->GetPosition(), pObject); + CLuaArguments Arguments; + Arguments.PushNumber(fLoss); + + if (pAttacker) + Arguments.PushElement(pAttacker); + else + Arguments.PushNil(); + + pObject->CallEvent("onObjectDamage", Arguments); } - if (pData->ucFlags & 0x2) - pObject->SetRotation(pData->vecRotation); - if (pData->ucFlags & 0x4) - pObject->SetHealth(pData->fHealth); + } + else // object has been break? + { + CLuaArguments Arguments; + if (pAttacker) + Arguments.PushElement(pAttacker); + else + Arguments.PushNil(); - // Send this sync - pData->bSend = true; + pObject->CallEvent("onObjectBreak", Arguments); } } } + if (pData->ucFlags & 0x20) // Sync inWater state from client + pObject->SetInWater(pData->bIsInWater); - // Tell everyone - m_pPlayerManager->BroadcastOnlyJoined(Packet, pPlayer); + // Send this sync + pData->bSend = true; } + + // Tell everyone + m_pPlayerManager->BroadcastOnlyJoined(Packet, pPlayer); } #endif diff --git a/Server/mods/deathmatch/logic/CObjectSync.h b/Server/mods/deathmatch/logic/CObjectSync.h index 09b7166d8b..26cff826d3 100644 --- a/Server/mods/deathmatch/logic/CObjectSync.h +++ b/Server/mods/deathmatch/logic/CObjectSync.h @@ -10,11 +10,11 @@ *****************************************************************************/ #pragma once +#include "CObjectManager.h" #ifdef WITH_OBJECT_SYNC #include "CPlayerManager.h" -#include "CObjectManager.h" #include "packets/CObjectSyncPacket.h" class CObjectSync diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index ad06e54a70..28d2496bcf 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -32,6 +32,7 @@ #include "CColPolygon.h" #include "CColSphere.h" #include "CPedSync.h" +#include "CObjectSync.h" #include "CZoneNames.h" #include "CKeyBinds.h" #include "CAccountManager.h" @@ -906,6 +907,13 @@ bool CStaticFunctionDefinitions::IsElementInWater(CElement* pElement, bool& bInW bInWater = pVehicle->IsInWater(); break; } + case CElement::OBJECT: + case CElement::WEAPON: + { + CObject* pObject = static_cast(pElement); + bInWater = pObject->IsInWater(); + break; + } default: return false; } @@ -1193,6 +1201,14 @@ bool CStaticFunctionDefinitions::GetElementVelocity(CElement* pElement, CVector& break; } + case CElement::OBJECT: + case CElement::WEAPON: + { + CObject* pObject = static_cast(pElement); + vecVelocity = pObject->GetMoveSpeed(); + + break; + } default: return false; } @@ -1214,6 +1230,13 @@ bool CStaticFunctionDefinitions::GetElementTurnVelocity(CElement* pElement, CVec break; } + case CElement::WEAPON: + case CElement::OBJECT: + { + CObject* pObject = static_cast(pElement); + vecTurnVelocity = pObject->GetTurnSpeed(); + break; + } default: return false; } @@ -1360,7 +1383,8 @@ bool CStaticFunctionDefinitions::SetElementVelocity(CElement* pElement, const CV case CElement::OBJECT: case CElement::WEAPON: { - // Don't store velocity serverside (requires potentially needless additional sizeof(CVector) bytes per object) + CObject* pObject = static_cast(pElement); + pObject->SetMoveSpeed(vecVelocity); break; } default: @@ -1400,7 +1424,9 @@ bool CStaticFunctionDefinitions::SetElementAngularVelocity(CElement* pElement, c case CElement::OBJECT: case CElement::WEAPON: { - // Don't store velocity serverside (requires potentially needless additional sizeof(CVector) bytes per object) + CObject* pObject = static_cast(pElement); + pObject->SetTurnSpeed(vecTurnVelocity); + break; } default: diff --git a/Server/mods/deathmatch/logic/packets/CEntityAddPacket.cpp b/Server/mods/deathmatch/logic/packets/CEntityAddPacket.cpp index a001ba518f..4b657e2dc9 100644 --- a/Server/mods/deathmatch/logic/packets/CEntityAddPacket.cpp +++ b/Server/mods/deathmatch/logic/packets/CEntityAddPacket.cpp @@ -300,6 +300,12 @@ bool CEntityAddPacket::Write(NetBitStreamInterface& BitStream) const // is object break? if (BitStream.Can(eBitStreamVersion::BreakObject_Serverside)) BitStream.WriteBit(pObject->GetHealth() <= 0); + + // Static flag + if (BitStream.Can(eBitStreamVersion::ObjectSync_FixAndUpdate)) + { + BitStream.WriteBit(pObject->IsStatic()); + } // Respawnable if (BitStream.Can(eBitStreamVersion::RespawnObject_Serverside)) diff --git a/Server/mods/deathmatch/logic/packets/CObjectStartSyncPacket.cpp b/Server/mods/deathmatch/logic/packets/CObjectStartSyncPacket.cpp index 6bd5c2ee54..cdfbf3809b 100644 --- a/Server/mods/deathmatch/logic/packets/CObjectStartSyncPacket.cpp +++ b/Server/mods/deathmatch/logic/packets/CObjectStartSyncPacket.cpp @@ -32,6 +32,16 @@ bool CObjectStartSyncPacket::Write(NetBitStreamInterface& BitStream) const m_pObject->GetRotation(rotation.data.vecRotation); BitStream.Write(&rotation); + // Write the velocity + SVelocitySync velocity; + velocity.data.vecVelocity = m_pObject->GetMoveSpeed(); + BitStream.Write(&velocity); + + // Write the angular velocity + SVelocitySync turnVelocity; + turnVelocity.data.vecVelocity = m_pObject->GetTurnSpeed(); + BitStream.Write(&turnVelocity); + // Write the health SObjectHealthSync health; health.data.fValue = m_pObject->GetHealth(); diff --git a/Server/mods/deathmatch/logic/packets/CObjectSyncPacket.cpp b/Server/mods/deathmatch/logic/packets/CObjectSyncPacket.cpp index 28f6dfae0d..b48b53f998 100644 --- a/Server/mods/deathmatch/logic/packets/CObjectSyncPacket.cpp +++ b/Server/mods/deathmatch/logic/packets/CObjectSyncPacket.cpp @@ -40,13 +40,14 @@ bool CObjectSyncPacket::Read(NetBitStreamInterface& BitStream) if (!BitStream.Read(pData->ucSyncTimeContext)) return false; - // Read out flags - SIntegerSync flags; - if (!BitStream.Read(&flags)) + // Read out the flags + //SIntegerSync flags; + unsigned int flags; + if (!BitStream.Read(flags)) return false; pData->ucFlags = flags; - // Read out the position if we need + // Read out the position if (flags & 0x1) { SPositionSync position; @@ -64,15 +65,39 @@ bool CObjectSyncPacket::Read(NetBitStreamInterface& BitStream) pData->vecRotation = rotation.data.vecRotation; } - // Read out the health + // Read out the velocity if (flags & 0x4) + { + SVelocitySync velocity; + if (!BitStream.Read(&velocity)) + return false; + + pData->vecVelocity = velocity.data.vecVelocity; + } + + // Read out the angular velocity + if (flags & 0x8) + { + SVelocitySync angularVelocity; + if (!BitStream.Read(&angularVelocity)) + return false; + + pData->vecTurnVelocity = angularVelocity.data.vecVelocity; + } + + // Read out the health & attacker + if (flags & 0x10) { SObjectHealthSync health; - if (!BitStream.Read(&health)) + if (!BitStream.Read(&health) || !BitStream.Read(pData->attackerID)) return false; pData->fHealth = health.data.fValue; } + // Read out inWater state + if (flags & 0x20) + pData->bIsInWater = BitStream.ReadBit(); + // Add it to our list m_Syncs.push_back(pData); } @@ -97,11 +122,12 @@ bool CObjectSyncPacket::Write(NetBitStreamInterface& BitStream) const // Write the sync time context BitStream.Write(pData->ucSyncTimeContext); - // Write flags - SIntegerSync flags(pData->ucFlags); - BitStream.Write(&flags); + // Write the flags + //SIntegerSync flags(pData->ucFlags); + unsigned int flags = pData->ucFlags; + BitStream.Write(flags); - // Write position if we need + // Write the position if (flags & 0x1) { SPositionSync position; @@ -109,7 +135,7 @@ bool CObjectSyncPacket::Write(NetBitStreamInterface& BitStream) const BitStream.Write(&position); } - // Write rotation + // Write the rotation if (flags & 0x2) { SRotationRadiansSync rotation; @@ -117,13 +143,35 @@ bool CObjectSyncPacket::Write(NetBitStreamInterface& BitStream) const BitStream.Write(&rotation); } - // Write health + // Write the velocity if (flags & 0x4) + { + SVelocitySync velocity; + velocity.data.vecVelocity = pData->vecVelocity; + BitStream.Write(&velocity); + } + + // Write the angular velocity + if (flags & 0x8) + { + SVelocitySync angularVelocity; + angularVelocity.data.vecVelocity = pData->vecTurnVelocity; + BitStream.Write(&angularVelocity); + } + + // Write the health & attacker + if (flags & 0x10) { SObjectHealthSync health; health.data.fValue = pData->fHealth; + BitStream.Write(&health); + BitStream.Write(pData->attackerID); } + // Write the inWater state + if (flags & 0x20) + BitStream.WriteBit(pData->bIsInWater); + // We've sent atleast one sync bSent = true; } diff --git a/Server/mods/deathmatch/logic/packets/CObjectSyncPacket.h b/Server/mods/deathmatch/logic/packets/CObjectSyncPacket.h index e5db9bbe00..6973cce0e7 100644 --- a/Server/mods/deathmatch/logic/packets/CObjectSyncPacket.h +++ b/Server/mods/deathmatch/logic/packets/CObjectSyncPacket.h @@ -23,9 +23,14 @@ class CObjectSyncPacket final : public CPacket ElementID ID; CVector vecPosition; CVector vecRotation; + CVector vecVelocity; + CVector vecTurnVelocity; float fHealth; + bool bIsInWater; + ElementID attackerID; + unsigned char ucSyncTimeContext; - unsigned char ucFlags; + unsigned int ucFlags; bool bSend; }; diff --git a/Shared/mods/deathmatch/logic/Enums.cpp b/Shared/mods/deathmatch/logic/Enums.cpp index 1e3d0b2003..2063cf35b9 100644 --- a/Shared/mods/deathmatch/logic/Enums.cpp +++ b/Shared/mods/deathmatch/logic/Enums.cpp @@ -103,6 +103,16 @@ ADD_ENUM(WorldSpecialProperty::ROADSIGNSTEXT, "roadsignstext") ADD_ENUM(WorldSpecialProperty::TUNNELWEATHERBLEND, "tunnelweatherblend") IMPLEMENT_ENUM_CLASS_END("world-special-property") +IMPLEMENT_ENUM_BEGIN(eObjectProperty) +ADD_ENUM(OBJECT_PROPERTY_ALL, "all") +ADD_ENUM(OBJECT_PROPERTY_MASS, "mass") +ADD_ENUM(OBJECT_PROPERTY_TURNMASS, "turn_mass") +ADD_ENUM(OBJECT_PROPERTY_AIRRESISTANCE, "air_resistance") +ADD_ENUM(OBJECT_PROPERTY_ELASTICITY, "elasticity") +ADD_ENUM(OBJECT_PROPERTY_CENTEROFMASS, "center_of_mass") +ADD_ENUM(OBJECT_PROPERTY_BUOYANCY, "buoyancy") +IMPLEMENT_ENUM_END("object-property") + IMPLEMENT_ENUM_BEGIN(ePacketID) ADD_ENUM1(PACKET_ID_SERVER_JOIN) ADD_ENUM1(PACKET_ID_SERVER_JOIN_DATA) diff --git a/Shared/mods/deathmatch/logic/Enums.h b/Shared/mods/deathmatch/logic/Enums.h index e975d0d907..e18aafbece 100644 --- a/Shared/mods/deathmatch/logic/Enums.h +++ b/Shared/mods/deathmatch/logic/Enums.h @@ -94,4 +94,17 @@ enum class WorldSpecialProperty }; DECLARE_ENUM_CLASS(WorldSpecialProperty); +enum eObjectProperty +{ + OBJECT_PROPERTY_ALL, + OBJECT_PROPERTY_MASS, + OBJECT_PROPERTY_TURNMASS, + OBJECT_PROPERTY_AIRRESISTANCE, + OBJECT_PROPERTY_ELASTICITY, + OBJECT_PROPERTY_CENTEROFMASS, + OBJECT_PROPERTY_BUOYANCY, + OBJECT_PROPERTY_MAX, +}; +DECLARE_ENUM(eObjectProperty); + DECLARE_ENUM(ePacketID); diff --git a/Shared/sdk/net/bitstream.h b/Shared/sdk/net/bitstream.h index c29f739ff1..997e3b534d 100644 --- a/Shared/sdk/net/bitstream.h +++ b/Shared/sdk/net/bitstream.h @@ -572,6 +572,10 @@ enum class eBitStreamVersion : unsigned short // 2024-09-04 RespawnObject_Serverside, + // Object sync fix & improvments + // 2024-06-11 + ObjectSync_FixAndUpdate, + // This allows us to automatically increment the BitStreamVersion when things are added to this enum. // Make sure you only add things above this comment. Next,