RNG Session

Introduction

In a deterministic setting, the output will always be the same given the same input. However, there are some situations where one would want to introduce some randomness to simulate the effects of unpredictable events or to provide some degree of variability to a system. Random number generators, also known as RNGs, are an important component in achieving this inside of Quantum.

RNGSession

Quantum provides the developer with RNGSession. This can be used in the simulation to generate pseudorandom numbers deterministically. The frame globals come preloaded with a global session. A session will ALWAYS produce the same sequence of numbers unless seeded differently.

Usage:


// inside of a system
public override void OnInit(Frame f)
{
    int randomNum = f.Global->RngSession.Next(0, 100);
}

The session found in globals is seeded with the runtime config Seed field. By default this number will never change. An example on how to set it is as follows:


// inside of unity, prior to starting quantum
public void SetSeed(RuntimeConfig config)
{
    // set seed to a random integer
    config.Seed = UnityEngine.Random.Range(int.MinValue, int.MaxValue);
}

In Quantum's default scripts, the seed can be set in the UIRoom script. When running in local debug mode, it can be modified in the QuantumRunnerLocalDebug script.

Changing Seed at Runtime

If required, the seed can be changed at runtime by overwriting the session with a new one. Example:


// inside of simulation
public void ResetSeed(Frame frame)
{
    int newSeed = 100;
    frame.Global->RngSession = new Photon.Deterministic.RNGSession(newSeed);
}

This can be useful in some cases, such as frequently resetting the session in order to make the generation even more unpredictable.

Component Usage

In development, it may be favorable to have your RNG on a per-component basis, instead of just using the global session. This could be useful for having each entity behave slightly differently, for example; having plants in a farming game grow at different intervals instead of all at the same time.

// DSL component
component MyComponent
{
    RNGSession Session;
}

You can also set the seed in the same way as the global session:

public void InitComponentWithSeed(MyComponent* component)
{
    int newSeed = 100;
    component->Session = new RNGSession(newSeed);
}

Avoiding Prediction Issues

Having the RNG on a per component basis also guarantees culling will not affect the final positions of predicted entities unless the rollback actually required it.

for more information, see: Avoiding RNG Issues

Cheating

Due to the nature of determinism, predicting randomness is quite trivial. For example, a hacker could read the simulation locally, then duplicate the RNGSession outside of the simulation and know the given sequence of numbers before anyone else. A common way to combat this is to frequently reset the seed to a number that cannot be easily predicted. For example, you could hash the player's input and use the result as the seed. This makes it very hard for anyone to control OR predict what the seed will be.

기술 문서 TOP으로 돌아가기