- Home /
How do you get a seed value from UnityEngine.Random.State?
Random.seed is obsolete but I would like to get an integer value from the current Random.state to tell other players on a network how to seed Random.InitState.
Answer by Mouton · Oct 07, 2019 at 11:18 PM
EDIT
I completely changed my previous answer (which was very poor in explanations and example) since I misunderstood your use case.
Instead of using the clock, get a seed from the game server or the host if you use peer-to-peer communication.
You don't need to extract the internal seed of Unity, and its a bad idea since it won't survive API changes. Instead, send a fixed seed generated by the server. The method InitState
should be portable across Unity version until a major API break change.
public class WebRandom : MonoBehaviour
{
public string SeedUrl;
private IEnumerator Start()
{
// You need to use a token for players connected to the same game
using (UnityWebRequest webRequest = UnityWebRequest.Get(SeedUrl))
{
yield return webRequest.SendWebRequest();
if (!webRequest.isNetworkError)
{
var seed = webRequest.downloadHandler.text;
Random.InitState(seed); // Init the random state with the seed
}
else
{
// ...
}
}
}
}
A more lifetime-proof solution would be to implement your own solution (as @Bunny83 suggest) or use a versioned library so that you have more control on the whole mechanism and the seed initialization won't over Unity versions. Another advantage is that you can use multiple random generators without flipping seeds in the generator.
This isn't quite what I'm looking for, apologies if I worded the question poorly :/ Is there a non-obsolete way to get the seed value from Random after its state has been initialized?
I've updated my answer to be more relevant with your use case. Sorry for the poor answer.
Answer by Bunny83 · Oct 08, 2019 at 01:46 AM
Well the internall state of the pseudo random number generator that Unity uses consists of 4 32 bit integer values. You get them back combined in the State struct when you read Random.state. Unfortunately those 4 values are private values so you can not directly access those. However the struct and its fields is marked as serializable so Unity's serialization logic is able to serialize the State struct. You can use Unity's JsonUtility to convert the current state into a json string and send that over to the other side.
Another solution, which is a bit hacky, would be to extract those 4 32 bit values by creating a "union struct". A union struct allows you to define several member variables to occupy the same memory location. This of course only works properly for value types. However since we only have to deal with structs this should actually work:
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Explicit)]
public struct RandomStateWrapper
{
[FieldOffset(0)] public Random.State state;
[FieldOffset(0)] public uint v0;
[FieldOffset(4)] public uint v1;
[FieldOffset(8)] public uint v2;
[FieldOffset(12)] public uint v3;
public static implicit operator RandomStateWrapper(Random.State aState)
{
return new RandomStateWrapper { state = aState };
}
public static implicit operator Random.State(RandomStateWrapper aState)
{
return aState.state;
}
}
To get access to the 4 uint values you can use this helper struct like this:
RandomStateWrapper data = Random.state;
Debug.Log("Current random state: " + data.v0 + ", "+data.v1 + ", "+data.v2 + ", "+data.v3);
To restore the state from the 4 values, just go the other way round
RandomStateWrapper data = new RandomStateWrapper();
data.v0 = ....;
data.v1 = ....;
data.v2 = ....;
data.v3 = ....;
Random.state = data;
As far as I know Unity currently uses the xorshift+ algorithm or something similar. At least I remember reading a post from a Unity staff member who said that they have switched to xorshift. AFAIK previously they used a mersenne twister variant.
Since we do not have access to their exact source code and they could change the algorithm in the future, it's a bit risky to rely on the built-in PRNG. I've also implemented an xorshift variant (though only 64 bits state instead of 128 bits). Depending on what you need you may want to switch to your own implementation.