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

再シミュレーション中、RobloxはBindToSimulation()を介してシミュレーションにバインドされた関数を再実行します。プレイヤー入力の処理、同期された物理オブジェクトとの相互作用、コアゲーム状態の更新は、これらのバインドされた関数内に存在する必要があります。
バウンドシミュレーション関数内の時間ベースのロジック(アニメーション速度の制御や時間の経過に伴う値の振動など)にはtime()を使用します。Workspace.AuthorityModeがEnum.AuthorityMode.Serverの場合、time()はクライアントとサーバー間で同期され、固定ステップシミュレーション時間を使用します。再シミュレーション中、権威あるフレームに巻き戻り、クライアントがフレームを再生するにつれて進行するため、各フレームがシミュレートされるたびに一貫した値を返します。
ModuleScriptの名前はSimulationで、ReplicatedStorage内にあります:
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()でバインドされた関数内でアクセスできます。
インスタンスの作成と削除
BindToSimulation()を介してバインドされた関数内で、Instance.new()、Instance:Clone()、またはInstance.fromExisting()を使用してインスタンスを作成できます。クライアントはインスタンスを即座に作成し、Robloxはそのコピーが到着したときにサーバーの権威あるコピーとマージします。詳細については、予測インスタンスの作成を参照してください。
インスタンスの削除は異なる方法で行われます。Instance:Destroy()はシミュレーションアクセスを持たず、すでにDataModelにあるインスタンスのParentを変更することはできないため、バインドされた関数内でこれらのいずれかを呼び出すとエラーが発生します。代わりに、シミュレーション内で属性にインスタンスを削除する意図を記録し、その後、サーバーのPostSimulation接続などでインスタンスを削除します。
local RunService = game:GetService("RunService")
local character = script.Parent
RunService.PostSimulation:Connect(function()
-- "SwordEquipped"はプレイヤーが剣を外したときにシミュレーションによって書き込まれます
local sword = character:FindFirstChild("Sword")
if sword and not character:GetAttribute("SwordEquipped") then
sword:Destroy()
end
end)入力アクション
サーバー権限のゲームでは、クライアントがゲームの状態に影響を与える主な方法は入力アクションシステムを通じてです。これらの入力はサーバーに送信され、再シミュレーション中にクライアントで再生されます。その結果、InputActionsはコアシミュレーションに影響を与えるすべての入力に使用され、処理される前に妥当性を確認する必要があります。
InputContextsは、エンジンがInputContextの所有権を知るためにPlayerの子孫である必要があります。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入力アクションがトリガーされたときにキャラクターのランをトリガーするためです。
リモートイベント
リモートイベントは、サーバー権限モデル内でクライアントとサーバー間の明示的な通信を促進するために引き続き使用できます。たとえば、サーバーはリモートイベントを使用して、プレイヤーがポイントを獲得したりオブジェクトを拾ったりするデータをブロードキャストし、クライアントはリモートイベントをサーバーへの入力送信の代替APIとして使用できます。たとえば、ボタンの押下や3D世界内のオブジェクトのタップなどです。
アニメーション
キャラクターの移動や攻撃アニメーションなど、ゲームプレイに影響を与えるアニメーションは、クライアントとサーバーの両方で実行される同じModuleScript内のBindToSimulation()を介して制御する必要があります。コアのAnimatorおよびAnimationTrackメンバー(LoadAnimation()、Play()、Stop()、AdjustSpeed()、およびTimePosition)にはシミュレーションアクセスがあります。
アニメーション状態は予測されたシミュレーションの一部です。アニメーション中にロールバックが発生すると、クライアントはアニメーションを権威ある状態に巻き戻し、シミュレーションの残りの部分とともに再生します。これにより、クライアントとサーバーのアニメーションが同期します。クライアントはロールバック中にアニメーショントラックを置き換える可能性があるため、フレーム間でAnimationTrackの参照をキャッシュしないでください。代わりに、各フレームでAnimator:GetTrackByAnimationId()を使用してライブトラックを検索します。完全な例については、アニメーションコードの記述を参照してください。
サウンドとエフェクト
クライアント側のエフェクト(サウンドやパーティクルなど)は、クライアントシミュレーションが権威あるサーバー状態の単なる予測であることを考慮して書く必要があります。BindToSimulation()は、バインドされた関数内で呼び出すことができるプロパティとメソッドを制限し、同期されたシミュレーション状態にのみ書き込むようにガイドします。このシミュレーションの結果を表示し、エフェクトやサウンドをトリガーするなどは、シミュレーションの結果を読み取り、希望するエフェクトをトリガーするRenderSteppedに接続された別の関数で行うべきです。
クライアントがサーバーで発生しないイベントを予測する可能性があるため、レンダリングコードはミス予測されたエフェクトを元に戻したり隠したりできる必要があります。予測シミュレーションのレンダリングに関するさらなるガイダンスは、サウンドと視覚効果の再生で説明されています。
例プロジェクト
このドキュメントに加えて、以下のテンプレートがスタートを助けることができます:


