Advertisement

RTS game lockstep packet design

Started by November 24, 2016 12:44 PM
6 comments, last by Guns Akimbo 7 years, 11 months ago

Currently I am working on a real time strategy game with a lot of units and I was thinking and googling about packet design for a lockstep networking model.

As I understand the lockstep networking model is based on capturing input and sending it to other players, who will confirm it and then execute it (in time). But "input" is a wide concept, what is input? Mouse position? Keystrokes? Or more abstract "I want to do this with unit x", or, "I want to do this with unit x on position y".

"Proven" solution

I googled a lot, and found a solution that is used in classic RTS games:

Command packets have a structure like:

  • command type
  • player id
  • x
  • y
  • target

Player 456 wants to move unit 123 to coordinate 5,6:

  • Player first selects the unit:
    • Command packet: COMMAND_SELECT,456,0,0,123
  • Then clicks on a location:
    • Command packet: COMMAND_MOVE_TO,456,5,6,0
  • The other side knows the selection for that player and moves the unit.

In this case, all selection changes have to be communicated via the network and every client stores the selection per player. I was wondering if there is no other solution for this, because also unuseful selections are communicated every time:

Player 456 selects 100 units, and then deselects them in the next tick. This will result in 200 packets just wasted.

Alternative solution

I was thinking more like a packet that has the structure:

  • command type
  • player id (or maybe even not, as the client knows the sender when it receives a packet and knows what unit the command is about)
  • subject
  • x
  • y
  • target

Player 456 wants to move unit 123 to coordinate 5,6:

  • Player first selects the unit
  • Then clicks on a location:
    • Command packet: COMMAND_MOVE_TO,456,123,5,6,0
  • The other side knows what unit to move where and does that.

Selections are not communicated, only the move commands. This, however, results in a slightly bigger packet and also more data in the following situation:

Player 456 selects 100 units and commands them to go to a coordinate -> 100 packets. The player doesn't change the selection and in the next tick commands the units to go to a new coordinate -> another 100 packets, etc.

Both could win

Player selects two units, moves them, selects another two, moves them, etc -> Alternative solution wins, two packets per movement (and no packets for selection/deselection)

Player selects two units, moves them, then moves them again, then again, etc -> Proven solution wins, as there is only one packet per movement and one for the selection (and maybe one for deselecting)

Conclusion?

I really don't know which one is better, as both solutions seem to have drawbacks. Does anyone know how to handle a situation like this?

Fat Mole and [s]quaredrop, our mobile games for iOS and Android

"input" is a wide concept, what is input? Mouse position? Keystrokes? Or more abstract "I want to do this with unit x"

The latter. The physical input device used is a problem for the local machine and isn't relevant to network play. And obviously if it's an AI player there is no physical input device at all.

In this case, all selection changes have to be communicated via the network

No, because selection is (again) usually a client-side concern, just an implementation detail of the user interface. Unless it needs showing on other people's machines, don't send it.

This will result in 200 packets just wasted.

You don't have to send the information for each unit separately. Your messages can have variable length. I'd advise you not to try and copy the networking decisions of the mid-90s (eg. fixed message sizes, everything done via separate packets written with fread/fwrite, etc) because there's no need.

Advertisement

Thanks for the reply!

So you suggest to combine movement packets for multiple units into one packet and not send anything that involves selection across the network? My initial feeling was also that it is weird to communicate selections to other clients, but then I found some resources that suggested otherwise. But maybe those people had a solution for 20 years ago :)

Fat Mole and [s]quaredrop, our mobile games for iOS and Android

There might be scenarios where selections are relevant to other players. Age of Empires allowed a cooperative mode where 2 players could control 1 empire, and being able to see that your partner was controlling a unit would be useful. But if you don't need it, don't implement it.

I don't see any reason why you shouldn't send instructions about multiple units in one message. Your send and receive code might become a tiny bit more complex, that's all.

The only thing I have to deal with for packet size is MTU, right?

Fat Mole and [s]quaredrop, our mobile games for iOS and Android

Perhaps, but it's probably easier to use a networking layer that will handle that for you, unless you have a good reason to roll your own.

Advertisement

I once reversed a game that did this for movement of monsters (which is basically the same)

- Game loop

- Loop through all monsters and if a monster moved, save this location in a list of some sort.

- All monster possitions are updated and we've a list

Packet p;

p.WriteInt(MonsterMovement.Size();

for(int i = 0; i < MonsterMovemnts.Size(); i++)

{

// Add monster id, old x,y, new X ,y

// They send old x,y for 'cheaters'

}

SendPacket(p);

I guess this is the best method for a RTS game to.

With regards what is input... As Kylotan said: Input == intent.

With regarding selecting 200 units: You could track which unit a player has selected as:

a) [COMMAND_SELECT_1, id] if one unit is selected ... Easy peasy, 1 unit just store the id.

b) [COMMAND_SELECT, point_a, point_b, frame] ... point_a + point_b describe a bounding box at time frame/timestamp ... Anything in that box during that frame is the selected unit.

Back to communicating intent:

You drag and select 200 units, then click on x300,y400 (the command to move) so you send:

1: [COMMAND_SELECT, point_a, point_b, frame_at_mouse_up] ... Server stores selected units against your server side representation as "selected"

2: [COMMAND_MOVE, x, y, frame]... Server executes a move action on selected units to: [x,y]

That's: 2 small packets that could, in theory move a million units or just one. Sent far enough apart (due to SLOW human input) that they would have little to no impact on even a very congested network.

I'm a newbie myself and here are some blogs I'm following that may help:

http://ithare.com/category/programming/network-programming/

http://gafferongames.com/networking-for-game-programmers/

This topic is closed to new replies.

Advertisement