19
\$\begingroup\$

I've been thinking about a multi player RTS game. The part that I can't seem to get around is keeping unit movement synced. If I move unit A to spot XY, I have to communicate that back to server that relays to the other client.

I'm curious what the communications would look like. Would you just communicate to the server that I'm moving unit A to XY from JZ? Maybe you need to communicate movement coord by coord instead? What's the most efficient methodology to communicate movement of units from one client to the other?

EDIT

This is a reposted question from stackoverflow. I found that this site was probably a better place for the question.

One of the better answers from that post:

I assume you're intending to use the Client-Server networking paradigm? In which case you cannot trust the clients to handle the actual positioning of units, you must delegate that task to the server. You then take the command list from each client per-tick, and compute the movement of each unit, once this has been completed, next tick you relay the position of each unit relevant to each client (either on a whole-map basis, or per-view basis), and start the process again.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ The answer really depends which method you want to use. Client - client or client - server. Client to server is easier but it requires a trustable server \$\endgroup\$ Commented Jul 25, 2011 at 20:15

2 Answers 2

27
\$\begingroup\$

You don't want to sync the positions of all the units from the server to each client; that will take up way more bandwidth than you need. You'd also have to deal with interpolating/extrapolating unit positions, etc. Almost no professional RTS's use client/server!

Instead, you want to send only the players' commands. Rather than moving the units immediately when the player clicks, you'll queue the move-command to be done at some point in the future - usually just a couple of frames. Everyone sends their commands to everyone. A couple of frames later, everyone executes all the commands, and because the game is deterministic, they all see the same result.

The downside is that every player is as slow as the slowest player - if anyone falls behind in sending out commands, everyone has to slow down and wait for him to catch up (in Starcraft 2, this is the "XXX is slowing down the game" dialog).


In fact, there is one more thing that is usually done: eliminate the server altogether. Have every client send their commands to every other client. This reduces lag (instead of a command going from you-->server-->opponent, it just goes from you-->opponent) and makes coding easier, since you no longer need to code a separate server. This sort of architecture is called peer-to-peer (P2P).

The downside is that now you need a way of resolving conflicts, but since players' commands are independent of each other in most RTS's, this usually isn't much of a problem. Also, it doesn't scale well - every time you add a new player, every player needs to send him their commands. You're not going to be making an MMO RTS using P2P.


This setup (sending only commands using P2P) is how most RTS's, including Starcraft, C&C, and AoE work, and is the only way AoE could possibly support 1500 units on a 28.8kbps connection.

(image of networking in AoE)

Here are a few more tips for writing a P2P RTS:

  • For obvious reasons, this setup can only work if your game uses fixed-step time - you don't want the results of a calculation to be dependent on the framerate! Fixed-step is easier to work with for most things, so this shouldn't be a problem.
  • In order for this to work, the results of every command must be completely deterministic.
    • This is usually pretty easy if you restrict yourself to one system (such as 32-bit Windows) and force all clients to use the same executable: make sure any random-number generators have the same seed and are always called in the same order; be extremely careful when iterating over unordered collections; etc.
    • This is extremely difficult if you plan on making the game playable across different platforms, or (as is often the case with Linux) allow the clients to compile the code themselves. Not only are different system libraries pretty much guaranteed to use different implementations of rand(), cos() etc, but pretty much all floating-point math is out of the question (see here, here, and here)! In that case, you may be better off using client-server.
  • You're going to want to send out all unit positions every once in a while, at least while debugging, to detect desync bugs (which, trust me, you will have). Whether you keep that in the final game is up to you - I would sync at least some units (or use some sort of checksum), to detect attempted-hacking.
\$\endgroup\$
1
  • \$\begingroup\$ Good post. Small thing to add, even the same compilers optimize, debug/release and other flags may change the result. Be careful! \$\endgroup\$ Commented Jul 25, 2011 at 18:44
14
\$\begingroup\$

I've made a TCP-networked RTS, in which I passed the commands themselves, rather than the results of the commands. For instance, a player gives a move order. If the move order is valid according to that client, it is sent to the server. The server then sends it back to all clients, who validate and execute it.

So all client machines run the game themselves, the server code accepts messages and sends them back to all clients. If a client gives a move order, it won't start executing it until it is received back from the server.

The server sends a 'tick' number at which to execute the command as well, which is a few ticks ahead of the 'current' tick. This way all commands can be executed at the same 'tick' on all machines.

One benefit this method is that it doesn't depend on any individual client machine to validate the command. If I passed the results of the move, I might be able to hack it to move my units faster. All clients have to execute the same command and if one machine executes it differently, it will be obvious.

Validating the command client-side before sending it to the server isn't necessary, but in theory it saves network traffic. I used the same validation code to tell the UI that the move was possible, so it didn't require writing extra code.

As for what the messages might look like. I wasn't concerned with ultra efficiency as it was my first networked game. I passed commands as strings. The commands would be formatted like this: "<player_id>:<command>:<parameters>"

For a contrived example, a move command might look like this: "3:move:522:100:200". This means Player 3 wants to move unit 522 to (100,200).

The server passes the command on to all clients, including the one who sent it, with a tick number attached like this: "153238:3:move:522:100:200".

Then the clients would all execute this command when tick 153238 is executed.

\$\endgroup\$
2
  • \$\begingroup\$ I added a bit more info to the question. The answer from SO seems to be counter to what you said and I'd love to discuss the finer details. \$\endgroup\$
    – Darthg8r
    Commented Jul 25, 2011 at 14:55
  • \$\begingroup\$ Yes, that's another way to do it, but it seems to me that it would be more work to pass so much of the game state around, rather than just the commands. My game was simple enough that the entire thing can run on each client machine. For an MMO, or for something like Minecraft, you don't have the entire simulation running on the client side, so you pass only information relevant to each client individually. \$\endgroup\$
    – Philip
    Commented Jul 25, 2011 at 15:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .