RNG Session
簡介
在決定性環境中,給予相同輸入時輸出將永遠一致。然而在某些情境下,使用者可能需要引入隨機性以模擬不可預測事件的影響,或為系統提供一定程度的變異性。亂數產生器(亦稱RNG)是在 Quantum 中實現此功能的重要元件。
RNG工作階段(RNGSession)
Quantum 為開發者提供RNGSession,可用於在模擬中決定性地產生虛擬亂數。框架的globals預先載入了一個全域工作階段,除非使用不同的種子值(seed),否則該工作階段必定會產生相同的數值序列。
使用方式:
C#
// inside of a system
public override void OnInit(Frame frame)
{
int randomNum = frame.RNG->Next(0, 100);
}
globals中的工作階段透過RuntimeConfig.Seed欄位設定種子值,使用者可根據需求自訂特定種子。透過QuantumRunnerLocalDebug執行離線工作階段時,種子值永不改變,因此產生的亂數序列也永遠相同。
若使用範例選單執行,且使用者未自行變更種子值(例如保持預設值 0),則種子值會自動重新隨機化。
執行階段變更種子值
若有需要,可透過建立新工作階段覆蓋原有物件,在執行階段變更種子值。範例如下:
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 還能確保:除非實際需要復滾(rollback),否則剔除機制(culling)不會影響預測實體的最終位置。
詳細資訊請參閱:避免RNG問題
防作弊機制
基於決定性的特性,預測亂數相當容易。例如駭客可在本機讀取模擬數據,在模擬外部複製RNGSession,並提前得知後續的亂數序列。常見的防範方法是頻繁重設種子值,且種子值需難以預測。例如可對玩家輸入進行雜湊運算,並將結果做為種子值,大幅提高他人控制或預測種子值的難度。
關於決定性的注意事項
重點: 僅能在 Quantum 模擬程式碼中推進 RNG 工作階段,切勿在 Unity / 視圖程式碼中操作。原因在於 RNG 工作階段會內部儲存狀態值,而該狀態值決定了亂數序列的產生。
這意味著使用frame.RNG->Next()(或元件中包含的工作階段)及類似 API 會推進內部狀態,若在視圖程式碼中錯誤使用,將導致遊戲非同步(校驗和錯誤)。