サーバー権限モデルでは、サーバーが全ゲーム状態の唯一の真実の供給元となり、クライアントは自分自身の入力を報告することだけが信頼されます。このアーキテクチャは、公正で競争力のあるゲームのコアネットコード基盤であり、クライアントが自分の位置や状態を報告することを決して信頼しないことによって、フライハックやスピードハックのような大規模なチートを防ぎます。
利点
ナイーブなサーバー所有のシステムでは、クライアントが単純に自分の入力をサーバーに送信し、サーバーから返されるゲームの結果を表示します。技術的には正しいですが、そのようなシステムは、すべてのプレイヤーアクションがサーバーに送信され、処理され、結果がクライアントに返される必要があるため、重大な入力待機時間に直面します。ほとんどのゲーム、特に速いペースのゲームにとって、その往復遅延は、ゲームプレイが遅れているように感じさせたり、反応がない、またはプレイできないと感じさせることがあります。
Robloxのサーバー権限モデルでは、待機時間はクライアントが自分の入力がサーバーに送信されるのに加えて即座に予測することによって補償されます。例えば、プレイヤーがキーを押すと、クライアントはサーバーの応答を待たず、代わりに予測を行い、最後に知られているサーバーの状態から数フレーム先を見越します。これにより、クライアントは入力アクションの結果を即座に表示でき、ネットワーク待機時間を隠し、ゲームが反応的に感じられるようにします。
時々、クライアントはその予測が間違っていることが判明します([ミス予測](#client-misprediction))し、ネットワークの待機時間のために、クライアントは数フレームの間、その間違いに気づきません。例えば:
ミス予測が検出された場合、クライアントはサーバーの権威のある状態に基づいて予測を修正する必要があります。権威のある状態がクライアントの予測された状態と異なる場合、クライアントはロールバックと再シミュレーションを行う必要があります。このクライアント側の予測、ロールバック、および再シミュレーションのシステムは「待機時間補償」として知られ、サーバー権限のマルチプレイヤーゲームがスムーズで反応が良いと感じさせるのに役立ちます。
設定
サーバー権限モデルは、正しく動作するために特定の他のエンジン技術を必要とするため、まずWorkspaceオブジェクトの以下のプロパティをExplorerで設定する必要があります:
- Workspace.NextGenerationReplicationを有効にする必要があります
- Workspace.PlayerScriptsUseInputActionSystemを有効にする必要があります
- Workspace.SignalBehaviorはDeferredである必要があります
- Workspace.UseFixedSimulationを有効にする必要があります
- Workspace.StreamingEnabledを有効にする必要があります
- Workspace.AuthorityModeはServerである必要があります(以上のすべてを最初に設定する必要があります)
概念
サーバー権限システムは、次のようないくつかのコア概念に基づいて動作します。
クライアント予測
クライアント予測を通じて、クライアントは最後に知られているサーバー状態から数フレーム先をシミュレートしてプレイヤー入力の効果を即座に予測します。これにより入力待機時間が隠れますが、後に予測が間違っていることが判明する場合があります(クライアントミス予測)そのため修正が必要です。クライアントは、その入力が意図されたフレームでサーバーに到達するように、最後に知られている権威のあるサーバー状態の少しだけ先をシミュレートするよう努めます。クライアントが知っているサーバー状態の先を予測するフレーム数は、クライアントとサーバーの遅延に基づいて決まります。
クライアントミス予測
クライアントがサーバーから権威のある状態を受信すると、その状態がそのフレームのローカルで予測した履歴と比較されます。クライアントの予測と実際のサーバーの動作との間に違いがある場合、これはミス予測になります。ミス予測は、ネットワーク遅延の変動、クライアントが予見しなかった他のプレイヤーの行動、サーバーでのみ実行されるゲームのロジックなど、様々な理由で発生する可能性があります。
権威のある状態がクライアントの予測された状態と異なる場合、クライアントはロールバックと再シミュレーションを行う必要があります。
ロールバックと再シミュレーション
クライアントがミス予測を発見した場合、サーバーの権威のある状態にリセットし、その後自分の予測フレームに戻るために再シミュレートする必要があります。ネットワークの待機時間に基づいて、クライアントはその入力が意図されたフレームでサーバーに到達するように、最後に知られている権威のあるサーバー状態の少しだけ先をシミュレートしようとします。
要約すると、クライアントは:
- サーバーから権威のある状態を受信し、それを自分の予測された状態と比較します。
- クライアントの予測が間違っていた場合:
- クライアントはサーバーから受信した最後の権威のある状態にロールバックします。
- クライアントは権威のある状態から予測された状態まで再シミュレートし、すべてのローカル入力を再適用します。
実装
ネットワーク所有権と予測
サーバー権限モデルでは、核心的なゲームプレイオブジェクトをサーバー所有のままにし、通常サーバー所有に関連する入力待機時間のコストを負担することなく保つことができます。車両、プレイヤーキャラクター、または他のゲームプレイに不可欠なオブジェクトなどがサーバー所有のままで、他のプレイヤーとインタラクションすることができます。
デフォルトでは、RobloxはローカルプレイヤーCharacter近くのシミュレーションアクセスを持つプロパティを自動的に予測しますが、より細かい制御が必要な場合、RunService:SetPredictionMode()を使用してインスタンスの予測を明示的にオンまたはオフに設定することができます。
シミュレーション同期
サーバー権限モデルでは、クライアントとサーバーの両方がコアシミュレーションを実行する必要があり、クライアントのシミュレーションはロールバックと再シミュレーションを行える必要があります。これを有効にするには、RunService:BindToSimulation()を通じてバインドされた関数内にコアロジックを記述します。この関数は、クライアントとサーバーの両方で初期化されるModuleScript内でバインドされます。

再シミュレーション中、RobloxはBindToSimulation()を介してシミュレーションにバインドされた関数を再実行します。プレイヤー入力の処理、同期された物理オブジェクトとの相互作用、コアゲーム状態の更新は、これらのバインドされた関数内で行うべきです。
ModuleScriptという名前のSimulationをReplicatedStorageに作成します:
Simulation
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local Simulation = {}
Simulation.Initialize = function()
RunService:BindToSimulation(function(deltaTime)
-- プレイヤー入力を読み取る
-- ゲーム状態を更新する
end)
end
return Simulation
属性を使った状態同期
Robloxは、予測されたインスタンスに対してシミュレーションアクセスを持つすべてのプロパティを自動的に同期します。カスタムデータについては、属性が予測されたインスタンスを同期する主要な方法です。これらのインスタンス上では、サーバーの真実の供給元とクライアントの予測との間の属性値の不一致は、完全なロールバックと再シミュレーションを引き起こします。
属性の制限
複製されるためには、属性は以下のすべての基準を満たす必要があります:
- それはそのInstanceの最初の64の属性の中にあります。
- 名前は最大50文字を含むことができます。
- 文字列型の属性の場合、その値は最大50文字を含むことができます。
シミュレーションアクセス
エンジンAPIリファレンスの多くのプロパティやメソッドにはシミュレーションアクセスのラベルが含まれています。例えば、BasePart.CFrameのように。これらのプロパティには、サーバー権限システムによって予測されます。さらに、このラベルを持つプロパティおよびメソッドのみがRunService:BindToSimulation()でバインドされた関数内でアクセス可能です。
入力アクション
サーバー権限型ゲームでは、クライアントがゲームの状態に影響を与える主な方法は入力アクションシステムを通じて行われます。これらの入力はサーバーに送信され、再シミュレーション中にクライアントで再生されます。その結果、InputActionsはコアシミュレーションに影響を与えるすべての入力に使用されるべきであり、それらは処理される前に妥当性を確認すべきです。
InputContextsは、エンジンがInputContextの所有者を知るためにPlayerの子孫でなければなりません。1つのアプローチは、InputContextsをReplicatedStorageの下のフォルダに追加し、ServerScriptServiceの下でScriptを使用して各プレイヤーにInputContextsをクローンすることです:

InputSetup
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local InputsFolder = ReplicatedStorage:WaitForChild("Inputs")
local function onPlayerAdded(player)
local clone = InputsFolder:Clone()
clone.Parent = player
end
Players.PlayerAdded:Connect(onPlayerAdded)
for _, player in Players:GetPlayers() do
onPlayerAdded(player)
end
このパターンを使用すると、クライアントとサーバーの両方でRunService:BindToSimulation()内のすべてのプレイヤーに対してInputActionsを読み取ることができ、特定のフレームの同じデータを受け取り、前のフレームの入力を属性に記録することができます。例えば、RunAction入力アクションがトリガーされたときにキャラクターを走らせるために。
カスタムデータを入力アクションシステムに書き込む必要がある場合は、RunService.RenderSteppedまたはRunService:BindToRenderStep()に接続された関数を使用するべきであり、RunService:BindToSimulation()に接続するべきではありません。RunService:BindToSimulation()内でInputActionを発火すると、クライアントは再シミュレーション中に不正確な結果を生じる可能性があります。
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local Workspace = game:GetService("Workspace")
RunService:BindToRenderStep("CameraInput", Enum.RenderPriority.Last.Value, function()
-- クライアントのカメラの前方ベクターをサーバーに入力アクションを通じて送信します
local cameraForwardInputAction = Players.LocalPlayer.PlayContext.CameraForward
local cameraForwardVector = Workspace.CurrentCamera.CFrame.LookVector
cameraForwardInputAction:Fire(cameraForwardVector)
end)
リモートイベント
リモートイベントは、クライアントとサーバー間の離散的な通信を促進するために、サーバー権限モデル内でも引き続き使用できます。例えば、サーバーはプレイヤーが得点を獲得したりオブジェクトを取得したりするデータをブロードキャストするためにリモートイベントを使用し、クライアントはボタン押下や3D空間内のオブジェクトをタップするなど、サーバーに入力を送信するための代替APIとしてリモートイベントを使用できます。
アニメーション、サウンド、およびエフェクト
クライアント側のエフェクトであるアニメーションやサウンドは、クライアントシミュレーションが単なる権威のあるサーバー状態の予測であることを考慮して書く必要があります。BindToSimulation()は、バインドされた関数内から呼び出すことができるプロパティやメソッドを制限し、同期されたシミュレーション状態にのみ書き込むことを促します。シミュレーションの結果を表示し、エフェクトやサウンドをトリガーするなどは、シミュレーションの結果を読み取って目的のエフェクトをトリガーするために、RenderSteppedに接続された別の関数で行うべきです。
予測されたシミュレーションをレンダリングするためのさらなるガイダンスは、高度な技術ガイドで詳しく説明されています。
例プロジェクト
このドキュメントに加えて、以下のテンプレートがスタート地点として役立つかもしれません:


