Skip to content
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

Add new event onPlayerTeleport. #3941

Open
wants to merge 17 commits into
base: master
Choose a base branch
from

Conversation

imfelipedev
Copy link

I developed this event to detect players using teleport cheats. The onPlayerTeleport event will only be triggered when the player's position is significantly distant from the position registered on the server, and this change was not caused by the setElementPosition function. This implementation is based on the suggestion provided in the issue: #3293.

Server/mods/deathmatch/logic/CGame.cpp Outdated Show resolved Hide resolved
Server/mods/deathmatch/logic/CMainConfig.cpp Outdated Show resolved Hide resolved
Server/mods/deathmatch/logic/CPlayer.cpp Outdated Show resolved Hide resolved
Server/mods/deathmatch/logic/CPlayer.cpp Outdated Show resolved Hide resolved
Shared/mods/deathmatch/logic/CTickRateSettings.h Outdated Show resolved Hide resolved
Shared/mods/deathmatch/logic/CTickRateSettings.h Outdated Show resolved Hide resolved
Server/mods/deathmatch/logic/CPlayer.h Outdated Show resolved Hide resolved
Server/mods/deathmatch/logic/CPlayer.h Outdated Show resolved Hide resolved
imfelipedev and others added 2 commits January 10, 2025 01:58
Co-authored-by: Nico <[email protected]>
Co-authored-by: Nico <[email protected]>
@CArg22
Copy link
Contributor

CArg22 commented Jan 10, 2025

This event will give people false belief that they are protected from cheaters. Cheater can just teleport X times by 49 units.

Also,. take an account years of backlog where people teleporting players clientside what means they will get false positive detection. Refactoring may not be an option.

If you want to protect your server from cheaters that using teleport hacks, calculate traveled distance over time and implement your "customSetElementPosition" that skips accumulation and use it only server side. Code will be look like:

local playersTraveledDistance = {}

local function customSetElementPosition(element, x, y, z)
    if isElement(element) and getElementType(element) == "player" then
        local playerData = playersTraveledDistance[element]
        if playerData then
            playerData.lastPosition = { x, y, z }
        end
        setElementPosition(element, x, y, z)
    end
end

setTimer(function()
    for _, player in ipairs(getElementsByType("player")) do
        if isElement(player) then
            local x, y, z = getElementPosition(player)
            
            if not playersTraveledDistance[player] then
                playersTraveledDistance[player] = {
                    lastPosition = { x, y, z },
                    totalDistance = 0
                }
            end

            local playerData = playersTraveledDistance[player]
            local lastPos = playerData.lastPosition

            local dx, dy, dz = x - lastPos[1], y - lastPos[2], z - lastPos[3]
            local distance = math.sqrt(dx * dx + dy * dy + dz * dz)

            playerData.totalDistance = playerData.totalDistance + distance
            playerData.lastPosition = { x, y, z }
        end
    end
end, 1000, 0)

@Proxy-99
Copy link
Contributor

Proxy-99 commented Jan 10, 2025

building project "Deathmatch.vcxproj" -- FAILED.
4>F:\MTA\mtasa-blue\Server\mods\deathmatch\logic\packets\CPlayerPuresyncPacket.cpp(136,32): error C2660: 'CElement::CallEvent': function does not take 1 arguments

 pSourcePlayer->CallEvent("onPlayerTeleport");

@imfelipedev imfelipedev reopened this Jan 10, 2025
@imfelipedev
Copy link
Author

imfelipedev commented Jan 10, 2025

This event will give people false belief that they are protected from cheaters. Cheater can just teleport X times by 49 units.

Also,. take an account years of backlog where people teleporting players clientside what means they will get false positive detection. Refactoring may not be an option.

If you want to protect your server from cheaters that using teleport hacks, calculate traveled distance over time and implement your "customSetElementPosition" that skips accumulation and use it only server side. Code will be look like:

local playersTraveledDistance = {}

local function customSetElementPosition(element, x, y, z)
    if isElement(element) and getElementType(element) == "player" then
        local playerData = playersTraveledDistance[element]
        if playerData then
            playerData.lastPosition = { x, y, z }
        end
        setElementPosition(element, x, y, z)
    end
end

setTimer(function()
    for _, player in ipairs(getElementsByType("player")) do
        if isElement(player) then
            local x, y, z = getElementPosition(player)
            
            if not playersTraveledDistance[player] then
                playersTraveledDistance[player] = {
                    lastPosition = { x, y, z },
                    totalDistance = 0
                }
            end

            local playerData = playersTraveledDistance[player]
            local lastPos = playerData.lastPosition

            local dx, dy, dz = x - lastPos[1], y - lastPos[2], z - lastPos[3]
            local distance = math.sqrt(dx * dx + dy * dy + dz * dz)

            playerData.totalDistance = playerData.totalDistance + distance
            playerData.lastPosition = { x, y, z }
        end
    end
end, 1000, 0)

Regarding the minimum value, I found it valid to change. As for altering the player's position on the client side, I believe that if someone truly wants to protect their server and avoid desynchronizations, they wouldn't use this approach. Furthermore, in larger servers, your example code wouldn't be optimized and would likely cause issues. I tested the first code version with a "hacker" colleague, and it worked very well.

@ffsPLASMA
Copy link
Contributor

I would rather put it on server network level whenever the client sends a new position sync update and distance is greater than a server config var, trigger the event. That behaviour should also ignore sync updates done by server itself via setElementPosition or respawnPlayer or whatever.

Also account for all client updates done in whatever way, in your example, what does the client stop from executing custom lua code with setElementPosition.

@imfelipedev
Copy link
Author

I would rather put it on server network level whenever the client sends a new position sync update and distance is greater than a server config var, trigger the event. That behaviour should also ignore sync updates done by server itself via setElementPosition or respawnPlayer or whatever.

Also account for all client updates done in whatever way, in your example, what does the client stop from executing custom lua code with setElementPosition.

But the code is doing exactly that. The onPlayerTeleport event will only be triggered when the client sends a significantly distant position to the server. This code was not designed to prevent a client-side script from using setElementPosition but rather to alert the server when a client moves irregularly without prior server action.

@tederis tederis added the enhancement New feature or request label Jan 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants