views:

544

answers:

5

I'm writing a 2D space RTS game in C#. Single player works. Now I want to add some multiplayer functionality. I googled for it and it seems there is only one way to have thousands of units continuously moving without a powerful net connection: send only the commands through the network while running the same simulation at every player.

And now there is a problem the entire engine uses doubles everywhere. And floating point calculations are depends heavily on compiler optimalizations and cpu architecture so it is very hard to keep things syncronized. And it is not grid based at all, and have a simple phisics engine to move the space-ships (space ships have impulse and angular-momentum...). So recoding the entire stuff to use fixed point would be quite cumbersome (but probably the only solution).

So I have 2 options so far:

  • Say bye to the current code and restart from scratch using integers
  • Make the game LAN only where there is enough bandwidth to have 8 players with thousands of units and sending the positions and orientation etc in (almost) every frame...

So I looking for better opinions, (or even tips on migrating the code to fixed-point without messing everything up...)

+1  A: 

Surely all your client will be using the same binary, so compiler optimisations have no effect on synchronisation issues.

Also, if you are only planning on targeting one architecture (or are at least only allowing people to play against each other if they are on the same architecture) then that doesn't matter either.

I've done exactly the same thing using floating points in C# developing games for the iPhone and desktop, and they both give the same results, even though the iPhone is ARM and desktop is x86.

Just make sure the game does exactly the same calculations and you will be fine.

If all else fails, just replace all instances of float in your game to a standard fixed-point arithmetic class. That way you can be 100% sure that your calculations are deterministic across architectures, although the nature of fixed-point arithmetic may adversely effect your game.

Peter Alexander
Even 2 instances of the exact same architecture can have different floating point results, due to things like the FPU control word, CPU instruction reordering based on pipeline usage, etc.
Kylotan
I'm aware that CPU will reorder instructions, but I don't believe that it will reorder the operations of floating point operations in such a way that would break determinism.
Peter Alexander
It read somewhere that floating point operations are not associative (due to rounding), and one bit difference can matter an can cause desync.Even different versions of .NET can have different JIT optimizers which can cause different results. And I just can't ask my users to have .NET 2.0 (because I want it work with Mono on Linux too).So I decided to create a fixed-point class and replace (almost) all double with according to this:http://stackoverflow.com/questions/605124/fixed-point-math-in-c(he probably faced exactly the same problem)
Calmarius
fixed-point arithmetic worked, everything in sync. thx
Calmarius
A: 

A common technique is to have all clients describe their current state to the other clients, periodically.

When two computers disagree about the state of an object, presumably due to floating point error, the game has some rule to determine which is correct, and all clients adjust to match it.

Shmoopty
As he stated in the original post, the game state will consist of thousands of objects, making entire state synchronisation infeasible. I do not know of a single real time strategy game that uses that approach -- they all synchronise by syncing input and ensuring that the simulation is deterministic.
Peter Alexander
A: 

What are you using doubles for specifically? Could you use decimal instead?

Generaly the server would store the state(position/oriantaion/type) of all players units.

When player1 moves a unit either... the instuction to move is sent to the server or... the updated state is sent to the server

When the player client needs to render the scene the server sends back state info on the location of all the units within a requested scope.

runrunraygun
A: 

I've been wondering about this as well.

The "run the simulation on every client, but only broadcast the changes", approach seems to be the most efficient from a network standpoint. But how do you keep the clients in sync?

Did you ever get anywhere with your project?

Matt
I finally banished floating point from my game, and did everything using integers only. Now everything is in sync.
Calmarius
A: 

I'm a little late responding to this, but from a Game Security point of view the simulation should only be running on the server/host (i.e.: don't trust the clients, they could be cheating):

  1. The clients should only be sending their movements/commands to the server (which discards bad inputs or clamps them within game limits, so a client saying "I'm running at 10,000m/s" gets clamped by the server to say 10m/s).

  2. The server/host only tells clients about things happening within their field of view (i.e.: a player at co-ordinates 0,0 doesn't get told about two AIs fighting each other at 200,0 if he can only see a radius of 50 units around him/herself).

It's the second part that saves the bandwidth - the simulation on the server/host may have thousands of objects to manage but the clients only need to know about 100 or 200 things within their own field of view.

The only wrinkle in the situation is things like dynamic fire (bullets, missiles, etc) whose range may be greater than a client's view radius. The server/host tells the clients their origin and initial trajectory/target object, the clients then simulate their path according to the same rules, but the kills are only valid in the simulation on the server/host.

Serializing the client-specific world state and compressing it before transmission can also be a huge win, especially if your class properties are only Public where needed. (I normally avoid XML, but we significantly improved compression ratios in one application by serializing to XML and compressing it versus serializing to a binary format and compressing that. I suspect the limited range of ASCII characters used had a hand in it, YMMV.)

AlwaysLearning