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

再シミュレーション中、RobloxはBindToSimulation()を介してシミュレーションにバインドされた関数を再実行します。プレイヤー入力の処理、同期された物理オブジェクトとの相互作用、およびコアゲーム状態の更新は、これらのバインドされた関数内で行うべきです。
ModuleScriptは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属性の1つである。
- 名前は最大50文字である。
- 文字列型の属性の場合、値は最大50文字である。
シミュレーションアクセス
エンジンAPIリファレンスの多くのプロパティおよびメソッドにはシミュレーションアクセスラベルが含まれています。例えば、BasePart.CFrameなどです。このラベルが付けられたプロパティはサーバー権限システムによって予測されます。さらに、このラベルが付いているプロパティとメソッドのみが、RunService:BindToSimulation()でバインドされた関数内からアクセスできます。
入力アクション
サーバー権限ゲームでは、クライアントがゲームの状態に影響を与える主な方法は入力アクションシステムを通じてです。これらの入力はサーバーに送信され、再シミュレーション中にクライアントで再生されます。そのため、InputActionsはコアシミュレーションに影響を与えるすべての入力に対して使用されるべきであり、処理される前に整合性を確認する必要があります。
InputContextsはPlayerの子である必要があるので、エンジンがInputContextの所有権を知ることができます。1つのアプローチは、InputContextsをReplicatedStorageの下のフォルダーに追加し、ServerScriptServiceの下にScriptを使って各プレイヤー毎にInputContextsをクローンすることです:

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入力アクションがトリガーされたときにキャラクターのランをトリガーできます。
リモートイベント
リモートイベントは、サーバー権限モデル内でクライアントとサーバー間の離散的なコミュニケーションを促進するために引き続き使用できます。たとえば、サーバーはリモートイベントを使用してプレイヤーの得点やオブジェクトの取得に関するデータをブロードキャストし、クライアントはボタンを押す、または3Dワールド内のオブジェクトをタップするなどの入力をサーバーに送信する代替APIとしてリモートイベントを使用できます。
アニメーション、音、効果
クライアント側の効果(アニメーションや音など)は、クライアントのシミュレーションが権限のあるサーバー状態の単なる予測であることを考慮して記述する必要があります。BindToSimulation()は、バインドされた関数内から呼び出すことができるプロパティおよびメソッドを制限し、同期されたシミュレーション状態のみに書き込むことを助けるガイドとなります。このシミュレーションの結果を表示し、効果や音をトリガーするなどの操作は、シミュレーションの結果を読み取り、期待される効果をトリガーするRenderSteppedに接続された別の関数で行うべきです。
予測されたシミュレーションをレンダリングする際のさらなるガイダンスは、高度な技術ガイドに説明されています。
サンプルプロジェクト
このドキュメントに加えて、以下のテンプレートがスタート地点に役立ちます:


