Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

This is a more conceptual, thinking-out-loud question than a technical one. I have a 3D heightmapped terrain as part of a multiplayer RTS that I would like to terraform over a network. The terraforming will be done by units within the gameworld; the player will paint a "target heightmap" that they'd like the current terrain to resemble and units will deform towards that on their own (a la Perimeter).

Given my terrain is 257x257 vertices, the naive approach of sending heights when they change will flood the bandwidth very quickly - updating a quarter of the terrain every second will hit ~66kB/s. This is clearly way too much.

My next thought was to move to a brush-based system, where you send e.g. the centre of a circle, its radius, and some function defining the influence of the brush from the centre going outwards. But even with reliable UDP the "start" and "stop" messages could still be delayed. I guess I could compare timestamps and compensate for this, although it'd likely mean that clients would deform verts too much on their local simulations and then have to smooth them back to the correct heights. I could also send absolute vert heights in the "start" and "stop" messages to guarantee correct data on the clients.

Alternatively I could treat brushes in a similar way to units, and do the standard position + velocity + client-side prediction jazz on them, with the added stipulation that they deform terrain within a certain radius around them. The server could then intermittently do a pass and send (a subset of) recently updated verts to clients as and when there's bandwidth to spare.

Any other suggestions, or indications that I'm on the right (or wrong!) track with any of these ideas would be greatly appreciated.

share|improve this question
add comment

2 Answers

I don't know why you think you should use UDP. A RTS or similar can benefit from running the simulation consistently on all nodes, which means that the ordering of messages is vital to avoid going out of sync. This means that you need to essentially do everything that TCP does anyway, so using UDP is not necessary.

So you'd typically have the stream being a sequence of commands. Or rather, a stream of "tick" messages each containing a command-list. The command-list would be executed, in sequence, by each node playing the game (and the server). Provided the simulation is deterministic, nobody would be out of sync.

You can certainly extend that to a height map modification. So for example, you have a type of unit which has a command called "do some terraforming", in which they modify the map in a specific way, over the subsequent ticks. No data need be transferred at all except for the initial command, as the consistent simulations on each node will take care of terraforming their own height maps in a completely consistent way.

Note that to do this kind of approach, the player's actions (clicking widgets in the UI which have some effect, or commanding individual units / groups of units) need to be sent to the server, NOT EXECUTED LOCALLY. The server will then receive them at some point, and insert them into the tick-stream at an appropriate point, at which point they then take effect.

But as RTS are basically not very time critical, this won't matter in the slightest. The player will hardly notice any lag.


This is possibly not the only strategy for running a simulation game, but it is one which has been used by several games and works pretty well (if your code is bug-free).

In summary:

  • Each client starts with a consistent world view, which they download from the server as a bulk download when they connect or at the start of the game
  • Simulation happens in a series of ticks, which are fixed-timestep and completely deterministic ("random" events need to be pseudorandom seeded in a consistent way on all clients)
  • The client only ever sends commands which change behaviour or carry out actions to the server; it does not execute them locally.
  • The server sends a sequence of commands per tick to each client, in the order it expects to execute them, and also executes them locally.

You can use TCP for this, because it's extremely dependent on the reliable, in-order delivery of messages, which is what TCP works well at.

This system sends very little data over the network, because the amount of data generated by a player is essentially limited by how much they can click the mouse (or whatever), NOT how many tanks, troops etc, they have.

No messages change hands to indicate that a unit who was already doing something, is continuing. Or indeed, anything which happens autonomously. Entire battles can take place without a single message (except "tick" timestamps) changing hands (assuming all the players are happy to sit back and watch).

share|improve this answer
1  
The canonical article on this is here: gamasutra.com/view/feature/3094/… It's a very instructive read. I don't know how SE etiquette works here. This is good advice, in that it's the best way to do things if you're just starting off. But it's not the answer to the question I asked, which was specifically limited to UDP, and while it's been food for thought, I'm not sure whether how much the answer to "How do I do x?" can reasonably be "don't". Do I accept it? –  Floomi Dec 30 '10 at 12:18
    
"Don't do X, do Y instead" unless the question is specifically meant to exclude Y (e.g. if you need to use an OS without a TCP stack), is a fine answer to accept. If it makes you uneasy, you can also change the title of the question to remove "UDP". –  user744 Dec 30 '10 at 13:06
    
Sorry if my answer didn't answer the question very well, I think that it is an approach worth considering though. –  MarkR Dec 30 '10 at 14:26
add comment

Regarding the data you are sending, you could "pack" data together since all you need to send is the new height and the index of the vertex in the buffer, you could pack both of these in an int or a long depending on the max/min values of the vertex positions. Still, that won't solve the problem, since, even if you are sending less data, you are still sending data that may not get to the client side, so would need a way to reliably send the data over but without killing the bandwidth. IMHO using client side prediction with you "brush-based system, is a good idea, that way you can send less data, less often.

share|improve this answer
1  
A short is indeed large enough for me to specify the vertex and the height is also a short, so I've packed the data as small as I can. That's what I based my figure of 66kB/s on, at least. –  Floomi Dec 29 '10 at 0:14
    
You can also use a binary protocol as opposed to a text protocol for the data sent over the network, even though that's a pretty obvious one. –  dotminic Dec 29 '10 at 0:19
    
-1, Do the math. A two byte height plus a two byte index sent as binary for a quarter of the map still results in 64kbps, which is the same result Floomi gave in the question. –  user744 Dec 30 '10 at 13:03
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.