From 750d09adb9fd35f4c1b7786966b7ca292e35c200 Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Wed, 13 Nov 2024 00:16:06 +0300 Subject: [PATCH 1/4] Add element data client trust options. (#3839) --- Server/mods/deathmatch/local.conf | 6 ++++++ Server/mods/deathmatch/logic/CCustomData.cpp | 9 ++++++++- Server/mods/deathmatch/logic/CCustomData.h | 16 ++++++++++++--- Server/mods/deathmatch/logic/CElement.cpp | 8 ++++++-- Server/mods/deathmatch/logic/CElement.h | 2 +- Server/mods/deathmatch/logic/CGame.cpp | 20 ++++++++++++++++++- Server/mods/deathmatch/logic/CMainConfig.cpp | 3 +++ Server/mods/deathmatch/logic/CMainConfig.h | 2 ++ .../logic/CStaticFunctionDefinitions.cpp | 11 +++++++--- .../logic/CStaticFunctionDefinitions.h | 3 ++- .../logic/lua/CLuaFunctionParseHelpers.cpp | 6 ++++++ .../logic/lua/CLuaFunctionParseHelpers.h | 1 + .../logic/luadefs/CLuaElementDefs.cpp | 10 +++++++++- Server/mods/deathmatch/mtaserver.conf | 6 ++++++ .../mods/deathmatch/mtaserver.conf.template | 6 ++++++ 15 files changed, 96 insertions(+), 13 deletions(-) diff --git a/Server/mods/deathmatch/local.conf b/Server/mods/deathmatch/local.conf index 99b97bee07..039e155d81 100644 --- a/Server/mods/deathmatch/local.conf +++ b/Server/mods/deathmatch/local.conf @@ -268,6 +268,12 @@ Values: 0 - Off, 1 - Enabled. Default - 1 --> 1 + + 0 + diff --git a/Server/mods/deathmatch/logic/CCustomData.cpp b/Server/mods/deathmatch/logic/CCustomData.cpp index f18bbd37d1..545df5a0c3 100644 --- a/Server/mods/deathmatch/logic/CCustomData.cpp +++ b/Server/mods/deathmatch/logic/CCustomData.cpp @@ -21,7 +21,7 @@ void CCustomData::Copy(CCustomData* pCustomData) } } -SCustomData* CCustomData::Get(const char* szName) +SCustomData* CCustomData::Get(const char* szName) const { assert(szName); @@ -100,6 +100,7 @@ void CCustomData::Set(const char* szName, const CLuaArgument& Variable, ESyncTyp SCustomData newData; newData.Variable = Variable; newData.syncType = syncType; + newData.clientChangesMode = eCustomDataClientTrust::UNSET; m_Data[szName] = newData; UpdateSynced(szName, Variable, syncType); } @@ -120,6 +121,12 @@ bool CCustomData::Delete(const char* szName) return false; } +void CCustomData::SetClientChangesMode(const char* szName, eCustomDataClientTrust mode) +{ + SCustomData& pData = m_Data[szName]; + pData.clientChangesMode = mode; +} + CXMLNode* CCustomData::OutputToXML(CXMLNode* pNode) { std::map::const_iterator iter = m_Data.begin(); diff --git a/Server/mods/deathmatch/logic/CCustomData.h b/Server/mods/deathmatch/logic/CCustomData.h index bfb17ff529..887ef34dee 100644 --- a/Server/mods/deathmatch/logic/CCustomData.h +++ b/Server/mods/deathmatch/logic/CCustomData.h @@ -25,10 +25,18 @@ enum class ESyncType SUBSCRIBE, }; +enum class eCustomDataClientTrust : std::uint8_t +{ + UNSET, + ALLOW, + DENY, +}; + struct SCustomData { - CLuaArgument Variable; - ESyncType syncType; + CLuaArgument Variable; + ESyncType syncType; + eCustomDataClientTrust clientChangesMode; }; class CCustomData @@ -36,12 +44,14 @@ class CCustomData public: void Copy(CCustomData* pCustomData); - SCustomData* Get(const char* szName); + SCustomData* Get(const char* szName) const; SCustomData* GetSynced(const char* szName); void Set(const char* szName, const CLuaArgument& Variable, ESyncType syncType = ESyncType::BROADCAST); bool Delete(const char* szName); + void SetClientChangesMode(const char* szName, eCustomDataClientTrust mode); + unsigned short CountOnlySynchronized(); CXMLNode* OutputToXML(CXMLNode* pNode); diff --git a/Server/mods/deathmatch/logic/CElement.cpp b/Server/mods/deathmatch/logic/CElement.cpp index 59086a2f14..79a051b545 100644 --- a/Server/mods/deathmatch/logic/CElement.cpp +++ b/Server/mods/deathmatch/logic/CElement.cpp @@ -508,7 +508,7 @@ void CElement::ReadCustomData(CEvents* pEvents, CXMLNode& Node) } } -CLuaArgument* CElement::GetCustomData(const char* szName, bool bInheritData, ESyncType* pSyncType) +CLuaArgument* CElement::GetCustomData(const char* szName, bool bInheritData, ESyncType* pSyncType, eCustomDataClientTrust* clientChangesMode) { assert(szName); @@ -518,13 +518,17 @@ CLuaArgument* CElement::GetCustomData(const char* szName, bool bInheritData, ESy { if (pSyncType) *pSyncType = pData->syncType; + + if (clientChangesMode) + *clientChangesMode = pData->clientChangesMode; + return &pData->Variable; } // If none, try returning parent's custom data if (bInheritData && m_pParent) { - return m_pParent->GetCustomData(szName, true, pSyncType); + return m_pParent->GetCustomData(szName, true, pSyncType, clientChangesMode); } // None available diff --git a/Server/mods/deathmatch/logic/CElement.h b/Server/mods/deathmatch/logic/CElement.h index e3a0fa4d07..802981cd5a 100644 --- a/Server/mods/deathmatch/logic/CElement.h +++ b/Server/mods/deathmatch/logic/CElement.h @@ -136,7 +136,7 @@ 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 char* szName, bool bInheritData, ESyncType* pSyncType = nullptr, eCustomDataClientTrust* clientChangesMode = nullptr); 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/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp index d4efea393f..9543e1e447 100644 --- a/Server/mods/deathmatch/logic/CGame.cpp +++ b/Server/mods/deathmatch/logic/CGame.cpp @@ -1607,6 +1607,7 @@ void CGame::AddBuiltInEvents() m_Events.AddEvent("onPlayerTriggerEventThreshold", "", nullptr, false); m_Events.AddEvent("onPlayerTeamChange", "oldTeam, newTeam", nullptr, false); m_Events.AddEvent("onPlayerTriggerInvalidEvent", "eventName, isAdded, isRemote", nullptr, false); + m_Events.AddEvent("onPlayerChangesProtectedData", "element, key, value", nullptr, false); // Ped events m_Events.AddEvent("onPedVehicleEnter", "vehicle, seat, jacked", NULL, false); @@ -2652,7 +2653,24 @@ void CGame::Packet_CustomData(CCustomDataPacket& Packet) } ESyncType lastSyncType = ESyncType::BROADCAST; - pElement->GetCustomData(szName, false, &lastSyncType); + eCustomDataClientTrust clientChangesMode{}; + + pElement->GetCustomData(szName, false, &lastSyncType, &clientChangesMode); + + const bool changesAllowed = clientChangesMode == eCustomDataClientTrust::UNSET ? !m_pMainConfig->IsElementDataWhitelisted() + : clientChangesMode == eCustomDataClientTrust::ALLOW; + if (!changesAllowed) + { + CLogger::ErrorPrintf("Client trying to change protected element data %s (%s)", Packet.GetSourcePlayer()->GetNick(), + szName); + + CLuaArguments arguments; + arguments.PushElement(pElement); + arguments.PushString(szName); + arguments.PushArgument(Value); + pSourcePlayer->CallEvent("onPlayerChangesProtectedData", arguments); + return; + } if (lastSyncType != ESyncType::LOCAL) { diff --git a/Server/mods/deathmatch/logic/CMainConfig.cpp b/Server/mods/deathmatch/logic/CMainConfig.cpp index 4e6b84ce3f..bece65e885 100644 --- a/Server/mods/deathmatch/logic/CMainConfig.cpp +++ b/Server/mods/deathmatch/logic/CMainConfig.cpp @@ -79,6 +79,7 @@ CMainConfig::CMainConfig(CConsole* pConsole) : CXMLConfig(NULL) m_iBackupInterval = 3; m_iBackupAmount = 5; m_bSyncMapElementData = true; + m_elementDataWhitelisted = false; } bool CMainConfig::Load() @@ -526,6 +527,8 @@ bool CMainConfig::Load() g_TickRateSettings.iLightSync = Clamp(200, g_TickRateSettings.iLightSync, 4000); } + GetBoolean(m_pRootNode, "elementdata_whitelisted", m_elementDataWhitelisted); + ApplyNetOptions(); return true; diff --git a/Server/mods/deathmatch/logic/CMainConfig.h b/Server/mods/deathmatch/logic/CMainConfig.h index 1ddb0c8645..9758ae2dbf 100644 --- a/Server/mods/deathmatch/logic/CMainConfig.h +++ b/Server/mods/deathmatch/logic/CMainConfig.h @@ -126,6 +126,7 @@ class CMainConfig : public CXMLConfig const std::vector& GetOwnerEmailAddressList() const { return m_OwnerEmailAddressList; } bool IsDatabaseCredentialsProtectionEnabled() const { return m_bDatabaseCredentialsProtectionEnabled != 0; } bool IsFakeLagCommandEnabled() const { return m_bFakeLagCommandEnabled != 0; } + bool IsElementDataWhitelisted() const { return m_elementDataWhitelisted; } bool IsCheckResourceClientFilesEnabled() const noexcept { return m_checkResourceClientFiles != 0; } SString GetSetting(const SString& configSetting); @@ -228,5 +229,6 @@ class CMainConfig : public CXMLConfig int m_bFakeLagCommandEnabled; int m_iPlayerTriggeredEventIntervalMs; int m_iMaxPlayerTriggeredEventsPerInterval; + bool m_elementDataWhitelisted; int m_checkResourceClientFiles; }; diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 67764f8057..b4d1de641f 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -954,14 +954,19 @@ 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 char* szName, const CLuaArgument& Variable, ESyncType syncType, + std::optional clientTrust) { assert(pElement); assert(szName); assert(strlen(szName) <= MAX_CUSTOMDATA_NAME_LENGTH); - ESyncType lastSyncType = ESyncType::BROADCAST; - CLuaArgument* pCurrentVariable = pElement->GetCustomData(szName, false, &lastSyncType); + ESyncType lastSyncType = ESyncType::BROADCAST; + eCustomDataClientTrust lastClientTrust{}; + CLuaArgument* pCurrentVariable = pElement->GetCustomData(szName, false, &lastSyncType, &lastClientTrust); + + if (clientTrust.has_value() && lastClientTrust != clientTrust.value()) + pElement->GetCustomDataManager().SetClientChangesMode(szName, clientTrust.value()); if (!pCurrentVariable || *pCurrentVariable != Variable || lastSyncType != syncType) { diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h index dd6202208f..8c947d6f34 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h @@ -83,7 +83,8 @@ 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 SetElementData(CElement* pElement, const char* szName, const CLuaArgument& Variable, ESyncType syncType, + std::optional clientTrust); 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); diff --git a/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp b/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp index ef25750c05..76540327af 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp +++ b/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp @@ -285,6 +285,12 @@ ADD_ENUM(ESyncType::LOCAL, "local") ADD_ENUM(ESyncType::SUBSCRIBE, "subscribe") IMPLEMENT_ENUM_CLASS_END("sync-mode") +IMPLEMENT_ENUM_CLASS_BEGIN(eCustomDataClientTrust) +ADD_ENUM(eCustomDataClientTrust::UNSET, "default") +ADD_ENUM(eCustomDataClientTrust::ALLOW, "allow") +ADD_ENUM(eCustomDataClientTrust::DENY, "deny") +IMPLEMENT_ENUM_CLASS_END("client-trust-mode") + // // CResource from userdata // diff --git a/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h b/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h index 52a4536012..796ca3c702 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h +++ b/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h @@ -38,6 +38,7 @@ DECLARE_ENUM(CAccessControlListRight::ERightType); DECLARE_ENUM(CElement::EElementType); DECLARE_ENUM(CAccountPassword::EAccountPasswordType); DECLARE_ENUM_CLASS(ESyncType); +DECLARE_ENUM_CLASS(eCustomDataClientTrust) enum eHudComponent { diff --git a/Server/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp b/Server/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp index 6cacbdcc98..f8effd7b89 100644 --- a/Server/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp +++ b/Server/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp @@ -1538,6 +1538,7 @@ int CLuaElementDefs::setElementData(lua_State* luaVM) SString strKey; CLuaArgument value; ESyncType syncType = ESyncType::BROADCAST; + std::optional clientTrust{}; CScriptArgReader argStream(luaVM); argStream.ReadUserData(pElement); @@ -1554,6 +1555,13 @@ int CLuaElementDefs::setElementData(lua_State* luaVM) else argStream.ReadEnumString(syncType, ESyncType::BROADCAST); + if (!argStream.NextIsNone()) + { + eCustomDataClientTrust trustReaded; + argStream.ReadEnumString(trustReaded); + clientTrust = trustReaded; + } + if (!argStream.HasErrors()) { LogWarningIfPlayerHasNotJoinedYet(luaVM, pElement); @@ -1566,7 +1574,7 @@ int CLuaElementDefs::setElementData(lua_State* luaVM) strKey = strKey.Left(MAX_CUSTOMDATA_NAME_LENGTH); } - if (CStaticFunctionDefinitions::SetElementData(pElement, strKey, value, syncType)) + if (CStaticFunctionDefinitions::SetElementData(pElement, strKey, value, syncType, clientTrust)) { lua_pushboolean(luaVM, true); return 1; diff --git a/Server/mods/deathmatch/mtaserver.conf b/Server/mods/deathmatch/mtaserver.conf index 31faba9112..11ef497fa7 100644 --- a/Server/mods/deathmatch/mtaserver.conf +++ b/Server/mods/deathmatch/mtaserver.conf @@ -268,6 +268,12 @@ Values: 0 - Off, 1 - Enabled. Default - 1 --> 1 + + 0 + 1 + + 0 +