Skip to content

Element data optimizations #3287

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 53 additions & 50 deletions Client/mods/deathmatch/logic/CClientEntity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,12 +279,10 @@ void CClientEntity::SetID(ElementID ID)
}
}

CLuaArgument* CClientEntity::GetCustomData(const char* szName, bool bInheritData, bool* pbIsSynced)
const 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);
const SCustomData* pData = m_pCustomData->Get(strName);
if (pData)
{
if (pbIsSynced)
Expand All @@ -295,30 +293,30 @@ 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;
}

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
Expand Down Expand Up @@ -353,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
Expand Down Expand Up @@ -391,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
Expand All @@ -418,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
Expand Down Expand Up @@ -470,54 +468,59 @@ 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(SString&& strName, CLuaArgument&& Variable, bool bSynchronized, bool bSendPacket)
{
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 oldValue;

// Grab the old variable
CLuaArgument oldVariable;
SCustomData* pData = m_pCustomData->Get(szName);
if (pData)
if (const auto result = m_pCustomData->Set(std::move(strName), std::move(Variable), bSynchronized, &oldValue))
{
oldVariable = pData->Variable;
}
const auto& newName = result.GetName();
const auto& newValue = result.GetData();

// Set the new data
m_pCustomData->Set(szName, Variable, bSynchronized);
// Trigger the onClientElementDataChange event on us
CLuaArguments Arguments;
Arguments.PushString(newName);
Arguments.PushArgumentWeak(&oldValue.Variable);
Arguments.PushArgumentWeak(&newValue.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);
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<unsigned short>(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;
}

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.PushArgumentWeak(&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
Expand Down
6 changes: 3 additions & 3 deletions Client/mods/deathmatch/logic/CClientEntity.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,14 +201,14 @@ class CClientEntity : public CClientEntityBase
void SetID(ElementID ID);

CCustomData* GetCustomDataPointer() { return m_pCustomData; }
CLuaArgument* GetCustomData(const char* szName, 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);
void SetCustomData(const char* szName, const CLuaArgument& Variable, bool bSynchronized = true);
void DeleteCustomData(const char* szName);
bool SetCustomData(SString&& strName, CLuaArgument&& Variable, bool bSynchronized = true, bool bSendPacket = false);
void DeleteCustomData(const SString& strName);

virtual bool GetMatrix(CMatrix& matrix) const;
virtual bool SetMatrix(const CMatrix& matrix);
Expand Down
63 changes: 33 additions & 30 deletions Client/mods/deathmatch/logic/CCustomData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,52 +14,55 @@

void CCustomData::Copy(CCustomData* pCustomData)
{
std::map<std::string, SCustomData>::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(SString(key), CLuaArgument(data.Variable));
}

SCustomData* CCustomData::Get(const char* szName)
const SCustomData* CCustomData::Get(const SString& strName)
{
assert(szName);

std::map<std::string, SCustomData>::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;
return {};
}

void CCustomData::Set(const char* szName, const CLuaArgument& Variable, bool bSynchronized)
SCustomDataResult CCustomData::Set(SString&& strName, CLuaArgument&& Variable, bool bSynchronized, SCustomData* oldValue)
{
assert(szName);

// Grab the item with the given name
SCustomData* pData = Get(szName);
if (pData)
{
// Update existing
pData->Variable = Variable;
pData->bSynchronized = bSynchronized;
}
else
if (strName.length() > MAX_CUSTOMDATA_NAME_LENGTH)
{
// Add new
SCustomData newData;
newData.Variable = Variable;
newData.bSynchronized = bSynchronized;
m_Data[szName] = newData;
// 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 {};
}

auto iter = m_Data.try_emplace(std::move(strName)).first;
SCustomData& pCurrentVariable = iter->second;

if (pCurrentVariable.Variable.IsEmpty() || pCurrentVariable.bSynchronized != bSynchronized || pCurrentVariable.Variable != Variable )
{
// Save the old variable
if (oldValue)
*oldValue = std::move(pCurrentVariable);

// Set the new data
pCurrentVariable.Variable = std::move(Variable);
pCurrentVariable.bSynchronized = bSynchronized;

return SCustomDataResult(iter);
}

return {};
}

bool CCustomData::Delete(const char* szName)
bool CCustomData::Delete(const SString& strName, SCustomData* pOldData)
{
// Find the item and delete it
std::map<std::string, SCustomData>::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;
}
Expand Down
34 changes: 27 additions & 7 deletions Client/mods/deathmatch/logic/CCustomData.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,42 @@
struct SCustomData
{
CLuaArgument Variable;
bool bSynchronized;
bool bSynchronized{true};
};

struct SCustomDataResult
{
using iterator = std::unordered_map<SString, SCustomData>::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 char* szName);
void Set(const char* szName, const CLuaArgument& Variable, bool bSynchronized = true);
const SCustomData* Get(const SString& strName);
SCustomDataResult Set(SString&& strName, CLuaArgument&& Variable, bool bSynchronized = true, SCustomData* oldValue = {});

bool Delete(const char* szName);
bool Delete(const SString& strName, SCustomData* pOldData = {});

std::map<std::string, SCustomData>::const_iterator IterBegin() { return m_Data.begin(); }
std::map<std::string, SCustomData>::const_iterator IterEnd() { return m_Data.end(); }
const std::unordered_map<SString, SCustomData>& GetData() const { return m_Data; }

private:
std::map<std::string, SCustomData> m_Data;
std::unordered_map<SString, SCustomData> m_Data;
};
2 changes: 1 addition & 1 deletion Client/mods/deathmatch/logic/CPacketHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2875,7 +2875,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
{
Expand Down
32 changes: 0 additions & 32 deletions Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1017,38 +1017,6 @@ bool CStaticFunctionDefinitions::SetElementID(CClientEntity& Entity, const char*
return false;
}

bool CStaticFunctionDefinitions::SetElementData(CClientEntity& Entity, const char* szName, 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 (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<unsigned short>(strlen(szName));
pBitStream->WriteCompressed(usNameLength);
pBitStream->Write(szName, 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);
}

// Set its custom data
Entity.SetCustomData(szName, Variable, bSynchronize);
return true;
}

return false;
}

bool CStaticFunctionDefinitions::RemoveElementData(CClientEntity& Entity, const char* szName)
{
// TODO
Expand Down
1 change: 0 additions & 1 deletion Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 char* szName, 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);
Expand Down
Loading
Loading