Skip to content

Commit ce4913e

Browse files
committed
onElementDataChange can be cancelled.
onElementDataChange can now be cancelled when a client, setElementData, or removeElementData changes an element data. This is useful because right now you have to do setElementData to cancel a change, which broadcasts to all players and also triggers the event again. Being able to just cancel the event is the cleanest way to deal with unauthorized data changes.
1 parent 0a36c63 commit ce4913e

File tree

4 files changed

+66
-26
lines changed

4 files changed

+66
-26
lines changed

Server/mods/deathmatch/logic/CElement.cpp

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -709,22 +709,24 @@ bool CElement::GetCustomDataBool(const char* szName, bool& bOut, bool bInheritDa
709709
return false;
710710
}
711711

712-
void CElement::SetCustomData(const char* szName, const CLuaArgument& Variable, ESyncType syncType, CPlayer* pClient, bool bTriggerEvent)
712+
bool CElement::SetCustomData(const char* szName, const CLuaArgument& Variable, ESyncType syncType, CPlayer* pClient, bool bTriggerEvent)
713713
{
714714
assert(szName);
715715
if (strlen(szName) > MAX_CUSTOMDATA_NAME_LENGTH)
716716
{
717717
// Don't allow it to be set if the name is too long
718718
CLogger::ErrorPrintf("Custom data name too long (%s)\n", *SStringX(szName).Left(MAX_CUSTOMDATA_NAME_LENGTH + 1));
719-
return;
719+
return false;
720720
}
721721

722-
// Grab the old variable
722+
// Grab the old variable and sync type
723723
CLuaArgument oldVariable;
724+
ESyncType oldSyncType = ESyncType::LOCAL;
724725
const SCustomData* pData = m_CustomData.Get(szName);
725726
if (pData)
726727
{
727728
oldVariable = pData->Variable;
729+
oldSyncType = pData->syncType;
728730
}
729731

730732
// Set the new data
@@ -737,18 +739,27 @@ void CElement::SetCustomData(const char* szName, const CLuaArgument& Variable, E
737739
Arguments.PushString(szName);
738740
Arguments.PushArgument(oldVariable);
739741
Arguments.PushArgument(Variable);
740-
CallEvent("onElementDataChange", Arguments, pClient);
742+
if (!CallEvent("onElementDataChange", Arguments, pClient))
743+
{
744+
// Event was cancelled, restore previous value
745+
if (pData)
746+
m_CustomData.Set(szName, oldVariable, oldSyncType);
747+
else
748+
m_CustomData.Delete(szName);
749+
return false;
750+
}
741751
}
752+
return true;
742753
}
743754

744-
void CElement::DeleteCustomData(const char* szName)
755+
bool CElement::DeleteCustomData(const char* szName)
745756
{
746757
// Grab the old variable
747758
SCustomData* pData = m_CustomData.Get(szName);
748759
if (pData)
749760
{
750-
CLuaArgument oldVariable;
751-
oldVariable = pData->Variable;
761+
CLuaArgument oldVariable = pData->Variable;
762+
ESyncType oldSyncType = pData->syncType;
752763

753764
// Delete the custom data
754765
m_CustomData.Delete(szName);
@@ -758,8 +769,15 @@ void CElement::DeleteCustomData(const char* szName)
758769
Arguments.PushString(szName);
759770
Arguments.PushArgument(oldVariable);
760771
Arguments.PushArgument(CLuaArgument()); // Use nil as the new value to indicate the data has been removed
761-
CallEvent("onElementDataChange", Arguments);
772+
if (!CallEvent("onElementDataChange", Arguments))
773+
{
774+
// Event was cancelled, restore previous value
775+
m_CustomData.Set(szName, oldVariable, oldSyncType);
776+
return false;
777+
}
778+
return true;
762779
}
780+
return false;
763781
}
764782

765783
// Used to send the root element data when a player joins

Server/mods/deathmatch/logic/CElement.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,9 @@ class CElement
144144
bool GetCustomDataInt(const char* szName, int& iOut, bool bInheritData);
145145
bool GetCustomDataFloat(const char* szName, float& fOut, bool bInheritData);
146146
bool GetCustomDataBool(const char* szName, bool& bOut, bool bInheritData);
147-
void SetCustomData(const char* szName, const CLuaArgument& Variable, ESyncType syncType = ESyncType::BROADCAST, CPlayer* pClient = NULL,
147+
bool SetCustomData(const char* szName, const CLuaArgument& Variable, ESyncType syncType = ESyncType::BROADCAST, CPlayer* pClient = NULL,
148148
bool bTriggerEvent = true);
149-
void DeleteCustomData(const char* szName);
149+
bool DeleteCustomData(const char* szName);
150150
void SendAllCustomData(CPlayer* pPlayer);
151151

152152
CXMLNode* OutputToXML(CXMLNode* pNode);

Server/mods/deathmatch/logic/CGame.cpp

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2738,25 +2738,45 @@ void CGame::Packet_CustomData(CCustomDataPacket& Packet)
27382738
return;
27392739
}
27402740

2741-
if (lastSyncType != ESyncType::LOCAL)
2741+
if (pElement->SetCustomData(szName, Value, lastSyncType, pSourcePlayer))
27422742
{
2743-
// Tell our clients to update their data. Send to everyone but the one we got this packet from.
2743+
if (lastSyncType != ESyncType::LOCAL)
2744+
{
2745+
// Tell our clients to update their data. Send to everyone but the one we got this packet from.
2746+
unsigned short usNameLength = static_cast<unsigned short>(strlen(szName));
2747+
CBitStream BitStream;
2748+
BitStream.pBitStream->WriteCompressed(usNameLength);
2749+
BitStream.pBitStream->Write(szName, usNameLength);
2750+
Value.WriteToBitStream(*BitStream.pBitStream);
2751+
if (lastSyncType == ESyncType::BROADCAST)
2752+
m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(pElement, SET_ELEMENT_DATA, *BitStream.pBitStream), pSourcePlayer);
2753+
else
2754+
m_pPlayerManager->BroadcastOnlySubscribed(CElementRPCPacket(pElement, SET_ELEMENT_DATA, *BitStream.pBitStream), pElement, szName,
2755+
pSourcePlayer);
2756+
2757+
CPerfStatEventPacketUsage::GetSingleton()->UpdateElementDataUsageRelayed(szName, m_pPlayerManager->Count(),
2758+
BitStream.pBitStream->GetNumberOfBytesUsed());
2759+
}
2760+
}
2761+
else
2762+
{
2763+
// Event was cancelled; sync the authoritative value back to the source player
27442764
unsigned short usNameLength = static_cast<unsigned short>(strlen(szName));
27452765
CBitStream BitStream;
27462766
BitStream.pBitStream->WriteCompressed(usNameLength);
27472767
BitStream.pBitStream->Write(szName, usNameLength);
2748-
Value.WriteToBitStream(*BitStream.pBitStream);
2749-
if (lastSyncType == ESyncType::BROADCAST)
2750-
m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(pElement, SET_ELEMENT_DATA, *BitStream.pBitStream), pSourcePlayer);
2751-
else
2752-
m_pPlayerManager->BroadcastOnlySubscribed(CElementRPCPacket(pElement, SET_ELEMENT_DATA, *BitStream.pBitStream), pElement, szName,
2753-
pSourcePlayer);
27542768

2755-
CPerfStatEventPacketUsage::GetSingleton()->UpdateElementDataUsageRelayed(szName, m_pPlayerManager->Count(),
2756-
BitStream.pBitStream->GetNumberOfBytesUsed());
2769+
if (CLuaArgument* pServerValue = pElement->GetCustomData(szName, false))
2770+
{
2771+
pServerValue->WriteToBitStream(*BitStream.pBitStream);
2772+
pSourcePlayer->Send(CElementRPCPacket(pElement, SET_ELEMENT_DATA, *BitStream.pBitStream));
2773+
}
2774+
else
2775+
{
2776+
BitStream.pBitStream->WriteBit(false);
2777+
pSourcePlayer->Send(CElementRPCPacket(pElement, REMOVE_ELEMENT_DATA, *BitStream.pBitStream));
2778+
}
27572779
}
2758-
2759-
pElement->SetCustomData(szName, Value, lastSyncType, pSourcePlayer);
27602780
}
27612781
}
27622782
}

Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,6 +1014,9 @@ bool CStaticFunctionDefinitions::SetElementData(CElement* pElement, const char*
10141014

10151015
if (!pCurrentVariable || *pCurrentVariable != Variable || lastSyncType != syncType)
10161016
{
1017+
if (!pElement->SetCustomData(szName, Variable, syncType))
1018+
return false; // The server cancelled the change in onElementDataChange
1019+
10171020
if (syncType != ESyncType::LOCAL)
10181021
{
10191022
// Tell our clients to update their data
@@ -1034,8 +1037,6 @@ bool CStaticFunctionDefinitions::SetElementData(CElement* pElement, const char*
10341037
if (lastSyncType == ESyncType::SUBSCRIBE && syncType != ESyncType::SUBSCRIBE)
10351038
m_pPlayerManager->ClearElementData(pElement, szName);
10361039

1037-
// Set its custom data
1038-
pElement->SetCustomData(szName, Variable, syncType);
10391040
return true;
10401041
}
10411042
return false;
@@ -1050,6 +1051,9 @@ bool CStaticFunctionDefinitions::RemoveElementData(CElement* pElement, const cha
10501051
// Check it exists
10511052
if (pElement->GetCustomData(szName, false))
10521053
{
1054+
if (!pElement->DeleteCustomData(szName))
1055+
return false; // The server cancelled the change in onElementDataChange
1056+
10531057
// Tell our clients to update their data
10541058
unsigned short usNameLength = static_cast<unsigned short>(strlen(szName));
10551059
CBitStream BitStream;
@@ -1061,8 +1065,6 @@ bool CStaticFunctionDefinitions::RemoveElementData(CElement* pElement, const cha
10611065
// Clean up after the data removal
10621066
m_pPlayerManager->ClearElementData(pElement, szName);
10631067

1064-
// Delete here
1065-
pElement->DeleteCustomData(szName);
10661068
return true;
10671069
}
10681070

0 commit comments

Comments
 (0)