First of all, this is my very first post on these forums so yay for that and good day to everybody!
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.
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?
Does anyone have experience with an engine like this? Any common problems? How did you deal with for example float operations?
Hey, and welcome to the forums! Letâs dig right into answering your questions.
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.
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â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.
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.
@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
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.
Well, the thing is that I really dont see how I can not do it!
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.