As I'm writing client/server netcode for a flight sim right at this
very moment, I can tell you that it is a grade-A ***.
This is the basic way things work...
You have a whole bunch of clients who are trying to play the same
game-that is, everyone needs to know where everyone else is, what
they're doing, etc. This is called the game state. You designate a
server to be the one 'true' game, and each client sends info on what
they are doing to the server, and the server collates it and sends it
all back out to the clients. As a client, you tell the server what
you're doing, the server tells you what everybody else is doing.
Except... the game state is *huge*, much bigger than even broadband
could possibly cope with as player numbers go up, so the server only
sends 'deltas', it only sends what changed since the last frame. But
each packet might get lost en route, a series of packets might arrive
out of order, so the client has to somehow patch this all together to
get some kind of representation of what's going on.
Also, when you steer left, you don't send your new position/velocity to
the server, you send your control input, and the server does the
physics and stuff, then tells you where you end up. This is because
you might have just steered into another car. Lets say you're driving
alongside somebody else, there's a bit of a gap between you, and you
move towards them just as they move towards you. You (your computer)
thinks there is no crash (because you steer immediately but you don't
see them move for a while due to lag), their computer thinks there is
no crash, but the server sees you *both* steer, decides you crashed and
then has to tell you both (and everybody else) that you just crashed.
Even stranger, because of lag, lets say everyone in the game has a ping
of 100ms to the server. If you steer, the server only finds out about
it 100ms later. If someone else steers, you only find out about it
200ms later. 1/5 of a second. If you're on dialup and your ping is
500ms, you steer and it happens on your screen *half a second* later.
That's unplayable, so your computer doesn't wait for the server, it
does it immediately, assuming that the server will tell you the same
thing anyway. Your computer also predicts what everybody else is up
to. When you finally get an answer from the server, your computer
shifts everybody in the world into their proper place, which makes them
jump, or 'warp'. Of course, they warp to the places they were at when
the server sent the packet, so 100ms ago...
Basically, no client ever sees what's really going on. They are always
incorrect by some margin. If you have a steady broadband connection to
a decent server in a game with good netcode and prediction, you might
not even notice anything except the occasional warp, but you're still
seeing into the past to a certain extent.
As for client replays, the positions of the cars comes from the server,
the client does no physics on them, it just puts them where it's told,
or predicts if it has no data. Client replays are *always* incorrect.
Plus, good netcode will drop distant state info. If the server is
sending out state for 40 cars, that's a lot of data (=bandwidth), so it
will drop cars which are further away, updating them less often, so the
client does more prediction. It's less accurate, but you don't care.
Sometimes they might disappear completely. The only replay which shows
what really happened to everybody is (by design) the server replay.
Why are flight sims better for replays? Because if you're 10 miles
from someone and the server isn't giving you much info, or you have a
lot of lag, then you start to predict, your predictions start to go
wrong, but hey! If they are 10 miles away and their position is 5
metres out of true, can you tell? No. If you're driving alongside
someone at 200mph and their position is 5 metres out, can you tell?
You betcha.
I know this is a bit epic, but I've had my head in this stuff for ages
and I'm only just figuring it out. I'm making my netcode generic, but
I'm starting with a flight sim because it hides the errors ;-) The
biggest problem I've had (thankfully 'solved' now) is, if you're
sending the difference on each frame, what happens if the last packet
didn't arrive? How do you work out the new values if you never had the
old ones?! You could just resend the lot, but that takes *ages*. What
happens if you get packet 6 before packet 5? Arrgh, it's a nightmare!
Thanks for letting me vent! :-)
By the way if anybody wants to know more (details, code), I'm happy to
help out. The internet is great for WinSock tutorials, great to tell
you the problems for games, but thin on solutions... all of my info
comes mainly from Quake, Quake 2 and Freespace 2 source code.