Lockstep games - waiting and synching worlds

Started by
14 comments, last by suliman 11 years, 11 months ago
I write my own RNG, they're really trivial to make, unless this RNG must be used for encryption or other sensitive applications, which isn't your case (Google Linear random number generators, or mersene twister rng). The trouble with rand() is that it's one seed for each thread, and you don't trully control what happens inside. Don't forget to seed each properly, and of course, call your rand() equivalent the same number of times on each machine. Writing your own RNG eases you the ability to include debug logs that warns you when a PC called rand() more often that it should.[/quote]
If you mean implement your own MT or LCG (with good parameters), sure, but never (I repeat, never) design your own homemade PRNG unless you really know what you are doing. It's incredibly easy to screw up, even on applications that don't require cryptographic-grade quality. There are many very fast, very good, and very simple PRNG's people have tested and analyzed all over the internet, there is no good reason not to use them (in applications, that is, if you want to roll your own, great but do it separately). This can never be repeated enough.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

Advertisement
The server is supposed to generate random numbers for each client individually and send the numbers to them.[/quote]

For game simulation, this statement does not make sense. For cryptography, "random numbers" are special, and you really, really need to use an entire framework that treats the numbers right, but for game simulation, doing your own RNG is fine and expected. The RNG will be as consistent as any other part of your game simulation. If you run all commands for all users in the same order on all machines, the RNG should end up with the same value. However, you must be careful to not use the same RNG for things like particle systems, random sounds, etc, as you do for simulation. The easiest way to ensure this, is to create your own RNG; either use a linear-congruential (same algorithm as rand()) for simplicity or drop in the Mersenne Twister library for very high quality.
enum Bool { True, False, FileNotFound };

The easiest way to ensure this, is to create your own RNG; either use a linear-congruential (same algorithm as rand()) for simplicity or drop in the Mersenne Twister library for very high quality.

This, is what I said. If you are *implementing* an existing high-quality generator, this is what you should do. What I was saying is that you should not roll your own *algorithm* which is the wrong approach even for games and simulations. "Decent quality" random numbers are needed wherever random numbers are needed. Use a biased algorithm and your simulation will be biased. Use a biased algorithm and your game can be predicted and "feels" nonrandom in the worst of cases. I was just saying this because many people tend to see random number generation as an afterthought and if for some reason they can't use rand, they just cobble together their own which is a massive red flag. This is in particular why you should never pick LCG parameters randomly. They need to be chosen carefully (according to a couple number-theoretic criteria you can find on Wikipedia) to ensure the LCG's period is maximized, otherwise you may well end up with an LCG which repeats every 100 values, or outputs values which are all divisible by the same number, if not worse.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

Hi again
Im struggling to get my lockstep to work (nothing to do with random numbers by the way).

My setup works fine at start but pretty soon it goes unsync and i dont know why. Is there any basic setup in what order to do what, how to lock a turn and wait etc that i can look at becouse ive redone it several times and it always bugs out on me.

Im trying to implement a system where each command is executed two turns later. Its certainly not solid for me... I think to problem might come from if the window is not active (if you drag the window for example) it cannot send/recieve messages which messes up the cue of commands. Might also be other problems. Would be great to see a working setup of the relevant functions and in what order to put them (i know how to send/recieve messages)

Thanks
Erik
First, you want to number each simulation step. Step 1, 2, 3, ...
Second, you want to "tag" each command for what step it should be executed in, when the commands are sent (and then received.)
Third, you should send a "I've sent all commands for step N" message, for each step -- even if there are no commands from you that step.
Fourth, you don't want to actually execute any commands for a step, until you have received all the "step N commands done" messages from all the players.
Fifth, you should sort execution order of the commands in a deterministic order -- specifically, in which order you run commands from different players, because the arrival order may be different on different machines. If you let the server aggregate all the commands, and THEN send out the aggregate commands to all players, this is already done by the server.

So, finally, while you may have executed step 12, the commands you send to the server should be for some future step, to cover round-trip delay. Let's say you send commands 5 step into the future.

Finally, there really isn't necessarily a time-to-step-number relationship. Clients simply execute step N when all the data for step N is available. The server can pace the game so you don't run faster than some particular number of steps per second, but if the latency is too high, all that will happen is that the rate of step execution will go down (play will run slower.) You can detect this and adjust now big you make the command window, if you want.
enum Bool { True, False, FileNotFound };
Now i achieved full sync even when client or server is loosing "activeness" and keeping track of each command by turnID. And random number works fine as well. Im using a random seed at startup of the match given by the server and everyone gets the same randoms from that. Seems to work flawlessly.

Im a happy camper now.
Thanks for your input guys
Erik

This topic is closed to new replies.

Advertisement