From c50fd5ffb421111ab6e6c97c002b3076c022d575 Mon Sep 17 00:00:00 2001 From: TEDERIs Date: Wed, 10 Jan 2024 16:00:18 +0700 Subject: [PATCH 1/7] Element data optimizations --- .../mods/deathmatch/logic/CClientEntity.cpp | 79 +++++------- Client/mods/deathmatch/logic/CClientEntity.h | 6 +- Client/mods/deathmatch/logic/CCustomData.cpp | 64 +++++----- Client/mods/deathmatch/logic/CCustomData.h | 13 +- .../logic/CStaticFunctionDefinitions.cpp | 17 +-- .../logic/CStaticFunctionDefinitions.h | 2 +- .../mods/deathmatch/logic/lua/CLuaArgument.h | 2 + Server/mods/deathmatch/logic/CCustomData.cpp | 118 +++++++++--------- Server/mods/deathmatch/logic/CCustomData.h | 28 ++--- Server/mods/deathmatch/logic/CElement.cpp | 86 ++++++------- Server/mods/deathmatch/logic/CElement.h | 7 +- Server/mods/deathmatch/logic/CGame.cpp | 50 +++----- .../logic/CPerfStat.EventPacketUsage.cpp | 18 +-- .../mods/deathmatch/logic/CPerfStatModule.h | 6 +- .../mods/deathmatch/logic/CPlayerManager.cpp | 16 +-- Server/mods/deathmatch/logic/CPlayerManager.h | 2 +- .../logic/CStaticFunctionDefinitions.cpp | 71 +++++------ .../logic/CStaticFunctionDefinitions.h | 12 +- .../mods/deathmatch/logic/lua/CLuaArgument.h | 4 +- .../logic/packets/CCustomDataPacket.cpp | 9 +- .../logic/packets/CCustomDataPacket.h | 8 +- .../logic/packets/CEntityAddPacket.cpp | 19 ++- 22 files changed, 287 insertions(+), 350 deletions(-) diff --git a/Client/mods/deathmatch/logic/CClientEntity.cpp b/Client/mods/deathmatch/logic/CClientEntity.cpp index 849f218e25b..16e5145eb51 100644 --- a/Client/mods/deathmatch/logic/CClientEntity.cpp +++ b/Client/mods/deathmatch/logic/CClientEntity.cpp @@ -279,12 +279,10 @@ void CClientEntity::SetID(ElementID ID) } } -CLuaArgument* CClientEntity::GetCustomData(const char* szName, bool bInheritData, bool* pbIsSynced) +CLuaArgument* CClientEntity::GetCustomData(const SString& strName, bool bInheritData, bool* pbIsSynced) { - assert(szName); - // Grab it and return a pointer to the variable - SCustomData* pData = m_pCustomData->Get(szName); + SCustomData* pData = m_pCustomData->Get(strName); if (pData) { if (pbIsSynced) @@ -295,22 +293,22 @@ CLuaArgument* CClientEntity::GetCustomData(const char* szName, bool bInheritData // If none, try returning parent's custom data if (bInheritData && m_pParent) { - return m_pParent->GetCustomData(szName, true, pbIsSynced); + return m_pParent->GetCustomData(strName, true, pbIsSynced); } // None available - return NULL; + return {}; } CLuaArguments* CClientEntity::GetAllCustomData(CLuaArguments* table) { assert(table); - for (auto it = m_pCustomData->IterBegin(); it != m_pCustomData->IterEnd(); it++) + for (const auto& [key, data] : m_pCustomData->GetData()) { - table->PushString(it->first); // key - table->PushArgument(it->second.Variable); // value - } + table->PushString(key); // key + table->PushArgument(data.Variable); // value + } return table; } @@ -470,54 +468,41 @@ bool CClientEntity::GetCustomDataBool(const char* szName, bool& bOut, bool bInhe return false; } -void CClientEntity::SetCustomData(const char* szName, const CLuaArgument& Variable, bool bSynchronized) +bool CClientEntity::SetCustomData(const SString& strName, const CLuaArgument& Variable, bool bSynchronized) { - assert(szName); - if (strlen(szName) > MAX_CUSTOMDATA_NAME_LENGTH) - { - // Don't allow it to be set if the name is too long - CLogger::ErrorPrintf("Custom data name too long (%s)", *SStringX(szName).Left(MAX_CUSTOMDATA_NAME_LENGTH + 1)); - return; - } + // SCustomData is 64(88 in debug) bytes long. A static storage can be more efficient. + static SCustomData oldData; - // Grab the old variable - CLuaArgument oldVariable; - SCustomData* pData = m_pCustomData->Get(szName); - if (pData) + if (m_pCustomData->Set(strName, Variable, bSynchronized, &oldData)) { - oldVariable = pData->Variable; - } - - // Set the new data - m_pCustomData->Set(szName, Variable, bSynchronized); + // Trigger the onClientElementDataChange event on us + CLuaArguments Arguments; + Arguments.PushString(strName); + Arguments.PushArgument(oldData.Variable); + Arguments.PushArgument(Variable); + CallEvent("onClientElementDataChange", Arguments, true); - // Trigger the onClientElementDataChange event on us - CLuaArguments Arguments; - Arguments.PushString(szName); - Arguments.PushArgument(oldVariable); - Arguments.PushArgument(Variable); - CallEvent("onClientElementDataChange", Arguments, true); + return true; + } + + return false; } -void CClientEntity::DeleteCustomData(const char* szName) +void CClientEntity::DeleteCustomData(const SString& strName) { - // Grab the old variable - SCustomData* pData = m_pCustomData->Get(szName); - if (pData) - { - CLuaArgument oldVariable; - oldVariable = pData->Variable; - - // Delete the custom data - m_pCustomData->Delete(szName); + // SCustomData is 64(88 in debug) bytes long. A static storage can be more efficient. + static SCustomData oldData; + // Delete the custom data + if (m_pCustomData->Delete(strName, &oldData)) + { // Trigger the onClientElementDataChange event on us CLuaArguments Arguments; - Arguments.PushString(szName); - Arguments.PushArgument(oldVariable); - Arguments.PushArgument(CLuaArgument()); // Use nil as the new value to indicate the data has been removed + Arguments.PushString(strName); + Arguments.PushArgument(oldData.Variable); + Arguments.PushArgument(CLuaArgument{}); // Use nil as the new value to indicate the data has been removed CallEvent("onClientElementDataChange", Arguments, true); - } + } } bool CClientEntity::GetMatrix(CMatrix& matrix) const diff --git a/Client/mods/deathmatch/logic/CClientEntity.h b/Client/mods/deathmatch/logic/CClientEntity.h index bd60dab3ba4..2071a19bfa6 100644 --- a/Client/mods/deathmatch/logic/CClientEntity.h +++ b/Client/mods/deathmatch/logic/CClientEntity.h @@ -199,14 +199,14 @@ class CClientEntity : public CClientEntityBase void SetID(ElementID ID); CCustomData* GetCustomDataPointer() { return m_pCustomData; } - CLuaArgument* GetCustomData(const char* szName, bool bInheritData, bool* pbIsSynced = nullptr); + CLuaArgument* GetCustomData(const SString& strName, bool bInheritData, bool* pbIsSynced = nullptr); CLuaArguments* GetAllCustomData(CLuaArguments* table); bool GetCustomDataString(const char* szKey, SString& strOut, bool bInheritData); bool GetCustomDataFloat(const char* szKey, float& fOut, bool bInheritData); bool GetCustomDataInt(const char* szKey, int& iOut, bool bInheritData); bool GetCustomDataBool(const char* szKey, bool& bOut, bool bInheritData); - void SetCustomData(const char* szName, const CLuaArgument& Variable, bool bSynchronized = true); - void DeleteCustomData(const char* szName); + bool SetCustomData(const SString& strName, const CLuaArgument& Variable, bool bSynchronized = true); + void DeleteCustomData(const SString& strName); virtual bool GetMatrix(CMatrix& matrix) const; virtual bool SetMatrix(const CMatrix& matrix); diff --git a/Client/mods/deathmatch/logic/CCustomData.cpp b/Client/mods/deathmatch/logic/CCustomData.cpp index 8f441030783..ab618f96785 100644 --- a/Client/mods/deathmatch/logic/CCustomData.cpp +++ b/Client/mods/deathmatch/logic/CCustomData.cpp @@ -14,52 +14,58 @@ void CCustomData::Copy(CCustomData* pCustomData) { - std::map::const_iterator iter = pCustomData->IterBegin(); - for (; iter != pCustomData->IterEnd(); iter++) - { - Set(iter->first.c_str(), iter->second.Variable); - } + for (const auto& [key, data] : pCustomData->GetData()) + Set(key, data.Variable); } -SCustomData* CCustomData::Get(const char* szName) +SCustomData* CCustomData::Get(const SString& strName, bool bCreate) { - assert(szName); - - std::map::iterator it = m_Data.find(szName); - if (it != m_Data.end()) + if (auto it = m_Data.find(strName); it != m_Data.end()) return &it->second; - return NULL; + if (bCreate) + return &m_Data[strName]; + + return {}; } -void CCustomData::Set(const char* szName, const CLuaArgument& Variable, bool bSynchronized) +bool CCustomData::Set(const SString& strName, const CLuaArgument& Variable, bool bSynchronized, SCustomData* pOldData) { - assert(szName); - - // Grab the item with the given name - SCustomData* pData = Get(szName); - if (pData) + if (strName.length() > MAX_CUSTOMDATA_NAME_LENGTH) { - // Update existing - pData->Variable = Variable; - pData->bSynchronized = bSynchronized; + // Don't allow it to be set if the name is too long + CLogger::ErrorPrintf("Custom data name too long (%s)", *strName.Left(MAX_CUSTOMDATA_NAME_LENGTH + 1)); + return false; } - else + + SCustomData* pCurrentVariable = Get(strName, true); + assert(pCurrentVariable); + + if (pCurrentVariable->Variable.IsEmpty() || pCurrentVariable->Variable != Variable || pCurrentVariable->bSynchronized != bSynchronized) { - // Add new - SCustomData newData; - newData.Variable = Variable; - newData.bSynchronized = bSynchronized; - m_Data[szName] = newData; - } + // Save the old variable + if (pOldData) + *pOldData = *pCurrentVariable; + + // Set the new data + pCurrentVariable->Variable = Variable; + pCurrentVariable->bSynchronized = bSynchronized; + + return true; + } + + return false; } -bool CCustomData::Delete(const char* szName) +bool CCustomData::Delete(const SString& strName, SCustomData* pOldData) { // Find the item and delete it - std::map::iterator it = m_Data.find(szName); + auto it = m_Data.find(strName); if (it != m_Data.end()) { + if (pOldData) + *pOldData = it->second; + m_Data.erase(it); return true; } diff --git a/Client/mods/deathmatch/logic/CCustomData.h b/Client/mods/deathmatch/logic/CCustomData.h index 01e5eb81cdb..70fb515f88c 100644 --- a/Client/mods/deathmatch/logic/CCustomData.h +++ b/Client/mods/deathmatch/logic/CCustomData.h @@ -17,7 +17,7 @@ struct SCustomData { CLuaArgument Variable; - bool bSynchronized; + bool bSynchronized{true}; }; class CCustomData @@ -25,14 +25,13 @@ class CCustomData public: void Copy(CCustomData* pCustomData); - SCustomData* Get(const char* szName); - void Set(const char* szName, const CLuaArgument& Variable, bool bSynchronized = true); + SCustomData* Get(const SString& strName, bool bCreate = false); + bool Set(const SString& strName, const CLuaArgument& Variable, bool bSynchronized = true, SCustomData* pOldData = {}); - bool Delete(const char* szName); + bool Delete(const SString& strName, SCustomData* pOldData = {}); - std::map::const_iterator IterBegin() { return m_Data.begin(); } - std::map::const_iterator IterEnd() { return m_Data.end(); } + const std::unordered_map& GetData() const { return m_Data; } private: - std::map m_Data; + std::unordered_map m_Data; }; diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index ffc4466a339..40c3c45ff70 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -993,23 +993,18 @@ bool CStaticFunctionDefinitions::SetElementID(CClientEntity& Entity, const char* return false; } -bool CStaticFunctionDefinitions::SetElementData(CClientEntity& Entity, const char* szName, CLuaArgument& Variable, bool bSynchronize) +bool CStaticFunctionDefinitions::SetElementData(CClientEntity& Entity, const SString& strName, CLuaArgument& Variable, bool bSynchronize) { - assert(szName); - assert(strlen(szName) <= MAX_CUSTOMDATA_NAME_LENGTH); - - bool bIsSynced; - CLuaArgument* pCurrentVariable = Entity.GetCustomData(szName, false, &bIsSynced); - if (!pCurrentVariable || Variable != *pCurrentVariable || bIsSynced != bSynchronize) + if (Entity.SetCustomData(strName, Variable, bSynchronize)) { if (bSynchronize && !Entity.IsLocalEntity()) { NetBitStreamInterface* pBitStream = g_pNet->AllocateNetBitStream(); // Write element ID, name length and the name. Also write the variable. pBitStream->Write(Entity.GetID()); - unsigned short usNameLength = static_cast(strlen(szName)); + const unsigned short usNameLength = static_cast(strName.length()); pBitStream->WriteCompressed(usNameLength); - pBitStream->Write(szName, usNameLength); + pBitStream->Write(strName.c_str(), usNameLength); Variable.WriteToBitStream(*pBitStream); // Send the packet and deallocate @@ -1017,10 +1012,8 @@ bool CStaticFunctionDefinitions::SetElementData(CClientEntity& Entity, const cha g_pNet->DeallocateNetBitStream(pBitStream); } - // Set its custom data - Entity.SetCustomData(szName, Variable, bSynchronize); return true; - } + } return false; } diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h index 437e4503f65..ab7dfa0640f 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h @@ -81,7 +81,7 @@ class CStaticFunctionDefinitions static CClientDummy* CreateElement(CResource& Resource, const char* szTypeName, const char* szID); static bool DestroyElement(CClientEntity& Entity); static bool SetElementID(CClientEntity& Entity, const char* szID); - static bool SetElementData(CClientEntity& Entity, const char* szName, CLuaArgument& Variable, bool bSynchronize); + static bool SetElementData(CClientEntity& Entity, const SString& strName, CLuaArgument& Variable, bool bSynchronize); static bool RemoveElementData(CClientEntity& Entity, const char* szName); static bool SetElementMatrix(CClientEntity& Entity, const CMatrix& matrix); static bool SetElementPosition(CClientEntity& Entity, const CVector& vecPosition, bool bWarp = true); diff --git a/Client/mods/deathmatch/logic/lua/CLuaArgument.h b/Client/mods/deathmatch/logic/lua/CLuaArgument.h index a0b8a416edb..745df187f1c 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaArgument.h +++ b/Client/mods/deathmatch/logic/lua/CLuaArgument.h @@ -51,6 +51,8 @@ class CLuaArgument int GetType() const { return m_iType; }; int GetIndex() const { return m_iIndex; }; + bool IsEmpty() const { return m_iType == m_iType; } + bool GetBoolean() const { return m_bBoolean; }; lua_Number GetNumber() const { return m_Number; }; const SString& GetString() { return m_strString; }; diff --git a/Server/mods/deathmatch/logic/CCustomData.cpp b/Server/mods/deathmatch/logic/CCustomData.cpp index f18bbd37d19..b613403b2d0 100644 --- a/Server/mods/deathmatch/logic/CCustomData.cpp +++ b/Server/mods/deathmatch/logic/CCustomData.cpp @@ -14,39 +14,35 @@ void CCustomData::Copy(CCustomData* pCustomData) { - std::map::const_iterator iter = pCustomData->IterBegin(); - for (; iter != pCustomData->IterEnd(); iter++) - { - Set(iter->first.c_str(), iter->second.Variable); - } + for (const auto& [key, data] : pCustomData->GetData()) + Set(key, data.Variable); } -SCustomData* CCustomData::Get(const char* szName) +SCustomData* CCustomData::Get(const SString& strName, bool bCreate) { - assert(szName); - - std::map::const_iterator it = m_Data.find(szName); + auto it = m_Data.find(strName); if (it != m_Data.end()) - return (SCustomData*)&it->second; + return &it->second; - return NULL; + if (bCreate) + return &m_Data[strName]; + + return {}; } -SCustomData* CCustomData::GetSynced(const char* szName) +SCustomData* CCustomData::GetSynced(const SString& strName) { - assert(szName); - - std::map::const_iterator it = m_SyncedData.find(szName); + auto it = m_SyncedData.find(strName); if (it != m_SyncedData.end()) - return (SCustomData*)&it->second; + return &it->second; - return NULL; + return {}; } -bool CCustomData::DeleteSynced(const char* szName) +bool CCustomData::DeleteSynced(const SString& strName) { // Find the item and delete it - std::map::iterator iter = m_SyncedData.find(szName); + auto iter = m_SyncedData.find(strName); if (iter != m_SyncedData.end()) { m_SyncedData.erase(iter); @@ -57,11 +53,11 @@ bool CCustomData::DeleteSynced(const char* szName) return false; } -void CCustomData::UpdateSynced(const char* szName, const CLuaArgument& Variable, ESyncType syncType) +void CCustomData::UpdateSynced(const SString& strName, const CLuaArgument& Variable, ESyncType syncType) { if (syncType == ESyncType::BROADCAST) { - SCustomData* pDataSynced = GetSynced(szName); + SCustomData* pDataSynced = GetSynced(strName); if (pDataSynced) { pDataSynced->Variable = Variable; @@ -72,46 +68,53 @@ void CCustomData::UpdateSynced(const char* szName, const CLuaArgument& Variable, SCustomData newData; newData.Variable = Variable; newData.syncType = syncType; - m_SyncedData[szName] = newData; + m_SyncedData[strName] = newData; } } else { - DeleteSynced(szName); + DeleteSynced(strName); } } -void CCustomData::Set(const char* szName, const CLuaArgument& Variable, ESyncType syncType) +bool CCustomData::Set(const SString& strName, const CLuaArgument& Variable, ESyncType syncType, SCustomData* pOldData) { - assert(szName); + if (strName.length() > MAX_CUSTOMDATA_NAME_LENGTH) + return false; - // Grab the item with the given name - SCustomData* pData = Get(szName); - if (pData) - { - // Update existing - pData->Variable = Variable; - pData->syncType = syncType; - UpdateSynced(szName, Variable, syncType); - } - else + SCustomData* pCurrentVariable = Get(strName, true); + assert(pCurrentVariable); + + if (pCurrentVariable->Variable.IsEmpty() || pCurrentVariable->Variable != Variable || pCurrentVariable->syncType != syncType) { - // Add new - SCustomData newData; - newData.Variable = Variable; - newData.syncType = syncType; - m_Data[szName] = newData; - UpdateSynced(szName, Variable, syncType); - } + if (syncType == ESyncType::PERSISTENT) + syncType = pCurrentVariable->syncType; + + // Save the old variable + if (pOldData) + *pOldData = *pCurrentVariable; + + // Set the new data + pCurrentVariable->Variable = Variable; + pCurrentVariable->syncType = syncType; + UpdateSynced(strName, Variable, syncType); + + return true; + } + + return false; } -bool CCustomData::Delete(const char* szName) +bool CCustomData::Delete(const SString& strName, SCustomData* pOldData) { // Find the item and delete it - std::map::iterator it = m_Data.find(szName); + auto it = m_Data.find(strName); if (it != m_Data.end()) { - DeleteSynced(szName); + if (pOldData) + *pOldData = it->second; + + DeleteSynced(strName); m_Data.erase(it); return true; } @@ -122,37 +125,32 @@ bool CCustomData::Delete(const char* szName) CXMLNode* CCustomData::OutputToXML(CXMLNode* pNode) { - std::map::const_iterator iter = m_Data.begin(); - for (; iter != m_Data.end(); iter++) + for (const auto& [key, data] : m_Data) { - CLuaArgument* arg = (CLuaArgument*)&iter->second.Variable; + const CLuaArgument& arg = data.Variable; - switch (arg->GetType()) + switch (arg.GetType()) { case LUA_TSTRING: { - CXMLAttribute* attr = pNode->GetAttributes().Create(iter->first.c_str()); - attr->SetValue(arg->GetString().c_str()); + CXMLAttribute* attr = pNode->GetAttributes().Create(key.c_str()); + attr->SetValue(arg.GetString().c_str()); break; } case LUA_TNUMBER: { - CXMLAttribute* attr = pNode->GetAttributes().Create(iter->first.c_str()); - attr->SetValue((float)arg->GetNumber()); + CXMLAttribute* attr = pNode->GetAttributes().Create(key.c_str()); + attr->SetValue((float)arg.GetNumber()); break; } case LUA_TBOOLEAN: { - CXMLAttribute* attr = pNode->GetAttributes().Create(iter->first.c_str()); - attr->SetValue(arg->GetBoolean()); + CXMLAttribute* attr = pNode->GetAttributes().Create(key.c_str()); + attr->SetValue(arg.GetBoolean()); break; } } } + return pNode; } - -unsigned short CCustomData::CountOnlySynchronized() -{ - return static_cast(m_SyncedData.size()); -} diff --git a/Server/mods/deathmatch/logic/CCustomData.h b/Server/mods/deathmatch/logic/CCustomData.h index bfb17ff5290..84a5898adec 100644 --- a/Server/mods/deathmatch/logic/CCustomData.h +++ b/Server/mods/deathmatch/logic/CCustomData.h @@ -23,12 +23,13 @@ enum class ESyncType LOCAL, BROADCAST, SUBSCRIBE, + PERSISTENT }; struct SCustomData { CLuaArgument Variable; - ESyncType syncType; + ESyncType syncType{ESyncType::BROADCAST}; }; class CCustomData @@ -36,26 +37,21 @@ class CCustomData public: void Copy(CCustomData* pCustomData); - SCustomData* Get(const char* szName); - SCustomData* GetSynced(const char* szName); - void Set(const char* szName, const CLuaArgument& Variable, ESyncType syncType = ESyncType::BROADCAST); + SCustomData* Get(const SString& strName, bool bCreate = false); + SCustomData* GetSynced(const SString& strName); + bool Set(const SString& strName, const CLuaArgument& Variable, ESyncType syncType = ESyncType::BROADCAST, SCustomData* pOldData = {}); - bool Delete(const char* szName); - - unsigned short CountOnlySynchronized(); + bool Delete(const SString& strName, SCustomData* pOldData = {}); CXMLNode* OutputToXML(CXMLNode* pNode); - std::map::const_iterator IterBegin() { return m_Data.begin(); } - std::map::const_iterator IterEnd() { return m_Data.end(); } - - std::map::const_iterator SyncedIterBegin() { return m_SyncedData.begin(); } - std::map::const_iterator SyncedIterEnd() { return m_SyncedData.end(); } + const std::unordered_map& GetData() const { return m_Data; } + const std::unordered_map& GetSyncedData() const { return m_SyncedData; } private: - bool DeleteSynced(const char* szName); - void UpdateSynced(const char* szName, const CLuaArgument& Variable, ESyncType syncType); + bool DeleteSynced(const SString& strName); + void UpdateSynced(const SString& strName, const CLuaArgument& Variable, ESyncType syncType); - std::map m_Data; - std::map m_SyncedData; + std::unordered_map m_Data; + std::unordered_map m_SyncedData; }; diff --git a/Server/mods/deathmatch/logic/CElement.cpp b/Server/mods/deathmatch/logic/CElement.cpp index 59086a2f143..8dd02344bb6 100644 --- a/Server/mods/deathmatch/logic/CElement.cpp +++ b/Server/mods/deathmatch/logic/CElement.cpp @@ -503,17 +503,15 @@ void CElement::ReadCustomData(CEvents* pEvents, CXMLNode& Node) args.PushString(pAttribute->GetValue().c_str()); // Don't trigger onElementDataChanged event - ESyncType syncType = g_pGame->GetConfig()->GetSyncMapElementData() ? ESyncType::BROADCAST : ESyncType::LOCAL; - SetCustomData(pAttribute->GetName().c_str(), *args[0], syncType, NULL, false); + const ESyncType syncType = g_pGame->GetConfig()->GetSyncMapElementData() ? ESyncType::BROADCAST : ESyncType::LOCAL; + SetCustomData(pAttribute->GetName(), *args[0], syncType, {}, false); } } -CLuaArgument* CElement::GetCustomData(const char* szName, bool bInheritData, ESyncType* pSyncType) +CLuaArgument* CElement::GetCustomData(const SString& strName, bool bInheritData, ESyncType* pSyncType) { - assert(szName); - // Grab it and return a pointer to the variable - SCustomData* pData = m_CustomData.Get(szName); + SCustomData* pData = m_CustomData.Get(strName); if (pData) { if (pSyncType) @@ -524,11 +522,11 @@ CLuaArgument* CElement::GetCustomData(const char* szName, bool bInheritData, ESy // If none, try returning parent's custom data if (bInheritData && m_pParent) { - return m_pParent->GetCustomData(szName, true, pSyncType); + return m_pParent->GetCustomData(strName, true, pSyncType); } // None available - return NULL; + return {}; } CLuaArguments* CElement::GetAllCustomData(CLuaArguments* table) @@ -536,12 +534,11 @@ CLuaArguments* CElement::GetAllCustomData(CLuaArguments* table) assert(table); // Grab it and return a pointer to the variable - map::const_iterator iter = m_CustomData.IterBegin(); - for (; iter != m_CustomData.IterEnd(); iter++) + for (const auto& [key, data] : m_CustomData.GetData()) { - table->PushString(iter->first.c_str()); // key - table->PushArgument(iter->second.Variable); // value - } + table->PushString(key); // key + table->PushArgument(data.Variable); // value + } return table; } @@ -705,67 +702,60 @@ bool CElement::GetCustomDataBool(const char* szName, bool& bOut, bool bInheritDa return false; } -void CElement::SetCustomData(const char* szName, const CLuaArgument& Variable, ESyncType syncType, CPlayer* pClient, bool bTriggerEvent) +const SCustomData* CElement::SetCustomData(const SString& strName, const CLuaArgument& Variable, ESyncType syncType, CPlayer* pClient, bool bTriggerEvent) { - assert(szName); - if (strlen(szName) > MAX_CUSTOMDATA_NAME_LENGTH) + if (strName.length() > MAX_CUSTOMDATA_NAME_LENGTH) { // Don't allow it to be set if the name is too long - CLogger::ErrorPrintf("Custom data name too long (%s)\n", *SStringX(szName).Left(MAX_CUSTOMDATA_NAME_LENGTH + 1)); - return; + CLogger::ErrorPrintf("Custom data name too long (%s)\n", *strName.Left(MAX_CUSTOMDATA_NAME_LENGTH + 1)); + return {}; } - // Grab the old variable - CLuaArgument oldVariable; - const SCustomData* pData = m_CustomData.Get(szName); - if (pData) - { - oldVariable = pData->Variable; - } + // SCustomData is 64(88 in debug) bytes long. A static storage can be more efficient. + static SCustomData oldData; - // Set the new data - m_CustomData.Set(szName, Variable, syncType); + if (m_CustomData.Set(strName, Variable, syncType, &oldData) != true) + return {}; if (bTriggerEvent) { // Trigger the onElementDataChange event on us CLuaArguments Arguments; - Arguments.PushString(szName); - Arguments.PushArgument(oldVariable); + Arguments.PushString(strName); + Arguments.PushArgument(oldData.Variable); Arguments.PushArgument(Variable); CallEvent("onElementDataChange", Arguments, pClient); - } + } + + return &oldData; } -void CElement::DeleteCustomData(const char* szName) +bool CElement::DeleteCustomData(const SString& strName) { - // Grab the old variable - SCustomData* pData = m_CustomData.Get(szName); - if (pData) - { - CLuaArgument oldVariable; - oldVariable = pData->Variable; - - // Delete the custom data - m_CustomData.Delete(szName); + // SCustomData is 64(88 in debug) bytes long. A static storage can be more efficient. + static SCustomData oldData; + // Delete the custom data + if (m_CustomData.Delete(strName, &oldData)) + { // Trigger the onElementDataChange event on us CLuaArguments Arguments; - Arguments.PushString(szName); - Arguments.PushArgument(oldVariable); - Arguments.PushArgument(CLuaArgument()); // Use nil as the new value to indicate the data has been removed + Arguments.PushString(strName); + Arguments.PushArgument(oldData.Variable); + Arguments.PushArgument(CLuaArgument{}); // Use nil as the new value to indicate the data has been removed CallEvent("onElementDataChange", Arguments); + + return true; } + + return false; } // Used to send the root element data when a player joins void CElement::SendAllCustomData(CPlayer* pPlayer) { - for (map::const_iterator iter = m_CustomData.SyncedIterBegin(); iter != m_CustomData.SyncedIterEnd(); ++iter) + for (const auto& [strName, customData] : m_CustomData.GetSyncedData()) { - const std::string& strName = iter->first; - const SCustomData& customData = iter->second; - if (customData.syncType == ESyncType::LOCAL) continue; @@ -778,7 +768,7 @@ void CElement::SendAllCustomData(CPlayer* pPlayer) if (customData.syncType == ESyncType::BROADCAST || pPlayer->IsSubscribed(this, strName)) pPlayer->Send(CElementRPCPacket(this, SET_ELEMENT_DATA, *BitStream.pBitStream)); - } + } } CXMLNode* CElement::OutputToXML(CXMLNode* pNodeParent) diff --git a/Server/mods/deathmatch/logic/CElement.h b/Server/mods/deathmatch/logic/CElement.h index e3a0fa4d070..ce59a825704 100644 --- a/Server/mods/deathmatch/logic/CElement.h +++ b/Server/mods/deathmatch/logic/CElement.h @@ -136,15 +136,16 @@ class CElement void ReadCustomData(CEvents* pEvents, CXMLNode& Node); CCustomData& GetCustomDataManager() { return m_CustomData; } - CLuaArgument* GetCustomData(const char* szName, bool bInheritData, ESyncType* pSyncType = NULL); + CLuaArgument* GetCustomData(const SString& strName, bool bInheritData, ESyncType* pSyncType = NULL); CLuaArguments* GetAllCustomData(CLuaArguments* table); bool GetCustomDataString(const char* szName, char* pOut, size_t sizeBuffer, bool bInheritData); bool GetCustomDataInt(const char* szName, int& iOut, bool bInheritData); bool GetCustomDataFloat(const char* szName, float& fOut, bool bInheritData); bool GetCustomDataBool(const char* szName, bool& bOut, bool bInheritData); - void SetCustomData(const char* szName, const CLuaArgument& Variable, ESyncType syncType = ESyncType::BROADCAST, CPlayer* pClient = NULL, + // Note that returned SCustomData* cannot be used with recursive algorithms! + const SCustomData* SetCustomData(const SString& strName, const CLuaArgument& Variable, ESyncType syncType = ESyncType::BROADCAST, CPlayer* pClient = {}, bool bTriggerEvent = true); - void DeleteCustomData(const char* szName); + bool DeleteCustomData(const SString& strName); void SendAllCustomData(CPlayer* pPlayer); CXMLNode* OutputToXML(CXMLNode* pNode); diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp index c2c84855629..0c8be06eafd 100644 --- a/Server/mods/deathmatch/logic/CGame.cpp +++ b/Server/mods/deathmatch/logic/CGame.cpp @@ -2593,39 +2593,29 @@ void CGame::Packet_CustomData(CCustomDataPacket& Packet) if (pElement) { // Change the data - const char* szName = Packet.GetName(); - CLuaArgument& Value = Packet.GetValue(); + const SString& strName = Packet.GetName(); + const CLuaArgument& Value = Packet.GetValue(); - // Ignore if the wrong length - if (strlen(szName) > MAX_CUSTOMDATA_NAME_LENGTH) + if (const SCustomData* pOldData = pElement->SetCustomData(strName, Value, ESyncType::PERSISTENT, pSourcePlayer)) { - CLogger::ErrorPrintf("Received oversized custom data name from %s (%s)", Packet.GetSourcePlayer()->GetNick(), - *SStringX(szName).Left(MAX_CUSTOMDATA_NAME_LENGTH + 1)); - return; - } - - ESyncType lastSyncType = ESyncType::BROADCAST; - pElement->GetCustomData(szName, false, &lastSyncType); - - if (lastSyncType != ESyncType::LOCAL) - { - // Tell our clients to update their data. Send to everyone but the one we got this packet from. - unsigned short usNameLength = static_cast(strlen(szName)); - CBitStream BitStream; - BitStream.pBitStream->WriteCompressed(usNameLength); - BitStream.pBitStream->Write(szName, usNameLength); - Value.WriteToBitStream(*BitStream.pBitStream); - if (lastSyncType == ESyncType::BROADCAST) - m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(pElement, SET_ELEMENT_DATA, *BitStream.pBitStream), pSourcePlayer); - else - m_pPlayerManager->BroadcastOnlySubscribed(CElementRPCPacket(pElement, SET_ELEMENT_DATA, *BitStream.pBitStream), pElement, szName, - pSourcePlayer); - - CPerfStatEventPacketUsage::GetSingleton()->UpdateElementDataUsageRelayed(szName, m_pPlayerManager->Count(), - BitStream.pBitStream->GetNumberOfBytesUsed()); - } + if (pOldData->syncType != ESyncType::LOCAL) + { + // Tell our clients to update their data. Send to everyone but the one we got this packet from. + unsigned short usNameLength = static_cast(strName.length()); + CBitStream BitStream; + BitStream.pBitStream->WriteCompressed(usNameLength); + BitStream.pBitStream->Write(strName.c_str(), usNameLength); + Value.WriteToBitStream(*BitStream.pBitStream); + if (pOldData->syncType == ESyncType::BROADCAST) + m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(pElement, SET_ELEMENT_DATA, *BitStream.pBitStream), pSourcePlayer); + else + m_pPlayerManager->BroadcastOnlySubscribed(CElementRPCPacket(pElement, SET_ELEMENT_DATA, *BitStream.pBitStream), pElement, strName, + pSourcePlayer); - pElement->SetCustomData(szName, Value, lastSyncType, pSourcePlayer); + CPerfStatEventPacketUsage::GetSingleton()->UpdateElementDataUsageRelayed(strName, m_pPlayerManager->Count(), + BitStream.pBitStream->GetNumberOfBytesUsed()); + } + } } } } diff --git a/Server/mods/deathmatch/logic/CPerfStat.EventPacketUsage.cpp b/Server/mods/deathmatch/logic/CPerfStat.EventPacketUsage.cpp index 206c81e2fef..5d50b499db1 100644 --- a/Server/mods/deathmatch/logic/CPerfStat.EventPacketUsage.cpp +++ b/Server/mods/deathmatch/logic/CPerfStat.EventPacketUsage.cpp @@ -43,9 +43,9 @@ class CPerfStatEventPacketUsageImpl : public CPerfStatEventPacketUsage virtual void GetStats(CPerfStatResult* pOutResult, const std::map& optionMap, const SString& strFilter); // CPerfStatEventPacketUsage - virtual void UpdateElementDataUsageOut(const char* szName, uint uiNumPlayers, uint uiSize); - virtual void UpdateElementDataUsageRelayed(const char* szName, uint uiNumPlayers, uint uiSize); - virtual void UpdateEventUsageOut(const char* szName, uint uiNumPlayers); + virtual void UpdateElementDataUsageOut(const SString& strName, uint uiNumPlayers, uint uiSize); + virtual void UpdateElementDataUsageRelayed(const SString& strName, uint uiNumPlayers, uint uiSize); + virtual void UpdateEventUsageOut(const SString& strName, uint uiNumPlayers); // CPerfStatEventPacketUsageImpl void MaybeRecordStats(); @@ -128,12 +128,12 @@ void CPerfStatEventPacketUsageImpl::DoPulse() // // /////////////////////////////////////////////////////////////// -void CPerfStatEventPacketUsageImpl::UpdateElementDataUsageOut(const char* szName, uint uiNumPlayers, uint uiSize) +void CPerfStatEventPacketUsageImpl::UpdateElementDataUsageOut(const SString& strName, uint uiNumPlayers, uint uiSize) { if (!m_bEnabled) return; - SEventUsage& usage = MapGet(m_EventUsageLiveMap, szName); + SEventUsage& usage = MapGet(m_EventUsageLiveMap, strName); usage.iTotal += uiNumPlayers; usage.iElementDataOut += uiNumPlayers; } @@ -145,12 +145,12 @@ void CPerfStatEventPacketUsageImpl::UpdateElementDataUsageOut(const char* szName // // /////////////////////////////////////////////////////////////// -void CPerfStatEventPacketUsageImpl::UpdateElementDataUsageRelayed(const char* szName, uint uiNumPlayers, uint uiSize) +void CPerfStatEventPacketUsageImpl::UpdateElementDataUsageRelayed(const SString& strName, uint uiNumPlayers, uint uiSize) { if (!m_bEnabled) return; - SEventUsage& usage = MapGet(m_EventUsageLiveMap, szName); + SEventUsage& usage = MapGet(m_EventUsageLiveMap, strName); usage.iTotal += uiNumPlayers; usage.iElementDataRelay += uiNumPlayers; } @@ -162,12 +162,12 @@ void CPerfStatEventPacketUsageImpl::UpdateElementDataUsageRelayed(const char* sz // // /////////////////////////////////////////////////////////////// -void CPerfStatEventPacketUsageImpl::UpdateEventUsageOut(const char* szName, uint uiNumPlayers) +void CPerfStatEventPacketUsageImpl::UpdateEventUsageOut(const SString& strName, uint uiNumPlayers) { if (!m_bEnabled) return; - SEventUsage& usage = MapGet(m_EventUsageLiveMap, szName); + SEventUsage& usage = MapGet(m_EventUsageLiveMap, strName); usage.iTotal += uiNumPlayers; usage.iEventOut += uiNumPlayers; } diff --git a/Server/mods/deathmatch/logic/CPerfStatModule.h b/Server/mods/deathmatch/logic/CPerfStatModule.h index 795df5daaf8..f42783ecb6a 100644 --- a/Server/mods/deathmatch/logic/CPerfStatModule.h +++ b/Server/mods/deathmatch/logic/CPerfStatModule.h @@ -223,9 +223,9 @@ class CPerfStatEventPacketUsage : public CPerfStatModule virtual void GetStats(CPerfStatResult* pOutResult, const std::map& optionMap, const SString& strFilter) = 0; // CPerfStatRPCPacketUsage - virtual void UpdateElementDataUsageOut(const char* szName, uint uiNumPlayers, uint uiSize) = 0; - virtual void UpdateElementDataUsageRelayed(const char* szName, uint uiNumPlayers, uint uiSize) = 0; - virtual void UpdateEventUsageOut(const char* szName, uint uiNumPlayers) = 0; + virtual void UpdateElementDataUsageOut(const SString& strName, uint uiNumPlayers, uint uiSize) = 0; + virtual void UpdateElementDataUsageRelayed(const SString& strName, uint uiNumPlayers, uint uiSize) = 0; + virtual void UpdateEventUsageOut(const SString& strName, uint uiNumPlayers) = 0; static CPerfStatEventPacketUsage* GetSingleton(); }; diff --git a/Server/mods/deathmatch/logic/CPlayerManager.cpp b/Server/mods/deathmatch/logic/CPlayerManager.cpp index abdf923df7d..c2ea91eb765 100644 --- a/Server/mods/deathmatch/logic/CPlayerManager.cpp +++ b/Server/mods/deathmatch/logic/CPlayerManager.cpp @@ -188,7 +188,7 @@ size_t CPlayerManager::BroadcastDimensionOnlyJoined(const CPacket& Packet, ushor return sendList.size(); } -size_t CPlayerManager::BroadcastOnlySubscribed(const CPacket& Packet, CElement* pElement, const char* szName, CPlayer* pSkip) +size_t CPlayerManager::BroadcastOnlySubscribed(const CPacket& Packet, CElement* pElement, const SString& strName, CPlayer* pSkip) { // Make a list of players to send this packet to CSendList sendList; @@ -198,7 +198,7 @@ size_t CPlayerManager::BroadcastOnlySubscribed(const CPacket& Packet, CElement* for (; iter != m_Players.end(); iter++) { CPlayer* pPlayer = *iter; - if (pPlayer != pSkip && pPlayer->IsJoined() && pPlayer->IsSubscribed(pElement, szName)) + if (pPlayer != pSkip && pPlayer->IsJoined() && pPlayer->IsSubscribed(pElement, strName)) { sendList.push_back(pPlayer); } @@ -347,20 +347,14 @@ bool CPlayerManager::IsValidPlayerModel(unsigned short model) void CPlayerManager::ClearElementData(CElement* pElement, const std::string& name) { - list::const_iterator iter = m_Players.begin(); - for (; iter != m_Players.end(); iter++) - { - CPlayer* pPlayer = *iter; - pPlayer->UnsubscribeElementData(pElement, name); - } + for (auto* pPlayer : m_Players) + pPlayer->UnsubscribeElementData(pElement, name); } void CPlayerManager::ClearElementData(CElement* pElement) { - for (auto pPlayer : m_Players) - { + for (auto* pPlayer : m_Players) pPlayer->UnsubscribeElementData(pElement); - } } void CPlayerManager::ResetAll() diff --git a/Server/mods/deathmatch/logic/CPlayerManager.h b/Server/mods/deathmatch/logic/CPlayerManager.h index bd503380f4a..14703819118 100644 --- a/Server/mods/deathmatch/logic/CPlayerManager.h +++ b/Server/mods/deathmatch/logic/CPlayerManager.h @@ -46,7 +46,7 @@ class CPlayerManager size_t BroadcastOnlyJoined(const CPacket& Packet, CPlayer* pSkip = NULL); size_t BroadcastDimensionOnlyJoined(const CPacket& Packet, ushort usDimension, CPlayer* pSkip = NULL); - size_t BroadcastOnlySubscribed(const CPacket& Packet, CElement* pElement, const char* szName, CPlayer* pSkip = NULL); + size_t BroadcastOnlySubscribed(const CPacket& Packet, CElement* pElement, const SString& strName, CPlayer* pSkip = NULL); static void Broadcast(const CPacket& Packet, const std::set& sendList); static void Broadcast(const CPacket& Packet, const std::list& sendList); diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 0542dce5fdc..59b6fe9634e 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -458,13 +458,12 @@ CElement* CStaticFunctionDefinitions::GetElementByIndex(const char* szType, unsi return m_pMapManager->GetRootElement()->FindChildByType(szType, uiIndex, true); } -CLuaArgument* CStaticFunctionDefinitions::GetElementData(CElement* pElement, const char* szName, bool bInherit) +CLuaArgument* CStaticFunctionDefinitions::GetElementData(CElement* pElement, const SString& strName, bool bInherit) { assert(pElement); - assert(szName); // Return its custom data - return pElement->GetCustomData(szName, bInherit); + return pElement->GetCustomData(strName, bInherit); } CLuaArguments* CStaticFunctionDefinitions::GetAllElementData(CElement* pElement, CLuaArguments* table) @@ -937,97 +936,87 @@ bool CStaticFunctionDefinitions::SetElementID(CElement* pElement, const char* sz return true; } -bool CStaticFunctionDefinitions::SetElementData(CElement* pElement, const char* szName, const CLuaArgument& Variable, ESyncType syncType) +bool CStaticFunctionDefinitions::SetElementData(CElement* pElement, const SString& strName, const CLuaArgument& Variable, ESyncType syncType) { assert(pElement); - assert(szName); - assert(strlen(szName) <= MAX_CUSTOMDATA_NAME_LENGTH); + assert(strName.length() <= MAX_CUSTOMDATA_NAME_LENGTH); - ESyncType lastSyncType = ESyncType::BROADCAST; - CLuaArgument* pCurrentVariable = pElement->GetCustomData(szName, false, &lastSyncType); - - if (!pCurrentVariable || *pCurrentVariable != Variable || lastSyncType != syncType) + if (const SCustomData* pOldData = pElement->SetCustomData(strName, Variable, syncType)) { if (syncType != ESyncType::LOCAL) { // Tell our clients to update their data - unsigned short usNameLength = static_cast(strlen(szName)); + const unsigned short usNameLength = static_cast(strName.length()); CBitStream BitStream; BitStream.pBitStream->WriteCompressed(usNameLength); - BitStream.pBitStream->Write(szName, usNameLength); + BitStream.pBitStream->Write(strName.c_str(), usNameLength); Variable.WriteToBitStream(*BitStream.pBitStream); const CElementRPCPacket packet(pElement, SET_ELEMENT_DATA, *BitStream.pBitStream); const size_t numPlayers = syncType == ESyncType::BROADCAST ? m_pPlayerManager->BroadcastOnlyJoined(packet) - : m_pPlayerManager->BroadcastOnlySubscribed(packet, pElement, szName); + : m_pPlayerManager->BroadcastOnlySubscribed(packet, pElement, strName); - CPerfStatEventPacketUsage::GetSingleton()->UpdateElementDataUsageOut(szName, numPlayers, BitStream.pBitStream->GetNumberOfBytesUsed()); + CPerfStatEventPacketUsage::GetSingleton()->UpdateElementDataUsageOut(strName, numPlayers, BitStream.pBitStream->GetNumberOfBytesUsed()); } // Unsubscribe all the players - if (lastSyncType == ESyncType::SUBSCRIBE && syncType != ESyncType::SUBSCRIBE) - m_pPlayerManager->ClearElementData(pElement, szName); + if (pOldData->syncType == ESyncType::SUBSCRIBE && syncType != ESyncType::SUBSCRIBE) + m_pPlayerManager->ClearElementData(pElement, strName); - // Set its custom data - pElement->SetCustomData(szName, Variable, syncType); return true; } + return false; } -bool CStaticFunctionDefinitions::RemoveElementData(CElement* pElement, const char* szName) +bool CStaticFunctionDefinitions::RemoveElementData(CElement* pElement, const SString& strName) { assert(pElement); - assert(szName); - assert(strlen(szName) <= MAX_CUSTOMDATA_NAME_LENGTH); + assert(strName.length() <= MAX_CUSTOMDATA_NAME_LENGTH); - // Check it exists - if (pElement->GetCustomData(szName, false)) + if (pElement->DeleteCustomData(strName)) { // Tell our clients to update their data - unsigned short usNameLength = static_cast(strlen(szName)); + unsigned short usNameLength = static_cast(strName.length()); CBitStream BitStream; BitStream.pBitStream->WriteCompressed(usNameLength); - BitStream.pBitStream->Write(szName, usNameLength); + BitStream.pBitStream->Write(strName.c_str(), usNameLength); BitStream.pBitStream->WriteBit(false); // Unused (was recursive flag) m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(pElement, REMOVE_ELEMENT_DATA, *BitStream.pBitStream)); // Clean up after the data removal - m_pPlayerManager->ClearElementData(pElement, szName); + m_pPlayerManager->ClearElementData(pElement, strName); - // Delete here - pElement->DeleteCustomData(szName); return true; - } + } // Failed return false; } -bool CStaticFunctionDefinitions::AddElementDataSubscriber(CElement* pElement, const char* szName, CPlayer* pPlayer) +bool CStaticFunctionDefinitions::AddElementDataSubscriber(CElement* pElement, const SString& strName, CPlayer* pPlayer) { assert(pElement); - assert(szName); assert(pPlayer); ESyncType lastSyncType = ESyncType::LOCAL; - CLuaArgument* pCurrentVariable = pElement->GetCustomData(szName, false, &lastSyncType); + CLuaArgument* pCurrentVariable = pElement->GetCustomData(strName, false, &lastSyncType); if (pCurrentVariable != nullptr && lastSyncType == ESyncType::SUBSCRIBE) { - if (!pPlayer->SubscribeElementData(pElement, szName)) + if (!pPlayer->SubscribeElementData(pElement, strName)) return false; // Tell our clients to update their data - unsigned short usNameLength = static_cast(strlen(szName)); + unsigned short usNameLength = static_cast(strName.length()); CBitStream BitStream; BitStream.pBitStream->WriteCompressed(usNameLength); - BitStream.pBitStream->Write(szName, usNameLength); + BitStream.pBitStream->Write(strName.c_str(), usNameLength); pCurrentVariable->WriteToBitStream(*BitStream.pBitStream); pPlayer->Send(CElementRPCPacket(pElement, SET_ELEMENT_DATA, *BitStream.pBitStream)); - CPerfStatEventPacketUsage::GetSingleton()->UpdateElementDataUsageOut(szName, 1, BitStream.pBitStream->GetNumberOfBytesUsed()); + CPerfStatEventPacketUsage::GetSingleton()->UpdateElementDataUsageOut(strName, 1, BitStream.pBitStream->GetNumberOfBytesUsed()); return true; } @@ -1035,22 +1024,20 @@ bool CStaticFunctionDefinitions::AddElementDataSubscriber(CElement* pElement, co return false; } -bool CStaticFunctionDefinitions::RemoveElementDataSubscriber(CElement* pElement, const char* szName, CPlayer* pPlayer) +bool CStaticFunctionDefinitions::RemoveElementDataSubscriber(CElement* pElement, const SString& strName, CPlayer* pPlayer) { assert(pElement); - assert(szName); assert(pPlayer); - return pPlayer->UnsubscribeElementData(pElement, szName); + return pPlayer->UnsubscribeElementData(pElement, strName); } -bool CStaticFunctionDefinitions::HasElementDataSubscriber(CElement* pElement, const char* szName, CPlayer* pPlayer) +bool CStaticFunctionDefinitions::HasElementDataSubscriber(CElement* pElement, const SString& strName, CPlayer* pPlayer) { assert(pElement); - assert(szName); assert(pPlayer); - return pPlayer->IsSubscribed(pElement, szName); + return pPlayer->IsSubscribed(pElement, strName); } bool CStaticFunctionDefinitions::SetElementParent(CElement* pElement, CElement* pParent) diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h index fe9d20ebf84..940ddf22b9b 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h @@ -51,7 +51,7 @@ class CStaticFunctionDefinitions static CElement* GetElementByIndex(const char* szType, unsigned int uiIndex); static CElement* GetElementChild(CElement* pElement, unsigned int uiIndex); static bool GetElementChildrenCount(CElement* pElement, unsigned int& uiCount); - static CLuaArgument* GetElementData(CElement* pElement, const char* szName, bool bInherit); + static CLuaArgument* GetElementData(CElement* pElement, const SString& strName, bool bInherit); static CLuaArguments* GetAllElementData(CElement* pElement, CLuaArguments* table); static CElement* GetElementParent(CElement* pElement); static bool GetElementMatrix(CElement* pElement, CMatrix& matrix); @@ -83,11 +83,11 @@ class CStaticFunctionDefinitions // Element set funcs static bool ClearElementVisibleTo(CElement* pElement); static bool SetElementID(CElement* pElement, const char* szID); - static bool SetElementData(CElement* pElement, const char* szName, const CLuaArgument& Variable, ESyncType syncType); - static bool RemoveElementData(CElement* pElement, const char* szName); - static bool AddElementDataSubscriber(CElement* pElement, const char* szName, CPlayer* pPlayer); - static bool RemoveElementDataSubscriber(CElement* pElement, const char* szName, CPlayer* pPlayer); - static bool HasElementDataSubscriber(CElement* pElement, const char* szName, CPlayer* pPlayer); + static bool SetElementData(CElement* pElement, const SString& strName, const CLuaArgument& Variable, ESyncType syncType); + static bool RemoveElementData(CElement* pElement, const SString& strName); + static bool AddElementDataSubscriber(CElement* pElement, const SString& strName, CPlayer* pPlayer); + static bool RemoveElementDataSubscriber(CElement* pElement, const SString& strName, CPlayer* pPlayer); + static bool HasElementDataSubscriber(CElement* pElement, const SString& strName, CPlayer* pPlayer); static bool SetElementParent(CElement* pElement, CElement* pParent); static bool SetElementMatrix(CElement* pElement, const CMatrix& matrix); static bool SetElementPosition(CElement* pElement, const CVector& vecPosition, bool bWarp = true); diff --git a/Server/mods/deathmatch/logic/lua/CLuaArgument.h b/Server/mods/deathmatch/logic/lua/CLuaArgument.h index bb6c8581f8b..5b69210291e 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaArgument.h +++ b/Server/mods/deathmatch/logic/lua/CLuaArgument.h @@ -51,9 +51,11 @@ class CLuaArgument int GetType() const { return m_iType; }; + bool IsEmpty() const { return m_iType == LUA_TNIL; } + bool GetBoolean() const { return m_bBoolean; }; lua_Number GetNumber() const { return m_Number; }; - const std::string& GetString() { return m_strString; }; + const std::string& GetString() const { return m_strString; }; void* GetUserData() const { return m_pUserData; }; CElement* GetElement() const; bool GetAsString(SString& strBuffer); diff --git a/Server/mods/deathmatch/logic/packets/CCustomDataPacket.cpp b/Server/mods/deathmatch/logic/packets/CCustomDataPacket.cpp index d2bfb1ee4ac..86d9911409d 100644 --- a/Server/mods/deathmatch/logic/packets/CCustomDataPacket.cpp +++ b/Server/mods/deathmatch/logic/packets/CCustomDataPacket.cpp @@ -15,13 +15,10 @@ CCustomDataPacket::CCustomDataPacket() { - m_szName = NULL; } CCustomDataPacket::~CCustomDataPacket() { - delete[] m_szName; - m_szName = NULL; } bool CCustomDataPacket::Read(NetBitStreamInterface& BitStream) @@ -29,10 +26,10 @@ bool CCustomDataPacket::Read(NetBitStreamInterface& BitStream) unsigned short usNameLength; if (BitStream.Read(m_ElementID) && BitStream.ReadCompressed(usNameLength) && usNameLength > 0 && usNameLength <= MAX_CUSTOMDATA_NAME_LENGTH) { - m_szName = new char[usNameLength + 1]; - if (BitStream.Read(m_szName, usNameLength)) + m_strName.resize(usNameLength); + + if (BitStream.Read(m_strName.data(), usNameLength)) { - m_szName[usNameLength] = 0; if (m_Value.ReadFromBitStream(BitStream)) { return true; diff --git a/Server/mods/deathmatch/logic/packets/CCustomDataPacket.h b/Server/mods/deathmatch/logic/packets/CCustomDataPacket.h index 96b18b9867d..620d30edfb7 100644 --- a/Server/mods/deathmatch/logic/packets/CCustomDataPacket.h +++ b/Server/mods/deathmatch/logic/packets/CCustomDataPacket.h @@ -26,12 +26,12 @@ class CCustomDataPacket final : public CPacket bool Read(NetBitStreamInterface& BitStream); bool Write(NetBitStreamInterface& BitStream) const; - ElementID GetElementID() { return m_ElementID; } - char* GetName() { return m_szName; } - CLuaArgument& GetValue() { return m_Value; } + const ElementID GetElementID() const { return m_ElementID; } + const SString& GetName() const { return m_strName; } + const CLuaArgument& GetValue() const { return m_Value; } private: ElementID m_ElementID; - char* m_szName; + SString m_strName; CLuaArgument m_Value; }; diff --git a/Server/mods/deathmatch/logic/packets/CEntityAddPacket.cpp b/Server/mods/deathmatch/logic/packets/CEntityAddPacket.cpp index 858cf5c56b3..70c13562eb3 100644 --- a/Server/mods/deathmatch/logic/packets/CEntityAddPacket.cpp +++ b/Server/mods/deathmatch/logic/packets/CEntityAddPacket.cpp @@ -170,19 +170,16 @@ bool CEntityAddPacket::Write(NetBitStreamInterface& BitStream) const BitStream.WriteBit(pElement->IsCallPropagationEnabled()); // Write custom data - CCustomData& pCustomData = pElement->GetCustomDataManager(); - BitStream.WriteCompressed(pCustomData.CountOnlySynchronized()); - map::const_iterator iter = pCustomData.SyncedIterBegin(); - for (; iter != pCustomData.SyncedIterEnd(); ++iter) + const CCustomData& pCustomData = pElement->GetCustomDataManager(); + const uint16_t usSyncronizedDataCount = static_cast(pCustomData.GetSyncedData().size()); + BitStream.WriteCompressed(usSyncronizedDataCount); + for (const auto& [key, data] : pCustomData.GetSyncedData()) { - const char* szName = iter->first.c_str(); - const CLuaArgument* pArgument = &iter->second.Variable; - - unsigned char ucNameLength = static_cast(strlen(szName)); + const unsigned char ucNameLength = static_cast(key.length()); BitStream.Write(ucNameLength); - BitStream.Write(szName, ucNameLength); - pArgument->WriteToBitStream(BitStream); - } + BitStream.Write(key.c_str(), ucNameLength); + data.Variable.WriteToBitStream(BitStream); + } // Grab its name char szEmpty[1]; From cbfed4827ffa1a0c9c7bc3e3630d648b8d5edf4f Mon Sep 17 00:00:00 2001 From: TEDERIs Date: Wed, 10 Jan 2024 16:41:49 +0700 Subject: [PATCH 2/7] Fix misprint --- Client/mods/deathmatch/logic/lua/CLuaArgument.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/mods/deathmatch/logic/lua/CLuaArgument.h b/Client/mods/deathmatch/logic/lua/CLuaArgument.h index 745df187f1c..8c122628590 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaArgument.h +++ b/Client/mods/deathmatch/logic/lua/CLuaArgument.h @@ -51,7 +51,7 @@ class CLuaArgument int GetType() const { return m_iType; }; int GetIndex() const { return m_iIndex; }; - bool IsEmpty() const { return m_iType == m_iType; } + bool IsEmpty() const { return m_iType == LUA_TNIL; } bool GetBoolean() const { return m_bBoolean; }; lua_Number GetNumber() const { return m_Number; }; From 347f9ccdb10250179caf12a5e541b0d14b576295 Mon Sep 17 00:00:00 2001 From: TEDERIs Date: Fri, 12 Jan 2024 21:57:30 +0700 Subject: [PATCH 3/7] Further optimizations --- .../mods/deathmatch/logic/CClientEntity.cpp | 42 +++++--- Client/mods/deathmatch/logic/CClientEntity.h | 4 +- Client/mods/deathmatch/logic/CCustomData.cpp | 31 +++--- Client/mods/deathmatch/logic/CCustomData.h | 25 ++++- .../mods/deathmatch/logic/CPacketHandler.cpp | 2 +- .../logic/CStaticFunctionDefinitions.cpp | 25 ----- .../logic/CStaticFunctionDefinitions.h | 1 - .../deathmatch/logic/lua/CLuaArgument.cpp | 95 ++++++++++++++++++- .../mods/deathmatch/logic/lua/CLuaArgument.h | 18 ++-- .../deathmatch/logic/lua/CLuaArguments.cpp | 66 ++++++++----- .../mods/deathmatch/logic/lua/CLuaArguments.h | 2 + .../logic/luadefs/CLuaElementDefs.cpp | 2 +- .../deathmatch/logic/rpc/CElementRPCs.cpp | 2 +- Server/mods/deathmatch/logic/CCustomData.cpp | 24 ++--- Server/mods/deathmatch/logic/CCustomData.h | 23 ++++- Server/mods/deathmatch/logic/CElement.cpp | 50 ++++++++-- Server/mods/deathmatch/logic/CElement.h | 11 ++- Server/mods/deathmatch/logic/CGame.cpp | 27 +----- .../logic/CStaticFunctionDefinitions.cpp | 33 ------- .../logic/CStaticFunctionDefinitions.h | 1 - .../deathmatch/logic/lua/CLuaArgument.cpp | 88 ++++++++++++++++- .../mods/deathmatch/logic/lua/CLuaArgument.h | 18 ++-- .../deathmatch/logic/lua/CLuaArguments.cpp | 75 ++++++++------- .../mods/deathmatch/logic/lua/CLuaArguments.h | 1 + .../logic/luadefs/CLuaElementDefs.cpp | 2 +- .../logic/packets/CCustomDataPacket.h | 4 +- .../logic/luadefs/CLuaElementDefsShared.cpp | 2 +- 27 files changed, 445 insertions(+), 229 deletions(-) diff --git a/Client/mods/deathmatch/logic/CClientEntity.cpp b/Client/mods/deathmatch/logic/CClientEntity.cpp index 16e5145eb51..efbac757689 100644 --- a/Client/mods/deathmatch/logic/CClientEntity.cpp +++ b/Client/mods/deathmatch/logic/CClientEntity.cpp @@ -279,10 +279,10 @@ void CClientEntity::SetID(ElementID ID) } } -CLuaArgument* CClientEntity::GetCustomData(const SString& strName, bool bInheritData, bool* pbIsSynced) +const CLuaArgument* CClientEntity::GetCustomData(const SString& strName, bool bInheritData, bool* pbIsSynced) { // Grab it and return a pointer to the variable - SCustomData* pData = m_pCustomData->Get(strName); + const SCustomData* pData = m_pCustomData->Get(strName); if (pData) { if (pbIsSynced) @@ -316,7 +316,7 @@ CLuaArguments* CClientEntity::GetAllCustomData(CLuaArguments* table) bool CClientEntity::GetCustomDataString(const char* szName, SString& strOut, bool bInheritData) { // Grab the custom data variable - CLuaArgument* pData = GetCustomData(szName, bInheritData); + const CLuaArgument* pData = GetCustomData(szName, bInheritData); if (pData) { // Write the content depending on what type it is @@ -351,7 +351,7 @@ bool CClientEntity::GetCustomDataString(const char* szName, SString& strOut, boo bool CClientEntity::GetCustomDataInt(const char* szName, int& iOut, bool bInheritData) { // Grab the custom data variable - CLuaArgument* pData = GetCustomData(szName, bInheritData); + const CLuaArgument* pData = GetCustomData(szName, bInheritData); if (pData) { // Write the content depending on what type it is @@ -389,7 +389,7 @@ bool CClientEntity::GetCustomDataInt(const char* szName, int& iOut, bool bInheri bool CClientEntity::GetCustomDataFloat(const char* szName, float& fOut, bool bInheritData) { // Grab the custom data variable - CLuaArgument* pData = GetCustomData(szName, bInheritData); + const CLuaArgument* pData = GetCustomData(szName, bInheritData); if (pData) { // Write the content depending on what type it is @@ -416,7 +416,7 @@ bool CClientEntity::GetCustomDataFloat(const char* szName, float& fOut, bool bIn bool CClientEntity::GetCustomDataBool(const char* szName, bool& bOut, bool bInheritData) { // Grab the custom data variable - CLuaArgument* pData = GetCustomData(szName, bInheritData); + const CLuaArgument* pData = GetCustomData(szName, bInheritData); if (pData) { // Write the content depending on what type it is @@ -468,20 +468,38 @@ bool CClientEntity::GetCustomDataBool(const char* szName, bool& bOut, bool bInhe return false; } -bool CClientEntity::SetCustomData(const SString& strName, const CLuaArgument& Variable, bool bSynchronized) +bool CClientEntity::SetCustomData(SString&& strName, CLuaArgument&& Variable, bool bSynchronized, bool bSendPacket) { // SCustomData is 64(88 in debug) bytes long. A static storage can be more efficient. - static SCustomData oldData; + static SCustomData oldValue; - if (m_pCustomData->Set(strName, Variable, bSynchronized, &oldData)) + if (const auto result = m_pCustomData->Set(std::move(strName), std::move(Variable), bSynchronized, &oldValue)) { + const auto& newName = result.GetName(); + const auto& newValue = result.GetData(); + // Trigger the onClientElementDataChange event on us CLuaArguments Arguments; - Arguments.PushString(strName); - Arguments.PushArgument(oldData.Variable); - Arguments.PushArgument(Variable); + Arguments.PushString(newName); + Arguments.PushArgumentWeak(&oldValue.Variable); + Arguments.PushArgumentWeak(&newValue.Variable); CallEvent("onClientElementDataChange", Arguments, true); + if (bSendPacket && bSynchronized && !IsLocalEntity()) + { + NetBitStreamInterface* pBitStream = g_pNet->AllocateNetBitStream(); + // Write element ID, name length and the name. Also write the variable. + pBitStream->Write(GetID()); + const unsigned short usNameLength = static_cast(newName.length()); + pBitStream->WriteCompressed(usNameLength); + pBitStream->Write(newName.c_str(), usNameLength); + newValue.Variable.WriteToBitStream(*pBitStream); + + // Send the packet and deallocate + g_pNet->SendPacket(PACKET_ID_CUSTOM_DATA, pBitStream, PACKET_PRIORITY_HIGH, PACKET_RELIABILITY_RELIABLE_ORDERED); + g_pNet->DeallocateNetBitStream(pBitStream); + } + return true; } diff --git a/Client/mods/deathmatch/logic/CClientEntity.h b/Client/mods/deathmatch/logic/CClientEntity.h index 2071a19bfa6..29be0cfabd3 100644 --- a/Client/mods/deathmatch/logic/CClientEntity.h +++ b/Client/mods/deathmatch/logic/CClientEntity.h @@ -199,13 +199,13 @@ class CClientEntity : public CClientEntityBase void SetID(ElementID ID); CCustomData* GetCustomDataPointer() { return m_pCustomData; } - CLuaArgument* GetCustomData(const SString& strName, bool bInheritData, bool* pbIsSynced = nullptr); + const CLuaArgument* GetCustomData(const SString& strName, bool bInheritData, bool* pbIsSynced = nullptr); CLuaArguments* GetAllCustomData(CLuaArguments* table); bool GetCustomDataString(const char* szKey, SString& strOut, bool bInheritData); bool GetCustomDataFloat(const char* szKey, float& fOut, bool bInheritData); bool GetCustomDataInt(const char* szKey, int& iOut, bool bInheritData); bool GetCustomDataBool(const char* szKey, bool& bOut, bool bInheritData); - bool SetCustomData(const SString& strName, const CLuaArgument& Variable, bool bSynchronized = true); + bool SetCustomData(SString&& strName, CLuaArgument&& Variable, bool bSynchronized = true, bool bSendPacket = false); void DeleteCustomData(const SString& strName); virtual bool GetMatrix(CMatrix& matrix) const; diff --git a/Client/mods/deathmatch/logic/CCustomData.cpp b/Client/mods/deathmatch/logic/CCustomData.cpp index ab618f96785..0ee6a8c25b9 100644 --- a/Client/mods/deathmatch/logic/CCustomData.cpp +++ b/Client/mods/deathmatch/logic/CCustomData.cpp @@ -15,46 +15,43 @@ void CCustomData::Copy(CCustomData* pCustomData) { for (const auto& [key, data] : pCustomData->GetData()) - Set(key, data.Variable); + Set(SString(key), CLuaArgument(data.Variable)); } -SCustomData* CCustomData::Get(const SString& strName, bool bCreate) +const SCustomData* CCustomData::Get(const SString& strName) { if (auto it = m_Data.find(strName); it != m_Data.end()) return &it->second; - if (bCreate) - return &m_Data[strName]; - return {}; } -bool CCustomData::Set(const SString& strName, const CLuaArgument& Variable, bool bSynchronized, SCustomData* pOldData) +SCustomDataResult CCustomData::Set(SString&& strName, CLuaArgument&& Variable, bool bSynchronized, SCustomData* oldValue) { if (strName.length() > MAX_CUSTOMDATA_NAME_LENGTH) { // Don't allow it to be set if the name is too long CLogger::ErrorPrintf("Custom data name too long (%s)", *strName.Left(MAX_CUSTOMDATA_NAME_LENGTH + 1)); - return false; + return {}; } - SCustomData* pCurrentVariable = Get(strName, true); - assert(pCurrentVariable); + auto iter = m_Data.try_emplace(std::move(strName)).first; + SCustomData& pCurrentVariable = iter->second; - if (pCurrentVariable->Variable.IsEmpty() || pCurrentVariable->Variable != Variable || pCurrentVariable->bSynchronized != bSynchronized) - { + if (pCurrentVariable.Variable.IsEmpty() || pCurrentVariable.bSynchronized != bSynchronized || pCurrentVariable.Variable != Variable ) + { // Save the old variable - if (pOldData) - *pOldData = *pCurrentVariable; + if (oldValue) + *oldValue = std::move(pCurrentVariable); // Set the new data - pCurrentVariable->Variable = Variable; - pCurrentVariable->bSynchronized = bSynchronized; + pCurrentVariable.Variable = std::move(Variable); + pCurrentVariable.bSynchronized = bSynchronized; - return true; + return SCustomDataResult(iter); } - return false; + return {}; } bool CCustomData::Delete(const SString& strName, SCustomData* pOldData) diff --git a/Client/mods/deathmatch/logic/CCustomData.h b/Client/mods/deathmatch/logic/CCustomData.h index 70fb515f88c..26485460fdb 100644 --- a/Client/mods/deathmatch/logic/CCustomData.h +++ b/Client/mods/deathmatch/logic/CCustomData.h @@ -20,13 +20,34 @@ struct SCustomData bool bSynchronized{true}; }; +struct SCustomDataResult +{ + using iterator = std::unordered_map::iterator; + + SCustomDataResult() = default; + + SCustomDataResult(const iterator& iter) : + Iter(iter), + bValid(true) + { + } + + const SString& GetName() const { return Iter->first; } + const SCustomData& GetData() const { return Iter->second; } + + operator bool() const { return bValid; } + + iterator Iter; + bool bValid{}; +}; + class CCustomData { public: void Copy(CCustomData* pCustomData); - SCustomData* Get(const SString& strName, bool bCreate = false); - bool Set(const SString& strName, const CLuaArgument& Variable, bool bSynchronized = true, SCustomData* pOldData = {}); + const SCustomData* Get(const SString& strName); + SCustomDataResult Set(SString&& strName, CLuaArgument&& Variable, bool bSynchronized = true, SCustomData* oldValue = {}); bool Delete(const SString& strName, SCustomData* pOldData = {}); diff --git a/Client/mods/deathmatch/logic/CPacketHandler.cpp b/Client/mods/deathmatch/logic/CPacketHandler.cpp index 51cad6aed4a..776410a5b00 100644 --- a/Client/mods/deathmatch/logic/CPacketHandler.cpp +++ b/Client/mods/deathmatch/logic/CPacketHandler.cpp @@ -2871,7 +2871,7 @@ void CPacketHandler::Packet_EntityAdd(NetBitStreamInterface& bitStream) CLuaArgument Argument; Argument.ReadFromBitStream(bitStream); - pCustomData->Set(strName, Argument); + pCustomData->Set(std::move(strName), std::move(Argument)); } else { diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 40c3c45ff70..38bf6d920a1 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -993,31 +993,6 @@ bool CStaticFunctionDefinitions::SetElementID(CClientEntity& Entity, const char* return false; } -bool CStaticFunctionDefinitions::SetElementData(CClientEntity& Entity, const SString& strName, CLuaArgument& Variable, bool bSynchronize) -{ - if (Entity.SetCustomData(strName, Variable, bSynchronize)) - { - if (bSynchronize && !Entity.IsLocalEntity()) - { - NetBitStreamInterface* pBitStream = g_pNet->AllocateNetBitStream(); - // Write element ID, name length and the name. Also write the variable. - pBitStream->Write(Entity.GetID()); - const unsigned short usNameLength = static_cast(strName.length()); - pBitStream->WriteCompressed(usNameLength); - pBitStream->Write(strName.c_str(), usNameLength); - Variable.WriteToBitStream(*pBitStream); - - // Send the packet and deallocate - g_pNet->SendPacket(PACKET_ID_CUSTOM_DATA, pBitStream, PACKET_PRIORITY_HIGH, PACKET_RELIABILITY_RELIABLE_ORDERED); - g_pNet->DeallocateNetBitStream(pBitStream); - } - - return true; - } - - return false; -} - bool CStaticFunctionDefinitions::RemoveElementData(CClientEntity& Entity, const char* szName) { // TODO diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h index ab7dfa0640f..eb0911623c2 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h @@ -81,7 +81,6 @@ class CStaticFunctionDefinitions static CClientDummy* CreateElement(CResource& Resource, const char* szTypeName, const char* szID); static bool DestroyElement(CClientEntity& Entity); static bool SetElementID(CClientEntity& Entity, const char* szID); - static bool SetElementData(CClientEntity& Entity, const SString& strName, CLuaArgument& Variable, bool bSynchronize); static bool RemoveElementData(CClientEntity& Entity, const char* szName); static bool SetElementMatrix(CClientEntity& Entity, const CMatrix& matrix); static bool SetElementPosition(CClientEntity& Entity, const CVector& vecPosition, bool bWarp = true); diff --git a/Client/mods/deathmatch/logic/lua/CLuaArgument.cpp b/Client/mods/deathmatch/logic/lua/CLuaArgument.cpp index 3a5f50df3f6..ad3af3d7525 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaArgument.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaArgument.cpp @@ -29,7 +29,8 @@ using namespace std; // Prevent the warning issued when doing unsigned short -> void* #pragma warning(disable:4312) -CLuaArgument::CLuaArgument() +CLuaArgument::CLuaArgument(CLuaArguments* pOwner) : + m_pOwner(pOwner) { m_iType = LUA_TNIL; m_iIndex = -1; @@ -37,20 +38,31 @@ CLuaArgument::CLuaArgument() m_pUserData = NULL; } -CLuaArgument::CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables) +CLuaArgument::CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables, CLuaArguments* pOwner) : + m_pOwner(pOwner) { // Initialize and call our = on the argument m_pTableData = NULL; CopyRecursive(Argument, pKnownTables); } -CLuaArgument::CLuaArgument(NetBitStreamInterface& bitStream, std::vector* pKnownTables) +CLuaArgument::CLuaArgument(CLuaArgument&& Argument, CFastHashMap* pKnownTables, CLuaArguments* pOwner) : + m_pOwner(pOwner) +{ + // Initialize and call our = on the argument + m_pTableData = NULL; + MoveRecursive(std::move(Argument)); +} + +CLuaArgument::CLuaArgument(NetBitStreamInterface& bitStream, std::vector* pKnownTables, CLuaArguments* pOwner) : + m_pOwner(pOwner) { m_pTableData = NULL; ReadFromBitStream(bitStream, pKnownTables); } -CLuaArgument::CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables) +CLuaArgument::CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables, CLuaArguments* pOwner) : + m_pOwner(pOwner) { // Read the argument out of the lua VM m_pTableData = NULL; @@ -67,7 +79,7 @@ CLuaArgument::~CLuaArgument() void CLuaArgument::CopyRecursive(const CLuaArgument& Argument, CFastHashMap* pKnownTables) { // Clear the string - m_strString = ""; + m_strString.clear(); // Destroy our old tabledata if neccessary DeleteTableData(); @@ -126,6 +138,71 @@ void CLuaArgument::CopyRecursive(const CLuaArgument& Argument, CFastHashMap* pKnownTables) +{ + // Clear the string + m_strString.clear(); + + // Destroy our old tabledata if neccessary + DeleteTableData(); + +#ifdef MTA_DEBUG + // Copy over line and filename too + m_strFilename = std::move(Argument.m_strFilename); + m_iLine = std::exchange(Argument.m_iLine, 0); +#endif + + // Set our variable equally to the copy class + m_iType = Argument.m_iType; + switch (m_iType) + { + case LUA_TBOOLEAN: + { + m_bBoolean = std::exchange(Argument.m_bBoolean, false); + break; + } + + case LUA_TUSERDATA: + case LUA_TLIGHTUSERDATA: + { + m_pUserData = std::exchange(Argument.m_pUserData, nullptr); + break; + } + + case LUA_TNUMBER: + { + m_Number = std::exchange(Argument.m_Number, 0); + break; + } + + case LUA_TTABLE: + { + if (pKnownTables && (m_pTableData = MapFindRef(*pKnownTables, Argument.m_pTableData))) + { + m_bWeakTableRef = true; + } + else + { + m_pTableData = std::exchange(Argument.m_pTableData, nullptr); + m_bWeakTableRef = false; + } + break; + } + + case LUA_TSTRING: + { + m_strString = std::move(Argument.m_strString); + break; + } + + default: + break; + } + + Argument.m_iType = LUA_TNIL; + Argument.m_iIndex = -1; +} + const CLuaArgument& CLuaArgument::operator=(const CLuaArgument& Argument) { CopyRecursive(Argument); @@ -134,6 +211,14 @@ const CLuaArgument& CLuaArgument::operator=(const CLuaArgument& Argument) return Argument; } +const CLuaArgument& CLuaArgument::operator=(CLuaArgument&& Argument) +{ + MoveRecursive(std::move(Argument)); + + // Return the given class allowing for chaining + return Argument; +} + bool CLuaArgument::operator==(const CLuaArgument& Argument) { std::set knownTables; diff --git a/Client/mods/deathmatch/logic/lua/CLuaArgument.h b/Client/mods/deathmatch/logic/lua/CLuaArgument.h index 8c122628590..3db092f02d0 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaArgument.h +++ b/Client/mods/deathmatch/logic/lua/CLuaArgument.h @@ -26,14 +26,17 @@ class CLuaArguments; class CLuaArgument { + friend class CLuaArguments; public: - CLuaArgument(); - CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables = NULL); - CLuaArgument(NetBitStreamInterface& bitStream, std::vector* pKnownTables = NULL); - CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables = NULL); + CLuaArgument(CLuaArguments* pOwner = {}); + CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables = NULL, CLuaArguments* pOwner = {}); + CLuaArgument(CLuaArgument&& Argument, CFastHashMap* pKnownTables = NULL, CLuaArguments* pOwner = {}); + CLuaArgument(NetBitStreamInterface& bitStream, std::vector* pKnownTables = NULL, CLuaArguments* pOwner = {}); + CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables = NULL, CLuaArguments* pOwner = {}); ~CLuaArgument(); const CLuaArgument& operator=(const CLuaArgument& Argument); + const CLuaArgument& operator=(CLuaArgument&& Argument); bool operator==(const CLuaArgument& Argument); bool operator!=(const CLuaArgument& Argument); @@ -55,7 +58,7 @@ class CLuaArgument bool GetBoolean() const { return m_bBoolean; }; lua_Number GetNumber() const { return m_Number; }; - const SString& GetString() { return m_strString; }; + const SString& GetString() const { return m_strString; }; void* GetUserData() const { return m_pUserData; }; CClientEntity* GetElement() const; @@ -68,14 +71,16 @@ class CLuaArgument private: void LogUnableToPacketize(const char* szMessage) const; + CLuaArguments* m_pOwner{}; + int m_iType; int m_iIndex; bool m_bBoolean; + bool m_bWeakTableRef; lua_Number m_Number; SString m_strString; void* m_pUserData; CLuaArguments* m_pTableData; - bool m_bWeakTableRef; #ifdef MTA_DEBUG std::string m_strFilename; @@ -83,6 +88,7 @@ class CLuaArgument #endif void CopyRecursive(const CLuaArgument& Argument, CFastHashMap* pKnownTables = NULL); + void MoveRecursive(CLuaArgument&& Argument, CFastHashMap* pKnownTables = NULL); bool CompareRecursive(const CLuaArgument& Argument, std::set* pKnownTables = NULL); void DeleteTableData(); }; diff --git a/Client/mods/deathmatch/logic/lua/CLuaArguments.cpp b/Client/mods/deathmatch/logic/lua/CLuaArguments.cpp index c93cc86bb4b..71c6ef7ebaf 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaArguments.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaArguments.cpp @@ -65,7 +65,7 @@ void CLuaArguments::CopyRecursive(const CLuaArguments& Arguments, CFastHashMap::const_iterator iter = Arguments.m_Arguments.begin(); for (; iter != Arguments.m_Arguments.end(); iter++) { - CLuaArgument* pArgument = new CLuaArgument(**iter, pKnownTables); + CLuaArgument* pArgument = new CLuaArgument(**iter, pKnownTables, this); m_Arguments.push_back(pArgument); } @@ -84,7 +84,7 @@ void CLuaArguments::ReadArguments(lua_State* luaVM, signed int uiIndexBegin) while (lua_type(luaVM, uiIndexBegin) != LUA_TNONE) { // Create an argument, let it read out the argument and add it to our vector - CLuaArgument* pArgument = new CLuaArgument(luaVM, uiIndexBegin++, &knownTables); + CLuaArgument* pArgument = new CLuaArgument(luaVM, uiIndexBegin++, &knownTables, this); m_Arguments.push_back(pArgument); knownTables.clear(); @@ -113,10 +113,10 @@ void CLuaArguments::ReadTable(lua_State* luaVM, int iIndexBegin, CFastHashMap::const_iterator iter = Arguments.IterBegin(); for (; iter != Arguments.IterEnd(); iter++) { - CLuaArgument* pArgument = new CLuaArgument(**iter); + CLuaArgument* pArgument = new CLuaArgument(**iter, {}, this); m_Arguments.push_back(pArgument); } } @@ -316,14 +316,14 @@ bool CLuaArguments::CallGlobal(CLuaMain* pLuaMain, const char* szFunction, CLuaA CLuaArgument* CLuaArguments::PushNil() { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); m_Arguments.push_back(pArgument); return pArgument; } CLuaArgument* CLuaArguments::PushBoolean(bool bBool) { - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadBool(bBool); m_Arguments.push_back(pArgument); return pArgument; @@ -331,7 +331,7 @@ CLuaArgument* CLuaArguments::PushBoolean(bool bBool) CLuaArgument* CLuaArguments::PushNumber(double dNumber) { - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadNumber(dNumber); m_Arguments.push_back(pArgument); return pArgument; @@ -339,7 +339,7 @@ CLuaArgument* CLuaArguments::PushNumber(double dNumber) CLuaArgument* CLuaArguments::PushString(const std::string& strString) { - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadString(strString); m_Arguments.push_back(pArgument); return pArgument; @@ -347,7 +347,7 @@ CLuaArgument* CLuaArguments::PushString(const std::string& strString) CLuaArgument* CLuaArguments::PushResource(CResource* pResource) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadScriptID(pResource->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -355,7 +355,7 @@ CLuaArgument* CLuaArguments::PushResource(CResource* pResource) CLuaArgument* CLuaArguments::PushElement(CClientEntity* pElement) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadElement(pElement); m_Arguments.push_back(pArgument); return pArgument; @@ -363,14 +363,26 @@ CLuaArgument* CLuaArguments::PushElement(CClientEntity* pElement) CLuaArgument* CLuaArguments::PushArgument(const CLuaArgument& Argument) { - CLuaArgument* pArgument = new CLuaArgument(Argument); + CLuaArgument* pArgument = new CLuaArgument(Argument, {}, this); m_Arguments.push_back(pArgument); return pArgument; } +CLuaArgument* CLuaArguments::PushArgument(CLuaArgument&& argument) +{ + CLuaArgument* pArgument = new CLuaArgument(std::move(argument), {}, this); + m_Arguments.push_back(pArgument); + return pArgument; +} + +void CLuaArguments::PushArgumentWeak(const CLuaArgument* pArgument) +{ + m_Arguments.push_back(const_cast(pArgument)); +} + CLuaArgument* CLuaArguments::PushTable(CLuaArguments* table) { - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadTable(table); m_Arguments.push_back(pArgument); return pArgument; @@ -383,7 +395,8 @@ void CLuaArguments::DeleteArguments() vector::iterator iter = m_Arguments.begin(); for (; iter != m_Arguments.end(); iter++) { - delete *iter; + if ((*iter)->m_pOwner == this) + delete *iter; } // Clear the vector @@ -394,8 +407,9 @@ void CLuaArguments::DeleteArguments() void CLuaArguments::Pop() { // Delete the last element - CLuaArgument* item = m_Arguments.back(); - delete item; + auto item = m_Arguments.back(); + if (item->m_pOwner == this) + delete item; // Pop it out of the vector m_Arguments.pop_back(); @@ -413,11 +427,13 @@ void CLuaArguments::ValidateTableKeys() { // TODO - Handle ref in KnownTables // Remove pair - delete *iter; + if ((*iter)->m_pOwner == this) + delete *iter; iter = m_Arguments.erase(iter); if (iter != m_Arguments.end()) { - delete *iter; + if ((*iter)->m_pOwner == this) + delete *iter; iter = m_Arguments.erase(iter); } // Check if end @@ -452,7 +468,7 @@ bool CLuaArguments::ReadFromBitStream(NetBitStreamInterface& bitStream, std::vec pKnownTables->push_back(this); for (unsigned int ui = 0; ui < uiNumArgs; ++ui) { - CLuaArgument* pArgument = new CLuaArgument(bitStream, pKnownTables); + CLuaArgument* pArgument = new CLuaArgument(bitStream, pKnownTables, this); m_Arguments.push_back(pArgument); } } @@ -644,7 +660,7 @@ bool CLuaArguments::ReadFromJSONString(const char* szJSON) for (uint i = 0; i < json_object_array_length(object); i++) { json_object* arrayObject = json_object_array_get_idx(object, i); - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); bSuccess = pArgument->ReadFromJSONObject(arrayObject, &knownTables); m_Arguments.push_back(pArgument); // then the value if (!bSuccess) @@ -656,7 +672,7 @@ bool CLuaArguments::ReadFromJSONString(const char* szJSON) else if (json_object_get_type(object) == json_type_object) { std::vector knownTables; - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); bool bSuccess = pArgument->ReadFromJSONObject(object, &knownTables); m_Arguments.push_back(pArgument); // value json_object_put(object); @@ -690,7 +706,7 @@ bool CLuaArguments::ReadFromJSONObject(json_object* object, std::vectorReadString(key); m_Arguments.push_back(pArgument); // push the key first pArgument = new CLuaArgument(); @@ -729,11 +745,11 @@ bool CLuaArguments::ReadFromJSONArray(json_object* object, std::vectorReadNumber(i + 1); // push the key m_Arguments.push_back(pArgument); - pArgument = new CLuaArgument(); + pArgument = new CLuaArgument(this); bSuccess = pArgument->ReadFromJSONObject(arrayObject, pKnownTables); m_Arguments.push_back(pArgument); // then the valoue if (!bSuccess) diff --git a/Client/mods/deathmatch/logic/lua/CLuaArguments.h b/Client/mods/deathmatch/logic/lua/CLuaArguments.h index 89011983f20..4630ed77fb3 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaArguments.h +++ b/Client/mods/deathmatch/logic/lua/CLuaArguments.h @@ -58,6 +58,8 @@ class CLuaArguments CLuaArgument* PushString(const std::string& strString); CLuaArgument* PushElement(CClientEntity* pElement); CLuaArgument* PushArgument(const CLuaArgument& argument); + CLuaArgument* PushArgument(CLuaArgument&& argument); + void PushArgumentWeak(const CLuaArgument* pArgument); CLuaArgument* PushResource(CResource* pResource); CLuaArgument* PushTable(CLuaArguments* table); diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp index 0e0175e6ce4..1bba6da7cc6 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp @@ -1779,7 +1779,7 @@ int CLuaElementDefs::SetElementData(lua_State* luaVM) strKey = strKey.Left(MAX_CUSTOMDATA_NAME_LENGTH); } - if (CStaticFunctionDefinitions::SetElementData(*pEntity, strKey, value, bSynchronize)) + if (pEntity->SetCustomData(std::move(strKey), std::move(value), bSynchronize, true)) { lua_pushboolean(luaVM, true); return 1; diff --git a/Client/mods/deathmatch/logic/rpc/CElementRPCs.cpp b/Client/mods/deathmatch/logic/rpc/CElementRPCs.cpp index 1b5da5c7803..dacdf342090 100644 --- a/Client/mods/deathmatch/logic/rpc/CElementRPCs.cpp +++ b/Client/mods/deathmatch/logic/rpc/CElementRPCs.cpp @@ -97,7 +97,7 @@ void CElementRPCs::SetElementData(CClientEntity* pSource, NetBitStreamInterface& CLuaArgument Argument; if (bitStream.ReadStringCharacters(strName, usNameLength) && Argument.ReadFromBitStream(bitStream)) { - pSource->SetCustomData(strName, Argument); + pSource->SetCustomData(std::move(strName), std::move(Argument)); } } } diff --git a/Server/mods/deathmatch/logic/CCustomData.cpp b/Server/mods/deathmatch/logic/CCustomData.cpp index b613403b2d0..2642c4c8d9b 100644 --- a/Server/mods/deathmatch/logic/CCustomData.cpp +++ b/Server/mods/deathmatch/logic/CCustomData.cpp @@ -15,7 +15,7 @@ void CCustomData::Copy(CCustomData* pCustomData) { for (const auto& [key, data] : pCustomData->GetData()) - Set(key, data.Variable); + Set(SString(key), CLuaArgument(data.Variable)); } SCustomData* CCustomData::Get(const SString& strName, bool bCreate) @@ -77,32 +77,32 @@ void CCustomData::UpdateSynced(const SString& strName, const CLuaArgument& Varia } } -bool CCustomData::Set(const SString& strName, const CLuaArgument& Variable, ESyncType syncType, SCustomData* pOldData) +SCustomDataResult CCustomData::Set(SString&& strName, CLuaArgument&& Variable, ESyncType syncType, SCustomData* pOldData) { if (strName.length() > MAX_CUSTOMDATA_NAME_LENGTH) - return false; + return {}; - SCustomData* pCurrentVariable = Get(strName, true); - assert(pCurrentVariable); + auto iter = m_Data.try_emplace(std::move(strName)).first; + SCustomData& pCurrentVariable = iter->second; - if (pCurrentVariable->Variable.IsEmpty() || pCurrentVariable->Variable != Variable || pCurrentVariable->syncType != syncType) + if (pCurrentVariable.Variable.IsEmpty() || pCurrentVariable.syncType != syncType || pCurrentVariable.Variable != Variable) { if (syncType == ESyncType::PERSISTENT) - syncType = pCurrentVariable->syncType; + syncType = pCurrentVariable.syncType; // Save the old variable if (pOldData) - *pOldData = *pCurrentVariable; + *pOldData = std::move(pCurrentVariable); // Set the new data - pCurrentVariable->Variable = Variable; - pCurrentVariable->syncType = syncType; + pCurrentVariable.Variable = std::move(Variable); + pCurrentVariable.syncType = syncType; UpdateSynced(strName, Variable, syncType); - return true; + return SCustomDataResult(iter); } - return false; + return {}; } bool CCustomData::Delete(const SString& strName, SCustomData* pOldData) diff --git a/Server/mods/deathmatch/logic/CCustomData.h b/Server/mods/deathmatch/logic/CCustomData.h index 84a5898adec..bb531837db1 100644 --- a/Server/mods/deathmatch/logic/CCustomData.h +++ b/Server/mods/deathmatch/logic/CCustomData.h @@ -32,6 +32,27 @@ struct SCustomData ESyncType syncType{ESyncType::BROADCAST}; }; +struct SCustomDataResult +{ + using iterator = std::unordered_map::iterator; + + SCustomDataResult() = default; + + SCustomDataResult(const iterator& iter) : + Iter(iter), + bValid(true) + { + } + + const SString& GetName() const { return Iter->first; } + const SCustomData& GetData() const { return Iter->second; } + + operator bool() const { return bValid; } + + iterator Iter; + bool bValid{}; +}; + class CCustomData { public: @@ -39,7 +60,7 @@ class CCustomData SCustomData* Get(const SString& strName, bool bCreate = false); SCustomData* GetSynced(const SString& strName); - bool Set(const SString& strName, const CLuaArgument& Variable, ESyncType syncType = ESyncType::BROADCAST, SCustomData* pOldData = {}); + SCustomDataResult Set(SString&& strName, CLuaArgument&& Variable, ESyncType syncType = ESyncType::BROADCAST, SCustomData* pOldData = {}); bool Delete(const SString& strName, SCustomData* pOldData = {}); diff --git a/Server/mods/deathmatch/logic/CElement.cpp b/Server/mods/deathmatch/logic/CElement.cpp index 8dd02344bb6..c8bee60d366 100644 --- a/Server/mods/deathmatch/logic/CElement.cpp +++ b/Server/mods/deathmatch/logic/CElement.cpp @@ -23,6 +23,7 @@ #include "CElementRefManager.h" #include "CLogger.h" #include "CSpatialDatabase.h" +#include "CPerfStatModule.h" #include "packets/CElementRPCPacket.h" #include "Utils.h" #include "lua/CLuaFunctionParseHelpers.h" @@ -504,7 +505,7 @@ void CElement::ReadCustomData(CEvents* pEvents, CXMLNode& Node) // Don't trigger onElementDataChanged event const ESyncType syncType = g_pGame->GetConfig()->GetSyncMapElementData() ? ESyncType::BROADCAST : ESyncType::LOCAL; - SetCustomData(pAttribute->GetName(), *args[0], syncType, {}, false); + SetCustomData(pAttribute->GetName(), std::move(*args[0]), syncType, {}, false); } } @@ -702,32 +703,61 @@ bool CElement::GetCustomDataBool(const char* szName, bool& bOut, bool bInheritDa return false; } -const SCustomData* CElement::SetCustomData(const SString& strName, const CLuaArgument& Variable, ESyncType syncType, CPlayer* pClient, bool bTriggerEvent) +bool CElement::SetCustomData(SString&& strName, CLuaArgument&& Variable, ESyncType syncType, CPlayer* pClient, + bool bTriggerEvent, EElementDataPacketType packetType) { if (strName.length() > MAX_CUSTOMDATA_NAME_LENGTH) { // Don't allow it to be set if the name is too long CLogger::ErrorPrintf("Custom data name too long (%s)\n", *strName.Left(MAX_CUSTOMDATA_NAME_LENGTH + 1)); - return {}; + return false; } // SCustomData is 64(88 in debug) bytes long. A static storage can be more efficient. static SCustomData oldData; - if (m_CustomData.Set(strName, Variable, syncType, &oldData) != true) - return {}; + const SCustomDataResult result = m_CustomData.Set(std::move(strName), std::move(Variable), syncType, &oldData); + if (!result) + return false; + + const auto& strNewName = result.GetName(); + const auto& newData = result.GetData(); if (bTriggerEvent) { // Trigger the onElementDataChange event on us CLuaArguments Arguments; - Arguments.PushString(strName); - Arguments.PushArgument(oldData.Variable); - Arguments.PushArgument(Variable); + Arguments.PushString(strNewName); + Arguments.PushArgumentWeak(&oldData.Variable); + Arguments.PushArgumentWeak(&newData.Variable); CallEvent("onElementDataChange", Arguments, pClient); - } + } + + CPlayerManager* pPlayerManager = g_pGame->GetPlayerManager(); + + if (packetType != EElementDataPacketType::DoNotSend && newData.syncType != ESyncType::LOCAL) + { + // Tell our clients to update their data + const unsigned short usNameLength = static_cast(strNewName.length()); + CBitStream BitStream; + BitStream.pBitStream->WriteCompressed(usNameLength); + BitStream.pBitStream->Write(strNewName.c_str(), usNameLength); + newData.Variable.WriteToBitStream(*BitStream.pBitStream); + + const CElementRPCPacket packet(this, SET_ELEMENT_DATA, *BitStream.pBitStream); + const size_t numPlayers = syncType == ESyncType::BROADCAST ? pPlayerManager->BroadcastOnlyJoined(packet, pClient) + : pPlayerManager->BroadcastOnlySubscribed(packet, this, strNewName, pClient); + if (packetType == EElementDataPacketType::Broadcast) + CPerfStatEventPacketUsage::GetSingleton()->UpdateElementDataUsageOut(strNewName, numPlayers, BitStream.pBitStream->GetNumberOfBytesUsed()); + else + CPerfStatEventPacketUsage::GetSingleton()->UpdateElementDataUsageRelayed(strNewName, numPlayers, BitStream.pBitStream->GetNumberOfBytesUsed()); + } + + // Unsubscribe all the players + if (oldData.syncType == ESyncType::SUBSCRIBE && newData.syncType != ESyncType::SUBSCRIBE) + pPlayerManager->ClearElementData(this, strNewName); - return &oldData; + return true; } bool CElement::DeleteCustomData(const SString& strName) diff --git a/Server/mods/deathmatch/logic/CElement.h b/Server/mods/deathmatch/logic/CElement.h index ce59a825704..c14de247148 100644 --- a/Server/mods/deathmatch/logic/CElement.h +++ b/Server/mods/deathmatch/logic/CElement.h @@ -49,6 +49,13 @@ typedef CFastList CElementListType; typedef std::vector CElementListSnapshot; typedef std::shared_ptr CElementListSnapshotRef; +enum class EElementDataPacketType +{ + DoNotSend = 0, + Broadcast, + Relay +}; + class CElement { friend class CPerPlayerEntity; @@ -143,8 +150,8 @@ class CElement bool GetCustomDataFloat(const char* szName, float& fOut, bool bInheritData); bool GetCustomDataBool(const char* szName, bool& bOut, bool bInheritData); // Note that returned SCustomData* cannot be used with recursive algorithms! - const SCustomData* SetCustomData(const SString& strName, const CLuaArgument& Variable, ESyncType syncType = ESyncType::BROADCAST, CPlayer* pClient = {}, - bool bTriggerEvent = true); + bool SetCustomData(SString&& strName, CLuaArgument&& Variable, ESyncType syncType = ESyncType::BROADCAST, CPlayer* pClient = {}, + bool bTriggerEvent = true, EElementDataPacketType packetType = EElementDataPacketType::DoNotSend); bool DeleteCustomData(const SString& strName); void SendAllCustomData(CPlayer* pPlayer); diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp index 0c8be06eafd..ef6b5652d4d 100644 --- a/Server/mods/deathmatch/logic/CGame.cpp +++ b/Server/mods/deathmatch/logic/CGame.cpp @@ -2591,32 +2591,7 @@ void CGame::Packet_CustomData(CCustomDataPacket& Packet) ElementID ID = Packet.GetElementID(); CElement* pElement = CElementIDs::GetElement(ID); if (pElement) - { - // Change the data - const SString& strName = Packet.GetName(); - const CLuaArgument& Value = Packet.GetValue(); - - if (const SCustomData* pOldData = pElement->SetCustomData(strName, Value, ESyncType::PERSISTENT, pSourcePlayer)) - { - if (pOldData->syncType != ESyncType::LOCAL) - { - // Tell our clients to update their data. Send to everyone but the one we got this packet from. - unsigned short usNameLength = static_cast(strName.length()); - CBitStream BitStream; - BitStream.pBitStream->WriteCompressed(usNameLength); - BitStream.pBitStream->Write(strName.c_str(), usNameLength); - Value.WriteToBitStream(*BitStream.pBitStream); - if (pOldData->syncType == ESyncType::BROADCAST) - m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(pElement, SET_ELEMENT_DATA, *BitStream.pBitStream), pSourcePlayer); - else - m_pPlayerManager->BroadcastOnlySubscribed(CElementRPCPacket(pElement, SET_ELEMENT_DATA, *BitStream.pBitStream), pElement, strName, - pSourcePlayer); - - CPerfStatEventPacketUsage::GetSingleton()->UpdateElementDataUsageRelayed(strName, m_pPlayerManager->Count(), - BitStream.pBitStream->GetNumberOfBytesUsed()); - } - } - } + pElement->SetCustomData(std::move(Packet.GetName()), std::move(Packet.GetValue()), ESyncType::PERSISTENT, pSourcePlayer, true, EElementDataPacketType::Relay); } } diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 59b6fe9634e..66a75bdaf45 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -936,39 +936,6 @@ bool CStaticFunctionDefinitions::SetElementID(CElement* pElement, const char* sz return true; } -bool CStaticFunctionDefinitions::SetElementData(CElement* pElement, const SString& strName, const CLuaArgument& Variable, ESyncType syncType) -{ - assert(pElement); - assert(strName.length() <= MAX_CUSTOMDATA_NAME_LENGTH); - - if (const SCustomData* pOldData = pElement->SetCustomData(strName, Variable, syncType)) - { - if (syncType != ESyncType::LOCAL) - { - // Tell our clients to update their data - const unsigned short usNameLength = static_cast(strName.length()); - CBitStream BitStream; - BitStream.pBitStream->WriteCompressed(usNameLength); - BitStream.pBitStream->Write(strName.c_str(), usNameLength); - Variable.WriteToBitStream(*BitStream.pBitStream); - - const CElementRPCPacket packet(pElement, SET_ELEMENT_DATA, *BitStream.pBitStream); - const size_t numPlayers = syncType == ESyncType::BROADCAST ? m_pPlayerManager->BroadcastOnlyJoined(packet) - : m_pPlayerManager->BroadcastOnlySubscribed(packet, pElement, strName); - - CPerfStatEventPacketUsage::GetSingleton()->UpdateElementDataUsageOut(strName, numPlayers, BitStream.pBitStream->GetNumberOfBytesUsed()); - } - - // Unsubscribe all the players - if (pOldData->syncType == ESyncType::SUBSCRIBE && syncType != ESyncType::SUBSCRIBE) - m_pPlayerManager->ClearElementData(pElement, strName); - - return true; - } - - return false; -} - bool CStaticFunctionDefinitions::RemoveElementData(CElement* pElement, const SString& strName) { assert(pElement); diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h index 940ddf22b9b..64d869df659 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h @@ -83,7 +83,6 @@ class CStaticFunctionDefinitions // Element set funcs static bool ClearElementVisibleTo(CElement* pElement); static bool SetElementID(CElement* pElement, const char* szID); - static bool SetElementData(CElement* pElement, const SString& strName, const CLuaArgument& Variable, ESyncType syncType); static bool RemoveElementData(CElement* pElement, const SString& strName); static bool AddElementDataSubscriber(CElement* pElement, const SString& strName, CPlayer* pPlayer); static bool RemoveElementDataSubscriber(CElement* pElement, const SString& strName, CPlayer* pPlayer); diff --git a/Server/mods/deathmatch/logic/lua/CLuaArgument.cpp b/Server/mods/deathmatch/logic/lua/CLuaArgument.cpp index 6c2f02c3778..f20956a041b 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaArgument.cpp +++ b/Server/mods/deathmatch/logic/lua/CLuaArgument.cpp @@ -26,21 +26,32 @@ extern CGame* g_pGame; using namespace std; -CLuaArgument::CLuaArgument() +CLuaArgument::CLuaArgument(CLuaArguments* pOwner) : + m_pOwner(pOwner) { m_iType = LUA_TNIL; m_pTableData = NULL; m_pUserData = NULL; } -CLuaArgument::CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables) +CLuaArgument::CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables, CLuaArguments* pOwner) : + m_pOwner(pOwner) { // Initialize and call our = on the argument m_pTableData = NULL; CopyRecursive(Argument, pKnownTables); } -CLuaArgument::CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables) +CLuaArgument::CLuaArgument(CLuaArgument&& Argument, CFastHashMap* pKnownTables, CLuaArguments* pOwner) : + m_pOwner(pOwner) +{ + // Initialize and call our = on the argument + m_pTableData = NULL; + MoveRecursive(std::move(Argument), pKnownTables); +} + +CLuaArgument::CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables, CLuaArguments* pOwner) : + m_pOwner(pOwner) { // Read the argument out of the lua VM m_pTableData = NULL; @@ -53,6 +64,69 @@ CLuaArgument::~CLuaArgument() DeleteTableData(); } +void CLuaArgument::MoveRecursive(CLuaArgument&& Argument, CFastHashMap* pKnownTables) +{ + // Clear the string + m_strString.clear(); + + // Destroy our old tabledata if neccessary + DeleteTableData(); + +#ifdef MTA_DEBUG + m_strFilename = std::move(Argument.m_strFilename); + m_iLine = std::exchange(Argument.m_iLine, 0); +#endif + + // Set our variable equally to the copy class + m_iType = Argument.m_iType; + switch (m_iType) + { + case LUA_TBOOLEAN: + { + m_bBoolean = std::exchange(Argument.m_bBoolean, false); + break; + } + + case LUA_TLIGHTUSERDATA: + case LUA_TUSERDATA: + { + m_pUserData = std::exchange(Argument.m_pUserData, nullptr); + break; + } + + case LUA_TNUMBER: + { + m_Number = std::exchange(Argument.m_Number, 0); + break; + } + + case LUA_TTABLE: + { + if (pKnownTables && (m_pTableData = MapFindRef(*pKnownTables, Argument.m_pTableData))) + { + m_bWeakTableRef = true; + } + else + { + m_pTableData = std::exchange(Argument.m_pTableData, nullptr); + m_bWeakTableRef = false; + } + break; + } + + case LUA_TSTRING: + { + m_strString = std::move(Argument.m_strString); + break; + } + + default: + break; + } + + Argument.m_iType = LUA_TNIL; +} + void CLuaArgument::CopyRecursive(const CLuaArgument& Argument, CFastHashMap* pKnownTables) { // Clear the string @@ -123,6 +197,14 @@ const CLuaArgument& CLuaArgument::operator=(const CLuaArgument& Argument) return Argument; } +const CLuaArgument& CLuaArgument::operator=(CLuaArgument&& Argument) +{ + MoveRecursive(std::move(Argument)); + + // Return the given class allowing for chaining + return Argument; +} + bool CLuaArgument::operator==(const CLuaArgument& Argument) const { std::set knownTables; diff --git a/Server/mods/deathmatch/logic/lua/CLuaArgument.h b/Server/mods/deathmatch/logic/lua/CLuaArgument.h index 5b69210291e..ea3ad9bc585 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaArgument.h +++ b/Server/mods/deathmatch/logic/lua/CLuaArgument.h @@ -28,13 +28,16 @@ class CLuaArguments; class CLuaArgument { + friend class CLuaArguments; public: - CLuaArgument(); - CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables = NULL); - CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables = NULL); + CLuaArgument(CLuaArguments* pOwner = {}); + CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables = NULL, CLuaArguments* pOwner = {}); + CLuaArgument(CLuaArgument&& Argument, CFastHashMap* pKnownTables = NULL, CLuaArguments* pOwner = {}); + CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables = NULL, CLuaArguments* pOwner = {}); ~CLuaArgument(); const CLuaArgument& operator=(const CLuaArgument& Argument); + const CLuaArgument& operator=(CLuaArgument&& Argument); bool operator==(const CLuaArgument& Argument) const; bool operator!=(const CLuaArgument& Argument) const; @@ -71,19 +74,22 @@ class CLuaArgument private: void LogUnableToPacketize(const char* szMessage) const; + CLuaArguments* m_pOwner{}; + int m_iType; bool m_bBoolean; + bool m_bWeakTableRef; lua_Number m_Number; std::string m_strString; void* m_pUserData; - CLuaArguments* m_pTableData; - bool m_bWeakTableRef; + CLuaArguments* m_pTableData; #ifdef MTA_DEBUG std::string m_strFilename; int m_iLine; #endif - void CopyRecursive(const CLuaArgument& Argument, CFastHashMap* pKnownTables = NULL); + void MoveRecursive(CLuaArgument&& Argument, CFastHashMap* pKnownTables = {}); + void CopyRecursive(const CLuaArgument& Argument, CFastHashMap* pKnownTables = {}); void DeleteTableData(); }; diff --git a/Server/mods/deathmatch/logic/lua/CLuaArguments.cpp b/Server/mods/deathmatch/logic/lua/CLuaArguments.cpp index 3feadfeedb3..2cfb8d08994 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaArguments.cpp +++ b/Server/mods/deathmatch/logic/lua/CLuaArguments.cpp @@ -71,7 +71,7 @@ void CLuaArguments::CopyRecursive(const CLuaArguments& Arguments, CFastHashMap::const_iterator iter = Arguments.m_Arguments.begin(); for (; iter != Arguments.m_Arguments.end(); ++iter) { - CLuaArgument* pArgument = new CLuaArgument(**iter, pKnownTables); + CLuaArgument* pArgument = new CLuaArgument(**iter, pKnownTables, this); m_Arguments.push_back(pArgument); } @@ -90,7 +90,7 @@ void CLuaArguments::ReadArguments(lua_State* luaVM, signed int uiIndexBegin) while (lua_type(luaVM, uiIndexBegin) != LUA_TNONE) { // Create an argument, let it read out the argument and add it to our vector - CLuaArgument* pArgument = new CLuaArgument(luaVM, uiIndexBegin++, &knownTables); + CLuaArgument* pArgument = new CLuaArgument(luaVM, uiIndexBegin++, &knownTables, this); m_Arguments.push_back(pArgument); knownTables.clear(); @@ -119,10 +119,10 @@ void CLuaArguments::ReadTable(lua_State* luaVM, int iIndexBegin, CFastHashMap::const_iterator iter = Arguments.IterBegin(); for (; iter != Arguments.IterEnd(); ++iter) { - CLuaArgument* pArgument = new CLuaArgument(**iter); + CLuaArgument* pArgument = new CLuaArgument(**iter, {}, this); m_Arguments.push_back(pArgument); } } @@ -322,14 +322,14 @@ bool CLuaArguments::CallGlobal(CLuaMain* pLuaMain, const char* szFunction, CLuaA CLuaArgument* CLuaArguments::PushNil() { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); m_Arguments.push_back(pArgument); return pArgument; } CLuaArgument* CLuaArguments::PushBoolean(bool bBool) { - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadBool(bBool); m_Arguments.push_back(pArgument); return pArgument; @@ -337,7 +337,7 @@ CLuaArgument* CLuaArguments::PushBoolean(bool bBool) CLuaArgument* CLuaArguments::PushTable(CLuaArguments* table) { - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadTable(table); m_Arguments.push_back(pArgument); return pArgument; @@ -345,7 +345,7 @@ CLuaArgument* CLuaArguments::PushTable(CLuaArguments* table) CLuaArgument* CLuaArguments::PushNumber(double dNumber) { - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadNumber(dNumber); m_Arguments.push_back(pArgument); return pArgument; @@ -353,14 +353,19 @@ CLuaArgument* CLuaArguments::PushNumber(double dNumber) CLuaArgument* CLuaArguments::PushArgument(const CLuaArgument& argument) { - CLuaArgument* pArgument = new CLuaArgument(argument); // create a copy + CLuaArgument* pArgument = new CLuaArgument(argument, {}, this); // create a copy m_Arguments.push_back(pArgument); return pArgument; } +void CLuaArguments::PushArgumentWeak(const CLuaArgument* argument) +{ + m_Arguments.push_back(const_cast(argument)); +} + CLuaArgument* CLuaArguments::PushString(const std::string& strString) { - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadString(strString); m_Arguments.push_back(pArgument); return pArgument; @@ -368,7 +373,7 @@ CLuaArgument* CLuaArguments::PushString(const std::string& strString) CLuaArgument* CLuaArguments::PushElement(CElement* pElement) { - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadElement(pElement); m_Arguments.push_back(pArgument); return pArgument; @@ -376,7 +381,7 @@ CLuaArgument* CLuaArguments::PushElement(CElement* pElement) CLuaArgument* CLuaArguments::PushBan(CBan* pBan) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadScriptID(pBan->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -384,7 +389,7 @@ CLuaArgument* CLuaArguments::PushBan(CBan* pBan) CLuaArgument* CLuaArguments::PushACL(CAccessControlList* pACL) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadScriptID(pACL->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -392,7 +397,7 @@ CLuaArgument* CLuaArguments::PushACL(CAccessControlList* pACL) CLuaArgument* CLuaArguments::PushACLGroup(CAccessControlListGroup* pACLGroup) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadScriptID(pACLGroup->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -400,7 +405,7 @@ CLuaArgument* CLuaArguments::PushACLGroup(CAccessControlListGroup* pACLGroup) CLuaArgument* CLuaArguments::PushAccount(CAccount* pAccount) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadScriptID(pAccount->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -408,7 +413,7 @@ CLuaArgument* CLuaArguments::PushAccount(CAccount* pAccount) CLuaArgument* CLuaArguments::PushResource(CResource* pResource) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadScriptID(pResource->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -416,7 +421,7 @@ CLuaArgument* CLuaArguments::PushResource(CResource* pResource) CLuaArgument* CLuaArguments::PushTextDisplay(CTextDisplay* pTextDisplay) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadScriptID(pTextDisplay->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -424,7 +429,7 @@ CLuaArgument* CLuaArguments::PushTextDisplay(CTextDisplay* pTextDisplay) CLuaArgument* CLuaArguments::PushTextItem(CTextItem* pTextItem) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadScriptID(pTextItem->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -432,7 +437,7 @@ CLuaArgument* CLuaArguments::PushTextItem(CTextItem* pTextItem) CLuaArgument* CLuaArguments::PushTimer(CLuaTimer* pLuaTimer) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadScriptID(pLuaTimer->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -440,7 +445,7 @@ CLuaArgument* CLuaArguments::PushTimer(CLuaTimer* pLuaTimer) CLuaArgument* CLuaArguments::PushDbQuery(CDbJobData* pJobData) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadScriptID(pJobData->GetId()); m_Arguments.push_back(pArgument); return pArgument; @@ -452,7 +457,8 @@ void CLuaArguments::DeleteArguments() vector::iterator iter = m_Arguments.begin(); for (; iter != m_Arguments.end(); ++iter) { - delete *iter; + if ((*iter)->m_pOwner == this) + delete *iter; } // Clear the vector @@ -464,7 +470,8 @@ void CLuaArguments::Pop() { // Delete the last element CLuaArgument* item = m_Arguments.back(); - delete item; + if (item->m_pOwner == this) + delete item; // Pop it out of the vector m_Arguments.pop_back(); @@ -482,11 +489,13 @@ void CLuaArguments::ValidateTableKeys() { // TODO - Handle ref in KnownTables // Remove pair - delete *iter; + if ((*iter)->m_pOwner == this) + delete *iter; iter = m_Arguments.erase(iter); if (iter != m_Arguments.end()) { - delete *iter; + if ((*iter)->m_pOwner == this) + delete *iter; iter = m_Arguments.erase(iter); } // Check if end @@ -521,7 +530,7 @@ bool CLuaArguments::ReadFromBitStream(NetBitStreamInterface& bitStream, std::vec pKnownTables->push_back(this); for (unsigned int ui = 0; ui < uiNumArgs; ++ui) { - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); if (!pArgument->ReadFromBitStream(bitStream, pKnownTables)) { delete pArgument; @@ -720,7 +729,7 @@ bool CLuaArguments::ReadFromJSONString(const char* szJSON) for (uint i = 0; i < json_object_array_length(object); i++) { json_object* arrayObject = json_object_array_get_idx(object, i); - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); bSuccess = pArgument->ReadFromJSONObject(arrayObject, &knownTables); m_Arguments.push_back(pArgument); // then the value if (!bSuccess) @@ -732,7 +741,7 @@ bool CLuaArguments::ReadFromJSONString(const char* szJSON) else if (json_object_get_type(object) == json_type_object) { std::vector knownTables; - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); bool bSuccess = pArgument->ReadFromJSONObject(object, &knownTables); m_Arguments.push_back(pArgument); // value json_object_put(object); @@ -766,10 +775,10 @@ bool CLuaArguments::ReadFromJSONObject(json_object* object, std::vectorReadString(key); m_Arguments.push_back(pArgument); // push the key first - pArgument = new CLuaArgument(); + pArgument = new CLuaArgument(this); bSuccess = pArgument->ReadFromJSONObject(val, pKnownTables); // then the value m_Arguments.push_back(pArgument); if (!bSuccess) @@ -805,11 +814,11 @@ bool CLuaArguments::ReadFromJSONArray(json_object* object, std::vectorReadNumber(i + 1); // push the key m_Arguments.push_back(pArgument); - pArgument = new CLuaArgument(); + pArgument = new CLuaArgument(this); bSuccess = pArgument->ReadFromJSONObject(arrayObject, pKnownTables); m_Arguments.push_back(pArgument); // then the valoue if (!bSuccess) diff --git a/Server/mods/deathmatch/logic/lua/CLuaArguments.h b/Server/mods/deathmatch/logic/lua/CLuaArguments.h index 87fd92be206..8907b1ccd80 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaArguments.h +++ b/Server/mods/deathmatch/logic/lua/CLuaArguments.h @@ -80,6 +80,7 @@ class CLuaArguments CLuaArgument* PushDbQuery(CDbJobData* pJobData); CLuaArgument* PushArgument(const CLuaArgument& argument); + void PushArgumentWeak(const CLuaArgument* argument); CLuaArgument* PushTable(CLuaArguments* table); void DeleteArguments(); diff --git a/Server/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp b/Server/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp index 6cacbdcc989..d6b8bbe0575 100644 --- a/Server/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp +++ b/Server/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp @@ -1566,7 +1566,7 @@ int CLuaElementDefs::setElementData(lua_State* luaVM) strKey = strKey.Left(MAX_CUSTOMDATA_NAME_LENGTH); } - if (CStaticFunctionDefinitions::SetElementData(pElement, strKey, value, syncType)) + if (pElement->SetCustomData(std::move(strKey), std::move(value), syncType, {}, true, EElementDataPacketType::Broadcast)) { lua_pushboolean(luaVM, true); return 1; diff --git a/Server/mods/deathmatch/logic/packets/CCustomDataPacket.h b/Server/mods/deathmatch/logic/packets/CCustomDataPacket.h index 620d30edfb7..25ef48202e4 100644 --- a/Server/mods/deathmatch/logic/packets/CCustomDataPacket.h +++ b/Server/mods/deathmatch/logic/packets/CCustomDataPacket.h @@ -27,8 +27,8 @@ class CCustomDataPacket final : public CPacket bool Write(NetBitStreamInterface& BitStream) const; const ElementID GetElementID() const { return m_ElementID; } - const SString& GetName() const { return m_strName; } - const CLuaArgument& GetValue() const { return m_Value; } + SString& GetName() { return m_strName; } + CLuaArgument& GetValue() { return m_Value; } private: ElementID m_ElementID; diff --git a/Shared/mods/deathmatch/logic/luadefs/CLuaElementDefsShared.cpp b/Shared/mods/deathmatch/logic/luadefs/CLuaElementDefsShared.cpp index 7d331163014..57237a6c4c4 100644 --- a/Shared/mods/deathmatch/logic/luadefs/CLuaElementDefsShared.cpp +++ b/Shared/mods/deathmatch/logic/luadefs/CLuaElementDefsShared.cpp @@ -41,7 +41,7 @@ int CLuaElementDefs::GetElementData(lua_State* luaVM) } #ifdef MTA_CLIENT - CLuaArgument* pVariable = pElement->GetCustomData(strKey, bInherit); + const CLuaArgument* pVariable = pElement->GetCustomData(strKey, bInherit); #else CLuaArgument* pVariable = CStaticFunctionDefinitions::GetElementData(pElement, strKey, bInherit); #endif From 69b59606e088e9d2243a193e66ad1f3ba24ef39f Mon Sep 17 00:00:00 2001 From: TEDERIs Date: Fri, 12 Jan 2024 21:58:34 +0700 Subject: [PATCH 4/7] Revert "Further optimizations" This reverts commit 347f9ccdb10250179caf12a5e541b0d14b576295. --- .../mods/deathmatch/logic/CClientEntity.cpp | 42 +++----- Client/mods/deathmatch/logic/CClientEntity.h | 4 +- Client/mods/deathmatch/logic/CCustomData.cpp | 31 +++--- Client/mods/deathmatch/logic/CCustomData.h | 25 +---- .../mods/deathmatch/logic/CPacketHandler.cpp | 2 +- .../logic/CStaticFunctionDefinitions.cpp | 25 +++++ .../logic/CStaticFunctionDefinitions.h | 1 + .../deathmatch/logic/lua/CLuaArgument.cpp | 95 +------------------ .../mods/deathmatch/logic/lua/CLuaArgument.h | 18 ++-- .../deathmatch/logic/lua/CLuaArguments.cpp | 66 +++++-------- .../mods/deathmatch/logic/lua/CLuaArguments.h | 2 - .../logic/luadefs/CLuaElementDefs.cpp | 2 +- .../deathmatch/logic/rpc/CElementRPCs.cpp | 2 +- Server/mods/deathmatch/logic/CCustomData.cpp | 24 ++--- Server/mods/deathmatch/logic/CCustomData.h | 23 +---- Server/mods/deathmatch/logic/CElement.cpp | 50 ++-------- Server/mods/deathmatch/logic/CElement.h | 11 +-- Server/mods/deathmatch/logic/CGame.cpp | 27 +++++- .../logic/CStaticFunctionDefinitions.cpp | 33 +++++++ .../logic/CStaticFunctionDefinitions.h | 1 + .../deathmatch/logic/lua/CLuaArgument.cpp | 88 +---------------- .../mods/deathmatch/logic/lua/CLuaArgument.h | 18 ++-- .../deathmatch/logic/lua/CLuaArguments.cpp | 75 +++++++-------- .../mods/deathmatch/logic/lua/CLuaArguments.h | 1 - .../logic/luadefs/CLuaElementDefs.cpp | 2 +- .../logic/packets/CCustomDataPacket.h | 4 +- .../logic/luadefs/CLuaElementDefsShared.cpp | 2 +- 27 files changed, 229 insertions(+), 445 deletions(-) diff --git a/Client/mods/deathmatch/logic/CClientEntity.cpp b/Client/mods/deathmatch/logic/CClientEntity.cpp index efbac757689..16e5145eb51 100644 --- a/Client/mods/deathmatch/logic/CClientEntity.cpp +++ b/Client/mods/deathmatch/logic/CClientEntity.cpp @@ -279,10 +279,10 @@ void CClientEntity::SetID(ElementID ID) } } -const CLuaArgument* CClientEntity::GetCustomData(const SString& strName, bool bInheritData, bool* pbIsSynced) +CLuaArgument* CClientEntity::GetCustomData(const SString& strName, bool bInheritData, bool* pbIsSynced) { // Grab it and return a pointer to the variable - const SCustomData* pData = m_pCustomData->Get(strName); + SCustomData* pData = m_pCustomData->Get(strName); if (pData) { if (pbIsSynced) @@ -316,7 +316,7 @@ CLuaArguments* CClientEntity::GetAllCustomData(CLuaArguments* table) bool CClientEntity::GetCustomDataString(const char* szName, SString& strOut, bool bInheritData) { // Grab the custom data variable - const CLuaArgument* pData = GetCustomData(szName, bInheritData); + CLuaArgument* pData = GetCustomData(szName, bInheritData); if (pData) { // Write the content depending on what type it is @@ -351,7 +351,7 @@ bool CClientEntity::GetCustomDataString(const char* szName, SString& strOut, boo bool CClientEntity::GetCustomDataInt(const char* szName, int& iOut, bool bInheritData) { // Grab the custom data variable - const CLuaArgument* pData = GetCustomData(szName, bInheritData); + CLuaArgument* pData = GetCustomData(szName, bInheritData); if (pData) { // Write the content depending on what type it is @@ -389,7 +389,7 @@ bool CClientEntity::GetCustomDataInt(const char* szName, int& iOut, bool bInheri bool CClientEntity::GetCustomDataFloat(const char* szName, float& fOut, bool bInheritData) { // Grab the custom data variable - const CLuaArgument* pData = GetCustomData(szName, bInheritData); + CLuaArgument* pData = GetCustomData(szName, bInheritData); if (pData) { // Write the content depending on what type it is @@ -416,7 +416,7 @@ bool CClientEntity::GetCustomDataFloat(const char* szName, float& fOut, bool bIn bool CClientEntity::GetCustomDataBool(const char* szName, bool& bOut, bool bInheritData) { // Grab the custom data variable - const CLuaArgument* pData = GetCustomData(szName, bInheritData); + CLuaArgument* pData = GetCustomData(szName, bInheritData); if (pData) { // Write the content depending on what type it is @@ -468,38 +468,20 @@ bool CClientEntity::GetCustomDataBool(const char* szName, bool& bOut, bool bInhe return false; } -bool CClientEntity::SetCustomData(SString&& strName, CLuaArgument&& Variable, bool bSynchronized, bool bSendPacket) +bool CClientEntity::SetCustomData(const SString& strName, const CLuaArgument& Variable, bool bSynchronized) { // SCustomData is 64(88 in debug) bytes long. A static storage can be more efficient. - static SCustomData oldValue; + static SCustomData oldData; - if (const auto result = m_pCustomData->Set(std::move(strName), std::move(Variable), bSynchronized, &oldValue)) + if (m_pCustomData->Set(strName, Variable, bSynchronized, &oldData)) { - const auto& newName = result.GetName(); - const auto& newValue = result.GetData(); - // Trigger the onClientElementDataChange event on us CLuaArguments Arguments; - Arguments.PushString(newName); - Arguments.PushArgumentWeak(&oldValue.Variable); - Arguments.PushArgumentWeak(&newValue.Variable); + Arguments.PushString(strName); + Arguments.PushArgument(oldData.Variable); + Arguments.PushArgument(Variable); CallEvent("onClientElementDataChange", Arguments, true); - if (bSendPacket && bSynchronized && !IsLocalEntity()) - { - NetBitStreamInterface* pBitStream = g_pNet->AllocateNetBitStream(); - // Write element ID, name length and the name. Also write the variable. - pBitStream->Write(GetID()); - const unsigned short usNameLength = static_cast(newName.length()); - pBitStream->WriteCompressed(usNameLength); - pBitStream->Write(newName.c_str(), usNameLength); - newValue.Variable.WriteToBitStream(*pBitStream); - - // Send the packet and deallocate - g_pNet->SendPacket(PACKET_ID_CUSTOM_DATA, pBitStream, PACKET_PRIORITY_HIGH, PACKET_RELIABILITY_RELIABLE_ORDERED); - g_pNet->DeallocateNetBitStream(pBitStream); - } - return true; } diff --git a/Client/mods/deathmatch/logic/CClientEntity.h b/Client/mods/deathmatch/logic/CClientEntity.h index 29be0cfabd3..2071a19bfa6 100644 --- a/Client/mods/deathmatch/logic/CClientEntity.h +++ b/Client/mods/deathmatch/logic/CClientEntity.h @@ -199,13 +199,13 @@ class CClientEntity : public CClientEntityBase void SetID(ElementID ID); CCustomData* GetCustomDataPointer() { return m_pCustomData; } - const CLuaArgument* GetCustomData(const SString& strName, bool bInheritData, bool* pbIsSynced = nullptr); + CLuaArgument* GetCustomData(const SString& strName, bool bInheritData, bool* pbIsSynced = nullptr); CLuaArguments* GetAllCustomData(CLuaArguments* table); bool GetCustomDataString(const char* szKey, SString& strOut, bool bInheritData); bool GetCustomDataFloat(const char* szKey, float& fOut, bool bInheritData); bool GetCustomDataInt(const char* szKey, int& iOut, bool bInheritData); bool GetCustomDataBool(const char* szKey, bool& bOut, bool bInheritData); - bool SetCustomData(SString&& strName, CLuaArgument&& Variable, bool bSynchronized = true, bool bSendPacket = false); + bool SetCustomData(const SString& strName, const CLuaArgument& Variable, bool bSynchronized = true); void DeleteCustomData(const SString& strName); virtual bool GetMatrix(CMatrix& matrix) const; diff --git a/Client/mods/deathmatch/logic/CCustomData.cpp b/Client/mods/deathmatch/logic/CCustomData.cpp index 0ee6a8c25b9..ab618f96785 100644 --- a/Client/mods/deathmatch/logic/CCustomData.cpp +++ b/Client/mods/deathmatch/logic/CCustomData.cpp @@ -15,43 +15,46 @@ void CCustomData::Copy(CCustomData* pCustomData) { for (const auto& [key, data] : pCustomData->GetData()) - Set(SString(key), CLuaArgument(data.Variable)); + Set(key, data.Variable); } -const SCustomData* CCustomData::Get(const SString& strName) +SCustomData* CCustomData::Get(const SString& strName, bool bCreate) { if (auto it = m_Data.find(strName); it != m_Data.end()) return &it->second; + if (bCreate) + return &m_Data[strName]; + return {}; } -SCustomDataResult CCustomData::Set(SString&& strName, CLuaArgument&& Variable, bool bSynchronized, SCustomData* oldValue) +bool CCustomData::Set(const SString& strName, const CLuaArgument& Variable, bool bSynchronized, SCustomData* pOldData) { if (strName.length() > MAX_CUSTOMDATA_NAME_LENGTH) { // Don't allow it to be set if the name is too long CLogger::ErrorPrintf("Custom data name too long (%s)", *strName.Left(MAX_CUSTOMDATA_NAME_LENGTH + 1)); - return {}; + return false; } - auto iter = m_Data.try_emplace(std::move(strName)).first; - SCustomData& pCurrentVariable = iter->second; + SCustomData* pCurrentVariable = Get(strName, true); + assert(pCurrentVariable); - if (pCurrentVariable.Variable.IsEmpty() || pCurrentVariable.bSynchronized != bSynchronized || pCurrentVariable.Variable != Variable ) - { + if (pCurrentVariable->Variable.IsEmpty() || pCurrentVariable->Variable != Variable || pCurrentVariable->bSynchronized != bSynchronized) + { // Save the old variable - if (oldValue) - *oldValue = std::move(pCurrentVariable); + if (pOldData) + *pOldData = *pCurrentVariable; // Set the new data - pCurrentVariable.Variable = std::move(Variable); - pCurrentVariable.bSynchronized = bSynchronized; + pCurrentVariable->Variable = Variable; + pCurrentVariable->bSynchronized = bSynchronized; - return SCustomDataResult(iter); + return true; } - return {}; + return false; } bool CCustomData::Delete(const SString& strName, SCustomData* pOldData) diff --git a/Client/mods/deathmatch/logic/CCustomData.h b/Client/mods/deathmatch/logic/CCustomData.h index 26485460fdb..70fb515f88c 100644 --- a/Client/mods/deathmatch/logic/CCustomData.h +++ b/Client/mods/deathmatch/logic/CCustomData.h @@ -20,34 +20,13 @@ struct SCustomData bool bSynchronized{true}; }; -struct SCustomDataResult -{ - using iterator = std::unordered_map::iterator; - - SCustomDataResult() = default; - - SCustomDataResult(const iterator& iter) : - Iter(iter), - bValid(true) - { - } - - const SString& GetName() const { return Iter->first; } - const SCustomData& GetData() const { return Iter->second; } - - operator bool() const { return bValid; } - - iterator Iter; - bool bValid{}; -}; - class CCustomData { public: void Copy(CCustomData* pCustomData); - const SCustomData* Get(const SString& strName); - SCustomDataResult Set(SString&& strName, CLuaArgument&& Variable, bool bSynchronized = true, SCustomData* oldValue = {}); + SCustomData* Get(const SString& strName, bool bCreate = false); + bool Set(const SString& strName, const CLuaArgument& Variable, bool bSynchronized = true, SCustomData* pOldData = {}); bool Delete(const SString& strName, SCustomData* pOldData = {}); diff --git a/Client/mods/deathmatch/logic/CPacketHandler.cpp b/Client/mods/deathmatch/logic/CPacketHandler.cpp index 776410a5b00..51cad6aed4a 100644 --- a/Client/mods/deathmatch/logic/CPacketHandler.cpp +++ b/Client/mods/deathmatch/logic/CPacketHandler.cpp @@ -2871,7 +2871,7 @@ void CPacketHandler::Packet_EntityAdd(NetBitStreamInterface& bitStream) CLuaArgument Argument; Argument.ReadFromBitStream(bitStream); - pCustomData->Set(std::move(strName), std::move(Argument)); + pCustomData->Set(strName, Argument); } else { diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 38bf6d920a1..40c3c45ff70 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -993,6 +993,31 @@ bool CStaticFunctionDefinitions::SetElementID(CClientEntity& Entity, const char* return false; } +bool CStaticFunctionDefinitions::SetElementData(CClientEntity& Entity, const SString& strName, CLuaArgument& Variable, bool bSynchronize) +{ + if (Entity.SetCustomData(strName, Variable, bSynchronize)) + { + if (bSynchronize && !Entity.IsLocalEntity()) + { + NetBitStreamInterface* pBitStream = g_pNet->AllocateNetBitStream(); + // Write element ID, name length and the name. Also write the variable. + pBitStream->Write(Entity.GetID()); + const unsigned short usNameLength = static_cast(strName.length()); + pBitStream->WriteCompressed(usNameLength); + pBitStream->Write(strName.c_str(), usNameLength); + Variable.WriteToBitStream(*pBitStream); + + // Send the packet and deallocate + g_pNet->SendPacket(PACKET_ID_CUSTOM_DATA, pBitStream, PACKET_PRIORITY_HIGH, PACKET_RELIABILITY_RELIABLE_ORDERED); + g_pNet->DeallocateNetBitStream(pBitStream); + } + + return true; + } + + return false; +} + bool CStaticFunctionDefinitions::RemoveElementData(CClientEntity& Entity, const char* szName) { // TODO diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h index eb0911623c2..ab7dfa0640f 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h @@ -81,6 +81,7 @@ class CStaticFunctionDefinitions static CClientDummy* CreateElement(CResource& Resource, const char* szTypeName, const char* szID); static bool DestroyElement(CClientEntity& Entity); static bool SetElementID(CClientEntity& Entity, const char* szID); + static bool SetElementData(CClientEntity& Entity, const SString& strName, CLuaArgument& Variable, bool bSynchronize); static bool RemoveElementData(CClientEntity& Entity, const char* szName); static bool SetElementMatrix(CClientEntity& Entity, const CMatrix& matrix); static bool SetElementPosition(CClientEntity& Entity, const CVector& vecPosition, bool bWarp = true); diff --git a/Client/mods/deathmatch/logic/lua/CLuaArgument.cpp b/Client/mods/deathmatch/logic/lua/CLuaArgument.cpp index ad3af3d7525..3a5f50df3f6 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaArgument.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaArgument.cpp @@ -29,8 +29,7 @@ using namespace std; // Prevent the warning issued when doing unsigned short -> void* #pragma warning(disable:4312) -CLuaArgument::CLuaArgument(CLuaArguments* pOwner) : - m_pOwner(pOwner) +CLuaArgument::CLuaArgument() { m_iType = LUA_TNIL; m_iIndex = -1; @@ -38,31 +37,20 @@ CLuaArgument::CLuaArgument(CLuaArguments* pOwner) : m_pUserData = NULL; } -CLuaArgument::CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables, CLuaArguments* pOwner) : - m_pOwner(pOwner) +CLuaArgument::CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables) { // Initialize and call our = on the argument m_pTableData = NULL; CopyRecursive(Argument, pKnownTables); } -CLuaArgument::CLuaArgument(CLuaArgument&& Argument, CFastHashMap* pKnownTables, CLuaArguments* pOwner) : - m_pOwner(pOwner) -{ - // Initialize and call our = on the argument - m_pTableData = NULL; - MoveRecursive(std::move(Argument)); -} - -CLuaArgument::CLuaArgument(NetBitStreamInterface& bitStream, std::vector* pKnownTables, CLuaArguments* pOwner) : - m_pOwner(pOwner) +CLuaArgument::CLuaArgument(NetBitStreamInterface& bitStream, std::vector* pKnownTables) { m_pTableData = NULL; ReadFromBitStream(bitStream, pKnownTables); } -CLuaArgument::CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables, CLuaArguments* pOwner) : - m_pOwner(pOwner) +CLuaArgument::CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables) { // Read the argument out of the lua VM m_pTableData = NULL; @@ -79,7 +67,7 @@ CLuaArgument::~CLuaArgument() void CLuaArgument::CopyRecursive(const CLuaArgument& Argument, CFastHashMap* pKnownTables) { // Clear the string - m_strString.clear(); + m_strString = ""; // Destroy our old tabledata if neccessary DeleteTableData(); @@ -138,71 +126,6 @@ void CLuaArgument::CopyRecursive(const CLuaArgument& Argument, CFastHashMap* pKnownTables) -{ - // Clear the string - m_strString.clear(); - - // Destroy our old tabledata if neccessary - DeleteTableData(); - -#ifdef MTA_DEBUG - // Copy over line and filename too - m_strFilename = std::move(Argument.m_strFilename); - m_iLine = std::exchange(Argument.m_iLine, 0); -#endif - - // Set our variable equally to the copy class - m_iType = Argument.m_iType; - switch (m_iType) - { - case LUA_TBOOLEAN: - { - m_bBoolean = std::exchange(Argument.m_bBoolean, false); - break; - } - - case LUA_TUSERDATA: - case LUA_TLIGHTUSERDATA: - { - m_pUserData = std::exchange(Argument.m_pUserData, nullptr); - break; - } - - case LUA_TNUMBER: - { - m_Number = std::exchange(Argument.m_Number, 0); - break; - } - - case LUA_TTABLE: - { - if (pKnownTables && (m_pTableData = MapFindRef(*pKnownTables, Argument.m_pTableData))) - { - m_bWeakTableRef = true; - } - else - { - m_pTableData = std::exchange(Argument.m_pTableData, nullptr); - m_bWeakTableRef = false; - } - break; - } - - case LUA_TSTRING: - { - m_strString = std::move(Argument.m_strString); - break; - } - - default: - break; - } - - Argument.m_iType = LUA_TNIL; - Argument.m_iIndex = -1; -} - const CLuaArgument& CLuaArgument::operator=(const CLuaArgument& Argument) { CopyRecursive(Argument); @@ -211,14 +134,6 @@ const CLuaArgument& CLuaArgument::operator=(const CLuaArgument& Argument) return Argument; } -const CLuaArgument& CLuaArgument::operator=(CLuaArgument&& Argument) -{ - MoveRecursive(std::move(Argument)); - - // Return the given class allowing for chaining - return Argument; -} - bool CLuaArgument::operator==(const CLuaArgument& Argument) { std::set knownTables; diff --git a/Client/mods/deathmatch/logic/lua/CLuaArgument.h b/Client/mods/deathmatch/logic/lua/CLuaArgument.h index 3db092f02d0..8c122628590 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaArgument.h +++ b/Client/mods/deathmatch/logic/lua/CLuaArgument.h @@ -26,17 +26,14 @@ class CLuaArguments; class CLuaArgument { - friend class CLuaArguments; public: - CLuaArgument(CLuaArguments* pOwner = {}); - CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables = NULL, CLuaArguments* pOwner = {}); - CLuaArgument(CLuaArgument&& Argument, CFastHashMap* pKnownTables = NULL, CLuaArguments* pOwner = {}); - CLuaArgument(NetBitStreamInterface& bitStream, std::vector* pKnownTables = NULL, CLuaArguments* pOwner = {}); - CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables = NULL, CLuaArguments* pOwner = {}); + CLuaArgument(); + CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables = NULL); + CLuaArgument(NetBitStreamInterface& bitStream, std::vector* pKnownTables = NULL); + CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables = NULL); ~CLuaArgument(); const CLuaArgument& operator=(const CLuaArgument& Argument); - const CLuaArgument& operator=(CLuaArgument&& Argument); bool operator==(const CLuaArgument& Argument); bool operator!=(const CLuaArgument& Argument); @@ -58,7 +55,7 @@ class CLuaArgument bool GetBoolean() const { return m_bBoolean; }; lua_Number GetNumber() const { return m_Number; }; - const SString& GetString() const { return m_strString; }; + const SString& GetString() { return m_strString; }; void* GetUserData() const { return m_pUserData; }; CClientEntity* GetElement() const; @@ -71,16 +68,14 @@ class CLuaArgument private: void LogUnableToPacketize(const char* szMessage) const; - CLuaArguments* m_pOwner{}; - int m_iType; int m_iIndex; bool m_bBoolean; - bool m_bWeakTableRef; lua_Number m_Number; SString m_strString; void* m_pUserData; CLuaArguments* m_pTableData; + bool m_bWeakTableRef; #ifdef MTA_DEBUG std::string m_strFilename; @@ -88,7 +83,6 @@ class CLuaArgument #endif void CopyRecursive(const CLuaArgument& Argument, CFastHashMap* pKnownTables = NULL); - void MoveRecursive(CLuaArgument&& Argument, CFastHashMap* pKnownTables = NULL); bool CompareRecursive(const CLuaArgument& Argument, std::set* pKnownTables = NULL); void DeleteTableData(); }; diff --git a/Client/mods/deathmatch/logic/lua/CLuaArguments.cpp b/Client/mods/deathmatch/logic/lua/CLuaArguments.cpp index 71c6ef7ebaf..c93cc86bb4b 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaArguments.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaArguments.cpp @@ -65,7 +65,7 @@ void CLuaArguments::CopyRecursive(const CLuaArguments& Arguments, CFastHashMap::const_iterator iter = Arguments.m_Arguments.begin(); for (; iter != Arguments.m_Arguments.end(); iter++) { - CLuaArgument* pArgument = new CLuaArgument(**iter, pKnownTables, this); + CLuaArgument* pArgument = new CLuaArgument(**iter, pKnownTables); m_Arguments.push_back(pArgument); } @@ -84,7 +84,7 @@ void CLuaArguments::ReadArguments(lua_State* luaVM, signed int uiIndexBegin) while (lua_type(luaVM, uiIndexBegin) != LUA_TNONE) { // Create an argument, let it read out the argument and add it to our vector - CLuaArgument* pArgument = new CLuaArgument(luaVM, uiIndexBegin++, &knownTables, this); + CLuaArgument* pArgument = new CLuaArgument(luaVM, uiIndexBegin++, &knownTables); m_Arguments.push_back(pArgument); knownTables.clear(); @@ -113,10 +113,10 @@ void CLuaArguments::ReadTable(lua_State* luaVM, int iIndexBegin, CFastHashMap::const_iterator iter = Arguments.IterBegin(); for (; iter != Arguments.IterEnd(); iter++) { - CLuaArgument* pArgument = new CLuaArgument(**iter, {}, this); + CLuaArgument* pArgument = new CLuaArgument(**iter); m_Arguments.push_back(pArgument); } } @@ -316,14 +316,14 @@ bool CLuaArguments::CallGlobal(CLuaMain* pLuaMain, const char* szFunction, CLuaA CLuaArgument* CLuaArguments::PushNil() { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument; m_Arguments.push_back(pArgument); return pArgument; } CLuaArgument* CLuaArguments::PushBoolean(bool bBool) { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument(); pArgument->ReadBool(bBool); m_Arguments.push_back(pArgument); return pArgument; @@ -331,7 +331,7 @@ CLuaArgument* CLuaArguments::PushBoolean(bool bBool) CLuaArgument* CLuaArguments::PushNumber(double dNumber) { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument(); pArgument->ReadNumber(dNumber); m_Arguments.push_back(pArgument); return pArgument; @@ -339,7 +339,7 @@ CLuaArgument* CLuaArguments::PushNumber(double dNumber) CLuaArgument* CLuaArguments::PushString(const std::string& strString) { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument(); pArgument->ReadString(strString); m_Arguments.push_back(pArgument); return pArgument; @@ -347,7 +347,7 @@ CLuaArgument* CLuaArguments::PushString(const std::string& strString) CLuaArgument* CLuaArguments::PushResource(CResource* pResource) { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument; pArgument->ReadScriptID(pResource->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -355,7 +355,7 @@ CLuaArgument* CLuaArguments::PushResource(CResource* pResource) CLuaArgument* CLuaArguments::PushElement(CClientEntity* pElement) { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument; pArgument->ReadElement(pElement); m_Arguments.push_back(pArgument); return pArgument; @@ -363,26 +363,14 @@ CLuaArgument* CLuaArguments::PushElement(CClientEntity* pElement) CLuaArgument* CLuaArguments::PushArgument(const CLuaArgument& Argument) { - CLuaArgument* pArgument = new CLuaArgument(Argument, {}, this); + CLuaArgument* pArgument = new CLuaArgument(Argument); m_Arguments.push_back(pArgument); return pArgument; } -CLuaArgument* CLuaArguments::PushArgument(CLuaArgument&& argument) -{ - CLuaArgument* pArgument = new CLuaArgument(std::move(argument), {}, this); - m_Arguments.push_back(pArgument); - return pArgument; -} - -void CLuaArguments::PushArgumentWeak(const CLuaArgument* pArgument) -{ - m_Arguments.push_back(const_cast(pArgument)); -} - CLuaArgument* CLuaArguments::PushTable(CLuaArguments* table) { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument(); pArgument->ReadTable(table); m_Arguments.push_back(pArgument); return pArgument; @@ -395,8 +383,7 @@ void CLuaArguments::DeleteArguments() vector::iterator iter = m_Arguments.begin(); for (; iter != m_Arguments.end(); iter++) { - if ((*iter)->m_pOwner == this) - delete *iter; + delete *iter; } // Clear the vector @@ -407,9 +394,8 @@ void CLuaArguments::DeleteArguments() void CLuaArguments::Pop() { // Delete the last element - auto item = m_Arguments.back(); - if (item->m_pOwner == this) - delete item; + CLuaArgument* item = m_Arguments.back(); + delete item; // Pop it out of the vector m_Arguments.pop_back(); @@ -427,13 +413,11 @@ void CLuaArguments::ValidateTableKeys() { // TODO - Handle ref in KnownTables // Remove pair - if ((*iter)->m_pOwner == this) - delete *iter; + delete *iter; iter = m_Arguments.erase(iter); if (iter != m_Arguments.end()) { - if ((*iter)->m_pOwner == this) - delete *iter; + delete *iter; iter = m_Arguments.erase(iter); } // Check if end @@ -468,7 +452,7 @@ bool CLuaArguments::ReadFromBitStream(NetBitStreamInterface& bitStream, std::vec pKnownTables->push_back(this); for (unsigned int ui = 0; ui < uiNumArgs; ++ui) { - CLuaArgument* pArgument = new CLuaArgument(bitStream, pKnownTables, this); + CLuaArgument* pArgument = new CLuaArgument(bitStream, pKnownTables); m_Arguments.push_back(pArgument); } } @@ -660,7 +644,7 @@ bool CLuaArguments::ReadFromJSONString(const char* szJSON) for (uint i = 0; i < json_object_array_length(object); i++) { json_object* arrayObject = json_object_array_get_idx(object, i); - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument(); bSuccess = pArgument->ReadFromJSONObject(arrayObject, &knownTables); m_Arguments.push_back(pArgument); // then the value if (!bSuccess) @@ -672,7 +656,7 @@ bool CLuaArguments::ReadFromJSONString(const char* szJSON) else if (json_object_get_type(object) == json_type_object) { std::vector knownTables; - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument(); bool bSuccess = pArgument->ReadFromJSONObject(object, &knownTables); m_Arguments.push_back(pArgument); // value json_object_put(object); @@ -706,7 +690,7 @@ bool CLuaArguments::ReadFromJSONObject(json_object* object, std::vectorReadString(key); m_Arguments.push_back(pArgument); // push the key first pArgument = new CLuaArgument(); @@ -745,11 +729,11 @@ bool CLuaArguments::ReadFromJSONArray(json_object* object, std::vectorReadNumber(i + 1); // push the key m_Arguments.push_back(pArgument); - pArgument = new CLuaArgument(this); + pArgument = new CLuaArgument(); bSuccess = pArgument->ReadFromJSONObject(arrayObject, pKnownTables); m_Arguments.push_back(pArgument); // then the valoue if (!bSuccess) diff --git a/Client/mods/deathmatch/logic/lua/CLuaArguments.h b/Client/mods/deathmatch/logic/lua/CLuaArguments.h index 4630ed77fb3..89011983f20 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaArguments.h +++ b/Client/mods/deathmatch/logic/lua/CLuaArguments.h @@ -58,8 +58,6 @@ class CLuaArguments CLuaArgument* PushString(const std::string& strString); CLuaArgument* PushElement(CClientEntity* pElement); CLuaArgument* PushArgument(const CLuaArgument& argument); - CLuaArgument* PushArgument(CLuaArgument&& argument); - void PushArgumentWeak(const CLuaArgument* pArgument); CLuaArgument* PushResource(CResource* pResource); CLuaArgument* PushTable(CLuaArguments* table); diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp index 1bba6da7cc6..0e0175e6ce4 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp @@ -1779,7 +1779,7 @@ int CLuaElementDefs::SetElementData(lua_State* luaVM) strKey = strKey.Left(MAX_CUSTOMDATA_NAME_LENGTH); } - if (pEntity->SetCustomData(std::move(strKey), std::move(value), bSynchronize, true)) + if (CStaticFunctionDefinitions::SetElementData(*pEntity, strKey, value, bSynchronize)) { lua_pushboolean(luaVM, true); return 1; diff --git a/Client/mods/deathmatch/logic/rpc/CElementRPCs.cpp b/Client/mods/deathmatch/logic/rpc/CElementRPCs.cpp index dacdf342090..1b5da5c7803 100644 --- a/Client/mods/deathmatch/logic/rpc/CElementRPCs.cpp +++ b/Client/mods/deathmatch/logic/rpc/CElementRPCs.cpp @@ -97,7 +97,7 @@ void CElementRPCs::SetElementData(CClientEntity* pSource, NetBitStreamInterface& CLuaArgument Argument; if (bitStream.ReadStringCharacters(strName, usNameLength) && Argument.ReadFromBitStream(bitStream)) { - pSource->SetCustomData(std::move(strName), std::move(Argument)); + pSource->SetCustomData(strName, Argument); } } } diff --git a/Server/mods/deathmatch/logic/CCustomData.cpp b/Server/mods/deathmatch/logic/CCustomData.cpp index 2642c4c8d9b..b613403b2d0 100644 --- a/Server/mods/deathmatch/logic/CCustomData.cpp +++ b/Server/mods/deathmatch/logic/CCustomData.cpp @@ -15,7 +15,7 @@ void CCustomData::Copy(CCustomData* pCustomData) { for (const auto& [key, data] : pCustomData->GetData()) - Set(SString(key), CLuaArgument(data.Variable)); + Set(key, data.Variable); } SCustomData* CCustomData::Get(const SString& strName, bool bCreate) @@ -77,32 +77,32 @@ void CCustomData::UpdateSynced(const SString& strName, const CLuaArgument& Varia } } -SCustomDataResult CCustomData::Set(SString&& strName, CLuaArgument&& Variable, ESyncType syncType, SCustomData* pOldData) +bool CCustomData::Set(const SString& strName, const CLuaArgument& Variable, ESyncType syncType, SCustomData* pOldData) { if (strName.length() > MAX_CUSTOMDATA_NAME_LENGTH) - return {}; + return false; - auto iter = m_Data.try_emplace(std::move(strName)).first; - SCustomData& pCurrentVariable = iter->second; + SCustomData* pCurrentVariable = Get(strName, true); + assert(pCurrentVariable); - if (pCurrentVariable.Variable.IsEmpty() || pCurrentVariable.syncType != syncType || pCurrentVariable.Variable != Variable) + if (pCurrentVariable->Variable.IsEmpty() || pCurrentVariable->Variable != Variable || pCurrentVariable->syncType != syncType) { if (syncType == ESyncType::PERSISTENT) - syncType = pCurrentVariable.syncType; + syncType = pCurrentVariable->syncType; // Save the old variable if (pOldData) - *pOldData = std::move(pCurrentVariable); + *pOldData = *pCurrentVariable; // Set the new data - pCurrentVariable.Variable = std::move(Variable); - pCurrentVariable.syncType = syncType; + pCurrentVariable->Variable = Variable; + pCurrentVariable->syncType = syncType; UpdateSynced(strName, Variable, syncType); - return SCustomDataResult(iter); + return true; } - return {}; + return false; } bool CCustomData::Delete(const SString& strName, SCustomData* pOldData) diff --git a/Server/mods/deathmatch/logic/CCustomData.h b/Server/mods/deathmatch/logic/CCustomData.h index bb531837db1..84a5898adec 100644 --- a/Server/mods/deathmatch/logic/CCustomData.h +++ b/Server/mods/deathmatch/logic/CCustomData.h @@ -32,27 +32,6 @@ struct SCustomData ESyncType syncType{ESyncType::BROADCAST}; }; -struct SCustomDataResult -{ - using iterator = std::unordered_map::iterator; - - SCustomDataResult() = default; - - SCustomDataResult(const iterator& iter) : - Iter(iter), - bValid(true) - { - } - - const SString& GetName() const { return Iter->first; } - const SCustomData& GetData() const { return Iter->second; } - - operator bool() const { return bValid; } - - iterator Iter; - bool bValid{}; -}; - class CCustomData { public: @@ -60,7 +39,7 @@ class CCustomData SCustomData* Get(const SString& strName, bool bCreate = false); SCustomData* GetSynced(const SString& strName); - SCustomDataResult Set(SString&& strName, CLuaArgument&& Variable, ESyncType syncType = ESyncType::BROADCAST, SCustomData* pOldData = {}); + bool Set(const SString& strName, const CLuaArgument& Variable, ESyncType syncType = ESyncType::BROADCAST, SCustomData* pOldData = {}); bool Delete(const SString& strName, SCustomData* pOldData = {}); diff --git a/Server/mods/deathmatch/logic/CElement.cpp b/Server/mods/deathmatch/logic/CElement.cpp index c8bee60d366..8dd02344bb6 100644 --- a/Server/mods/deathmatch/logic/CElement.cpp +++ b/Server/mods/deathmatch/logic/CElement.cpp @@ -23,7 +23,6 @@ #include "CElementRefManager.h" #include "CLogger.h" #include "CSpatialDatabase.h" -#include "CPerfStatModule.h" #include "packets/CElementRPCPacket.h" #include "Utils.h" #include "lua/CLuaFunctionParseHelpers.h" @@ -505,7 +504,7 @@ void CElement::ReadCustomData(CEvents* pEvents, CXMLNode& Node) // Don't trigger onElementDataChanged event const ESyncType syncType = g_pGame->GetConfig()->GetSyncMapElementData() ? ESyncType::BROADCAST : ESyncType::LOCAL; - SetCustomData(pAttribute->GetName(), std::move(*args[0]), syncType, {}, false); + SetCustomData(pAttribute->GetName(), *args[0], syncType, {}, false); } } @@ -703,61 +702,32 @@ bool CElement::GetCustomDataBool(const char* szName, bool& bOut, bool bInheritDa return false; } -bool CElement::SetCustomData(SString&& strName, CLuaArgument&& Variable, ESyncType syncType, CPlayer* pClient, - bool bTriggerEvent, EElementDataPacketType packetType) +const SCustomData* CElement::SetCustomData(const SString& strName, const CLuaArgument& Variable, ESyncType syncType, CPlayer* pClient, bool bTriggerEvent) { if (strName.length() > MAX_CUSTOMDATA_NAME_LENGTH) { // Don't allow it to be set if the name is too long CLogger::ErrorPrintf("Custom data name too long (%s)\n", *strName.Left(MAX_CUSTOMDATA_NAME_LENGTH + 1)); - return false; + return {}; } // SCustomData is 64(88 in debug) bytes long. A static storage can be more efficient. static SCustomData oldData; - const SCustomDataResult result = m_CustomData.Set(std::move(strName), std::move(Variable), syncType, &oldData); - if (!result) - return false; - - const auto& strNewName = result.GetName(); - const auto& newData = result.GetData(); + if (m_CustomData.Set(strName, Variable, syncType, &oldData) != true) + return {}; if (bTriggerEvent) { // Trigger the onElementDataChange event on us CLuaArguments Arguments; - Arguments.PushString(strNewName); - Arguments.PushArgumentWeak(&oldData.Variable); - Arguments.PushArgumentWeak(&newData.Variable); + Arguments.PushString(strName); + Arguments.PushArgument(oldData.Variable); + Arguments.PushArgument(Variable); CallEvent("onElementDataChange", Arguments, pClient); - } - - CPlayerManager* pPlayerManager = g_pGame->GetPlayerManager(); - - if (packetType != EElementDataPacketType::DoNotSend && newData.syncType != ESyncType::LOCAL) - { - // Tell our clients to update their data - const unsigned short usNameLength = static_cast(strNewName.length()); - CBitStream BitStream; - BitStream.pBitStream->WriteCompressed(usNameLength); - BitStream.pBitStream->Write(strNewName.c_str(), usNameLength); - newData.Variable.WriteToBitStream(*BitStream.pBitStream); - - const CElementRPCPacket packet(this, SET_ELEMENT_DATA, *BitStream.pBitStream); - const size_t numPlayers = syncType == ESyncType::BROADCAST ? pPlayerManager->BroadcastOnlyJoined(packet, pClient) - : pPlayerManager->BroadcastOnlySubscribed(packet, this, strNewName, pClient); - if (packetType == EElementDataPacketType::Broadcast) - CPerfStatEventPacketUsage::GetSingleton()->UpdateElementDataUsageOut(strNewName, numPlayers, BitStream.pBitStream->GetNumberOfBytesUsed()); - else - CPerfStatEventPacketUsage::GetSingleton()->UpdateElementDataUsageRelayed(strNewName, numPlayers, BitStream.pBitStream->GetNumberOfBytesUsed()); - } - - // Unsubscribe all the players - if (oldData.syncType == ESyncType::SUBSCRIBE && newData.syncType != ESyncType::SUBSCRIBE) - pPlayerManager->ClearElementData(this, strNewName); + } - return true; + return &oldData; } bool CElement::DeleteCustomData(const SString& strName) diff --git a/Server/mods/deathmatch/logic/CElement.h b/Server/mods/deathmatch/logic/CElement.h index c14de247148..ce59a825704 100644 --- a/Server/mods/deathmatch/logic/CElement.h +++ b/Server/mods/deathmatch/logic/CElement.h @@ -49,13 +49,6 @@ typedef CFastList CElementListType; typedef std::vector CElementListSnapshot; typedef std::shared_ptr CElementListSnapshotRef; -enum class EElementDataPacketType -{ - DoNotSend = 0, - Broadcast, - Relay -}; - class CElement { friend class CPerPlayerEntity; @@ -150,8 +143,8 @@ class CElement bool GetCustomDataFloat(const char* szName, float& fOut, bool bInheritData); bool GetCustomDataBool(const char* szName, bool& bOut, bool bInheritData); // Note that returned SCustomData* cannot be used with recursive algorithms! - bool SetCustomData(SString&& strName, CLuaArgument&& Variable, ESyncType syncType = ESyncType::BROADCAST, CPlayer* pClient = {}, - bool bTriggerEvent = true, EElementDataPacketType packetType = EElementDataPacketType::DoNotSend); + const SCustomData* SetCustomData(const SString& strName, const CLuaArgument& Variable, ESyncType syncType = ESyncType::BROADCAST, CPlayer* pClient = {}, + bool bTriggerEvent = true); bool DeleteCustomData(const SString& strName); void SendAllCustomData(CPlayer* pPlayer); diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp index ef6b5652d4d..0c8be06eafd 100644 --- a/Server/mods/deathmatch/logic/CGame.cpp +++ b/Server/mods/deathmatch/logic/CGame.cpp @@ -2591,7 +2591,32 @@ void CGame::Packet_CustomData(CCustomDataPacket& Packet) ElementID ID = Packet.GetElementID(); CElement* pElement = CElementIDs::GetElement(ID); if (pElement) - pElement->SetCustomData(std::move(Packet.GetName()), std::move(Packet.GetValue()), ESyncType::PERSISTENT, pSourcePlayer, true, EElementDataPacketType::Relay); + { + // Change the data + const SString& strName = Packet.GetName(); + const CLuaArgument& Value = Packet.GetValue(); + + if (const SCustomData* pOldData = pElement->SetCustomData(strName, Value, ESyncType::PERSISTENT, pSourcePlayer)) + { + if (pOldData->syncType != ESyncType::LOCAL) + { + // Tell our clients to update their data. Send to everyone but the one we got this packet from. + unsigned short usNameLength = static_cast(strName.length()); + CBitStream BitStream; + BitStream.pBitStream->WriteCompressed(usNameLength); + BitStream.pBitStream->Write(strName.c_str(), usNameLength); + Value.WriteToBitStream(*BitStream.pBitStream); + if (pOldData->syncType == ESyncType::BROADCAST) + m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(pElement, SET_ELEMENT_DATA, *BitStream.pBitStream), pSourcePlayer); + else + m_pPlayerManager->BroadcastOnlySubscribed(CElementRPCPacket(pElement, SET_ELEMENT_DATA, *BitStream.pBitStream), pElement, strName, + pSourcePlayer); + + CPerfStatEventPacketUsage::GetSingleton()->UpdateElementDataUsageRelayed(strName, m_pPlayerManager->Count(), + BitStream.pBitStream->GetNumberOfBytesUsed()); + } + } + } } } diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 66a75bdaf45..59b6fe9634e 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -936,6 +936,39 @@ bool CStaticFunctionDefinitions::SetElementID(CElement* pElement, const char* sz return true; } +bool CStaticFunctionDefinitions::SetElementData(CElement* pElement, const SString& strName, const CLuaArgument& Variable, ESyncType syncType) +{ + assert(pElement); + assert(strName.length() <= MAX_CUSTOMDATA_NAME_LENGTH); + + if (const SCustomData* pOldData = pElement->SetCustomData(strName, Variable, syncType)) + { + if (syncType != ESyncType::LOCAL) + { + // Tell our clients to update their data + const unsigned short usNameLength = static_cast(strName.length()); + CBitStream BitStream; + BitStream.pBitStream->WriteCompressed(usNameLength); + BitStream.pBitStream->Write(strName.c_str(), usNameLength); + Variable.WriteToBitStream(*BitStream.pBitStream); + + const CElementRPCPacket packet(pElement, SET_ELEMENT_DATA, *BitStream.pBitStream); + const size_t numPlayers = syncType == ESyncType::BROADCAST ? m_pPlayerManager->BroadcastOnlyJoined(packet) + : m_pPlayerManager->BroadcastOnlySubscribed(packet, pElement, strName); + + CPerfStatEventPacketUsage::GetSingleton()->UpdateElementDataUsageOut(strName, numPlayers, BitStream.pBitStream->GetNumberOfBytesUsed()); + } + + // Unsubscribe all the players + if (pOldData->syncType == ESyncType::SUBSCRIBE && syncType != ESyncType::SUBSCRIBE) + m_pPlayerManager->ClearElementData(pElement, strName); + + return true; + } + + return false; +} + bool CStaticFunctionDefinitions::RemoveElementData(CElement* pElement, const SString& strName) { assert(pElement); diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h index 64d869df659..940ddf22b9b 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h @@ -83,6 +83,7 @@ class CStaticFunctionDefinitions // Element set funcs static bool ClearElementVisibleTo(CElement* pElement); static bool SetElementID(CElement* pElement, const char* szID); + static bool SetElementData(CElement* pElement, const SString& strName, const CLuaArgument& Variable, ESyncType syncType); static bool RemoveElementData(CElement* pElement, const SString& strName); static bool AddElementDataSubscriber(CElement* pElement, const SString& strName, CPlayer* pPlayer); static bool RemoveElementDataSubscriber(CElement* pElement, const SString& strName, CPlayer* pPlayer); diff --git a/Server/mods/deathmatch/logic/lua/CLuaArgument.cpp b/Server/mods/deathmatch/logic/lua/CLuaArgument.cpp index f20956a041b..6c2f02c3778 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaArgument.cpp +++ b/Server/mods/deathmatch/logic/lua/CLuaArgument.cpp @@ -26,32 +26,21 @@ extern CGame* g_pGame; using namespace std; -CLuaArgument::CLuaArgument(CLuaArguments* pOwner) : - m_pOwner(pOwner) +CLuaArgument::CLuaArgument() { m_iType = LUA_TNIL; m_pTableData = NULL; m_pUserData = NULL; } -CLuaArgument::CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables, CLuaArguments* pOwner) : - m_pOwner(pOwner) +CLuaArgument::CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables) { // Initialize and call our = on the argument m_pTableData = NULL; CopyRecursive(Argument, pKnownTables); } -CLuaArgument::CLuaArgument(CLuaArgument&& Argument, CFastHashMap* pKnownTables, CLuaArguments* pOwner) : - m_pOwner(pOwner) -{ - // Initialize and call our = on the argument - m_pTableData = NULL; - MoveRecursive(std::move(Argument), pKnownTables); -} - -CLuaArgument::CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables, CLuaArguments* pOwner) : - m_pOwner(pOwner) +CLuaArgument::CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables) { // Read the argument out of the lua VM m_pTableData = NULL; @@ -64,69 +53,6 @@ CLuaArgument::~CLuaArgument() DeleteTableData(); } -void CLuaArgument::MoveRecursive(CLuaArgument&& Argument, CFastHashMap* pKnownTables) -{ - // Clear the string - m_strString.clear(); - - // Destroy our old tabledata if neccessary - DeleteTableData(); - -#ifdef MTA_DEBUG - m_strFilename = std::move(Argument.m_strFilename); - m_iLine = std::exchange(Argument.m_iLine, 0); -#endif - - // Set our variable equally to the copy class - m_iType = Argument.m_iType; - switch (m_iType) - { - case LUA_TBOOLEAN: - { - m_bBoolean = std::exchange(Argument.m_bBoolean, false); - break; - } - - case LUA_TLIGHTUSERDATA: - case LUA_TUSERDATA: - { - m_pUserData = std::exchange(Argument.m_pUserData, nullptr); - break; - } - - case LUA_TNUMBER: - { - m_Number = std::exchange(Argument.m_Number, 0); - break; - } - - case LUA_TTABLE: - { - if (pKnownTables && (m_pTableData = MapFindRef(*pKnownTables, Argument.m_pTableData))) - { - m_bWeakTableRef = true; - } - else - { - m_pTableData = std::exchange(Argument.m_pTableData, nullptr); - m_bWeakTableRef = false; - } - break; - } - - case LUA_TSTRING: - { - m_strString = std::move(Argument.m_strString); - break; - } - - default: - break; - } - - Argument.m_iType = LUA_TNIL; -} - void CLuaArgument::CopyRecursive(const CLuaArgument& Argument, CFastHashMap* pKnownTables) { // Clear the string @@ -197,14 +123,6 @@ const CLuaArgument& CLuaArgument::operator=(const CLuaArgument& Argument) return Argument; } -const CLuaArgument& CLuaArgument::operator=(CLuaArgument&& Argument) -{ - MoveRecursive(std::move(Argument)); - - // Return the given class allowing for chaining - return Argument; -} - bool CLuaArgument::operator==(const CLuaArgument& Argument) const { std::set knownTables; diff --git a/Server/mods/deathmatch/logic/lua/CLuaArgument.h b/Server/mods/deathmatch/logic/lua/CLuaArgument.h index ea3ad9bc585..5b69210291e 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaArgument.h +++ b/Server/mods/deathmatch/logic/lua/CLuaArgument.h @@ -28,16 +28,13 @@ class CLuaArguments; class CLuaArgument { - friend class CLuaArguments; public: - CLuaArgument(CLuaArguments* pOwner = {}); - CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables = NULL, CLuaArguments* pOwner = {}); - CLuaArgument(CLuaArgument&& Argument, CFastHashMap* pKnownTables = NULL, CLuaArguments* pOwner = {}); - CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables = NULL, CLuaArguments* pOwner = {}); + CLuaArgument(); + CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables = NULL); + CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables = NULL); ~CLuaArgument(); const CLuaArgument& operator=(const CLuaArgument& Argument); - const CLuaArgument& operator=(CLuaArgument&& Argument); bool operator==(const CLuaArgument& Argument) const; bool operator!=(const CLuaArgument& Argument) const; @@ -74,22 +71,19 @@ class CLuaArgument private: void LogUnableToPacketize(const char* szMessage) const; - CLuaArguments* m_pOwner{}; - int m_iType; bool m_bBoolean; - bool m_bWeakTableRef; lua_Number m_Number; std::string m_strString; void* m_pUserData; - CLuaArguments* m_pTableData; + CLuaArguments* m_pTableData; + bool m_bWeakTableRef; #ifdef MTA_DEBUG std::string m_strFilename; int m_iLine; #endif - void MoveRecursive(CLuaArgument&& Argument, CFastHashMap* pKnownTables = {}); - void CopyRecursive(const CLuaArgument& Argument, CFastHashMap* pKnownTables = {}); + void CopyRecursive(const CLuaArgument& Argument, CFastHashMap* pKnownTables = NULL); void DeleteTableData(); }; diff --git a/Server/mods/deathmatch/logic/lua/CLuaArguments.cpp b/Server/mods/deathmatch/logic/lua/CLuaArguments.cpp index 2cfb8d08994..3feadfeedb3 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaArguments.cpp +++ b/Server/mods/deathmatch/logic/lua/CLuaArguments.cpp @@ -71,7 +71,7 @@ void CLuaArguments::CopyRecursive(const CLuaArguments& Arguments, CFastHashMap::const_iterator iter = Arguments.m_Arguments.begin(); for (; iter != Arguments.m_Arguments.end(); ++iter) { - CLuaArgument* pArgument = new CLuaArgument(**iter, pKnownTables, this); + CLuaArgument* pArgument = new CLuaArgument(**iter, pKnownTables); m_Arguments.push_back(pArgument); } @@ -90,7 +90,7 @@ void CLuaArguments::ReadArguments(lua_State* luaVM, signed int uiIndexBegin) while (lua_type(luaVM, uiIndexBegin) != LUA_TNONE) { // Create an argument, let it read out the argument and add it to our vector - CLuaArgument* pArgument = new CLuaArgument(luaVM, uiIndexBegin++, &knownTables, this); + CLuaArgument* pArgument = new CLuaArgument(luaVM, uiIndexBegin++, &knownTables); m_Arguments.push_back(pArgument); knownTables.clear(); @@ -119,10 +119,10 @@ void CLuaArguments::ReadTable(lua_State* luaVM, int iIndexBegin, CFastHashMap::const_iterator iter = Arguments.IterBegin(); for (; iter != Arguments.IterEnd(); ++iter) { - CLuaArgument* pArgument = new CLuaArgument(**iter, {}, this); + CLuaArgument* pArgument = new CLuaArgument(**iter); m_Arguments.push_back(pArgument); } } @@ -322,14 +322,14 @@ bool CLuaArguments::CallGlobal(CLuaMain* pLuaMain, const char* szFunction, CLuaA CLuaArgument* CLuaArguments::PushNil() { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument; m_Arguments.push_back(pArgument); return pArgument; } CLuaArgument* CLuaArguments::PushBoolean(bool bBool) { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument(); pArgument->ReadBool(bBool); m_Arguments.push_back(pArgument); return pArgument; @@ -337,7 +337,7 @@ CLuaArgument* CLuaArguments::PushBoolean(bool bBool) CLuaArgument* CLuaArguments::PushTable(CLuaArguments* table) { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument(); pArgument->ReadTable(table); m_Arguments.push_back(pArgument); return pArgument; @@ -345,7 +345,7 @@ CLuaArgument* CLuaArguments::PushTable(CLuaArguments* table) CLuaArgument* CLuaArguments::PushNumber(double dNumber) { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument(); pArgument->ReadNumber(dNumber); m_Arguments.push_back(pArgument); return pArgument; @@ -353,19 +353,14 @@ CLuaArgument* CLuaArguments::PushNumber(double dNumber) CLuaArgument* CLuaArguments::PushArgument(const CLuaArgument& argument) { - CLuaArgument* pArgument = new CLuaArgument(argument, {}, this); // create a copy + CLuaArgument* pArgument = new CLuaArgument(argument); // create a copy m_Arguments.push_back(pArgument); return pArgument; } -void CLuaArguments::PushArgumentWeak(const CLuaArgument* argument) -{ - m_Arguments.push_back(const_cast(argument)); -} - CLuaArgument* CLuaArguments::PushString(const std::string& strString) { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument(); pArgument->ReadString(strString); m_Arguments.push_back(pArgument); return pArgument; @@ -373,7 +368,7 @@ CLuaArgument* CLuaArguments::PushString(const std::string& strString) CLuaArgument* CLuaArguments::PushElement(CElement* pElement) { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument(); pArgument->ReadElement(pElement); m_Arguments.push_back(pArgument); return pArgument; @@ -381,7 +376,7 @@ CLuaArgument* CLuaArguments::PushElement(CElement* pElement) CLuaArgument* CLuaArguments::PushBan(CBan* pBan) { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument; pArgument->ReadScriptID(pBan->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -389,7 +384,7 @@ CLuaArgument* CLuaArguments::PushBan(CBan* pBan) CLuaArgument* CLuaArguments::PushACL(CAccessControlList* pACL) { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument; pArgument->ReadScriptID(pACL->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -397,7 +392,7 @@ CLuaArgument* CLuaArguments::PushACL(CAccessControlList* pACL) CLuaArgument* CLuaArguments::PushACLGroup(CAccessControlListGroup* pACLGroup) { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument; pArgument->ReadScriptID(pACLGroup->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -405,7 +400,7 @@ CLuaArgument* CLuaArguments::PushACLGroup(CAccessControlListGroup* pACLGroup) CLuaArgument* CLuaArguments::PushAccount(CAccount* pAccount) { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument; pArgument->ReadScriptID(pAccount->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -413,7 +408,7 @@ CLuaArgument* CLuaArguments::PushAccount(CAccount* pAccount) CLuaArgument* CLuaArguments::PushResource(CResource* pResource) { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument; pArgument->ReadScriptID(pResource->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -421,7 +416,7 @@ CLuaArgument* CLuaArguments::PushResource(CResource* pResource) CLuaArgument* CLuaArguments::PushTextDisplay(CTextDisplay* pTextDisplay) { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument; pArgument->ReadScriptID(pTextDisplay->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -429,7 +424,7 @@ CLuaArgument* CLuaArguments::PushTextDisplay(CTextDisplay* pTextDisplay) CLuaArgument* CLuaArguments::PushTextItem(CTextItem* pTextItem) { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument; pArgument->ReadScriptID(pTextItem->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -437,7 +432,7 @@ CLuaArgument* CLuaArguments::PushTextItem(CTextItem* pTextItem) CLuaArgument* CLuaArguments::PushTimer(CLuaTimer* pLuaTimer) { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument; pArgument->ReadScriptID(pLuaTimer->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -445,7 +440,7 @@ CLuaArgument* CLuaArguments::PushTimer(CLuaTimer* pLuaTimer) CLuaArgument* CLuaArguments::PushDbQuery(CDbJobData* pJobData) { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument; pArgument->ReadScriptID(pJobData->GetId()); m_Arguments.push_back(pArgument); return pArgument; @@ -457,8 +452,7 @@ void CLuaArguments::DeleteArguments() vector::iterator iter = m_Arguments.begin(); for (; iter != m_Arguments.end(); ++iter) { - if ((*iter)->m_pOwner == this) - delete *iter; + delete *iter; } // Clear the vector @@ -470,8 +464,7 @@ void CLuaArguments::Pop() { // Delete the last element CLuaArgument* item = m_Arguments.back(); - if (item->m_pOwner == this) - delete item; + delete item; // Pop it out of the vector m_Arguments.pop_back(); @@ -489,13 +482,11 @@ void CLuaArguments::ValidateTableKeys() { // TODO - Handle ref in KnownTables // Remove pair - if ((*iter)->m_pOwner == this) - delete *iter; + delete *iter; iter = m_Arguments.erase(iter); if (iter != m_Arguments.end()) { - if ((*iter)->m_pOwner == this) - delete *iter; + delete *iter; iter = m_Arguments.erase(iter); } // Check if end @@ -530,7 +521,7 @@ bool CLuaArguments::ReadFromBitStream(NetBitStreamInterface& bitStream, std::vec pKnownTables->push_back(this); for (unsigned int ui = 0; ui < uiNumArgs; ++ui) { - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument(); if (!pArgument->ReadFromBitStream(bitStream, pKnownTables)) { delete pArgument; @@ -729,7 +720,7 @@ bool CLuaArguments::ReadFromJSONString(const char* szJSON) for (uint i = 0; i < json_object_array_length(object); i++) { json_object* arrayObject = json_object_array_get_idx(object, i); - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument(); bSuccess = pArgument->ReadFromJSONObject(arrayObject, &knownTables); m_Arguments.push_back(pArgument); // then the value if (!bSuccess) @@ -741,7 +732,7 @@ bool CLuaArguments::ReadFromJSONString(const char* szJSON) else if (json_object_get_type(object) == json_type_object) { std::vector knownTables; - CLuaArgument* pArgument = new CLuaArgument(this); + CLuaArgument* pArgument = new CLuaArgument(); bool bSuccess = pArgument->ReadFromJSONObject(object, &knownTables); m_Arguments.push_back(pArgument); // value json_object_put(object); @@ -775,10 +766,10 @@ bool CLuaArguments::ReadFromJSONObject(json_object* object, std::vectorReadString(key); m_Arguments.push_back(pArgument); // push the key first - pArgument = new CLuaArgument(this); + pArgument = new CLuaArgument(); bSuccess = pArgument->ReadFromJSONObject(val, pKnownTables); // then the value m_Arguments.push_back(pArgument); if (!bSuccess) @@ -814,11 +805,11 @@ bool CLuaArguments::ReadFromJSONArray(json_object* object, std::vectorReadNumber(i + 1); // push the key m_Arguments.push_back(pArgument); - pArgument = new CLuaArgument(this); + pArgument = new CLuaArgument(); bSuccess = pArgument->ReadFromJSONObject(arrayObject, pKnownTables); m_Arguments.push_back(pArgument); // then the valoue if (!bSuccess) diff --git a/Server/mods/deathmatch/logic/lua/CLuaArguments.h b/Server/mods/deathmatch/logic/lua/CLuaArguments.h index 8907b1ccd80..87fd92be206 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaArguments.h +++ b/Server/mods/deathmatch/logic/lua/CLuaArguments.h @@ -80,7 +80,6 @@ class CLuaArguments CLuaArgument* PushDbQuery(CDbJobData* pJobData); CLuaArgument* PushArgument(const CLuaArgument& argument); - void PushArgumentWeak(const CLuaArgument* argument); CLuaArgument* PushTable(CLuaArguments* table); void DeleteArguments(); diff --git a/Server/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp b/Server/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp index d6b8bbe0575..6cacbdcc989 100644 --- a/Server/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp +++ b/Server/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp @@ -1566,7 +1566,7 @@ int CLuaElementDefs::setElementData(lua_State* luaVM) strKey = strKey.Left(MAX_CUSTOMDATA_NAME_LENGTH); } - if (pElement->SetCustomData(std::move(strKey), std::move(value), syncType, {}, true, EElementDataPacketType::Broadcast)) + if (CStaticFunctionDefinitions::SetElementData(pElement, strKey, value, syncType)) { lua_pushboolean(luaVM, true); return 1; diff --git a/Server/mods/deathmatch/logic/packets/CCustomDataPacket.h b/Server/mods/deathmatch/logic/packets/CCustomDataPacket.h index 25ef48202e4..620d30edfb7 100644 --- a/Server/mods/deathmatch/logic/packets/CCustomDataPacket.h +++ b/Server/mods/deathmatch/logic/packets/CCustomDataPacket.h @@ -27,8 +27,8 @@ class CCustomDataPacket final : public CPacket bool Write(NetBitStreamInterface& BitStream) const; const ElementID GetElementID() const { return m_ElementID; } - SString& GetName() { return m_strName; } - CLuaArgument& GetValue() { return m_Value; } + const SString& GetName() const { return m_strName; } + const CLuaArgument& GetValue() const { return m_Value; } private: ElementID m_ElementID; diff --git a/Shared/mods/deathmatch/logic/luadefs/CLuaElementDefsShared.cpp b/Shared/mods/deathmatch/logic/luadefs/CLuaElementDefsShared.cpp index 57237a6c4c4..7d331163014 100644 --- a/Shared/mods/deathmatch/logic/luadefs/CLuaElementDefsShared.cpp +++ b/Shared/mods/deathmatch/logic/luadefs/CLuaElementDefsShared.cpp @@ -41,7 +41,7 @@ int CLuaElementDefs::GetElementData(lua_State* luaVM) } #ifdef MTA_CLIENT - const CLuaArgument* pVariable = pElement->GetCustomData(strKey, bInherit); + CLuaArgument* pVariable = pElement->GetCustomData(strKey, bInherit); #else CLuaArgument* pVariable = CStaticFunctionDefinitions::GetElementData(pElement, strKey, bInherit); #endif From 5ee515a252ab2700d51ab3bda4abe0383cac8686 Mon Sep 17 00:00:00 2001 From: TEDERIs Date: Fri, 12 Jan 2024 21:59:01 +0700 Subject: [PATCH 5/7] Revert "Revert "Further optimizations"" This reverts commit 69b59606e088e9d2243a193e66ad1f3ba24ef39f. --- .../mods/deathmatch/logic/CClientEntity.cpp | 42 +++++--- Client/mods/deathmatch/logic/CClientEntity.h | 4 +- Client/mods/deathmatch/logic/CCustomData.cpp | 31 +++--- Client/mods/deathmatch/logic/CCustomData.h | 25 ++++- .../mods/deathmatch/logic/CPacketHandler.cpp | 2 +- .../logic/CStaticFunctionDefinitions.cpp | 25 ----- .../logic/CStaticFunctionDefinitions.h | 1 - .../deathmatch/logic/lua/CLuaArgument.cpp | 95 ++++++++++++++++++- .../mods/deathmatch/logic/lua/CLuaArgument.h | 18 ++-- .../deathmatch/logic/lua/CLuaArguments.cpp | 66 ++++++++----- .../mods/deathmatch/logic/lua/CLuaArguments.h | 2 + .../logic/luadefs/CLuaElementDefs.cpp | 2 +- .../deathmatch/logic/rpc/CElementRPCs.cpp | 2 +- Server/mods/deathmatch/logic/CCustomData.cpp | 24 ++--- Server/mods/deathmatch/logic/CCustomData.h | 23 ++++- Server/mods/deathmatch/logic/CElement.cpp | 50 ++++++++-- Server/mods/deathmatch/logic/CElement.h | 11 ++- Server/mods/deathmatch/logic/CGame.cpp | 27 +----- .../logic/CStaticFunctionDefinitions.cpp | 33 ------- .../logic/CStaticFunctionDefinitions.h | 1 - .../deathmatch/logic/lua/CLuaArgument.cpp | 88 ++++++++++++++++- .../mods/deathmatch/logic/lua/CLuaArgument.h | 18 ++-- .../deathmatch/logic/lua/CLuaArguments.cpp | 75 ++++++++------- .../mods/deathmatch/logic/lua/CLuaArguments.h | 1 + .../logic/luadefs/CLuaElementDefs.cpp | 2 +- .../logic/packets/CCustomDataPacket.h | 4 +- .../logic/luadefs/CLuaElementDefsShared.cpp | 2 +- 27 files changed, 445 insertions(+), 229 deletions(-) diff --git a/Client/mods/deathmatch/logic/CClientEntity.cpp b/Client/mods/deathmatch/logic/CClientEntity.cpp index 16e5145eb51..efbac757689 100644 --- a/Client/mods/deathmatch/logic/CClientEntity.cpp +++ b/Client/mods/deathmatch/logic/CClientEntity.cpp @@ -279,10 +279,10 @@ void CClientEntity::SetID(ElementID ID) } } -CLuaArgument* CClientEntity::GetCustomData(const SString& strName, bool bInheritData, bool* pbIsSynced) +const CLuaArgument* CClientEntity::GetCustomData(const SString& strName, bool bInheritData, bool* pbIsSynced) { // Grab it and return a pointer to the variable - SCustomData* pData = m_pCustomData->Get(strName); + const SCustomData* pData = m_pCustomData->Get(strName); if (pData) { if (pbIsSynced) @@ -316,7 +316,7 @@ CLuaArguments* CClientEntity::GetAllCustomData(CLuaArguments* table) bool CClientEntity::GetCustomDataString(const char* szName, SString& strOut, bool bInheritData) { // Grab the custom data variable - CLuaArgument* pData = GetCustomData(szName, bInheritData); + const CLuaArgument* pData = GetCustomData(szName, bInheritData); if (pData) { // Write the content depending on what type it is @@ -351,7 +351,7 @@ bool CClientEntity::GetCustomDataString(const char* szName, SString& strOut, boo bool CClientEntity::GetCustomDataInt(const char* szName, int& iOut, bool bInheritData) { // Grab the custom data variable - CLuaArgument* pData = GetCustomData(szName, bInheritData); + const CLuaArgument* pData = GetCustomData(szName, bInheritData); if (pData) { // Write the content depending on what type it is @@ -389,7 +389,7 @@ bool CClientEntity::GetCustomDataInt(const char* szName, int& iOut, bool bInheri bool CClientEntity::GetCustomDataFloat(const char* szName, float& fOut, bool bInheritData) { // Grab the custom data variable - CLuaArgument* pData = GetCustomData(szName, bInheritData); + const CLuaArgument* pData = GetCustomData(szName, bInheritData); if (pData) { // Write the content depending on what type it is @@ -416,7 +416,7 @@ bool CClientEntity::GetCustomDataFloat(const char* szName, float& fOut, bool bIn bool CClientEntity::GetCustomDataBool(const char* szName, bool& bOut, bool bInheritData) { // Grab the custom data variable - CLuaArgument* pData = GetCustomData(szName, bInheritData); + const CLuaArgument* pData = GetCustomData(szName, bInheritData); if (pData) { // Write the content depending on what type it is @@ -468,20 +468,38 @@ bool CClientEntity::GetCustomDataBool(const char* szName, bool& bOut, bool bInhe return false; } -bool CClientEntity::SetCustomData(const SString& strName, const CLuaArgument& Variable, bool bSynchronized) +bool CClientEntity::SetCustomData(SString&& strName, CLuaArgument&& Variable, bool bSynchronized, bool bSendPacket) { // SCustomData is 64(88 in debug) bytes long. A static storage can be more efficient. - static SCustomData oldData; + static SCustomData oldValue; - if (m_pCustomData->Set(strName, Variable, bSynchronized, &oldData)) + if (const auto result = m_pCustomData->Set(std::move(strName), std::move(Variable), bSynchronized, &oldValue)) { + const auto& newName = result.GetName(); + const auto& newValue = result.GetData(); + // Trigger the onClientElementDataChange event on us CLuaArguments Arguments; - Arguments.PushString(strName); - Arguments.PushArgument(oldData.Variable); - Arguments.PushArgument(Variable); + Arguments.PushString(newName); + Arguments.PushArgumentWeak(&oldValue.Variable); + Arguments.PushArgumentWeak(&newValue.Variable); CallEvent("onClientElementDataChange", Arguments, true); + if (bSendPacket && bSynchronized && !IsLocalEntity()) + { + NetBitStreamInterface* pBitStream = g_pNet->AllocateNetBitStream(); + // Write element ID, name length and the name. Also write the variable. + pBitStream->Write(GetID()); + const unsigned short usNameLength = static_cast(newName.length()); + pBitStream->WriteCompressed(usNameLength); + pBitStream->Write(newName.c_str(), usNameLength); + newValue.Variable.WriteToBitStream(*pBitStream); + + // Send the packet and deallocate + g_pNet->SendPacket(PACKET_ID_CUSTOM_DATA, pBitStream, PACKET_PRIORITY_HIGH, PACKET_RELIABILITY_RELIABLE_ORDERED); + g_pNet->DeallocateNetBitStream(pBitStream); + } + return true; } diff --git a/Client/mods/deathmatch/logic/CClientEntity.h b/Client/mods/deathmatch/logic/CClientEntity.h index 2071a19bfa6..29be0cfabd3 100644 --- a/Client/mods/deathmatch/logic/CClientEntity.h +++ b/Client/mods/deathmatch/logic/CClientEntity.h @@ -199,13 +199,13 @@ class CClientEntity : public CClientEntityBase void SetID(ElementID ID); CCustomData* GetCustomDataPointer() { return m_pCustomData; } - CLuaArgument* GetCustomData(const SString& strName, bool bInheritData, bool* pbIsSynced = nullptr); + const CLuaArgument* GetCustomData(const SString& strName, bool bInheritData, bool* pbIsSynced = nullptr); CLuaArguments* GetAllCustomData(CLuaArguments* table); bool GetCustomDataString(const char* szKey, SString& strOut, bool bInheritData); bool GetCustomDataFloat(const char* szKey, float& fOut, bool bInheritData); bool GetCustomDataInt(const char* szKey, int& iOut, bool bInheritData); bool GetCustomDataBool(const char* szKey, bool& bOut, bool bInheritData); - bool SetCustomData(const SString& strName, const CLuaArgument& Variable, bool bSynchronized = true); + bool SetCustomData(SString&& strName, CLuaArgument&& Variable, bool bSynchronized = true, bool bSendPacket = false); void DeleteCustomData(const SString& strName); virtual bool GetMatrix(CMatrix& matrix) const; diff --git a/Client/mods/deathmatch/logic/CCustomData.cpp b/Client/mods/deathmatch/logic/CCustomData.cpp index ab618f96785..0ee6a8c25b9 100644 --- a/Client/mods/deathmatch/logic/CCustomData.cpp +++ b/Client/mods/deathmatch/logic/CCustomData.cpp @@ -15,46 +15,43 @@ void CCustomData::Copy(CCustomData* pCustomData) { for (const auto& [key, data] : pCustomData->GetData()) - Set(key, data.Variable); + Set(SString(key), CLuaArgument(data.Variable)); } -SCustomData* CCustomData::Get(const SString& strName, bool bCreate) +const SCustomData* CCustomData::Get(const SString& strName) { if (auto it = m_Data.find(strName); it != m_Data.end()) return &it->second; - if (bCreate) - return &m_Data[strName]; - return {}; } -bool CCustomData::Set(const SString& strName, const CLuaArgument& Variable, bool bSynchronized, SCustomData* pOldData) +SCustomDataResult CCustomData::Set(SString&& strName, CLuaArgument&& Variable, bool bSynchronized, SCustomData* oldValue) { if (strName.length() > MAX_CUSTOMDATA_NAME_LENGTH) { // Don't allow it to be set if the name is too long CLogger::ErrorPrintf("Custom data name too long (%s)", *strName.Left(MAX_CUSTOMDATA_NAME_LENGTH + 1)); - return false; + return {}; } - SCustomData* pCurrentVariable = Get(strName, true); - assert(pCurrentVariable); + auto iter = m_Data.try_emplace(std::move(strName)).first; + SCustomData& pCurrentVariable = iter->second; - if (pCurrentVariable->Variable.IsEmpty() || pCurrentVariable->Variable != Variable || pCurrentVariable->bSynchronized != bSynchronized) - { + if (pCurrentVariable.Variable.IsEmpty() || pCurrentVariable.bSynchronized != bSynchronized || pCurrentVariable.Variable != Variable ) + { // Save the old variable - if (pOldData) - *pOldData = *pCurrentVariable; + if (oldValue) + *oldValue = std::move(pCurrentVariable); // Set the new data - pCurrentVariable->Variable = Variable; - pCurrentVariable->bSynchronized = bSynchronized; + pCurrentVariable.Variable = std::move(Variable); + pCurrentVariable.bSynchronized = bSynchronized; - return true; + return SCustomDataResult(iter); } - return false; + return {}; } bool CCustomData::Delete(const SString& strName, SCustomData* pOldData) diff --git a/Client/mods/deathmatch/logic/CCustomData.h b/Client/mods/deathmatch/logic/CCustomData.h index 70fb515f88c..26485460fdb 100644 --- a/Client/mods/deathmatch/logic/CCustomData.h +++ b/Client/mods/deathmatch/logic/CCustomData.h @@ -20,13 +20,34 @@ struct SCustomData bool bSynchronized{true}; }; +struct SCustomDataResult +{ + using iterator = std::unordered_map::iterator; + + SCustomDataResult() = default; + + SCustomDataResult(const iterator& iter) : + Iter(iter), + bValid(true) + { + } + + const SString& GetName() const { return Iter->first; } + const SCustomData& GetData() const { return Iter->second; } + + operator bool() const { return bValid; } + + iterator Iter; + bool bValid{}; +}; + class CCustomData { public: void Copy(CCustomData* pCustomData); - SCustomData* Get(const SString& strName, bool bCreate = false); - bool Set(const SString& strName, const CLuaArgument& Variable, bool bSynchronized = true, SCustomData* pOldData = {}); + const SCustomData* Get(const SString& strName); + SCustomDataResult Set(SString&& strName, CLuaArgument&& Variable, bool bSynchronized = true, SCustomData* oldValue = {}); bool Delete(const SString& strName, SCustomData* pOldData = {}); diff --git a/Client/mods/deathmatch/logic/CPacketHandler.cpp b/Client/mods/deathmatch/logic/CPacketHandler.cpp index 51cad6aed4a..776410a5b00 100644 --- a/Client/mods/deathmatch/logic/CPacketHandler.cpp +++ b/Client/mods/deathmatch/logic/CPacketHandler.cpp @@ -2871,7 +2871,7 @@ void CPacketHandler::Packet_EntityAdd(NetBitStreamInterface& bitStream) CLuaArgument Argument; Argument.ReadFromBitStream(bitStream); - pCustomData->Set(strName, Argument); + pCustomData->Set(std::move(strName), std::move(Argument)); } else { diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 40c3c45ff70..38bf6d920a1 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -993,31 +993,6 @@ bool CStaticFunctionDefinitions::SetElementID(CClientEntity& Entity, const char* return false; } -bool CStaticFunctionDefinitions::SetElementData(CClientEntity& Entity, const SString& strName, CLuaArgument& Variable, bool bSynchronize) -{ - if (Entity.SetCustomData(strName, Variable, bSynchronize)) - { - if (bSynchronize && !Entity.IsLocalEntity()) - { - NetBitStreamInterface* pBitStream = g_pNet->AllocateNetBitStream(); - // Write element ID, name length and the name. Also write the variable. - pBitStream->Write(Entity.GetID()); - const unsigned short usNameLength = static_cast(strName.length()); - pBitStream->WriteCompressed(usNameLength); - pBitStream->Write(strName.c_str(), usNameLength); - Variable.WriteToBitStream(*pBitStream); - - // Send the packet and deallocate - g_pNet->SendPacket(PACKET_ID_CUSTOM_DATA, pBitStream, PACKET_PRIORITY_HIGH, PACKET_RELIABILITY_RELIABLE_ORDERED); - g_pNet->DeallocateNetBitStream(pBitStream); - } - - return true; - } - - return false; -} - bool CStaticFunctionDefinitions::RemoveElementData(CClientEntity& Entity, const char* szName) { // TODO diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h index ab7dfa0640f..eb0911623c2 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h @@ -81,7 +81,6 @@ class CStaticFunctionDefinitions static CClientDummy* CreateElement(CResource& Resource, const char* szTypeName, const char* szID); static bool DestroyElement(CClientEntity& Entity); static bool SetElementID(CClientEntity& Entity, const char* szID); - static bool SetElementData(CClientEntity& Entity, const SString& strName, CLuaArgument& Variable, bool bSynchronize); static bool RemoveElementData(CClientEntity& Entity, const char* szName); static bool SetElementMatrix(CClientEntity& Entity, const CMatrix& matrix); static bool SetElementPosition(CClientEntity& Entity, const CVector& vecPosition, bool bWarp = true); diff --git a/Client/mods/deathmatch/logic/lua/CLuaArgument.cpp b/Client/mods/deathmatch/logic/lua/CLuaArgument.cpp index 3a5f50df3f6..ad3af3d7525 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaArgument.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaArgument.cpp @@ -29,7 +29,8 @@ using namespace std; // Prevent the warning issued when doing unsigned short -> void* #pragma warning(disable:4312) -CLuaArgument::CLuaArgument() +CLuaArgument::CLuaArgument(CLuaArguments* pOwner) : + m_pOwner(pOwner) { m_iType = LUA_TNIL; m_iIndex = -1; @@ -37,20 +38,31 @@ CLuaArgument::CLuaArgument() m_pUserData = NULL; } -CLuaArgument::CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables) +CLuaArgument::CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables, CLuaArguments* pOwner) : + m_pOwner(pOwner) { // Initialize and call our = on the argument m_pTableData = NULL; CopyRecursive(Argument, pKnownTables); } -CLuaArgument::CLuaArgument(NetBitStreamInterface& bitStream, std::vector* pKnownTables) +CLuaArgument::CLuaArgument(CLuaArgument&& Argument, CFastHashMap* pKnownTables, CLuaArguments* pOwner) : + m_pOwner(pOwner) +{ + // Initialize and call our = on the argument + m_pTableData = NULL; + MoveRecursive(std::move(Argument)); +} + +CLuaArgument::CLuaArgument(NetBitStreamInterface& bitStream, std::vector* pKnownTables, CLuaArguments* pOwner) : + m_pOwner(pOwner) { m_pTableData = NULL; ReadFromBitStream(bitStream, pKnownTables); } -CLuaArgument::CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables) +CLuaArgument::CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables, CLuaArguments* pOwner) : + m_pOwner(pOwner) { // Read the argument out of the lua VM m_pTableData = NULL; @@ -67,7 +79,7 @@ CLuaArgument::~CLuaArgument() void CLuaArgument::CopyRecursive(const CLuaArgument& Argument, CFastHashMap* pKnownTables) { // Clear the string - m_strString = ""; + m_strString.clear(); // Destroy our old tabledata if neccessary DeleteTableData(); @@ -126,6 +138,71 @@ void CLuaArgument::CopyRecursive(const CLuaArgument& Argument, CFastHashMap* pKnownTables) +{ + // Clear the string + m_strString.clear(); + + // Destroy our old tabledata if neccessary + DeleteTableData(); + +#ifdef MTA_DEBUG + // Copy over line and filename too + m_strFilename = std::move(Argument.m_strFilename); + m_iLine = std::exchange(Argument.m_iLine, 0); +#endif + + // Set our variable equally to the copy class + m_iType = Argument.m_iType; + switch (m_iType) + { + case LUA_TBOOLEAN: + { + m_bBoolean = std::exchange(Argument.m_bBoolean, false); + break; + } + + case LUA_TUSERDATA: + case LUA_TLIGHTUSERDATA: + { + m_pUserData = std::exchange(Argument.m_pUserData, nullptr); + break; + } + + case LUA_TNUMBER: + { + m_Number = std::exchange(Argument.m_Number, 0); + break; + } + + case LUA_TTABLE: + { + if (pKnownTables && (m_pTableData = MapFindRef(*pKnownTables, Argument.m_pTableData))) + { + m_bWeakTableRef = true; + } + else + { + m_pTableData = std::exchange(Argument.m_pTableData, nullptr); + m_bWeakTableRef = false; + } + break; + } + + case LUA_TSTRING: + { + m_strString = std::move(Argument.m_strString); + break; + } + + default: + break; + } + + Argument.m_iType = LUA_TNIL; + Argument.m_iIndex = -1; +} + const CLuaArgument& CLuaArgument::operator=(const CLuaArgument& Argument) { CopyRecursive(Argument); @@ -134,6 +211,14 @@ const CLuaArgument& CLuaArgument::operator=(const CLuaArgument& Argument) return Argument; } +const CLuaArgument& CLuaArgument::operator=(CLuaArgument&& Argument) +{ + MoveRecursive(std::move(Argument)); + + // Return the given class allowing for chaining + return Argument; +} + bool CLuaArgument::operator==(const CLuaArgument& Argument) { std::set knownTables; diff --git a/Client/mods/deathmatch/logic/lua/CLuaArgument.h b/Client/mods/deathmatch/logic/lua/CLuaArgument.h index 8c122628590..3db092f02d0 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaArgument.h +++ b/Client/mods/deathmatch/logic/lua/CLuaArgument.h @@ -26,14 +26,17 @@ class CLuaArguments; class CLuaArgument { + friend class CLuaArguments; public: - CLuaArgument(); - CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables = NULL); - CLuaArgument(NetBitStreamInterface& bitStream, std::vector* pKnownTables = NULL); - CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables = NULL); + CLuaArgument(CLuaArguments* pOwner = {}); + CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables = NULL, CLuaArguments* pOwner = {}); + CLuaArgument(CLuaArgument&& Argument, CFastHashMap* pKnownTables = NULL, CLuaArguments* pOwner = {}); + CLuaArgument(NetBitStreamInterface& bitStream, std::vector* pKnownTables = NULL, CLuaArguments* pOwner = {}); + CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables = NULL, CLuaArguments* pOwner = {}); ~CLuaArgument(); const CLuaArgument& operator=(const CLuaArgument& Argument); + const CLuaArgument& operator=(CLuaArgument&& Argument); bool operator==(const CLuaArgument& Argument); bool operator!=(const CLuaArgument& Argument); @@ -55,7 +58,7 @@ class CLuaArgument bool GetBoolean() const { return m_bBoolean; }; lua_Number GetNumber() const { return m_Number; }; - const SString& GetString() { return m_strString; }; + const SString& GetString() const { return m_strString; }; void* GetUserData() const { return m_pUserData; }; CClientEntity* GetElement() const; @@ -68,14 +71,16 @@ class CLuaArgument private: void LogUnableToPacketize(const char* szMessage) const; + CLuaArguments* m_pOwner{}; + int m_iType; int m_iIndex; bool m_bBoolean; + bool m_bWeakTableRef; lua_Number m_Number; SString m_strString; void* m_pUserData; CLuaArguments* m_pTableData; - bool m_bWeakTableRef; #ifdef MTA_DEBUG std::string m_strFilename; @@ -83,6 +88,7 @@ class CLuaArgument #endif void CopyRecursive(const CLuaArgument& Argument, CFastHashMap* pKnownTables = NULL); + void MoveRecursive(CLuaArgument&& Argument, CFastHashMap* pKnownTables = NULL); bool CompareRecursive(const CLuaArgument& Argument, std::set* pKnownTables = NULL); void DeleteTableData(); }; diff --git a/Client/mods/deathmatch/logic/lua/CLuaArguments.cpp b/Client/mods/deathmatch/logic/lua/CLuaArguments.cpp index c93cc86bb4b..71c6ef7ebaf 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaArguments.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaArguments.cpp @@ -65,7 +65,7 @@ void CLuaArguments::CopyRecursive(const CLuaArguments& Arguments, CFastHashMap::const_iterator iter = Arguments.m_Arguments.begin(); for (; iter != Arguments.m_Arguments.end(); iter++) { - CLuaArgument* pArgument = new CLuaArgument(**iter, pKnownTables); + CLuaArgument* pArgument = new CLuaArgument(**iter, pKnownTables, this); m_Arguments.push_back(pArgument); } @@ -84,7 +84,7 @@ void CLuaArguments::ReadArguments(lua_State* luaVM, signed int uiIndexBegin) while (lua_type(luaVM, uiIndexBegin) != LUA_TNONE) { // Create an argument, let it read out the argument and add it to our vector - CLuaArgument* pArgument = new CLuaArgument(luaVM, uiIndexBegin++, &knownTables); + CLuaArgument* pArgument = new CLuaArgument(luaVM, uiIndexBegin++, &knownTables, this); m_Arguments.push_back(pArgument); knownTables.clear(); @@ -113,10 +113,10 @@ void CLuaArguments::ReadTable(lua_State* luaVM, int iIndexBegin, CFastHashMap::const_iterator iter = Arguments.IterBegin(); for (; iter != Arguments.IterEnd(); iter++) { - CLuaArgument* pArgument = new CLuaArgument(**iter); + CLuaArgument* pArgument = new CLuaArgument(**iter, {}, this); m_Arguments.push_back(pArgument); } } @@ -316,14 +316,14 @@ bool CLuaArguments::CallGlobal(CLuaMain* pLuaMain, const char* szFunction, CLuaA CLuaArgument* CLuaArguments::PushNil() { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); m_Arguments.push_back(pArgument); return pArgument; } CLuaArgument* CLuaArguments::PushBoolean(bool bBool) { - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadBool(bBool); m_Arguments.push_back(pArgument); return pArgument; @@ -331,7 +331,7 @@ CLuaArgument* CLuaArguments::PushBoolean(bool bBool) CLuaArgument* CLuaArguments::PushNumber(double dNumber) { - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadNumber(dNumber); m_Arguments.push_back(pArgument); return pArgument; @@ -339,7 +339,7 @@ CLuaArgument* CLuaArguments::PushNumber(double dNumber) CLuaArgument* CLuaArguments::PushString(const std::string& strString) { - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadString(strString); m_Arguments.push_back(pArgument); return pArgument; @@ -347,7 +347,7 @@ CLuaArgument* CLuaArguments::PushString(const std::string& strString) CLuaArgument* CLuaArguments::PushResource(CResource* pResource) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadScriptID(pResource->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -355,7 +355,7 @@ CLuaArgument* CLuaArguments::PushResource(CResource* pResource) CLuaArgument* CLuaArguments::PushElement(CClientEntity* pElement) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadElement(pElement); m_Arguments.push_back(pArgument); return pArgument; @@ -363,14 +363,26 @@ CLuaArgument* CLuaArguments::PushElement(CClientEntity* pElement) CLuaArgument* CLuaArguments::PushArgument(const CLuaArgument& Argument) { - CLuaArgument* pArgument = new CLuaArgument(Argument); + CLuaArgument* pArgument = new CLuaArgument(Argument, {}, this); m_Arguments.push_back(pArgument); return pArgument; } +CLuaArgument* CLuaArguments::PushArgument(CLuaArgument&& argument) +{ + CLuaArgument* pArgument = new CLuaArgument(std::move(argument), {}, this); + m_Arguments.push_back(pArgument); + return pArgument; +} + +void CLuaArguments::PushArgumentWeak(const CLuaArgument* pArgument) +{ + m_Arguments.push_back(const_cast(pArgument)); +} + CLuaArgument* CLuaArguments::PushTable(CLuaArguments* table) { - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadTable(table); m_Arguments.push_back(pArgument); return pArgument; @@ -383,7 +395,8 @@ void CLuaArguments::DeleteArguments() vector::iterator iter = m_Arguments.begin(); for (; iter != m_Arguments.end(); iter++) { - delete *iter; + if ((*iter)->m_pOwner == this) + delete *iter; } // Clear the vector @@ -394,8 +407,9 @@ void CLuaArguments::DeleteArguments() void CLuaArguments::Pop() { // Delete the last element - CLuaArgument* item = m_Arguments.back(); - delete item; + auto item = m_Arguments.back(); + if (item->m_pOwner == this) + delete item; // Pop it out of the vector m_Arguments.pop_back(); @@ -413,11 +427,13 @@ void CLuaArguments::ValidateTableKeys() { // TODO - Handle ref in KnownTables // Remove pair - delete *iter; + if ((*iter)->m_pOwner == this) + delete *iter; iter = m_Arguments.erase(iter); if (iter != m_Arguments.end()) { - delete *iter; + if ((*iter)->m_pOwner == this) + delete *iter; iter = m_Arguments.erase(iter); } // Check if end @@ -452,7 +468,7 @@ bool CLuaArguments::ReadFromBitStream(NetBitStreamInterface& bitStream, std::vec pKnownTables->push_back(this); for (unsigned int ui = 0; ui < uiNumArgs; ++ui) { - CLuaArgument* pArgument = new CLuaArgument(bitStream, pKnownTables); + CLuaArgument* pArgument = new CLuaArgument(bitStream, pKnownTables, this); m_Arguments.push_back(pArgument); } } @@ -644,7 +660,7 @@ bool CLuaArguments::ReadFromJSONString(const char* szJSON) for (uint i = 0; i < json_object_array_length(object); i++) { json_object* arrayObject = json_object_array_get_idx(object, i); - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); bSuccess = pArgument->ReadFromJSONObject(arrayObject, &knownTables); m_Arguments.push_back(pArgument); // then the value if (!bSuccess) @@ -656,7 +672,7 @@ bool CLuaArguments::ReadFromJSONString(const char* szJSON) else if (json_object_get_type(object) == json_type_object) { std::vector knownTables; - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); bool bSuccess = pArgument->ReadFromJSONObject(object, &knownTables); m_Arguments.push_back(pArgument); // value json_object_put(object); @@ -690,7 +706,7 @@ bool CLuaArguments::ReadFromJSONObject(json_object* object, std::vectorReadString(key); m_Arguments.push_back(pArgument); // push the key first pArgument = new CLuaArgument(); @@ -729,11 +745,11 @@ bool CLuaArguments::ReadFromJSONArray(json_object* object, std::vectorReadNumber(i + 1); // push the key m_Arguments.push_back(pArgument); - pArgument = new CLuaArgument(); + pArgument = new CLuaArgument(this); bSuccess = pArgument->ReadFromJSONObject(arrayObject, pKnownTables); m_Arguments.push_back(pArgument); // then the valoue if (!bSuccess) diff --git a/Client/mods/deathmatch/logic/lua/CLuaArguments.h b/Client/mods/deathmatch/logic/lua/CLuaArguments.h index 89011983f20..4630ed77fb3 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaArguments.h +++ b/Client/mods/deathmatch/logic/lua/CLuaArguments.h @@ -58,6 +58,8 @@ class CLuaArguments CLuaArgument* PushString(const std::string& strString); CLuaArgument* PushElement(CClientEntity* pElement); CLuaArgument* PushArgument(const CLuaArgument& argument); + CLuaArgument* PushArgument(CLuaArgument&& argument); + void PushArgumentWeak(const CLuaArgument* pArgument); CLuaArgument* PushResource(CResource* pResource); CLuaArgument* PushTable(CLuaArguments* table); diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp index 0e0175e6ce4..1bba6da7cc6 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp @@ -1779,7 +1779,7 @@ int CLuaElementDefs::SetElementData(lua_State* luaVM) strKey = strKey.Left(MAX_CUSTOMDATA_NAME_LENGTH); } - if (CStaticFunctionDefinitions::SetElementData(*pEntity, strKey, value, bSynchronize)) + if (pEntity->SetCustomData(std::move(strKey), std::move(value), bSynchronize, true)) { lua_pushboolean(luaVM, true); return 1; diff --git a/Client/mods/deathmatch/logic/rpc/CElementRPCs.cpp b/Client/mods/deathmatch/logic/rpc/CElementRPCs.cpp index 1b5da5c7803..dacdf342090 100644 --- a/Client/mods/deathmatch/logic/rpc/CElementRPCs.cpp +++ b/Client/mods/deathmatch/logic/rpc/CElementRPCs.cpp @@ -97,7 +97,7 @@ void CElementRPCs::SetElementData(CClientEntity* pSource, NetBitStreamInterface& CLuaArgument Argument; if (bitStream.ReadStringCharacters(strName, usNameLength) && Argument.ReadFromBitStream(bitStream)) { - pSource->SetCustomData(strName, Argument); + pSource->SetCustomData(std::move(strName), std::move(Argument)); } } } diff --git a/Server/mods/deathmatch/logic/CCustomData.cpp b/Server/mods/deathmatch/logic/CCustomData.cpp index b613403b2d0..2642c4c8d9b 100644 --- a/Server/mods/deathmatch/logic/CCustomData.cpp +++ b/Server/mods/deathmatch/logic/CCustomData.cpp @@ -15,7 +15,7 @@ void CCustomData::Copy(CCustomData* pCustomData) { for (const auto& [key, data] : pCustomData->GetData()) - Set(key, data.Variable); + Set(SString(key), CLuaArgument(data.Variable)); } SCustomData* CCustomData::Get(const SString& strName, bool bCreate) @@ -77,32 +77,32 @@ void CCustomData::UpdateSynced(const SString& strName, const CLuaArgument& Varia } } -bool CCustomData::Set(const SString& strName, const CLuaArgument& Variable, ESyncType syncType, SCustomData* pOldData) +SCustomDataResult CCustomData::Set(SString&& strName, CLuaArgument&& Variable, ESyncType syncType, SCustomData* pOldData) { if (strName.length() > MAX_CUSTOMDATA_NAME_LENGTH) - return false; + return {}; - SCustomData* pCurrentVariable = Get(strName, true); - assert(pCurrentVariable); + auto iter = m_Data.try_emplace(std::move(strName)).first; + SCustomData& pCurrentVariable = iter->second; - if (pCurrentVariable->Variable.IsEmpty() || pCurrentVariable->Variable != Variable || pCurrentVariable->syncType != syncType) + if (pCurrentVariable.Variable.IsEmpty() || pCurrentVariable.syncType != syncType || pCurrentVariable.Variable != Variable) { if (syncType == ESyncType::PERSISTENT) - syncType = pCurrentVariable->syncType; + syncType = pCurrentVariable.syncType; // Save the old variable if (pOldData) - *pOldData = *pCurrentVariable; + *pOldData = std::move(pCurrentVariable); // Set the new data - pCurrentVariable->Variable = Variable; - pCurrentVariable->syncType = syncType; + pCurrentVariable.Variable = std::move(Variable); + pCurrentVariable.syncType = syncType; UpdateSynced(strName, Variable, syncType); - return true; + return SCustomDataResult(iter); } - return false; + return {}; } bool CCustomData::Delete(const SString& strName, SCustomData* pOldData) diff --git a/Server/mods/deathmatch/logic/CCustomData.h b/Server/mods/deathmatch/logic/CCustomData.h index 84a5898adec..bb531837db1 100644 --- a/Server/mods/deathmatch/logic/CCustomData.h +++ b/Server/mods/deathmatch/logic/CCustomData.h @@ -32,6 +32,27 @@ struct SCustomData ESyncType syncType{ESyncType::BROADCAST}; }; +struct SCustomDataResult +{ + using iterator = std::unordered_map::iterator; + + SCustomDataResult() = default; + + SCustomDataResult(const iterator& iter) : + Iter(iter), + bValid(true) + { + } + + const SString& GetName() const { return Iter->first; } + const SCustomData& GetData() const { return Iter->second; } + + operator bool() const { return bValid; } + + iterator Iter; + bool bValid{}; +}; + class CCustomData { public: @@ -39,7 +60,7 @@ class CCustomData SCustomData* Get(const SString& strName, bool bCreate = false); SCustomData* GetSynced(const SString& strName); - bool Set(const SString& strName, const CLuaArgument& Variable, ESyncType syncType = ESyncType::BROADCAST, SCustomData* pOldData = {}); + SCustomDataResult Set(SString&& strName, CLuaArgument&& Variable, ESyncType syncType = ESyncType::BROADCAST, SCustomData* pOldData = {}); bool Delete(const SString& strName, SCustomData* pOldData = {}); diff --git a/Server/mods/deathmatch/logic/CElement.cpp b/Server/mods/deathmatch/logic/CElement.cpp index 8dd02344bb6..c8bee60d366 100644 --- a/Server/mods/deathmatch/logic/CElement.cpp +++ b/Server/mods/deathmatch/logic/CElement.cpp @@ -23,6 +23,7 @@ #include "CElementRefManager.h" #include "CLogger.h" #include "CSpatialDatabase.h" +#include "CPerfStatModule.h" #include "packets/CElementRPCPacket.h" #include "Utils.h" #include "lua/CLuaFunctionParseHelpers.h" @@ -504,7 +505,7 @@ void CElement::ReadCustomData(CEvents* pEvents, CXMLNode& Node) // Don't trigger onElementDataChanged event const ESyncType syncType = g_pGame->GetConfig()->GetSyncMapElementData() ? ESyncType::BROADCAST : ESyncType::LOCAL; - SetCustomData(pAttribute->GetName(), *args[0], syncType, {}, false); + SetCustomData(pAttribute->GetName(), std::move(*args[0]), syncType, {}, false); } } @@ -702,32 +703,61 @@ bool CElement::GetCustomDataBool(const char* szName, bool& bOut, bool bInheritDa return false; } -const SCustomData* CElement::SetCustomData(const SString& strName, const CLuaArgument& Variable, ESyncType syncType, CPlayer* pClient, bool bTriggerEvent) +bool CElement::SetCustomData(SString&& strName, CLuaArgument&& Variable, ESyncType syncType, CPlayer* pClient, + bool bTriggerEvent, EElementDataPacketType packetType) { if (strName.length() > MAX_CUSTOMDATA_NAME_LENGTH) { // Don't allow it to be set if the name is too long CLogger::ErrorPrintf("Custom data name too long (%s)\n", *strName.Left(MAX_CUSTOMDATA_NAME_LENGTH + 1)); - return {}; + return false; } // SCustomData is 64(88 in debug) bytes long. A static storage can be more efficient. static SCustomData oldData; - if (m_CustomData.Set(strName, Variable, syncType, &oldData) != true) - return {}; + const SCustomDataResult result = m_CustomData.Set(std::move(strName), std::move(Variable), syncType, &oldData); + if (!result) + return false; + + const auto& strNewName = result.GetName(); + const auto& newData = result.GetData(); if (bTriggerEvent) { // Trigger the onElementDataChange event on us CLuaArguments Arguments; - Arguments.PushString(strName); - Arguments.PushArgument(oldData.Variable); - Arguments.PushArgument(Variable); + Arguments.PushString(strNewName); + Arguments.PushArgumentWeak(&oldData.Variable); + Arguments.PushArgumentWeak(&newData.Variable); CallEvent("onElementDataChange", Arguments, pClient); - } + } + + CPlayerManager* pPlayerManager = g_pGame->GetPlayerManager(); + + if (packetType != EElementDataPacketType::DoNotSend && newData.syncType != ESyncType::LOCAL) + { + // Tell our clients to update their data + const unsigned short usNameLength = static_cast(strNewName.length()); + CBitStream BitStream; + BitStream.pBitStream->WriteCompressed(usNameLength); + BitStream.pBitStream->Write(strNewName.c_str(), usNameLength); + newData.Variable.WriteToBitStream(*BitStream.pBitStream); + + const CElementRPCPacket packet(this, SET_ELEMENT_DATA, *BitStream.pBitStream); + const size_t numPlayers = syncType == ESyncType::BROADCAST ? pPlayerManager->BroadcastOnlyJoined(packet, pClient) + : pPlayerManager->BroadcastOnlySubscribed(packet, this, strNewName, pClient); + if (packetType == EElementDataPacketType::Broadcast) + CPerfStatEventPacketUsage::GetSingleton()->UpdateElementDataUsageOut(strNewName, numPlayers, BitStream.pBitStream->GetNumberOfBytesUsed()); + else + CPerfStatEventPacketUsage::GetSingleton()->UpdateElementDataUsageRelayed(strNewName, numPlayers, BitStream.pBitStream->GetNumberOfBytesUsed()); + } + + // Unsubscribe all the players + if (oldData.syncType == ESyncType::SUBSCRIBE && newData.syncType != ESyncType::SUBSCRIBE) + pPlayerManager->ClearElementData(this, strNewName); - return &oldData; + return true; } bool CElement::DeleteCustomData(const SString& strName) diff --git a/Server/mods/deathmatch/logic/CElement.h b/Server/mods/deathmatch/logic/CElement.h index ce59a825704..c14de247148 100644 --- a/Server/mods/deathmatch/logic/CElement.h +++ b/Server/mods/deathmatch/logic/CElement.h @@ -49,6 +49,13 @@ typedef CFastList CElementListType; typedef std::vector CElementListSnapshot; typedef std::shared_ptr CElementListSnapshotRef; +enum class EElementDataPacketType +{ + DoNotSend = 0, + Broadcast, + Relay +}; + class CElement { friend class CPerPlayerEntity; @@ -143,8 +150,8 @@ class CElement bool GetCustomDataFloat(const char* szName, float& fOut, bool bInheritData); bool GetCustomDataBool(const char* szName, bool& bOut, bool bInheritData); // Note that returned SCustomData* cannot be used with recursive algorithms! - const SCustomData* SetCustomData(const SString& strName, const CLuaArgument& Variable, ESyncType syncType = ESyncType::BROADCAST, CPlayer* pClient = {}, - bool bTriggerEvent = true); + bool SetCustomData(SString&& strName, CLuaArgument&& Variable, ESyncType syncType = ESyncType::BROADCAST, CPlayer* pClient = {}, + bool bTriggerEvent = true, EElementDataPacketType packetType = EElementDataPacketType::DoNotSend); bool DeleteCustomData(const SString& strName); void SendAllCustomData(CPlayer* pPlayer); diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp index 0c8be06eafd..ef6b5652d4d 100644 --- a/Server/mods/deathmatch/logic/CGame.cpp +++ b/Server/mods/deathmatch/logic/CGame.cpp @@ -2591,32 +2591,7 @@ void CGame::Packet_CustomData(CCustomDataPacket& Packet) ElementID ID = Packet.GetElementID(); CElement* pElement = CElementIDs::GetElement(ID); if (pElement) - { - // Change the data - const SString& strName = Packet.GetName(); - const CLuaArgument& Value = Packet.GetValue(); - - if (const SCustomData* pOldData = pElement->SetCustomData(strName, Value, ESyncType::PERSISTENT, pSourcePlayer)) - { - if (pOldData->syncType != ESyncType::LOCAL) - { - // Tell our clients to update their data. Send to everyone but the one we got this packet from. - unsigned short usNameLength = static_cast(strName.length()); - CBitStream BitStream; - BitStream.pBitStream->WriteCompressed(usNameLength); - BitStream.pBitStream->Write(strName.c_str(), usNameLength); - Value.WriteToBitStream(*BitStream.pBitStream); - if (pOldData->syncType == ESyncType::BROADCAST) - m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(pElement, SET_ELEMENT_DATA, *BitStream.pBitStream), pSourcePlayer); - else - m_pPlayerManager->BroadcastOnlySubscribed(CElementRPCPacket(pElement, SET_ELEMENT_DATA, *BitStream.pBitStream), pElement, strName, - pSourcePlayer); - - CPerfStatEventPacketUsage::GetSingleton()->UpdateElementDataUsageRelayed(strName, m_pPlayerManager->Count(), - BitStream.pBitStream->GetNumberOfBytesUsed()); - } - } - } + pElement->SetCustomData(std::move(Packet.GetName()), std::move(Packet.GetValue()), ESyncType::PERSISTENT, pSourcePlayer, true, EElementDataPacketType::Relay); } } diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 59b6fe9634e..66a75bdaf45 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -936,39 +936,6 @@ bool CStaticFunctionDefinitions::SetElementID(CElement* pElement, const char* sz return true; } -bool CStaticFunctionDefinitions::SetElementData(CElement* pElement, const SString& strName, const CLuaArgument& Variable, ESyncType syncType) -{ - assert(pElement); - assert(strName.length() <= MAX_CUSTOMDATA_NAME_LENGTH); - - if (const SCustomData* pOldData = pElement->SetCustomData(strName, Variable, syncType)) - { - if (syncType != ESyncType::LOCAL) - { - // Tell our clients to update their data - const unsigned short usNameLength = static_cast(strName.length()); - CBitStream BitStream; - BitStream.pBitStream->WriteCompressed(usNameLength); - BitStream.pBitStream->Write(strName.c_str(), usNameLength); - Variable.WriteToBitStream(*BitStream.pBitStream); - - const CElementRPCPacket packet(pElement, SET_ELEMENT_DATA, *BitStream.pBitStream); - const size_t numPlayers = syncType == ESyncType::BROADCAST ? m_pPlayerManager->BroadcastOnlyJoined(packet) - : m_pPlayerManager->BroadcastOnlySubscribed(packet, pElement, strName); - - CPerfStatEventPacketUsage::GetSingleton()->UpdateElementDataUsageOut(strName, numPlayers, BitStream.pBitStream->GetNumberOfBytesUsed()); - } - - // Unsubscribe all the players - if (pOldData->syncType == ESyncType::SUBSCRIBE && syncType != ESyncType::SUBSCRIBE) - m_pPlayerManager->ClearElementData(pElement, strName); - - return true; - } - - return false; -} - bool CStaticFunctionDefinitions::RemoveElementData(CElement* pElement, const SString& strName) { assert(pElement); diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h index 940ddf22b9b..64d869df659 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h @@ -83,7 +83,6 @@ class CStaticFunctionDefinitions // Element set funcs static bool ClearElementVisibleTo(CElement* pElement); static bool SetElementID(CElement* pElement, const char* szID); - static bool SetElementData(CElement* pElement, const SString& strName, const CLuaArgument& Variable, ESyncType syncType); static bool RemoveElementData(CElement* pElement, const SString& strName); static bool AddElementDataSubscriber(CElement* pElement, const SString& strName, CPlayer* pPlayer); static bool RemoveElementDataSubscriber(CElement* pElement, const SString& strName, CPlayer* pPlayer); diff --git a/Server/mods/deathmatch/logic/lua/CLuaArgument.cpp b/Server/mods/deathmatch/logic/lua/CLuaArgument.cpp index 6c2f02c3778..f20956a041b 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaArgument.cpp +++ b/Server/mods/deathmatch/logic/lua/CLuaArgument.cpp @@ -26,21 +26,32 @@ extern CGame* g_pGame; using namespace std; -CLuaArgument::CLuaArgument() +CLuaArgument::CLuaArgument(CLuaArguments* pOwner) : + m_pOwner(pOwner) { m_iType = LUA_TNIL; m_pTableData = NULL; m_pUserData = NULL; } -CLuaArgument::CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables) +CLuaArgument::CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables, CLuaArguments* pOwner) : + m_pOwner(pOwner) { // Initialize and call our = on the argument m_pTableData = NULL; CopyRecursive(Argument, pKnownTables); } -CLuaArgument::CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables) +CLuaArgument::CLuaArgument(CLuaArgument&& Argument, CFastHashMap* pKnownTables, CLuaArguments* pOwner) : + m_pOwner(pOwner) +{ + // Initialize and call our = on the argument + m_pTableData = NULL; + MoveRecursive(std::move(Argument), pKnownTables); +} + +CLuaArgument::CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables, CLuaArguments* pOwner) : + m_pOwner(pOwner) { // Read the argument out of the lua VM m_pTableData = NULL; @@ -53,6 +64,69 @@ CLuaArgument::~CLuaArgument() DeleteTableData(); } +void CLuaArgument::MoveRecursive(CLuaArgument&& Argument, CFastHashMap* pKnownTables) +{ + // Clear the string + m_strString.clear(); + + // Destroy our old tabledata if neccessary + DeleteTableData(); + +#ifdef MTA_DEBUG + m_strFilename = std::move(Argument.m_strFilename); + m_iLine = std::exchange(Argument.m_iLine, 0); +#endif + + // Set our variable equally to the copy class + m_iType = Argument.m_iType; + switch (m_iType) + { + case LUA_TBOOLEAN: + { + m_bBoolean = std::exchange(Argument.m_bBoolean, false); + break; + } + + case LUA_TLIGHTUSERDATA: + case LUA_TUSERDATA: + { + m_pUserData = std::exchange(Argument.m_pUserData, nullptr); + break; + } + + case LUA_TNUMBER: + { + m_Number = std::exchange(Argument.m_Number, 0); + break; + } + + case LUA_TTABLE: + { + if (pKnownTables && (m_pTableData = MapFindRef(*pKnownTables, Argument.m_pTableData))) + { + m_bWeakTableRef = true; + } + else + { + m_pTableData = std::exchange(Argument.m_pTableData, nullptr); + m_bWeakTableRef = false; + } + break; + } + + case LUA_TSTRING: + { + m_strString = std::move(Argument.m_strString); + break; + } + + default: + break; + } + + Argument.m_iType = LUA_TNIL; +} + void CLuaArgument::CopyRecursive(const CLuaArgument& Argument, CFastHashMap* pKnownTables) { // Clear the string @@ -123,6 +197,14 @@ const CLuaArgument& CLuaArgument::operator=(const CLuaArgument& Argument) return Argument; } +const CLuaArgument& CLuaArgument::operator=(CLuaArgument&& Argument) +{ + MoveRecursive(std::move(Argument)); + + // Return the given class allowing for chaining + return Argument; +} + bool CLuaArgument::operator==(const CLuaArgument& Argument) const { std::set knownTables; diff --git a/Server/mods/deathmatch/logic/lua/CLuaArgument.h b/Server/mods/deathmatch/logic/lua/CLuaArgument.h index 5b69210291e..ea3ad9bc585 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaArgument.h +++ b/Server/mods/deathmatch/logic/lua/CLuaArgument.h @@ -28,13 +28,16 @@ class CLuaArguments; class CLuaArgument { + friend class CLuaArguments; public: - CLuaArgument(); - CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables = NULL); - CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables = NULL); + CLuaArgument(CLuaArguments* pOwner = {}); + CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables = NULL, CLuaArguments* pOwner = {}); + CLuaArgument(CLuaArgument&& Argument, CFastHashMap* pKnownTables = NULL, CLuaArguments* pOwner = {}); + CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMap* pKnownTables = NULL, CLuaArguments* pOwner = {}); ~CLuaArgument(); const CLuaArgument& operator=(const CLuaArgument& Argument); + const CLuaArgument& operator=(CLuaArgument&& Argument); bool operator==(const CLuaArgument& Argument) const; bool operator!=(const CLuaArgument& Argument) const; @@ -71,19 +74,22 @@ class CLuaArgument private: void LogUnableToPacketize(const char* szMessage) const; + CLuaArguments* m_pOwner{}; + int m_iType; bool m_bBoolean; + bool m_bWeakTableRef; lua_Number m_Number; std::string m_strString; void* m_pUserData; - CLuaArguments* m_pTableData; - bool m_bWeakTableRef; + CLuaArguments* m_pTableData; #ifdef MTA_DEBUG std::string m_strFilename; int m_iLine; #endif - void CopyRecursive(const CLuaArgument& Argument, CFastHashMap* pKnownTables = NULL); + void MoveRecursive(CLuaArgument&& Argument, CFastHashMap* pKnownTables = {}); + void CopyRecursive(const CLuaArgument& Argument, CFastHashMap* pKnownTables = {}); void DeleteTableData(); }; diff --git a/Server/mods/deathmatch/logic/lua/CLuaArguments.cpp b/Server/mods/deathmatch/logic/lua/CLuaArguments.cpp index 3feadfeedb3..2cfb8d08994 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaArguments.cpp +++ b/Server/mods/deathmatch/logic/lua/CLuaArguments.cpp @@ -71,7 +71,7 @@ void CLuaArguments::CopyRecursive(const CLuaArguments& Arguments, CFastHashMap::const_iterator iter = Arguments.m_Arguments.begin(); for (; iter != Arguments.m_Arguments.end(); ++iter) { - CLuaArgument* pArgument = new CLuaArgument(**iter, pKnownTables); + CLuaArgument* pArgument = new CLuaArgument(**iter, pKnownTables, this); m_Arguments.push_back(pArgument); } @@ -90,7 +90,7 @@ void CLuaArguments::ReadArguments(lua_State* luaVM, signed int uiIndexBegin) while (lua_type(luaVM, uiIndexBegin) != LUA_TNONE) { // Create an argument, let it read out the argument and add it to our vector - CLuaArgument* pArgument = new CLuaArgument(luaVM, uiIndexBegin++, &knownTables); + CLuaArgument* pArgument = new CLuaArgument(luaVM, uiIndexBegin++, &knownTables, this); m_Arguments.push_back(pArgument); knownTables.clear(); @@ -119,10 +119,10 @@ void CLuaArguments::ReadTable(lua_State* luaVM, int iIndexBegin, CFastHashMap::const_iterator iter = Arguments.IterBegin(); for (; iter != Arguments.IterEnd(); ++iter) { - CLuaArgument* pArgument = new CLuaArgument(**iter); + CLuaArgument* pArgument = new CLuaArgument(**iter, {}, this); m_Arguments.push_back(pArgument); } } @@ -322,14 +322,14 @@ bool CLuaArguments::CallGlobal(CLuaMain* pLuaMain, const char* szFunction, CLuaA CLuaArgument* CLuaArguments::PushNil() { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); m_Arguments.push_back(pArgument); return pArgument; } CLuaArgument* CLuaArguments::PushBoolean(bool bBool) { - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadBool(bBool); m_Arguments.push_back(pArgument); return pArgument; @@ -337,7 +337,7 @@ CLuaArgument* CLuaArguments::PushBoolean(bool bBool) CLuaArgument* CLuaArguments::PushTable(CLuaArguments* table) { - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadTable(table); m_Arguments.push_back(pArgument); return pArgument; @@ -345,7 +345,7 @@ CLuaArgument* CLuaArguments::PushTable(CLuaArguments* table) CLuaArgument* CLuaArguments::PushNumber(double dNumber) { - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadNumber(dNumber); m_Arguments.push_back(pArgument); return pArgument; @@ -353,14 +353,19 @@ CLuaArgument* CLuaArguments::PushNumber(double dNumber) CLuaArgument* CLuaArguments::PushArgument(const CLuaArgument& argument) { - CLuaArgument* pArgument = new CLuaArgument(argument); // create a copy + CLuaArgument* pArgument = new CLuaArgument(argument, {}, this); // create a copy m_Arguments.push_back(pArgument); return pArgument; } +void CLuaArguments::PushArgumentWeak(const CLuaArgument* argument) +{ + m_Arguments.push_back(const_cast(argument)); +} + CLuaArgument* CLuaArguments::PushString(const std::string& strString) { - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadString(strString); m_Arguments.push_back(pArgument); return pArgument; @@ -368,7 +373,7 @@ CLuaArgument* CLuaArguments::PushString(const std::string& strString) CLuaArgument* CLuaArguments::PushElement(CElement* pElement) { - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadElement(pElement); m_Arguments.push_back(pArgument); return pArgument; @@ -376,7 +381,7 @@ CLuaArgument* CLuaArguments::PushElement(CElement* pElement) CLuaArgument* CLuaArguments::PushBan(CBan* pBan) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadScriptID(pBan->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -384,7 +389,7 @@ CLuaArgument* CLuaArguments::PushBan(CBan* pBan) CLuaArgument* CLuaArguments::PushACL(CAccessControlList* pACL) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadScriptID(pACL->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -392,7 +397,7 @@ CLuaArgument* CLuaArguments::PushACL(CAccessControlList* pACL) CLuaArgument* CLuaArguments::PushACLGroup(CAccessControlListGroup* pACLGroup) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadScriptID(pACLGroup->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -400,7 +405,7 @@ CLuaArgument* CLuaArguments::PushACLGroup(CAccessControlListGroup* pACLGroup) CLuaArgument* CLuaArguments::PushAccount(CAccount* pAccount) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadScriptID(pAccount->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -408,7 +413,7 @@ CLuaArgument* CLuaArguments::PushAccount(CAccount* pAccount) CLuaArgument* CLuaArguments::PushResource(CResource* pResource) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadScriptID(pResource->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -416,7 +421,7 @@ CLuaArgument* CLuaArguments::PushResource(CResource* pResource) CLuaArgument* CLuaArguments::PushTextDisplay(CTextDisplay* pTextDisplay) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadScriptID(pTextDisplay->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -424,7 +429,7 @@ CLuaArgument* CLuaArguments::PushTextDisplay(CTextDisplay* pTextDisplay) CLuaArgument* CLuaArguments::PushTextItem(CTextItem* pTextItem) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadScriptID(pTextItem->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -432,7 +437,7 @@ CLuaArgument* CLuaArguments::PushTextItem(CTextItem* pTextItem) CLuaArgument* CLuaArguments::PushTimer(CLuaTimer* pLuaTimer) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadScriptID(pLuaTimer->GetScriptID()); m_Arguments.push_back(pArgument); return pArgument; @@ -440,7 +445,7 @@ CLuaArgument* CLuaArguments::PushTimer(CLuaTimer* pLuaTimer) CLuaArgument* CLuaArguments::PushDbQuery(CDbJobData* pJobData) { - CLuaArgument* pArgument = new CLuaArgument; + CLuaArgument* pArgument = new CLuaArgument(this); pArgument->ReadScriptID(pJobData->GetId()); m_Arguments.push_back(pArgument); return pArgument; @@ -452,7 +457,8 @@ void CLuaArguments::DeleteArguments() vector::iterator iter = m_Arguments.begin(); for (; iter != m_Arguments.end(); ++iter) { - delete *iter; + if ((*iter)->m_pOwner == this) + delete *iter; } // Clear the vector @@ -464,7 +470,8 @@ void CLuaArguments::Pop() { // Delete the last element CLuaArgument* item = m_Arguments.back(); - delete item; + if (item->m_pOwner == this) + delete item; // Pop it out of the vector m_Arguments.pop_back(); @@ -482,11 +489,13 @@ void CLuaArguments::ValidateTableKeys() { // TODO - Handle ref in KnownTables // Remove pair - delete *iter; + if ((*iter)->m_pOwner == this) + delete *iter; iter = m_Arguments.erase(iter); if (iter != m_Arguments.end()) { - delete *iter; + if ((*iter)->m_pOwner == this) + delete *iter; iter = m_Arguments.erase(iter); } // Check if end @@ -521,7 +530,7 @@ bool CLuaArguments::ReadFromBitStream(NetBitStreamInterface& bitStream, std::vec pKnownTables->push_back(this); for (unsigned int ui = 0; ui < uiNumArgs; ++ui) { - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); if (!pArgument->ReadFromBitStream(bitStream, pKnownTables)) { delete pArgument; @@ -720,7 +729,7 @@ bool CLuaArguments::ReadFromJSONString(const char* szJSON) for (uint i = 0; i < json_object_array_length(object); i++) { json_object* arrayObject = json_object_array_get_idx(object, i); - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); bSuccess = pArgument->ReadFromJSONObject(arrayObject, &knownTables); m_Arguments.push_back(pArgument); // then the value if (!bSuccess) @@ -732,7 +741,7 @@ bool CLuaArguments::ReadFromJSONString(const char* szJSON) else if (json_object_get_type(object) == json_type_object) { std::vector knownTables; - CLuaArgument* pArgument = new CLuaArgument(); + CLuaArgument* pArgument = new CLuaArgument(this); bool bSuccess = pArgument->ReadFromJSONObject(object, &knownTables); m_Arguments.push_back(pArgument); // value json_object_put(object); @@ -766,10 +775,10 @@ bool CLuaArguments::ReadFromJSONObject(json_object* object, std::vectorReadString(key); m_Arguments.push_back(pArgument); // push the key first - pArgument = new CLuaArgument(); + pArgument = new CLuaArgument(this); bSuccess = pArgument->ReadFromJSONObject(val, pKnownTables); // then the value m_Arguments.push_back(pArgument); if (!bSuccess) @@ -805,11 +814,11 @@ bool CLuaArguments::ReadFromJSONArray(json_object* object, std::vectorReadNumber(i + 1); // push the key m_Arguments.push_back(pArgument); - pArgument = new CLuaArgument(); + pArgument = new CLuaArgument(this); bSuccess = pArgument->ReadFromJSONObject(arrayObject, pKnownTables); m_Arguments.push_back(pArgument); // then the valoue if (!bSuccess) diff --git a/Server/mods/deathmatch/logic/lua/CLuaArguments.h b/Server/mods/deathmatch/logic/lua/CLuaArguments.h index 87fd92be206..8907b1ccd80 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaArguments.h +++ b/Server/mods/deathmatch/logic/lua/CLuaArguments.h @@ -80,6 +80,7 @@ class CLuaArguments CLuaArgument* PushDbQuery(CDbJobData* pJobData); CLuaArgument* PushArgument(const CLuaArgument& argument); + void PushArgumentWeak(const CLuaArgument* argument); CLuaArgument* PushTable(CLuaArguments* table); void DeleteArguments(); diff --git a/Server/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp b/Server/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp index 6cacbdcc989..d6b8bbe0575 100644 --- a/Server/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp +++ b/Server/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp @@ -1566,7 +1566,7 @@ int CLuaElementDefs::setElementData(lua_State* luaVM) strKey = strKey.Left(MAX_CUSTOMDATA_NAME_LENGTH); } - if (CStaticFunctionDefinitions::SetElementData(pElement, strKey, value, syncType)) + if (pElement->SetCustomData(std::move(strKey), std::move(value), syncType, {}, true, EElementDataPacketType::Broadcast)) { lua_pushboolean(luaVM, true); return 1; diff --git a/Server/mods/deathmatch/logic/packets/CCustomDataPacket.h b/Server/mods/deathmatch/logic/packets/CCustomDataPacket.h index 620d30edfb7..25ef48202e4 100644 --- a/Server/mods/deathmatch/logic/packets/CCustomDataPacket.h +++ b/Server/mods/deathmatch/logic/packets/CCustomDataPacket.h @@ -27,8 +27,8 @@ class CCustomDataPacket final : public CPacket bool Write(NetBitStreamInterface& BitStream) const; const ElementID GetElementID() const { return m_ElementID; } - const SString& GetName() const { return m_strName; } - const CLuaArgument& GetValue() const { return m_Value; } + SString& GetName() { return m_strName; } + CLuaArgument& GetValue() { return m_Value; } private: ElementID m_ElementID; diff --git a/Shared/mods/deathmatch/logic/luadefs/CLuaElementDefsShared.cpp b/Shared/mods/deathmatch/logic/luadefs/CLuaElementDefsShared.cpp index 7d331163014..57237a6c4c4 100644 --- a/Shared/mods/deathmatch/logic/luadefs/CLuaElementDefsShared.cpp +++ b/Shared/mods/deathmatch/logic/luadefs/CLuaElementDefsShared.cpp @@ -41,7 +41,7 @@ int CLuaElementDefs::GetElementData(lua_State* luaVM) } #ifdef MTA_CLIENT - CLuaArgument* pVariable = pElement->GetCustomData(strKey, bInherit); + const CLuaArgument* pVariable = pElement->GetCustomData(strKey, bInherit); #else CLuaArgument* pVariable = CStaticFunctionDefinitions::GetElementData(pElement, strKey, bInherit); #endif From cd554b62f5e0a71c5f10dea3619c0998e08432cd Mon Sep 17 00:00:00 2001 From: TEDERIs Date: Fri, 12 Jan 2024 22:09:57 +0700 Subject: [PATCH 6/7] Remove CStaticFunctionDefinitions::GetElementData --- Server/mods/deathmatch/logic/CElement.cpp | 10 +++++----- Server/mods/deathmatch/logic/CElement.h | 2 +- .../deathmatch/logic/CStaticFunctionDefinitions.cpp | 10 +--------- .../mods/deathmatch/logic/CStaticFunctionDefinitions.h | 1 - .../deathmatch/logic/luadefs/CLuaElementDefsShared.cpp | 4 ---- 5 files changed, 7 insertions(+), 20 deletions(-) diff --git a/Server/mods/deathmatch/logic/CElement.cpp b/Server/mods/deathmatch/logic/CElement.cpp index c8bee60d366..cf2e25fdb71 100644 --- a/Server/mods/deathmatch/logic/CElement.cpp +++ b/Server/mods/deathmatch/logic/CElement.cpp @@ -509,7 +509,7 @@ void CElement::ReadCustomData(CEvents* pEvents, CXMLNode& Node) } } -CLuaArgument* CElement::GetCustomData(const SString& strName, bool bInheritData, ESyncType* pSyncType) +const CLuaArgument* CElement::GetCustomData(const SString& strName, bool bInheritData, ESyncType* pSyncType) { // Grab it and return a pointer to the variable SCustomData* pData = m_CustomData.Get(strName); @@ -547,7 +547,7 @@ CLuaArguments* CElement::GetAllCustomData(CLuaArguments* table) bool CElement::GetCustomDataString(const char* szName, char* pOut, size_t sizeBuffer, bool bInheritData) { // Grab the custom data variable - CLuaArgument* pData = GetCustomData(szName, bInheritData); + const CLuaArgument* pData = GetCustomData(szName, bInheritData); if (pData) { // Make sure it gets 0 terminated @@ -586,7 +586,7 @@ bool CElement::GetCustomDataString(const char* szName, char* pOut, size_t sizeBu bool CElement::GetCustomDataInt(const char* szName, int& iOut, bool bInheritData) { // Grab the custom data variable - CLuaArgument* pData = GetCustomData(szName, bInheritData); + const CLuaArgument* pData = GetCustomData(szName, bInheritData); if (pData) { // Write the content depending on what type it is @@ -624,7 +624,7 @@ bool CElement::GetCustomDataInt(const char* szName, int& iOut, bool bInheritData bool CElement::GetCustomDataFloat(const char* szName, float& fOut, bool bInheritData) { // Grab the custom data variable - CLuaArgument* pData = GetCustomData(szName, bInheritData); + const CLuaArgument* pData = GetCustomData(szName, bInheritData); if (pData) { // Write the content depending on what type it is @@ -651,7 +651,7 @@ bool CElement::GetCustomDataFloat(const char* szName, float& fOut, bool bInherit bool CElement::GetCustomDataBool(const char* szName, bool& bOut, bool bInheritData) { // Grab the custom data variable - CLuaArgument* pData = GetCustomData(szName, bInheritData); + const CLuaArgument* pData = GetCustomData(szName, bInheritData); if (pData) { // Write the content depending on what type it is diff --git a/Server/mods/deathmatch/logic/CElement.h b/Server/mods/deathmatch/logic/CElement.h index c14de247148..f9560d952ad 100644 --- a/Server/mods/deathmatch/logic/CElement.h +++ b/Server/mods/deathmatch/logic/CElement.h @@ -143,7 +143,7 @@ class CElement void ReadCustomData(CEvents* pEvents, CXMLNode& Node); CCustomData& GetCustomDataManager() { return m_CustomData; } - CLuaArgument* GetCustomData(const SString& strName, bool bInheritData, ESyncType* pSyncType = NULL); + const CLuaArgument* GetCustomData(const SString& strName, bool bInheritData, ESyncType* pSyncType = {}); CLuaArguments* GetAllCustomData(CLuaArguments* table); bool GetCustomDataString(const char* szName, char* pOut, size_t sizeBuffer, bool bInheritData); bool GetCustomDataInt(const char* szName, int& iOut, bool bInheritData); diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 66a75bdaf45..1e7f0523e6d 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -458,14 +458,6 @@ CElement* CStaticFunctionDefinitions::GetElementByIndex(const char* szType, unsi return m_pMapManager->GetRootElement()->FindChildByType(szType, uiIndex, true); } -CLuaArgument* CStaticFunctionDefinitions::GetElementData(CElement* pElement, const SString& strName, bool bInherit) -{ - assert(pElement); - - // Return its custom data - return pElement->GetCustomData(strName, bInherit); -} - CLuaArguments* CStaticFunctionDefinitions::GetAllElementData(CElement* pElement, CLuaArguments* table) { assert(pElement); @@ -967,7 +959,7 @@ bool CStaticFunctionDefinitions::AddElementDataSubscriber(CElement* pElement, co assert(pPlayer); ESyncType lastSyncType = ESyncType::LOCAL; - CLuaArgument* pCurrentVariable = pElement->GetCustomData(strName, false, &lastSyncType); + const CLuaArgument* pCurrentVariable = pElement->GetCustomData(strName, false, &lastSyncType); if (pCurrentVariable != nullptr && lastSyncType == ESyncType::SUBSCRIBE) { diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h index 64d869df659..0c5f3417b06 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h @@ -51,7 +51,6 @@ class CStaticFunctionDefinitions static CElement* GetElementByIndex(const char* szType, unsigned int uiIndex); static CElement* GetElementChild(CElement* pElement, unsigned int uiIndex); static bool GetElementChildrenCount(CElement* pElement, unsigned int& uiCount); - static CLuaArgument* GetElementData(CElement* pElement, const SString& strName, bool bInherit); static CLuaArguments* GetAllElementData(CElement* pElement, CLuaArguments* table); static CElement* GetElementParent(CElement* pElement); static bool GetElementMatrix(CElement* pElement, CMatrix& matrix); diff --git a/Shared/mods/deathmatch/logic/luadefs/CLuaElementDefsShared.cpp b/Shared/mods/deathmatch/logic/luadefs/CLuaElementDefsShared.cpp index 57237a6c4c4..f6f819d926b 100644 --- a/Shared/mods/deathmatch/logic/luadefs/CLuaElementDefsShared.cpp +++ b/Shared/mods/deathmatch/logic/luadefs/CLuaElementDefsShared.cpp @@ -40,11 +40,7 @@ int CLuaElementDefs::GetElementData(lua_State* luaVM) strKey = strKey.Left(MAX_CUSTOMDATA_NAME_LENGTH); } -#ifdef MTA_CLIENT const CLuaArgument* pVariable = pElement->GetCustomData(strKey, bInherit); -#else - CLuaArgument* pVariable = CStaticFunctionDefinitions::GetElementData(pElement, strKey, bInherit); -#endif if (pVariable) { pVariable->Push(luaVM); From b22af37d1f994c8404f1882aea6d84ffddc9d336 Mon Sep 17 00:00:00 2001 From: TEDERIs Date: Fri, 12 Jan 2024 22:37:41 +0700 Subject: [PATCH 7/7] Use weak argument for the data deletion --- Client/mods/deathmatch/logic/CClientEntity.cpp | 2 +- Server/mods/deathmatch/logic/CElement.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Client/mods/deathmatch/logic/CClientEntity.cpp b/Client/mods/deathmatch/logic/CClientEntity.cpp index efbac757689..d377d5bc768 100644 --- a/Client/mods/deathmatch/logic/CClientEntity.cpp +++ b/Client/mods/deathmatch/logic/CClientEntity.cpp @@ -517,7 +517,7 @@ void CClientEntity::DeleteCustomData(const SString& strName) // Trigger the onClientElementDataChange event on us CLuaArguments Arguments; Arguments.PushString(strName); - Arguments.PushArgument(oldData.Variable); + Arguments.PushArgumentWeak(&oldData.Variable); Arguments.PushArgument(CLuaArgument{}); // Use nil as the new value to indicate the data has been removed CallEvent("onClientElementDataChange", Arguments, true); } diff --git a/Server/mods/deathmatch/logic/CElement.cpp b/Server/mods/deathmatch/logic/CElement.cpp index cf2e25fdb71..e281b3b46c5 100644 --- a/Server/mods/deathmatch/logic/CElement.cpp +++ b/Server/mods/deathmatch/logic/CElement.cpp @@ -771,7 +771,7 @@ bool CElement::DeleteCustomData(const SString& strName) // Trigger the onElementDataChange event on us CLuaArguments Arguments; Arguments.PushString(strName); - Arguments.PushArgument(oldData.Variable); + Arguments.PushArgumentWeak(&oldData.Variable); Arguments.PushArgument(CLuaArgument{}); // Use nil as the new value to indicate the data has been removed CallEvent("onElementDataChange", Arguments);