Jump to content

cheaters canceling onClientPlayerDamage


Recommended Posts

Hello,

I'm developing an anti-cheat system in MTA:SA and I'm trying to detect players who block or cancel the `onClientPlayerDamage` event on their side, which prevents the server from detecting damage via `onPlayerDamage`.

I know that if the client cancels `onClientPlayerDamage` using `cancelEvent()`, the server-side `onPlayerDamage` event will not be triggered. Resulting in godmode and players not dying

So my question is:
- Is there a reliable way to detect if the client-side damage event was cancelled?
- Does MTA have an anti cheat against this type of cheating ?
-Are there other ways for cheating to cancel damage taken and not die?

Any suggestions or ideas to detect and prevent this kind of abuse would be appreciated!

Thanks in advance.

Link to comment
  • 2 weeks later...
function stopUnknownDamage(attacker, damagetype, bodypart)
	if (damagetype == 55) then --if the no known information about this damage type
		cancelEvent() --cancel the event
	end
end
addEventHandler("onClientPlayerDamage", localPlayer, stopUnknownDamage)

 

Link to comment
  • Moderators
On 22/06/2025 at 12:58, MineX server said:

- Is there a reliable way to detect if the client-side damage event was cancelled?

You might be able to detect it using:
https://wiki.multitheftauto.com/wiki/WasEventCancelled

Though I do not know if this functions works correctly for native events. Something you have to test yourself. Make sure to set the addEventHandler to low priority.

Link to comment
  • 2 months later...

Men the problem is that you dont get that you should never trust the client 

 

 use the onPlayerDamage in server side 

In this case and even if he cancel the event client side he still dies server side 

 

 

Only use the onclientDamage if you want to build a ui or some text only for visuals 

 

Don't ever make a system relies to the trust of the client side 

 

Hope you understand what i mean

Link to comment
  • 2 months later...
On 02/10/2025 at 20:42, Ze9 said:

Men the problem is that you dont get that you should never trust the client 

 

 use the onPlayerDamage in server side 

In this case and even if he cancel the event client side he still dies server side 

 

 

Only use the onclientDamage if you want to build a ui or some text only for visuals 

 

Don't ever make a system relies to the trust of the client side 

 

Hope you understand what i mean

Unfortunately that's not how MTA's damage system works.

The official Wiki explicitly states:


Canceling this event has no effect. Cancel the client-side event onClientPlayerDamage instead.

So onPlayerDamage server-side is not authoritative at all. If a cheater cancels onClientPlayerDamage on their client, the server never receives onPlayerDamage because the damage was prevented client-side before synchronization even happens. The player becomes invincible and your server sees absolutely nothing.

The phrase "never trust the client" is correct, but in this case MTA's architecture forces the client to be trusted for damage events. That's the core problem here.

A Real Approach: Server-Side Health Validation

Since you can't rely on damage events arriving, you need to validate expected damage against actual health changes using data you CAN trust server-side:

local playerHealthCache = {}
local HEALTH_DISCREPANCY_THRESHOLD = 50
	addEventHandler("onPlayerSpawn", root, function()
    playerHealthCache[source] = getElementHealth(source)
end)
	addEventHandler("onPlayerWeaponFire", root, function(weapon, _, _, _, _, _, target)
    if not target or not isElement(target) or getElementType(target) ~= "player" then return end
    
    local expectedDamage = getWeaponDamage(weapon)
    local currentHealth = playerHealthCache[target] or getElementHealth(target)
    local expectedHealth = math.max(0, currentHealth - expectedDamage)
    
    setTimer(function()
        if not isElement(target) then return end
        
        local actualHealth = getElementHealth(target)
        local discrepancy = actualHealth - expectedHealth
        
        if discrepancy > HEALTH_DISCREPANCY_THRESHOLD then
            flagSuspiciousPlayer(target, "GODMODE_SUSPECTED", discrepancy)
        end
        
        playerHealthCache[target] = actualHealth
    end, 150, 1)
end)
	function getWeaponDamage(weaponID)
    local damageTable = {
        [22] = 8.25, [23] = 13.2, [24] = 46.2,
        [25] = 49.5, [26] = 49.5, [27] = 39.6,
        [28] = 6.6, [29] = 8.25, [30] = 9.9,
        [31] = 9.9, [32] = 46.2, [33] = 75,
        [34] = 75, [38] = 46.2
    }
    return damageTable[weaponID] or 25
end
	function flagSuspiciousPlayer(player, reason, data)
    local serial = getPlayerSerial(player)
    outputDebugString(("[AC] %s flagged: %s (data: %s)"):format(getPlayerName(player), reason, tostring(data)))
end
	addEventHandler("onPlayerQuit", root, function()
    playerHealthCache[source] = nil
end)

The idea is simple: when someone fires a weapon at a player, you know the expected damage. Then you check if their health actually dropped by that amount. If they keep taking hits but health never goes down, something's wrong.

Also worth noting that wasEventCancelled() on client won't help for anti-cheat since the cheater controls that environment entirely. They can just patch out the detection or spoof the result.

Link to comment
  • 2 weeks later...
  • Moderators
On 22/12/2025 at 10:35, ZeusDev said:

The idea is simple: when someone fires a weapon at a player, you know the expected damage. Then you check if their health actually dropped by that amount. If they keep taking hits but health never goes down, something's wrong.

Just to verify, does this actually work?

Because 'target' is afaik set by the player that fired the weapon and not by the player that got hit. And therefore there are a lot false positives, unless you let remote players decide the damage done to the localPlayer (which is not handy).

addEventHandler("onPlayerWeaponFire", root, function(weapon, _, _, _, _, _, target)

 

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...