Dropped events get sent to the client after they've left and re-connected

This is pretty bad because the client is getting sent outdated information, and it’s being sent to a different server id.

Say for example, the server sends the client an event about updating the position of some object. If the client misses this event, it’ll get sent again. This is good, you wanna make sure events are actually received, but the problem comes up when they’ll get the event after leaving. When the client leaves, they miss the events the server is sending (and yes, they stop receiving events before playerDropped is triggered, so there’s no way for the server to avoid doing this). These missed events are then sent to the client when they re-connect!

So, join the server, get sent some events, leave, miss some events you were being sent, get them when you come back. These events should be discarded, as the game entirely restarted for the client and they’re basically a new client and should be run through the normal order of events (whatever kind of initialization the resource has will be done after these missed events were sent, causing all sorts of problems).

I’m not sure if this happens when restarting the game, or what the timeout for the missed events are, but all I know is that if I disconnect and reconnect to my server after missing events, I get sent them again. I also made a couple small scripts so anyone can test this and see it for themselves. I’ll put them here and explain what they’re doing further down the post.

server:

RegisterServerEvent("clientRespond")

local respond = true
RegisterCommand("stop_responding",function()
	respond = false
	print("stopped")
end)
AddEventHandler("clientRespond",function()
	local name = GetPlayerName(source) or "???"
	print(name.." replied")
	if respond then
		print("asking "..name)
		TriggerClientEvent("serverRespond",source)
	end
end)

client:

RegisterNetEvent("serverRespond")

AddEventHandler("serverRespond",function()
	TriggerServerEvent("clientRespond")
end)

TriggerServerEvent("clientRespond")

So, with these two scripts… the client first sends a clientRespond event to the server, which the server responds with a serverRespond event, which then makes the client respond again and so on. Now, that serverRespond event will only happen until the command stop_responding is entered. So to test this, start up the server and join it, notice the console talking about the responses, leave the game, stop_responding, and join back.

You’ll first get a response for the client initializing (that first clientRespond), but you’ll also get more depending on how many were missed. So if you see 2 “asking” printed without responses after you left, those 2 serverRespond events that failed to send are being sent after you join again, and you’ll see 2 extra responses printed out.

1 Like

huh? events don’t get replayed, and replayed packets are stored in the fx::Client context, so if they have a different netid they don’t get the same Client instance at all.

similarly the reliability layer is on peer level and peers are also not typically reused across Client instances :confused:

a valid explanation for this would be a crazy thread synchronization issue or something with split GSNet but that’s still a long shot

I’m not an expert with network protocols at all, and I shouldn’t really have made so many assumptions about them getting sent again after they’re missed (just thought that’s how it worked), but I can say for certain this is a persistent issue that’s easily reproduced.