multitheftauto / mtasa-blue

Multi Theft Auto is a game engine that incorporates an extendable network play element into a proprietary commercial single-player game.
https://multitheftauto.com
GNU General Public License v3.0
1.52k stars 465 forks source link

isPedDead client-side bug #4147

Open gh0st2k2 opened 2 months ago

gh0st2k2 commented 2 months ago

Describe the bug

Calling this function with onClientPlayerWasted will return false (ped is not dead) if you die by falling (client-side), However on server-side, calling it with onPlayerWasted will return true (ped is dead) if you also die for the same reason.

This bug happens only if you die by falling as far as I know but, if you delay the call to isPedDead function when onClientPlayerWasted, it returns true (player is dead)

It happens even for the localPlayer who is always considered as a streamed-in GTA SA entity.

Steps to reproduce

-- client (no call delay)
addEventHandler("onClientPlayerWasted", root, 
function()
      -- player dies due to falling (localPlayer included)
      iprint(isPedDead(source))
      -- returns false (ped not dead but he triggered the onClientPlayerWasted event?)
end)

-- client (with call delay)
addEventHandler("onClientPlayerWasted", root, 
function()
      -- player dies due to falling (localPlayer included)
      local player = source
      setTimer(
           function() iprint(isPedDead(player)) end
      100, 1)
      -- sometines 50ms of delay still causes it to out put false
      -- returns true (ped is dead)
end)

-- server
addEventHandler("onPlayerWasted", root, 
function()
      -- player dies due to falling.
      iprint(isPedDead(source))
      -- returns true (ped is dead)
end)

Version

Latest version (not nightly)

Additional context

No response

Relevant log output

Security Policy

FileEX commented 2 months ago

The reason for this is that the onClientPlayerWasted event is triggered before the player has actually died. This happens because of the onClientPedDamage event, which can be cancelled. If the event is not cancelled, the player will receive the damage, but only after onClientPlayerWasted has already been triggered. So, at the time onClientPlayerWasted runs, the ped/player is still technically 'alive' according to the game, which is why adding a timer works around the issue.

Why doesn’t this happen on the server side? Because the event on the server is triggered during HP synchronization, meaning after the player has actually died.

What’s the solution to this problem? I think it’s going to be hard to find one. We can't change the order in which the events are triggered to make onClientPlayerWasted fire after the ped dies, because backward compatibility gets in the way. Adding a new event doesn’t really make much sense either.

Even though calling isPedDead inside onClientPlayerWasted doesn’t make much sense, it’s still technically a bug. I think, for now, the best we can do is add a note about it on the wiki

PlatinMTA commented 2 months ago

Adding a new event doesn’t really make much sense either.

I think it should be ok, like having an event for before the ped dies and after the ped dies... that sounds ok to me. I just wonder what the use case would be, or why you need to check isPedDead() inside of that event.

gh0st2k2 commented 1 month ago

i have a function that updates some ui and it is called with other events (not only onClientPlayerWasted). in the update function, there is a call to isPedDead regardless of what event called it.