Skip to main content
GameDev.net gamedev.net
🔒 Locked

RTS netcode questions?

Started by Jasongame Jul 31, 2011 at 2:25 PM 6 replies 3.7k views
Original Post
Jasongame
Jasongame
Hi Iam working on an RTS game, and I have some questions about RTS netcode optimization. i've read the Gamasutra 1500 Archers article, which I will be basing my basic model on. It seems pretty straight forward, that all clients run a 100% deterministic simulation, with only transmitting non-deterministic player input etc.

However there is one bit I dont 100% understand, and that is the "Speed Control" part.
So the Host gathers 2 sets of data from each player: 'Ping' and an "Avarage FPS".
As far as I understand, it finds the largest ping, and then basically incrementally increases the "communication turn length" to be the same as the largest ping. So you get more "frames per Turn". Which is still more or less clear.

The area I really dont understand, is the "Avarage FPS" data, i dont understand how that is used? In the article it seems to suggest that each players "FPS" is also changed somehow, to the slowest avarage FPS??? I really dont understand whats the point of that?. And why would that improve the overall smoothess of the game for the other players? IE if the game runs on a Time-based loop, just because the FPS of one player is lower than the rest, it still wouldnt affect the rest right? The player with the slow computer would just have jagged gameplay, but would still have to keep the pace of the game, as everything is time based ?? (IE if it takes 5 seconds for a projectile to reach its destination, then it doesnt matter if your framerate is 5 or 50, it will still take 5 seconds in a time based gameloop?)

I've done some of research on this, and most other online references about RTS lock-step simulation only ever make references to changing the communication turn lengths, and never the FPS.. so I am a bit at loss with whats going on

Any ideas?

Jason

PS: Also a bit clueless, what happens if I would change the FPS as well as the Communication Turn at the same time, as if i Have an FPS of 30 with communication Length of 15 framesPerTurn, that equals to 2 Turns per second. however If I change the FPS, to maybe 15, that would mean that I get 1 communication turn per second already, without having to change the communication turn length directly...
hplus0603
hplus0603

However there is one bit I dont 100% understand, and that is the "Speed Control" part.


It's been a while since I read that article, so I don't remember that part perfectly. However, I would probably just implement implicit speed control.
Set a rate X. X times a second, a client needs to send its commands to the server, X times per second, the client needs to receive commands from server, and X times per second, the client needs to update simulation.

Now, your game loop becomes something like:


forever:
render a frame of graphics
if it's time for another command frame to be sent, send commands for command turn C to server, and increment C
if all-players commands form server has been received for turn T, simulate turn T and increment T
read commands and enqueue them for the next command turn


Note that this doesn't need to know anything about the round-trip latency or "speed" -- there is a fixed simulation speed. If some client just can't keep up, the server can detect this by the client not sending commands in time for the turn, and when it falls enough behind, it can be kicked, or perhaps the rate X can be adjusted.

The server loop looks something like:


forever:
receive commands for turn T
when all clients have sent commands for turn T, send all commands to all players for turn T and increment T
(optionally) simulate the game at turn T if I just sent commands for that turn


Note that server simulation is optional, assuming that all clients will stay in sync and you don't need to detect who "won" server-side.

Now, you can also make the speed of the game be automatically adjusted, by saying that C (the turn for which clients send commands) is fixed at T + V for some value V. However, at that point, you have to make sure that T doesn't increase faster than real time if everyone has low-ping connections and fast machines :-) This throttling can (and should) be done on the server, so there's one clock that drives the evolution of the turn/step count.
enum Bool { True, False, FileNotFound };
Jasongame
Jasongame
Thanks for the quick reply hplus0603 !
Although I think you misunderstood my question.

In the 1500 archers article, 2 sources of lag are identified, which both result in a delayed communication turn response, however they happen for 2 different reasons:

1) Lag in internet connection
2) Lag in game state updating ( slow computer)

What you seem to describe is Case (1), where there is an bad internet latency. By adjusting the Communication turn lengths, yes you can fix that, players will be able to have less input on the simulation but it will run smoothly. This part I am quite sure now how to do now.

However you cannot fix a slow computer with longer turns, as even if a communication turn is set to be 1000milisecs, the slow computer will get there later regardless, not due to a slow internet connection, but simply due to not being able to keep up the simulation. So no matter how long you set the communication turns, it will Always be behind, as the source of the lag is not the network latency, but a slow processor. At least this is what I understood from that article.

This is the area which isnt 100% clear, and no other tutorial or forum discussions seem to be addressing the delay caused by a slow computer, and low framerate, they all seem to be addressing the issue of a lag in network speed, which you just described.

I kept thinking about this today, and I come up with that the reason why this could be happening, as the Time Steps, for multiplayer RTS, must be fixed in length, so even if your computer is slow and would be "dropping frames" to keep up, it cant really drop anything as that would desync the whole simulation, so if a timestep is maybe 20milisecs, and a communication turn is 100milisecs, it needs to do 100/20 = 5 steps each turn, and if it cant do all 5 steps in 100milisecs, it cant just jump ahead and calculate the final state in 100 milisecs in the future, as that could desync it. It Always has to calculate every single 20 milisecs step to get an identical result as the rest of the players, and until it performs all these steps, it cannot send its "END_TURN" message, which is the source of the lag...

And the only way to fix that client perpetually falling behind and holding up the game for everyone else, if you increased the gameloop's "Time Step" length for all players, so that the slow player has to do less calculations and be able to keep the pace, and the rest of the players can keep in sync with the changed timestep... Im kindof answering my own question here, but im really not 100% sure about this, maybe i totally misunderstood something!
hplus0603
hplus0603

Thanks for the quick reply hplus0603 !
Although I think you misunderstood my question.



1) Lag in internet connection
2) Lag in game state updating ( slow computer)


The simplest implementation of my proposal would make it so that, if one client falls behind (CPU lag), all clients will be running slower.
The reason is that:
- the server doesn't step step T until all input is available for that step
- the clients won't update/display step T until they've gotten the data from the server
If you update the step at which you want players to submit commands at the same time as you update the step you're simulating (say, you always make the delta be 5 steps) then this will automatically throttle back the step rate when slow clients connect.

At the top level, you have two options to deal with slow clients:
1) slow everyone down
2) detect the slow client, and kick it out of the game

To do 2), you simply check the wall clock time when each client submits their commands, and if some client is more than X milliseconds behind for more than Y steps, then you say that it's too slow.
enum Bool { True, False, FileNotFound };
Jasongame
Jasongame
Sorry, maybe Im really not following you, but wouldn't your solution mean that the rest of the clients would have a "stop and start" type of game?

Process game up until they can, then stop entirely, wait for the "slow player", and then do another turn, and then "freeze" the game until the lagging computer catches up?


I though that the goal in the 1500 archers article was, that the gameplay is running continuously, ie smoothly without abrupt stops and then waiting, and then going, only to stop again ?
hplus0603
hplus0603

Sorry, maybe Im really not following you, but wouldn't your solution mean that the rest of the clients would have a "stop and start" type of game?


Not really. Personally, I think you should kick slow players :-)
However, if you don't, then the elasticity will reach whatever limit you've imposed, and then each time the slowest machine completes one tick, everyone will advance by one tick.
It may be jerky if there is jitter on the network. In general, though, you want to hide all that through a totally de-coupled rendering/animation frame rate.
enum Bool { True, False, FileNotFound };
Jasongame
Jasongame
Since my last post I have managed to implement the working system and it seems OK so far.

One thing that occured to me, only really after having an actual running system, and having played a few matches against people with various Pings is that according to the "lock step model", you do stuff
on turn 1, and execute those commands on turn 3.

And each turn maybe is 200ms in length ideally. Which will mean that if you try to place a unit on the map, and click, even if you have the lowest possible ping, it will still be 600ms before anything happes?
(ignoring latency masking techniques for now)

I recall that article said that players were having great fun and "500ms was very playable", as they put it. But that would mean if they do anything, it will be 1500ms, that is 1,5 secs before anything actually happens? Or was there something I missed, that they try to execute commands somehow sooner or I dunno, it just seems weird playing with an 1500ms lag. Or maybe back in good ol' 2001 that was still considered "acceptable"?

What do you think?
hplus0603
hplus0603

And each turn maybe is 200ms in length ideally. Which will mean that if you try to place a unit on the map, and click, even if you have the lowest possible ping, it will still be 600ms before anything happes?
(ignoring latency masking techniques for now)


Yes. However, "ignoring latency masking techniques" is not very useful, because RTS UI is _all_ about latency masking. Why do you think every unit plays a 600 millisecond "yes, sir!" animation before doing anything when you give it an order?

Also, your tick rate should be fixed -- say, 100 ms tick rate. The number of ticks into the future that you queue commands can vary. Thus, if your RTT is 600 ms, then you will queue commands for 6 ticks into the future.

So, on turn 100, the local player gives a "build building" command to a grunt.
On turn 100, the machine sends the "start building on turn 106" command to the server.
On turn 100, the grunt starts playing the "yes, sir!" animation.
On turn 103, the "start building on turn 106" command makes it to the server and gets echoed to other players. (The server can actually simulate at turn 106 at this point!)
On turn 105, the "yes, sir!" animation stops, if it's 500 ms in length. There is a 100 ms pause in visible animation at this point. Longer animations can hide more latency.
On turn 106, the "start building on turn 106" has made it out to all clients, and all clients run this command as part of the simulation. The grunt starts moving on the map.
enum Bool { True, False, FileNotFound };

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.