Sign in to follow this  

Terraforming over UDP

This topic is 2521 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi,

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.

Thanks!

Share this post


Link to post
Share on other sites
Your solution will work, but like all methods that involve the use of time and sending information over a network, you must have intermittent periods where you re sync everyone. The reason is because you have very small differences due to imprecision in the timestamps and other truncation that occurs. So, after a while you could have big differences in the terrain.

Also note, this will only work for users who are logged in to receive the updates. Those who log on after a change has occurred must download all of the changes previous users have made. Which makes me think you should do something where you have a 64 x 64 grid with a timestamps that holds the last time the patch was updated. When the user moves around in the world, he or she compares timestamps, if they are different, then the user downloads the entire patch.

This way, you dont need to hold an accumulation buffer of the changes that each user has made to the terrain. I would assume that after a long period of time, the number of people who have changed the same terrain might become rather large and storing all these modifications will require a large amount of ram.

Share this post


Link to post
Share on other sites
How persistent is your game? Does it support late joiners?

If it's an RTS, then sending unit commands using TCP, timestamped for the tick at which they take effect, is sufficient, and very efficient. See the "1,500 archers" article about Age of Empires networking, linked from the Forum FAQ.

If you support late joiners and persistency, then you have to cache the last-known state locally, and then send the delta applied since then. Each modification can have a serial number server-side, which increments monotonically. Save chunks of data, say 4x4 or 8x8, and store the last-changed serial number, to easily calculate what needs to be updated.

Also, your game design might want to take network constraints into consideration. If you can't support terraforming more than N samples per second, then implement game mechanics that prevent terraforming from happening more than N samples per second. Also, gradual changes can be sent as a single command -- between time A and time B, change the height from C to D. Each client can then calculate what it's supposed to be at a particular time step. This saves a lot of bandwidth compared to sending each changed sample each timestep as it changes.

Share this post


Link to post
Share on other sites
Quote:
How persistent is your game? Does it support late joiners?
It's not something that's crossed my mind; I don't see what advantage there'd be in supporting it. Probably not.

Quote:
See the "1,500 archers" article about Age of Empires networking, linked from the Forum FAQ.
I have read both the article and the FAQ. Unless I'm misunderstanding your point, I'm not sure it bears relevance to my question, which wasn't about how to send unit commands.

Quote:
Also, gradual changes can be sent as a single command -- between time A and time B, change the height from C to D. Each client can then calculate what it's supposed to be at a particular time step. This saves a lot of bandwidth compared to sending each changed sample each timestep as it changes.
That's the idea behind using brushes - it abstracts away sending the height of specific verts in favour of a more abstract concept that defines the velocity of multiple verts far more concisely.

Share this post


Link to post
Share on other sites
Quote:
Original post by Floomi
I have read both the article and the FAQ. Unless I'm misunderstanding your point, I'm not sure it bears relevance to my question, which wasn't about how to send unit commands.


But "change terrain" is a unit command. Or better yet, unless this is some collaborative (collaborative anything is all the rage these days) editor, users will not be editing terrain. They will perform actions which result in terrain deformation.

For example, when artillery fires, effects on terrain are deterministic and can be calculated from that alone. But even free form can be trivially implemented using such system - just send actions that modify the heightmap (raise x,y,r by z) or similar.

Precision can be solved fairly trivially by representing heightmap using integers. Each user keeps local heightmap and builds mesh as needed. This eliminates the floating point precision problem.

Despite seemingly large amounts of data, the actual entropy of change is defined by user input. So if some action is performed using a mouse click, the total amount of information that needs to be shared is the x and y coordinate of the click. Everything else can be computed from that independently by each client.

The communication, ordering and timing doesn't come into play here, since it's solved in same way as all other networking.

Share this post


Link to post
Share on other sites
Quote:
But "change terrain" is a unit command.
No, not really. Perhaps I didn't make it clear enough in my initial post: specifying the target heightmap and assigning "worker" units to deform the current terrain towards it are two separate actions. Once a unit has been assigned as a worker, it will make its own decision regarding which area to deform.

Quote:
Despite seemingly large amounts of data, the actual entropy of change is defined by user input. So if some action is performed using a mouse click, the total amount of information that needs to be shared is the x and y coordinate of the click. Everything else can be computed from that independently by each client.
This would only be possible if the client's local state was identical to the server's; otherwise, a worker unit would be liable to make a different decision on the client as to which area to move to and deform than on the server.

Avoiding this is the reason a) the server is authoritative, b) I want to decouple the act of modifying terrain from the unit that's doing it. I don't believe in simulating AI on the clients; that way lies madness.

Share this post


Link to post
Share on other sites
haven't read more than the first 2.5 posts...
instead of sending a start/stop signal for the terrain elevation brush, couldn't you just send the start signal and imply the stop, e.g. elevation is added for 1 second. meaning a change in elevation would be an easily calculatable change to the terrain and not based on time. you would also not have to synchronize terrain altered by millisecond, but by seconds and it would probably not be so terrible if it were out of sync by milliseconds.

Share this post


Link to post
Share on other sites
Quote:
Original post by Floomi
Quote:
But "change terrain" is a unit command.
No, not really. Perhaps I didn't make it clear enough in my initial post: specifying the target heightmap and assigning "worker" units to deform the current terrain towards it are two separate actions. Once a unit has been assigned as a worker, it will make its own decision regarding which area to deform.


That unit command is perfectly predictable once it starts. Everyone can simulate that in sync. Thus, you only need to send the unit command, not the output of that command. That's the whole idea behind the AoE article, which is why I recommended you read it.

Quote:
Avoiding this is the reason a) the server is authoritative, b) I want to decouple the act of modifying terrain from the unit that's doing it. I don't believe in simulating AI on the clients; that way lies madness.


You are making assumptions I'm not sure I follow here.

1) Yes, the server is authoritative. That doesn't mean that you can't make everyone else calculate exactly the same outcome, given the same input data. In effect, anyone trying to cheat will get a different outcome, and thus will de-sync. You can detect de-sync with occasional, cheap checksums, and kick anyone that's out of sync with the server.

2) Why is simulating AI on the clients as well as the server a problem? It's the exact same code, working on the exact same data.

Share this post


Link to post
Share on other sites
I agree. I think you have not understood the 1500 Archers article if you don't see how this is related to unit commands. As long as your simulation is deterministic, including generating the same pseudo-random numbers based on the same seeds, the rest should "just work". There's no need to worry about individual details like this if you set it up like that.

- Sean

Share this post


Link to post
Share on other sites

This topic is 2521 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this