collinsmith / riiablo

Diablo II remade using Java and LibGDX
http://riiablo.com
Apache License 2.0
872 stars 99 forks source link

Improve accuracy of netcode, ping packet and Pinger system #77

Closed collinsmith closed 4 years ago

collinsmith commented 4 years ago

Implementing support for ping has made me notice some deficiencies in my current networking code.

  1. the amount of variance indicates that the frame times aren't perfectly in sync -- probably because my networking syncs are using an interval system
  2. ping to a localhost server should be ~0ms, but I'm getting a frame's time added, sometimes two frames if the sync is bad
  3. I'd like ping to be a running average of the past n ping packets

Additionally, ping is currently acting more as a RTT and I'd like this changed to be the actual ping. It would be nice to eventually add support for RTT, CPU/GPU time, and ?server frame time? to the clients -- this may be extremely useful when more of the networking is being developed.

I thought about storing a client's systime in d2gs, but I don't think that's viable or accurate (unless to maybe establish some sort of delta between the two?). My current implementation passes the client systime and is echoed and used by the client in the response packet to calculate the delta as sent to receive and server_frame and response (hence the 1-2 frame times added). I could bypass a lot of this if I probably just handled the ping packet outside of the engine loop, but I think this is indicative that improvements are needed.

As far as networking, I may use the connection packet to establish a client-server tick counter handshake and then pass that value, incrementally, with packets (I think this is closer to how the original game works). This could be useful to perform client-server state validations.

collinsmith commented 4 years ago

https://stackoverflow.com/a/34379590/3134241

First of all, I don't think you need to timestamp the message on the server side. You just need the sending time to be added when you send the packet and then you can calculate the difference with the current time when the response get's back to the client (of course the server needs to copy the sent_time in the reply).

note: If your server takes "long" time to execute then you will need to add some kind of "time to process" information to the packet by the server.

RTT = (cur_clientTime_when_response_is_received - time_sent) - time_to_server_process This formula has the advantage that doesn't care about time differences between the client and the server clock.

collinsmith commented 4 years ago

I added a time field to server Packet to store time when packet was obtained and then passed the time delta with the response packet (the total time the server had the packet). This has resulted in a more accurate calculation from the server's end, but the client ping is still off by a bit because of the frame delay (client updates at 60Hz, so about 16ms over the actual ping). Also, sometimes the sync is just right and I get a correct 0-2ms ping (I assume the packet is processed on the server immediately and then passed back to the client before it has entered ClientNetworkReceiver).

collinsmith commented 4 years ago

I was able to implement a nice moving algorithm by creating a profiler that works using the current profiling plugin. This results in being able to see the ping history over the past n seconds (currently 30)

I changed my networking protocol and am experimenting with adding an ACK field to my flatbuffer spec as per below reading. When a ping packet is received by D2GS, it is immediately echoed back to the client so the client can determine the delay from send to receive. Another response is send the following frame without the ACK set so the client can calculate the RTT. Ping is ~5-10ms on localhost, RTT is ~30-40ms -- I think partially because ClientNetworkReceiver runs before Pinger, so if the server responded instantly, the client would need to wait until the following frame (this adds ~2ms based on the profiler numbers).

I'm going to start looking into implementing my own networking protocol and reliable ordered messaging. I'd really like to be able to estimate stuff like packet loss.

collinsmith commented 4 years ago

Closing this issue for the time being. The current impl is satisfactory and can be expanded upon later.

The immediate ping may be removed because it's not meaningful. RTT (delayed) response includes the time it took for the server to process the message and response, so this includes a roughly 1 tick delay. Some of this will be handled differently (and probably more effectively) with a UDP implementation.