Handling "jitter" using TCP for a slowpaced MMO

Started by
7 comments, last by Kylotan 7 years, 10 months ago

I'm not sure how to ask this, so I'll just get into it. I'm trying to figure out a way to handle network jitter, when packets received by the server aren't spaced out like the client sent them, using a de-jitter buffer.

The client sends commands immediately as they are given, they are not held in any buffer on the client. The server keeps them in a buffer until they are ready to be processed (validity checking, etc) and sends those updates to other clients at a rate of 20hz. The server's world simulation runs at 60hz as wells as the client's. The client does NOT send periodic position/state updates, it only sends changes. Like "player started moving in this direction at this speed", "player has stopped moving and is now here". If you start moving north and then after say, 100 ticks, you move east, the server might receive the first command(north) late and the second command(east) on time, which would put that player out of sync in the server until they stop and then they will snap to the correct position. The snapping isn't an issue as much as the player getting very much out of sync if they do not stop every once and a while.

My question is, how can I let the server know when the packet should be processed? I know I need to hold on to a command for a certain amount of time to let other commands come in to provide a smooth simulation, like when YouTube videos buffer. But I don't how the server will know for certain when a command was sent relative to the other commands.

The only solution I've heard of is to attach a "tick number" to each command and that way the server will know how many ticks are in between each command. But how would I handle a packet that comes late? Say you send two commands with 50ms between them. But for some reason, the second packet gets lost for 500ms and your buffer is only 100ms. By the time you get that second command it would be 350ms late. It can't just forget about that command because that command could be saying to stop the character or something.

Sorry if this is a dumb question, I want to be sure that my networking code is halfway decent before I code any further and inevitably run into a slew of bugs. I've heard WoW uses TCP and does just fine. If anyone has a link that explains how they do it, I would love that. Gaffer is awesome, but there's not enough about TCP that I've seen.

Advertisement
Say you send two commands with 50ms between them. But for some reason, the second packet gets lost for 500ms and your buffer is only 100ms. By the time you get that second command it would be 350ms late. It can't just forget about that command because that command could be saying to stop the character or something.

For movement i would not send start and stop commands. I would send a steady stream of their current positions.You can still sanity check those positions to make sure their are legal and allowable. Then if you get a position packet with an a "tick" lower than a different one you have received then you can safely ignore it. For one time even things that you CANNOT miss (cast spell, get powerup, etc) then you have to do some kind of reliable over UDP transport yourself....or use TCP but I still recommend against TCP.

I would love to use UDP, but I'm using LibGDX as a framework and that doesn't allow UDP. I could still send a steady stream and just lerp between positions but I want to see if this would be possible.

I read up on something called Floating point determinism. I think this is why my clients are out of sync. The server only sends a velocity vector to the clients and the client then sets that characters velocity to that value. Wouldn't two different machines always yield different results in calculating the next position based on velocity? Or is this not a problem with Java and the virtual machine?

Either way, I think I still need to figure out how to properly space out packets received by the server.

I read up on something called Floating point determinism. I think this is why my clients are out of sync.

IMO this is Very Unlikely in your case (floating point determinism comes into play when ALL the other sources of non-determinism are out, and this doesn't seem to be the case). What you have seems to be a classical problem, which can be seen as a problem of client-side prediction going out of sync from server-side representation. It is further exacerbated by using TCP, which (in case of packet loss) causes BIG FAT delays. Classical approach in authoritative-server world is simply to send updates to client coordinates more frequently than "when player stops"; normally it is done on each network tick (save for any "dead reckoning" stuff which allows to save on traffic and skip some of the updates), effectively synchronising client with server's representation on each tick (usually synchronisation is not exact, but within a pre-defined margin of error to save on traffic).

Well that's disappointing. I was hoping to be able to accomplish a smooth sync without having a stream of position packets.

(save for any "dead reckoning" stuff which allows to save on traffic and skip some of the updates)

What do you mean by "dead reckoning"? I'm guessing "I'm not moving so no need to send my coordinates"?

Dead reckoning can be read about on Wikipedia and is basically what you were hoping to do (send velocity only and other side can deduce position) but in practice you need to sprinkle in explicit position updates as well because you don't have control over the speed of the internet.

As I mentioned on the other thread, I think you're trying to solve a problem that (a) can't be truly solved in the fast real-time sense, and (b) you don't need to solve anyway. The errors accumulate because finding position using velocity is sensitive to time, and time variations are out of your hands. Switch to positions and that extra accumulated error goes away.

The client sends commands immediately as they are given, they are not held in any buffer on the client.

In addition to what others have said, you'll want to quantize your simulation into steps of known length, and count simulation time in the form of simulation steps.

Then, when a client sends a command, it says "do this at step X" and the next command will be "do this at step X+Y."

Yes, this means that commands on the client must be quantized to the simulation step rate before being sent. That's fine and expected, and actually simplifies everything.

enum Bool { True, False, FileNotFound };

First is it really needed for a "slowpaced MMORPG" to have server cycles 60hz simulation (or rather network thread processing frequency) and a 20hz update cycle (and there could be some other still fast cycle for the client doing tweening to smooth out movements on the client).

Might you be able to slow the server update cycle by half or more (and probably eliminate more than a few corrections or at least the processing they require). Experiment with it and you might be suprised that something like 5hz will be sufficient. And with that speed now bandwidth might be more available for the position sync data traffic.

-

Also TCP is supposed to have 'Out Of Band' asynchronus message sending that might serve for some of the UDP type uses

--------------------------------------------[size="1"]Ratings are Opinion, not Fact
I've certainly worked on MMOs where the update and broadcast frequencies were much lower than mentioned here, and everything worked perfectly.

Besides, any bandwidth benefit you get from not sending position updates is dwarfed by the position broadcasts sent to other players anyway - doubly so when those positions are broadcast at 20Hz when 5Hz or less would probably do.

There might be better ways to handle it these days, especially now network latency is better, but the old Age of Empires article about running simulations in lockstep says that they had to routinely accept a gameplay latency of over 250ms in order to ensure every player had enough time to submit commands for each simulation step, and the simulation only ran at about 5Hz. That's acceptable for click-to-move games but generally not for steer-to-move games.

This topic is closed to new replies.

Advertisement