From fc689ae0614b7d2b1ae7135c85d126fac86dad47 Mon Sep 17 00:00:00 2001 From: frqher Date: Tue, 26 Aug 2025 02:18:37 +0400 Subject: [PATCH 1/2] Add onElementPositionChange event to SetElementPosition for anti-cheat compatibility This event allows anti-cheat scripts to distinguish between server-initiated and client-initiated position changes, preventing false positives when the server teleports players (e.g., for elevators or scripted events). --- .../logic/CStaticFunctionDefinitions.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 14644dc1094..d65b816a19f 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -1340,6 +1340,24 @@ bool CStaticFunctionDefinitions::SetElementPosition(CElement* pElement, const CV if (ped && ped->HasJetPack()) m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(ped, GIVE_PED_JETPACK, *BitStream.pBitStream)); + // This event is triggered server-side to allow anti-cheat scripts to distinguish between + // position changes made by the server (e.g., elevators, scripted teleports) and those made by the client. + // Without this event, anti-cheat systems may falsely detect legitimate server-side teleports as cheats, + // since they only check the distance between old and new positions. + // By listening to this event, anti-cheat scripts can safely ignore server-initiated position changes. + CLuaArguments Arguments; + Arguments.PushElement(pElement); + Arguments.PushNumber(vecPosition.fX); + Arguments.PushNumber(vecPosition.fY); + Arguments.PushNumber(vecPosition.fZ); + Arguments.PushBool(bWarp); + + + if (!pElement->CallEvent("onElementPositionChange", Arguments)) + { + return false; + } + return true; } From 9f2aebbc27661110e300780e6b890ba30e937021 Mon Sep 17 00:00:00 2001 From: frqher Date: Tue, 26 Aug 2025 16:58:58 +0400 Subject: [PATCH 2/2] Add old position parameters to onElementPositionChange event The onElementPositionChange event now receives both the old and new position of the element as arguments. --- Server/mods/deathmatch/logic/CGame.cpp | 1 + Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp index 910a1722dde..3b21533de4a 100644 --- a/Server/mods/deathmatch/logic/CGame.cpp +++ b/Server/mods/deathmatch/logic/CGame.cpp @@ -1672,6 +1672,7 @@ void CGame::AddBuiltInEvents() m_Events.AddEvent("onElementInteriorChange", "oldInterior, newInterior", nullptr, false); m_Events.AddEvent("onElementAttach", "attachSource, attachOffsetX, attachOffsetY, attachOffsetZ, attachOffsetRX, attachOffsetRY, attachOffsetRZ", nullptr, false); m_Events.AddEvent("onElementDetach", "detachSource, detachWorldX, detachWorldY, detachWorldZ, detachWorldRX, detachWorldRY, detachWorldRZ", nullptr, false); + m_Events.AddEvent("onElementPositionChange", "oldX, oldY, oldZ, newX, newY, newZ", nullptr, false); // Radar area events diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index d65b816a19f..4a98dcbf21a 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -1305,6 +1305,9 @@ bool CStaticFunctionDefinitions::SetElementPosition(CElement* pElement, const CV player->SetTeleported(true); } + // Get element old position + CVector elementOldPosition = pElement->GetPosition(); + // Update our position for that entity. pElement->SetPosition(vecPosition); @@ -1347,6 +1350,9 @@ bool CStaticFunctionDefinitions::SetElementPosition(CElement* pElement, const CV // By listening to this event, anti-cheat scripts can safely ignore server-initiated position changes. CLuaArguments Arguments; Arguments.PushElement(pElement); + Arguments.PushNumber(elementOldPosition.fX); + Arguments.PushNumber(elementOldPosition.fY); + Arguments.PushNumber(elementOldPosition.fZ); Arguments.PushNumber(vecPosition.fX); Arguments.PushNumber(vecPosition.fY); Arguments.PushNumber(vecPosition.fZ);