Skip to content

Commit 3ab39b8

Browse files
authored
Cancel data change (#4503)
* 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 20d36cd commit 3ab39b8

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 CStringName& name, bool& bOut, bool bInhe
709709
return false;
710710
}
711711

712-
void CElement::SetCustomData(const CStringName& name, const CLuaArgument& Variable, ESyncType syncType, CPlayer* pClient, bool bTriggerEvent)
712+
bool CElement::SetCustomData(const CStringName& name, const CLuaArgument& Variable, ESyncType syncType, CPlayer* pClient, bool bTriggerEvent)
713713
{
714714
assert(name);
715715
if (name->length() > 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(name.ToCString()).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(name);
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 CStringName& name, const CLuaArgument& Variab
737739
Arguments.PushString(name);
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(name, oldVariable, oldSyncType);
747+
else
748+
m_CustomData.Delete(name);
749+
return false;
750+
}
741751
}
752+
return true;
742753
}
743754

744-
void CElement::DeleteCustomData(const CStringName& name)
755+
bool CElement::DeleteCustomData(const CStringName& name)
745756
{
746757
// Grab the old variable
747758
SCustomData* pData = m_CustomData.Get(name);
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(name);
@@ -758,8 +769,15 @@ void CElement::DeleteCustomData(const CStringName& name)
758769
Arguments.PushString(name);
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(name, 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
@@ -145,9 +145,9 @@ class CElement
145145
bool GetCustomDataInt(const CStringName& name, int& iOut, bool bInheritData);
146146
bool GetCustomDataFloat(const CStringName& name, float& fOut, bool bInheritData);
147147
bool GetCustomDataBool(const CStringName& name, bool& bOut, bool bInheritData);
148-
void SetCustomData(const CStringName& name, const CLuaArgument& Variable, ESyncType syncType = ESyncType::BROADCAST, CPlayer* pClient = NULL,
148+
bool SetCustomData(const CStringName& name, const CLuaArgument& Variable, ESyncType syncType = ESyncType::BROADCAST, CPlayer* pClient = NULL,
149149
bool bTriggerEvent = true);
150-
void DeleteCustomData(const CStringName& name);
150+
bool DeleteCustomData(const CStringName& name);
151151
void SendAllCustomData(CPlayer* pPlayer);
152152

153153
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
@@ -1017,6 +1017,9 @@ bool CStaticFunctionDefinitions::SetElementData(CElement* pElement, CStringName
10171017

10181018
if (!pCurrentVariable || *pCurrentVariable != Variable || lastSyncType != syncType)
10191019
{
1020+
if (!pElement->SetCustomData(name, Variable, syncType))
1021+
return false; // The server cancelled the change in onElementDataChange
1022+
10201023
if (syncType != ESyncType::LOCAL)
10211024
{
10221025
// Tell our clients to update their data
@@ -1037,8 +1040,6 @@ bool CStaticFunctionDefinitions::SetElementData(CElement* pElement, CStringName
10371040
if (lastSyncType == ESyncType::SUBSCRIBE && syncType != ESyncType::SUBSCRIBE)
10381041
m_pPlayerManager->ClearElementData(pElement, name);
10391042

1040-
// Set its custom data
1041-
pElement->SetCustomData(name, Variable, syncType);
10421043
return true;
10431044
}
10441045
return false;
@@ -1053,6 +1054,9 @@ bool CStaticFunctionDefinitions::RemoveElementData(CElement* pElement, CStringNa
10531054
// Check it exists
10541055
if (pElement->GetCustomData(name, false))
10551056
{
1057+
if (!pElement->DeleteCustomData(name))
1058+
return false; // The server cancelled the change in onElementDataChange
1059+
10561060
// Tell our clients to update their data
10571061
unsigned short usNameLength = static_cast<unsigned short>(name->length());
10581062
CBitStream BitStream;
@@ -1064,8 +1068,6 @@ bool CStaticFunctionDefinitions::RemoveElementData(CElement* pElement, CStringNa
10641068
// Clean up after the data removal
10651069
m_pPlayerManager->ClearElementData(pElement, name);
10661070

1067-
// Delete here
1068-
pElement->DeleteCustomData(name);
10691071
return true;
10701072
}
10711073

0 commit comments

Comments
 (0)