Deterministic RTS game engine

First of all, this is my very first post on these forums so yay for that and good day to everybody! :smile:

Secondly, as the title suggests I am working on a RTS game, using obviously the unity engine. It is my first attempt at making a game with the engine, but I have programmed in c# before and I study computer science, so the coding is not my biggest concern. What really concerns me is how to implement a working multiplayer mode (the game wont even have much of a singleplayer part). This is why I turn to you guys.

  1. I know the “state of the art” method for RTS games is to create a deterministic game engine, synchronize all players and their input and send only the input over the network, hoping that since everything is deterministic everyone will end up with the same game state.
    Is this concept applicable to the unity engine? Can everything be determinstic? What about for example the Physics?

  2. Does anyone have experience with an engine like this? Any common problems? How did you deal with for example float operations?

Thanks!
Greetings,
Obat

Hey, and welcome to the forums! Let’s dig right into answering your questions.

  1. It’s not so much state of the art as the only way to do it properly, I think there is one single RTS game in the past ten years or so that has not done it this way. You can apply this concept to unity, but you’re going to have to take a few things into consideration. First up is the physics engine, unitys engine is not deterministic which means you will be limited to use physics for “eye candy”, but this is not as big as you think as most RTS games rarely use physics for anything else.

  2. The common problem is really the solution also, making sure that everything stays in sync. It’s incredibly difficult, small things can go wrong and the end result/problem wont show up til much later. It’s sort of like chaos theory, a single small event can have huge impact on the game eventually.

There are ways to make floating point math deterministic, but I think the tricks you need to use are things which are not available in C#. There are other ways to get deterministic fractional math which is accurate enough though, it’s just a lot of of work.

I would recommend you to read the incredibly famous “1500 Archers” article on gamasutra: 1500 Archers on a 28.8: Network Programming in Age of Empires and Beyond

I’ve had some … uh … fun… handling these problems in my own RTS project.

fholm is right in that we are missing some key things to get absolutely deterministic behavior in Unity/C#, but… as I’ve found out, all hope isn’t lost.

Some easy things I do is delaying RPC calls in a staggered manner, which ensures that all computers roughly start an action at the same time.

I also key in a lot more information than just user input. Various points in time, states are also synchronized for units (ie: unit is beginning casting, shooting, etc). This, however, means that I’m sending in a lot more information. Luckily, I’m not programming for 56k dialup connections, and thus can afford to use significantly more bandwidth to exchange extra state information on a per-entity basis.

I’m not going to get 1500 archers, but I think I can squeeze out 100 units, which is enough… for now. :slight_smile:

andorov: Maybe I was unclear in my response, nothing is really missing in Unity. You have everything you need for deterministic math and honestly physics are mostly for eye candy.

Thanks for the fast replies!

@fholm: I actually stumbled upon that link a few minutes ago, although quite old not much seems to have changed. I will use that as my goto for now.

@andorov: Great to see that it “can” work! Some technical questions: Do you limit the framerate to the fps of the weakest member of the game? Or just fix it to something everyone can manage? Also, can this be done with the TimeManager of Unity or do I have to control it myself?
Out of curiosity: Have you added replays to your game? That shouldnt be a problem once the deterministic stuff is done, right?

You should not limit the FPS itself, this should not be needed on today’s computers (as they are more then fast enough). Rendering (FPS) and simulation (input/network logic) should be separate.

I don’t FPS rate my project, but its interesting to note that Starcraft 2 does FPS-limit players if one can’t keep up. Also, I have not added replays to my project, and have little desire to do so at this point in time.

[quote=“andorov, post:7, topic: 467205, username:andorov”]
that Starcraft 2 does FPS-limit.
[/quote]This is not completely true, star craft 2 will stop the simulation due to there being no input from the other player, but this has nothing to do with FPS limiting. It looks like you get “fps drops”, but this is really not it, they just freeze the simulation as there is no more input.

Hmm do you think I could use the FixedUpdate Function for my logic network updates? That should make sure that all players have the same amount of update cycles, right?

[quote=“anon_47683047, post:9, topic: 467205, username:anon_47683047”]
Hmm do you think I could use the FixedUpdate Function for my logic network updates? That should make sure that all players have the same amount of update cycles, right?
[/quote]Hm, in theory it might seem fine, but the reality is that it becomes a lot more complex , so I would advice against this.

I can write you a better explanation then “don’t do this” tomorrow, gotta take care of the wife now :slight_smile:

I remember asking x4000 (from Arcen Games) about it, his AI Wars game is a full deterministic multiplayer game which he ported to unity. I believe he mentioned he was using fixed update to run the game simulation. My understanding is that game commands are scheduled for a future game update tick, and if clients haven’t reported their commands (or lack of commands) by the time it comes to execute that tick, the simulation pauses until everyone has caught up. Each game update only occurs every 200ms or so (though you can actively adjust it). That means there’s a delay from when you execute commands and when the game responds, but realistically in an RTS you don’t really notice that kind of thing.

As Obatztrara suggests I think you can do it in fixed update but you can’t simply rely on everyone running the same number of fixed updates as everyone else, you’ll have to manually time the simulation to make sure the different clients are running commands at the right times. If someone’s computer is running too slow to meet the current simulation requirements you have to handle the result gracefully rather than desyncing.

[quote=“fholm, post:8, topic: 467205, username:fholm”]
This is not completely true, star craft 2 will stop the simulation due to there being no input from the other player, but this has nothing to do with FPS limiting. It looks like you get “fps drops”, but this is really not it, they just freeze the simulation as there is no more input.
[/quote]If one user is under heavy lag, the game prompts the rest with something like “XYZ is slowing down the game,” and the simulation of the game won’t stop, but it will slow down. I don’t believe its limiting frames drawn per second, so I suppose its incorrect to say its limiting FPS, but Its definitely running the simulation loops slower.

The simulation “slowing” down is exactly what I was talking about, it will not slow down the FPS at all (your game will still render at whatever FPS your computer can squeeze out) - but the simulation will halt/run slower. It will look as if the game is “choppy” as it’s not running in full real time due to the slower player. Slowing down the simulation and halting it is pretty much the same thing, if the halting is short enough it will look as if the game “stutters” which is basically what low FPS looks like, so people mix the concepts together.

@fholm: Looking forward to your explanation, for now I kinda feel like doing it with the FixedUpdate - especially after what Doddler wrote. I can see how there could be a problem in the following scenario though: Lets say my simulation would run at 10 fps (with the graphics as fast as whatever users machine can handle). This forces me to run the physics at 10 fps as well, so if I should ever decide to seriously use them I might be in trouble - since 10fps physics will look very awkward…

@Doddler: Good to know other people have done this. Thanks for your reply. Of course i would also track the current update number. Packages over the network would probably consist of the input and (currentSimulationCycle + 2) (or so). This would indicate when to run a certain command.

Thank you for starting this thread; I’ve been interested in the problem as well. In fact, I’d be surprised if it hasn’t been solved several times as well. Does anyone know of any reference implementations we can look at?

Also, I have a related question.

It makes sense to me to, say, run the simulation at 10Hz while letting people run their graphics at any speed they want. This way people stay in sync.

But doesn’t that mean that all the gameplay-relevant actors will tick forward at 10Hz, even if the game is re-rendering at 60Hz? I remember this happening back in the Quake 1 days. People would snap through space tick by tick.

I can imagine how to solve this with some sort of local interpolation, but that sounds very complicated and difficult.

Well, I guess nothing keeps you from implementing different speeds for different aspects of your game: You could run the Input/Network part at 10Hz, the GameLogic/Movement/Whatever at 30Hz and the graphics at whatever speed is possible. That shouldnt break the deterministic part, or am I missing something?

You know, now that I thought about it a bit more, this makes sense.

You could run the simulation at 30Hz, which is fast enough to look good. Perhaps camera, particles, and animations would run faster.

For netplay to work you don’t have to run at some really low refresh rate. All that matters is how far in the future you schedule the application of input commands. So you could schedule them 5/30 of a second in the future. As long as your ping is less than that, the game works. The actual update rate of the local sim doesn’t matter.

My [condensed] thoughts regarding deterministic engine:

Don’t do it!

You cannot use the special flags that force FPM to be deterministic.

Fixed point maths, at least in my experiments, will give you errors on the simplest things due to rounding. E.g. Divide by 0 exceptions.

Exceptions

Possibly using C++ plugins for FPM.

Game mechanics that can be written exclusively with integer math.

Well, the thing is that I really dont see how I can not do it! :stuck_out_tongue:

It seems to be the only legit approach to RTS multiplayer games. But yeah, it will probably come down to loosing float precision in favor of less precise integer approximations.

Also, noobish question: What does FPM mean. Sigh My only excuse is that I started last week.

Progress Update:

  • Input and GameLogic now run at 10 Hz
  • GameObject Logic runs at 50Hz (To prevent movement from being jerky)
  • Graphics run at maximum speed

All the frequency values can be changed easily at any time.

Fixed point math.

He just abbreviated it.