RNGセッション
はじめに
決定論的な設定では、同じ入力があれば出力は常に同じになります。しかし、予測不可能な事象の影響をシミュレートしたり、システムに何らかの可変性を与えるために、ランダム性を導入したい状況もあります。乱数ジェネレーターは「RNG」とも呼ばれ、 Quantumの中でこれを実現するための重要なコンポーネントで す。
RNGSession
Quantum は開発者に RNGSession
を提供します。これをシミュレーションで使うと、擬似乱数を決定論的に生成することができます。フレーム globals
にはグローバルセッションがあらかじめ組み込まれています。セッションはシードが異なる場合を除き、常に同じ乱数列を生成します。
使用方法:
C#
// inside of a system
public override void OnInit(Frame f)
{
int randomNum = f.Global->RngSession.Next(0, 100);
}
globals
のセッションはランタイム設定の Seed
フィールドでシードされます。デフォルトでは、この数値は変更さ れません。設定方法の例は以下です:
C#
// 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);
}
Quantum のデフォルトスクリプトでは、シードは UIRoom
スクリプトで設定できます。ローカルデバッグモードで実行する場合は、 QuantumRunnerLocalDebug
スクリプトで変更できます。
実行時にシードを変更する
必要であれば、セッションを新しいもので上書きすることで、実行時にシードを変更することができます。例:
C#
// inside of simulation
public void ResetSeed(Frame frame)
{
int newSeed = 100;
frame.Global->RngSession = new Photon.Deterministic.RNGSession(newSeed);
}
これは、セッションを頻繁にリセットして、生成の予測不可能性を高めるような場合に有効です。
コンポーネントの使用
開発においては、グローバルセッションを使うのではなく、コンポーネントごとにRNGを設定した方が有利かもしれません。これは、例えば、農業ゲームの植物を、すべて同時に成長させるのではなく、異なる間隔で成長させるなど、各エンティティがわずかに異なる振る舞いをするのに便利です。
C#
// DSL component
component MyComponent
{
RNGSession Session;
}
グローバルセッションと同じようにシードを設定することもできます:
C#
public void InitComponentWithSeed(MyComponent* component)
{
int newSeed = 100;
component->Session = new RNGSession(newSeed);
}
予測問題を回避する
コンポーネントごとにRNGを設定することで、ロールバックが実際に必要でない限り、カリングが予測されたエンティティの最終位置に影響を与えないことも保証さ れます。
詳しくは Avoiding RNG Issues を参照してください。
不正行為
決定論の性質上、ランダム性を予測することは非常に困難です。例えば、ハッカーはシミュレーションをローカルで読み、シミュレーションの外でRNGSession
を複製することで、与えられた数列を誰よりも早く知ることができます。これに対抗する一般的な方法は、シードを簡単に予測できないような数値に頻繁にリセットすることです。例えば、プレイヤーの入力をハッシュ化し、その結果をシードとして使用することができます。こうすることで、誰もシードを制御したり予測したりすることが非常に難しくなります。