Questions on Network Implementation

I was trying to say that for a real time game, those delayed TCP/IP packets may as well be dropped because they are too late to be useful. Provided each UDP packet is useful as a stand-alone update, it is possible to design to withstand packet loss. When a packet is lost, the screen object has to continue on a bit longer on dead reckoning.

Edit: You can see this in my 2011 Mage Wars entry for Java4k (Source code available), although being a 4k game, it’s not very well structured.

My philosophy here: I will need reliable data transfer somewhere in my game, and I don’t think my lone brain is superior to the sum of all brains that have worked on TCP, so reimplementing TCP over UDP sounds pretty stupid when there’s a perfectly fine solution just sitting there that’s easier to use and has been improved/perfected since before I was born.

What about reliable unordered data transfer? I had an article around here that explained how to do it…

EDIT: AHA! http://gafferongames.com/networking-for-game-programmers/
Amazing tutorials explaining lots of stuff about networking and physics and both at the same time!

SCTP would have been a nice contender for that, had it ever gained enough momentum. I’d say at this point it’s too late for SCTP to go anywhere though. :frowning:

Thanks, great article. I didn’t know the bit about parallel TCP streams increasing UDP packet loss and the section on reliable UDP communication is gold dust. I had been assuming that the best solution would be to use parallel UDP and TCP/IP streams so as to get the best of both worlds. I’m bookmarking this for a more thorough read.

Edit: The TCP/IP Sync causing UDP packet loss is interesting. However I think it might not matter so much if a parallel TCP/IP connection was only used for low bandwidth reliable data (e.g. inventory changes). It looks like using TCP/IP for dynamically downloading map segments, whilst simultaneously using UDP for real-time play, is a poor idea. It’s also interesting to see that UDP packet loss increases massively once the packet size reaches 160 bytes. There is clearly a trade off between packet overhead and packet loss.

Edit 2: The comments on the article make an interesting read too. Several people note that MMORPGs often use TCP/IP. That does make sense considering they are heavily event driven. However I used to play WoW several years ago and the lag was something awful, when an area got busy.

NETWORKING: One more reason to run simulations at fixed rates. As if the list wasn’t long enough. Note, attempting to be FP deterministic is crazy.

Huh? Is that really so difficult with Java? strictfp anyone?

I love this topic!

Firstly, I want to briefly talk about a protocol on top of UDP I’ve created that I think is useful.
Secondly, I made a simple networked game (using UDP) all in a few hours last night with interpolation and extrapolation - I’ll post some code.

A few concepts:

  • Multiple “channels” can be setup to differentiate between reliability and order.
  • A channel is marked as unreliable or reliable, and ordered or unordered.
  • A command is sent through a channel, has a retry count, a priority, has a determinable size in bytes, and can be read/written to a ByteBuffer
  • A packet is formatted [protocolId][sequence][ack][ackuence][command id+channel][command data][command id+channel][command data…]
    Where sequence is the remote packet sequence, ack is the last packet sequence received by the remote address, ackuence is 32-bits which stores which of the past 32 packets have been received by the remote address.

The strength of this system lies in the amount of data you send that you don’t care about. The more of that there is, the better this system performs over TCP (plus TCP acks one at a time, this does 32).
This is a library I’ve developed for my game engine, I’m going to have it available separately however.

Anyway, onto my experimentation last night!

The world consists of ships with position, velocity, direction:


public class Player extends SteerSprite
{
	public byte id;
	public String name;
	public long lastUpdateTime;
	public float ping;
	public float time;
	public Tween<Vec2f> tweenPosition = new Tween<Vec2f>( new Vec2f(), new Vec2f() );
	public Tween<Vec2f> tweenVelocity = new Tween<Vec2f>( new Vec2f(), new Vec2f() );
	public Tween<Vec2f> tweenDirection = new Tween<Vec2f>( new Vec2f(), new Vec2f() );
	public Vec2f position = new Vec2f();
	public Vec2f velocity = new Vec2f();
	public Vec2f direction = new Vec2f();
}

When I get the command that someone has joined, I do this:


Player p = new Player();
p.id = joined.id;
p.name = joined.name;
p.lastUpdateTime = System.currentTimeMillis();
p.time = 0;
p.ping = INTERVAL_CLIENT * 0.001f; // expected (INTERVAL_CLIENT = 50 which means 20 packets per second)

When I get the command that someone has updated, I do this:


long lastUpdateTime = p.lastUpdateTime;
p.lastUpdateTime = System.currentTimeMillis();
p.time = 0;
p.ping = (p.lastUpdateTime - lastUpdateTime) * 0.001f;	
// important for smoothness, the beginning of the tween should start in the players current position
p.tweenPosition.start.set( p.position );
p.tweenDirection.start.set( p.direction );
p.tweenVelocity.start.set( p.velocity );
// the most recent position, velocity, and direction
p.tweenPosition.end.set( update.x, update.y );
p.tweenDirection.end.set( update.dx, update.dy );
p.tweenVelocity.end.set( update.vx, update.vy );

And most importantly, here’s my update code:


p.time += gameState.seconds; // deltatime
				
if ( p.time <= p.ping )
{
	// Interpolate
	p.tweenPosition.set( p.position, p.time / p.ping ); // basically p.position = (p.tweenPosition.end - p.tweenPosition.start) * (p.time / p.ping ) + p.tweenPosition.start
	p.tweenDirection.set( p.direction, p.time / p.ping );
	p.tweenVelocity.set( p.velocity, p.time / p.ping );	
}
else
{
	// Extrapolate
	Vec2f subp = Vec2f.sub( p.tweenPosition.end, p.tweenPosition.start );
	Vec2f subd = Vec2f.sub( p.tweenDirection.end, p.tweenDirection.start );
	Vec2f subv = Vec2f.sub( p.tweenVelocity.end, p.tweenVelocity.start );
				
	p.position.add( subp, gameState.seconds ); // deltatime
	p.direction.add( subd, gameState.seconds );
	p.velocity.add( subv, gameState.seconds );
}

Results in perfectly smooth movement! However, the state of the ship you see on screen is out of date… but its worth the smoothness.

Hopefully this is helpful to someone…

Yup, it’s quite important to use strictfp in multiplayer games. It’s very slightly slower but less pain in your ass.

Actually it is harder than that. And worse is not a good idea…if fact it’s a terrible idea except in some very narrow scientific computations which won’t be using primitive types anyway. Bit-exact FP = higher errors & slower performance (over prims).

Cas decided to use ints for most logic, and it’s more than enough accuracy. We didn’t even resort to (cumbersome) fixed point decimals. Just make your base unit small enough (like 1mm or less). For most 2D games, this is enough, and makes your game deterministic across clients/platforms (assuming latency doesn’t affect logic).

If your using UDP and don’t know what the 2 generals problem is, or what flow control is, or why TCP has the handshaking it does to establish a connection, then i guarantee that as soon as the network is poor enough for you to notice packet loss with TCP. Your UDP solution will collapse.

Sure it works well when everything is peaches and roses. But that is not the same as faster/better than TCP. And what did you gain? Even AAA titles are moving to TCP now. And many of these titles have pretty crappy network code.

Of course there are situations where UDP works well. Fixed rate full state per packet is one of them.

I don’t think there’s an specific answer to your question, until you drill down to what kind of game you want to make. Some strategies might work better for some kind of games, and some for the other.

To be honest I don’t believe what you described could be very good, except for turn based games, unless the tick rate of your server is extremely high (which would easily saturate your network).

In a real-time game I would recommend the server to run the game as it were in the client: full logic at N ticks per second, process the player inputs as they come, broadcast it to everybody.

Now here it comes when I said the type of game:
If it is a FPS, let’s say Quake, players are likely to keep moving, rotating, dodging,shooting, at a very high rate; so you might want to have a packet being sent very often updating the players position.

However, if you have an action-rpg, think of Diablo, you don’t need such high rate of packages. (now I’ll tell you from experience. This is exactly how I implemented my online game Reign of Rebels).
You basically just need a package when an entity moves, or attacks (or performs any significant action).
Let’s say you have entity A standing on point 10,23 and the player (or the AI) directs it to move to point (14, 25). The client will send the message that it wants to move, server receives it and broadcasts this. Just 1 package exchange and you’ll have the entity performing the exact same move on the client and on server. When the entity hits is target, it will stay there until further orders are given. No need to send a shitload of packages telling that the entity A is standing in position 14,25.
This strategy might even work in some more fast paced games where your Physics/pathfinding is deterministic.

Of course you would use some interpolation tricks to make things smooth (some of which I discussed here ), but this is definitely a solution for this kind of game.

Maybe if you show us a video of a game similar to yours, we can give better suggestions on how to implement it.

As for TCP/UDP: Just go for TCP. You have already too much to worry in the making of a game, just let TCP handle some of the headache for you.