citizenfx / fivem

The source code for the Cfx.re modification frameworks, such as FiveM, RedM and LibertyM, as well as FXServer.
https://cfx.re/
3.53k stars 2.08k forks source link

Bullets not registering with Automatic Guns #1490

Closed Walker1390 closed 2 years ago

Walker1390 commented 2 years ago

When shooting another player with a fully automatic gun some, seemingly randomly, bullets do not deal any damage. I don't have the expertise or knowledge to speculate as to why this happens or if it is even something that can be fixed but wanted to make this issue to make someone aware of it if cfx isn't already.

Steps to Reproduce:

  1. Tap fire at a player X amount of times slowly until they die.
  2. Empty the magazine until there are only enough bullets to kill the player
  3. Hold Left Click (Or whatever shooting is bound to) and whats left of the magazine into the player
  4. The player won't have died despite you firing enough bullets to kill them.

Clip: https://streamable.com/3m6v0g

This can also be seen just spraying at players, you'll notice not every bullet deals damage however this was the easier way I could replicate it with steps to do it every time. I recreated this on various servers and also a completly fresh cfx server with only vMenu to give myself a weapon. The fresh server being the one used for the clip.

If the issue is ping related, I was in the UK and so was the server for the clip, the player I was shooting at was in the US.

Server Artifact: 5652

blattersturm commented 2 years ago

The repro steps are still a bit vague and the video isn't very clear on these either (same with how the player is being respawned in place), for example what are 'X amount of times' and how to tell what amount of bullets is enough?

For things like this the actual accuracy of the repro steps is very important, and currently there's just too many unknowns instead of 'have player 1 at coordinate A and player 2 at coordinate B and use weapon Y with Z bullets left and this script to respawn the dying player'.

Korioz commented 2 years ago

Hi, i will try to explain a bit better

When shooting with an automatic gun like GUSENBERG multiple bullets in a row by holding the left click mouse button, some bullets will not register.

The first part of the repro is made to know how many bullets are needed to kill a player with the chosen automatic weapon. The second part is made to only have the supposed number of bullets needed to kill a player in our gun's magazine. The third part we try to kill the player by holding left click with only the number of bullets we are supposed to need to kill a player.

When bullets are not registered the event weaponDamageEvent is not fired too, also we observed that by using ASSAULTRIFLE instead of GUSENBERG for the repro the repro was less reliable and the issue was happening only some times, but with the GUSENBERG weapon the repro is very reliable.

For a more clear repro:

  1. Get in front of a player we will call player X.
  2. Get the number of bullets needed to kill player X by shooting bullets only in his torso without holding left mouse click we will call this number of bullets Y.
  3. Shoot at player X torso with only the number of bullets Y we got at step 2 remaining in the weapon's magazine with holding left mouse click.
  4. Player X will not die despite the exact same number of bullets were fired.

Repro has been tested with mp_m_freemode_01 player ped, default max health and no weapon damage modifier.

Walker1390 commented 2 years ago

Thanks for the response, ill attempt to clarify everything you mentioned.

Clip 2:

https://streamable.com/omzqa3

In this clip I shoot player 2 with the microsmg until they die. It takes 5 bullets to kill them. This was the X amount of shots I refer to. I then shoot 11 bullets leaving only 5 in the magazine so theoretically these 5 bullets should be enough to kill player 2 but when I spray, although it looks like all the bullets hit he only recieved damage for 3 of the bullets.

After resetting everything (Player 2 respawned with full health and I have a full magazine) I shoot 8 bullets at him and again he does not die as expected.

I repeat the first attempt (Leaving only 5 bullets in the magazine) at the end of the clip and get the same result.

In an effort to try and convoy the problem I used this snippet of code to try and record how many times the ped was actually hit.

local hits = 0
AddEventHandler('gameEventTriggered', function(name, args)
    if name == 'CEventNetworkEntityDamage' then
        local victim, attacker = args[1], args[2]
        if attacker == PlayerPedId() then
            hits = hits + 1
        end
        print("Hits: " .. hits)
    end
end)

RegisterCommand("reset", function()
    hits = 0
    print("Hits is now: " .. hits)
end)

However this also seems to be 'out of sync', for lack of a better term, in some rare cases.

As I was typing this out Korioz responded with steps to repro that I think should suffice. One question he didn't cover was how these players are respawning, to that end I was using spawnmanager provided in cfx-server-data with only one 'map' containing a single spawnpoint. In the second clip I changed this spawnpoint to ontop of maze bank.

spawnpoint 'a_m_y_hipster_02' { x = -74.83, y = -818.51, z = 326.18 }
blattersturm commented 2 years ago

Right. I have a suspicion as to what this behavior may be related to - the game likely tries to append damage to any unacknowledged damage event, but the way we handle sending events is a bit crude at this time and the game may consider the already-sent damage event as 'still pending' and instead of sending a new event for the 'second' shot, try appending it to the first shot.

There was a generic fix for some similar event queue logic but it led to some other crashes and was reverted, I guess this needs special care per event type instead.

gottfriedleibniz commented 2 years ago

I have a suspicion as to what this behavior may be related to ...

This may be wishful thinking, but would a tup.sent check be suffice before the ev->Equals(ev) check? Well, for the current netEventMgr approximentation at least.

Otherwise, if per event type logic is required, I whipped up a quick IDA script and CWeaponDamageEvent, CGiveWeaponEvent, CGivePickupRewardsEvent, CScriptedGameEvent, and CUpdateNetworkSyncedSceneEvent seem to coalesce fields during a call to Equals. Also, CRequestPickupEvent, CRequestMapPickupEvent, and CRequestDoorEvent modify fields, however, are not used in equality checks nor serialized.

Also noticed CGiveWeaponEvent is incorrect; should be a 16-bit int.

blattersturm commented 2 years ago

Via @gottfriedleibniz:

This may be wishful thinking, but would a tup.sent check be suffice before the ev->Equals(ev) check? Well, for the current netEventMgr approximentation at least.

Yeah, this does seem to fix it (with the usual clumsy ping bumped to up ~150ms RTT on each side). At the time I wrote my earlier comment I didn't remember how event combining worked, so I left it ~vague.

Otherwise, if per event type logic is required, I whipped up a quick IDA script and CWeaponDamageEvent, CGiveWeaponEvent, CGivePickupRewardsEvent, CScriptedGameEvent, and CUpdateNetworkSyncedSceneEvent seem to coalesce fields during a call to Equals. Also, CRequestPickupEvent, CRequestMapPickupEvent, and CRequestDoorEvent modify fields, however, are not used in equality checks nor serialized.

Noted. To reduce the risk of any new event pool/queue length regressions (see manual responded-to-threat checks before queueing), I'll only be applying this sent check to these events listed. Thanks!

Also noticed CGiveWeaponEvent is incorrect; should be a 16-bit int.

I guess the person making this PR didn't understand ReadInteger, indeed, and interpreted the sign read + data read separately. This indeed should be a signed read, I'll also fix this.