Random.seed - how consistent is it across systems/platforms?

I am working on a multiplayer game that generates a game board based on a seed, and I need to do validations on the server as well so the game board needs to be synchronized.

If I set Random.seed to 123 on the server, would it produce the same results on all platforms (win/android/ios/etc) and all systems (my PC vs someone else’s PC)? I’m not sure how it works, and that info isn’t documented.

As far as I know. Yes.

You could also use the one in Mono (System.Random) which also is the same for all the mono platforms (I can’t guarantee that for iOS as I don’t have experience with compiling to that, but I’d assume Xamarin would maintain consistency).

Personally, I would use the one in Mono because you can instance out your random number generators. That way if you say use one for generating the map, no other script that also uses it happens to steal a call to Random knocking the sequence out of whack.

Thanks

My game is a grid-style turn-based mobile multiplayer game. For network performance reasons, I would like to be able to have the server simply send the seed to the client, rather than to have to send information about the entire game board to each client (the game board changes often). So my plan was to duplicate the procedural generation of the game board on both the client (for gameplay) and server (for validation/anti-cheat). I just wanted to make sure that if the server sent seed 123 to each client, the game would be synced properly across the board.

It would, as long as the sequence of calls to Random are the same as well. Using System.Random can help control that better, as it’s not a static class like UnityEngine.Random.

Can you elaborate on the “sequence of calls”? Does that sequence begin the moment you first set the seed, and each subsequent call alters the results? If so, if you reset the seed with the same seed number, would it revert back to the very first pseudo-random result on that seed?

How often? Why don’t you want to generate the random number on the server and send it to all clients every move? I think there wouldn’t be any critical performance issues for turn-based game.

I just don’t want to have to send information about every individual grid tile to every connected client. If I can just send the seed itself, and let each client deal with generating the board, that would easily be a reduction of like 1000% in network usage, even if the overall data transmission is still small in both cases.

My reasoning behind this is more for scaling reasons. If the game were to somehow miraculously become popular, all of that data adds up.

10000 8-byte seeds/second = 80KB/second

10000 requests for the entire board at ~8KB/sec = 80MB/second

That’s a difference bettween ISDN and gigabit fiber :). I doubt it would ever reach that kind of scale, but I want to keep the “just in case” in mind. Even if it’s not very popular, I’d like to keep high performance in mind.

Ok, look at this link: How do I generate a "random" number from a seed? - Questions & Answers - Unity Discussions

So, I’m going to describe this with System.Random instead of UnityEngine.Random, becuase it’s interface is better at describing what’s going on. With that said, whenever you call any of the methods that get random values on UnityEngine.Random, it is like calling System.Random.Next.

This is System.Random:
https://msdn.microsoft.com/en-us/library/system.random(v=vs.110).aspx

How random number generators work, it uses a special algorithm (like a Mersenne Twister) that generates a value from the previous value that has equal odds across the entire range of values that can be returned. In the case of System.Random it’s a value from 0 to Int.MaxValue. A float/double between 0->1 is calculated merely as that value in the sequence divided by Int.MaxValue.

This means that every value in the sequence is dependent on the previous value.

This means that the sequence must have a FIRST value. This value is called the ‘seed’.

Every time you call ‘Next’ it performs this algorithm on the last generated value (or seed if it’s the first call) to get the next value.

This is what I mean by “sequence of calls”.

So… if I seed a Random with some value, I’m guaranteed the SAME sequence. Sequences… are sequential. They’re in order.

So… if I generate 10 random tiles as 10 calls to Random.Next (or UnityEngine.Random.value), the 10 tiles in a row will be generate via the same sequence of numbers.

Problem arises if in the middle of that sequence some other piece of code ALSO calls Next to generate some other thing… maybe the position of the start point. Now in Unity, depending how you set up scripts, the order of these scripts may or may not be guaranteed from system to system. So what if one machine generates this random position between the 3 and 4 tile generation. And another does it between the 7 and 10 (this might happen just due to bad design… maybe you use coroutines to generate a couple tiles per frame. I don’t know… there’s all sorts of reasons this might happen).

Your system has become what’s called ‘indeterminate’.

Because by using the UnityEngine.Random class, because it’s “global”, the ENTIRE system must remain determinant for the sequence to remain determinate.

BUT, if you use System.Random, you create an instance of Random in the scope you want to use it. This means only that scope must remain determinate for the results to be the same every time you do it. By reducing this scope, you make debugging it that much easier.

2 Likes

Ah, that’s really interesting. Thanks.

lordofduct - That was super helpful. Comparing it to Random.next cleared everything up, and I definitely see the benefit of System.Random over UnityEngine.Random now. Thank you very much for writing all that up