Robloxのゲームはデフォルトでマルチプレイヤーであるため、すべてのゲームは本質的にサーバーとプレイヤーの接続されたクライアント間で通信します。最も単純なケースでは、プレイヤーがキャラクターを移動させると、状態などの特定の Humanoid プロパティがサーバーに送信され、サーバーはこの情報を他の接続されたクライアントに渡します。
リモートイベントとコールバックを使用すると、クライアントとサーバーの境界を越えて通信できます:
- RemoteEvents は一方向の通信を可能にします(リクエストを送信し、応答を待たない)。
- UnreliableRemoteEvents は、継続的に変化するデータやゲームの状態にとって重要でないデータのための一方向の通信を可能にします。これらのイベントは、順序と信頼性を犠牲にしてネットワークパフォーマンスを向上させます。
- RemoteFunctions は双方向の通信を可能にします(リクエストを送信し、受信者からの応答を受け取るまで待機します)。
バインダブルイベントとは異なり、リモートイベントと関数のユースケースは数え切れないほどあります:
- ゲームプレイ - プレイヤーがレベルの終わりに到達するなどの基本的なゲームプレイには、リモートイベントが必要です。クライアントスクリプトがサーバーに通知し、サーバースクリプトがプレイヤーの位置をリセットします。
- サーバーの検証 - プレイヤーがポーションを飲もうとした場合、実際にそのポーションを持っているのでしょうか?公正を確保するために、サーバーはゲームの真実の源でなければなりません。クライアントスクリプトはリモートイベントを使用してサーバーにプレイヤーがポーションを飲んでいることを通知し、サーバースクリプトはプレイヤーが実際にそのポーションを持っているか、どのような利益を与えるかを決定できます。
- ユーザーインターフェースの更新 - ゲームの状態が変化するにつれて、サーバースクリプトはリモートイベントを使用してクライアントにスコア、目標などの変更を通知できます。
- ゲーム内マーケットプレイスの購入 - リモート関数を使用した実装の例については、プロンプトサブスクリプション購入を参照してください。
クイックリファレンス
以下の表は、RemoteEvents と RemoteFunctions を使用してクライアントとサーバー間で通信する方法のクイックリファレンスとして機能します。
| クライアント → サーバー | |
|---|---|
| クライアント | RemoteEvent:FireServer(args) |
| サーバー | RemoteEvent.OnServerEvent:Connect(function(player, args)) |
| サーバー → クライアント | |
| サーバー | RemoteEvent:FireClient(player, args) |
| クライアント | RemoteEvent.OnClientEvent:Connect(function(args)) |
| サーバー → すべてのクライアント | |
| サーバー | RemoteEvent:FireAllClients(args) |
| クライアント | RemoteEvent.OnClientEvent:Connect(function(args)) |
リモートイベント
RemoteEvent オブジェクトは、応答を待たずにクライアントとサーバーの境界を越えた非同期の一方向通信を促進します。
StudioのExplorerウィンドウを使用して新しい RemoteEvent を作成するには:
- RemoteEvent を挿入したいコンテナの上にカーソルを合わせます。サーバーとクライアントの両方がアクセスできるようにするためには、ReplicatedStorage のように両方の側が見ることができる場所に配置する必要がありますが、場合によっては Workspace や Tool 内に保存するのが適切です。
- コンテナの名前の右側に表示される ⊕ ボタンをクリックして、RemoteEvent インスタンスを挿入します。
- インスタンスの名前をその目的を説明するように変更します。
RemoteEvent を作成すると、クライアントからサーバー、サーバーからクライアント、またはサーバーからすべてのクライアントへの一方向通信を促進できます。



クライアント → サーバー
LocalScript を使用して、FireServer() メソッドを呼び出すことで、サーバー上でイベントをトリガーできます。FireServer() に引数を渡すと、それらはサーバー上のイベントハンドラーに渡されますが、特定の制限があります。サーバー上のイベントハンドラーの最初のパラメーターは、常にそれを呼び出すクライアントの Player オブジェクトであり、追加のパラメーターが続きます。
| クライアント | RemoteEvent:FireServer(args) |
| サーバー | RemoteEvent.OnServerEvent:Connect(function(player, args)) |
以下の Script は、サーバー上で新しい Part を作成する OnServerEvent にイベントハンドラーを接続します。付随する LocalScript は、パートの希望する Color と Position を持つ FireServer() を呼び出します。
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
-- リモートイベントインスタンスへの参照を取得
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onCreatePart(player, partColor, partPosition)
print(player.Name .. " が RemoteEvent を発火しました")
local newPart = Instance.new("Part")
newPart.Color = partColor
newPart.Position = partPosition
newPart.Parent = Workspace
end
-- イベントに関数を接続
remoteEvent.OnServerEvent:Connect(onCreatePart)local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- リモートイベントインスタンスへの参照を取得
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- リモートイベントを発火し、追加の引数を渡す
remoteEvent:FireServer(Color3.fromRGB(255, 0, 0), Vector3.new(0, 25, -20))サーバー → クライアント
Script を使用して、FireClient() メソッドを呼び出すことで、クライアント上でイベントをトリガーできます。FireClient() の最初の引数は、イベントに応答するクライアントの Player オブジェクトであり、追加の引数は特定の制限を持ってクライアントに渡されます。イベントハンドラーは、クライアント上で Players.LocalPlayer を使用してプレイヤーを特定できるため、最初の引数として Player オブジェクトを含める必要はありません。
| サーバー | RemoteEvent:FireClient(player, args) |
| クライアント | RemoteEvent.OnClientEvent:Connect(function(args)) |
以下の LocalScript は、OnClientEvent イベントにイベントハンドラーを接続します。付随する Script は、サーバーへの新しいプレイヤーの到着をリッスンし、各プレイヤーに任意のデータで FireClient() を呼び出します。
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
-- リモートイベントインスタンスへの参照を取得
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local player = Players.LocalPlayer
local function onNotifyPlayer(maxPlayers, respawnTime)
print("[クライアント] プレイヤーにイベントが受信されました", player.Name)
print(maxPlayers, respawnTime)
end
-- イベントに関数を接続
remoteEvent.OnClientEvent:Connect(onNotifyPlayer)local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
-- リモートイベントインスタンスへの参照を取得
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- 新しいプレイヤーをリッスンし、各プレイヤーにリモートイベントを送信
local function onPlayerAdded(player)
print("[サーバー] プレイヤーにイベントを発火しています", player.Name)
remoteEvent:FireClient(player, Players.MaxPlayers, Players.RespawnTime)
end
Players.PlayerAdded:Connect(onPlayerAdded)サーバー → すべてのクライアント
Script を使用して、FireAllClients() メソッドを呼び出すことで、すべてのクライアント上でイベントをトリガーできます。FireClient() とは異なり、FireAllClients() メソッドは Player オブジェクトを必要とせず、すべてのクライアントに RemoteEvent を発火します。
| サーバー | RemoteEvent:FireAllClients(args) |
| クライアント | RemoteEvent.OnClientEvent:Connect(function(args)) |
以下の LocalScript は、残りのカウントダウン時間を出力する OnClientEvent イベントにイベントハンドラーを接続します。付随する Script は、すべてのクライアントに RemoteEvent を発火するために、毎秒 FireAllClients() をループ内で呼び出します。
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- リモートイベントインスタンスへの参照を取得
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onTimerUpdate(seconds)
print(seconds)
end
-- イベントに関数を接続
remoteEvent.OnClientEvent:Connect(onTimerUpdate)local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- リモートイベントインスタンスへの参照を取得
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local countdown = 5
-- 時間が切れるまで毎秒リモートイベントを発火
for timeRemaining = -1, countdown do
remoteEvent:FireAllClients(countdown - timeRemaining)
task.wait(1)
endリモートコールバック
RemoteFunction オブジェクトは、クライアントとサーバーの境界を越えた同期的な双方向通信を促進します。リモート関数の送信者は、受信者からの応答を受け取るまで待機します。
StudioのExplorerウィンドウを使用して新しい RemoteFunction を作成するには:
- RemoteFunction を挿入したいコンテナの上にカーソルを合わせます。サーバーとクライアントの両方がアクセスできるようにするためには、ReplicatedStorage のように両方の側が見ることができる場所に配置する必要がありますが、場合によっては Workspace や Tool 内に保存するのが適切です。
- コンテナの名前の右側に表示される ⊕ ボタンをクリックして、RemoteFunction インスタンスを挿入します。
- インスタンスの名前をその目的を説明するように変更します。
RemoteFunction を作成すると、クライアントとサーバー間、またはサーバーとクライアント間で双方向通信を促進できます。


クライアント → サーバー → クライアント
LocalScript を使用して、InvokeServer() メソッドを呼び出すことで、サーバー上の関数を呼び出すことができます。リモートイベントとは異なり、RemoteFunction を呼び出す LocalScript は、コールバックが返されるまで待機します。InvokeServer() に渡す引数は、OnServerInvoke コールバックに渡されますが、特定の制限があります。複数のコールバックを同じ RemoteFunction に定義した場合、最後の定義のみが実行されます。
| クライアント | RemoteFunction:InvokeServer(args) |
| サーバー | RemoteFunction.OnServerInvoke = function(player, args) |
以下の Script は、OnServerInvoke を介してコールバック関数を定義し、要求された Part をその return 値を通じて返します。付随する LocalScript は、要求されたパートの色と位置を定義する追加の引数を持って InvokeServer() を呼び出します。
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
-- リモート関数インスタンスへの参照を取得
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- コールバック関数
local function createPart(player, partColor, partPosition)
print(player.Name .. " が新しいパートを要求しました")
local newPart = Instance.new("Part")
newPart.Color = partColor
newPart.Position = partPosition
newPart.Parent = Workspace
return newPart
end
-- 関数をリモート関数のコールバックとして設定
remoteFunction.OnServerInvoke = createPartlocal ReplicatedStorage = game:GetService("ReplicatedStorage")
-- リモート関数インスタンスへの参照を取得
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- コールバックを呼び出す際に色と位置を渡す
local newPart = remoteFunction:InvokeServer(Color3.fromRGB(255, 0, 0), Vector3.new(0, 25, -20))
-- 返されたパートの参照を出力
print("サーバーが要求されたパートを作成しました:", newPart)サーバー → クライアント → サーバー
Script を使用して、InvokeClient() メソッドを呼び出すことで、クライアント上の関数を呼び出すことができますが、以下のような重大なリスクがあります:
- クライアントがエラーを投げると、サーバーもエラーを投げます。
- クライアントが呼び出されている間に切断されると、InvokeClient() はエラーを投げます。
- クライアントが値を返さない場合、サーバーは永遠に待機します。
双方向通信を必要としないアクション、例えばGUIの更新などには、RemoteEvent を使用してサーバーからクライアントに通信してください。
配信保証
各リモートタイプは、メッセージが到着するかどうか、またその順序について異なる約束をします。これらの約束は、単一の接続に対して単一の方向にのみ適用されます。つまり、サーバーから特定のクライアントへの通信、または特定のクライアントからサーバーへの通信です。
RemoteEvents
RemoteEvents は信頼性があり、順序が保証されています:
- メッセージが送信中に失われた場合、Robloxは受信者が接続されている限り、それを再送信します。
- メッセージは、発火した順序で到着します。異なる RemoteEvent インスタンス間でも同様です。例えば、サーバーがイベント A を発火し、その後 B を発火し、再び同じクライアントに A を発火した場合、そのクライアントは A, B, A を受け取ります。これは、FireClient() または FireAllClients() を使用する場合でも適用されます。
- クライアントがスロットリング制限よりも早くイベントを発火した場合、サーバーは余分なイベントを後で処理し、順序を保持します。
信頼性があり、順序が保証されたメッセージでも、以下のケースではコードに到達しない可能性があります:
- ハンドラーが接続されていない。 OnServerEvent または OnClientEvent に何も接続されていない場合、メッセージが到着すると、Robloxはそれをキューに入れ、ハンドラーが接続され次第、順番に配信します。キューには数とメモリの制限があります。満杯になると、Robloxはさらにメッセージを破棄し、Outputウィンドウに Remote event invocation エラーを記録します。
- 受信者が切断される。 クライアントが離れたときに配信されていないメッセージは失われます。
順序は各ハンドラーが開始する時点に適用され、完了する時点には適用されません。ハンドラーが待機する場合、例えば task.wait() や WaitForChild() を呼び出す場合、Robloxは以前のハンドラーが再開する前に次のメッセージの処理を開始することがあります。
RemoteFunctions
RemoteFunctions は、呼び出しと応答を信頼性を持って送信します。Robloxは、両方の側が接続されている限り、失われたメッセージを再送信します。InvokeServer() と InvokeClient() は応答が到着するまで待機するため、単一のスレッドでは同時に1つの呼び出ししか存在できません。ただし、別のスレッドは同時に呼び出すことができ、コールバックが待機する場合、応答は送信された呼び出しとは異なる順序で返されることがあります。
OnServerInvoke または OnClientInvoke にコールバックが割り当てられていない場合、Robloxはコールバックが割り当てられるまで呼び出しをキューに入れます。このキューは、RemoteEvent キューと同様の制限があります。
UnreliableRemoteEvents
UnreliableRemoteEvents は、配信や順序を保証しません。また、RemoteEvents や RemoteFunctions との順序関係もありません。Robloxは、以下のいずれかのケースでメッセージを破棄する可能性がありますが、再送信は行いません:
- メッセージが送信中に失われる。
- ネットワークが混雑しており、メッセージの送信が長時間待機する。
- ペイロードが1,000バイトを超える。
- クライアントがスロットリング制限よりも早く発火する。RemoteEvent とは異なり、サーバーは余分なメッセージを破棄します。
- メッセージが到着したときに OnServerEvent または OnClientEvent に何も接続されていない。RemoteEvent とは異なり、Robloxはメッセージをキューに入れるのではなく、即座に破棄します。
Robloxは、後のメッセージを処理する前に以前のメッセージが到着するのを待たないため、メッセージが順序通りに到着しない可能性があります。順序が重要な場合は、各メッセージにタイムスタンプやシーケンス番号を含め、処理した最新のメッセージよりも古いメッセージを無視してください。
スロットリングとサイズ制限
クライアントからサーバーへのメッセージは、すべてのインスタンス間で共有されるレート制限の対象となります。現在の制限については、RemoteEvent のスロットリングセクションおよび UnreliableRemoteEvent のペイロード制限を参照してください。
引数の制限
RemoteEvent を発火させたり、RemoteFunction を呼び出したりすると、イベントやコールバック関数に渡す引数が転送されます。Enum、Instance などのRobloxオブジェクトの任意のタイプや、数値、文字列、ブール値などのLuauタイプを渡すことができますが、以下の制限を注意深く確認してください。
非文字列インデックス
渡されたテーブルのインデックスが Instance、userdata、またはfunctionなどの非文字列タイプである場合、Robloxは自動的にそれらのインデックスを文字列に変換します。
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onEventFire(passedTable)
for k, v in passedTable do
print(typeof(k)) --> string
end
end
-- イベントに関数を接続
remoteEvent.OnClientEvent:Connect(onEventFire)local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local Workspace = game:GetService("Workspace")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- 新しいプレイヤーをリッスンし、各プレイヤーにリモートイベントを送信
local function onPlayerAdded(player)
remoteEvent:FireClient(player,
{
[Workspace.Baseplate] = true
}
)
end
Players.PlayerAdded:Connect(onPlayerAdded)渡された関数
RemoteEvent または RemoteFunction の引数として含まれる関数は、クライアントとサーバーの境界を越えて複製されず、リモートで関数を渡すことは不可能です。受信側の結果として得られる引数は nil になります。
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onClientEvent(func)
print(func) --> nil
end
remoteEvent.OnClientEvent:Connect(onClientEvent)local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function testFunction()
print("こんにちは、世界!")
end
-- 関数を引数として持つリモートイベントを発火
remoteEvent:FireAllClients(testFunction)テーブルインデックス
データのテーブルを渡す場合、数値キーと文字列キーの混合テーブルを渡さないでください。代わりに、完全にキーと値のペア(辞書)からなるテーブルまたは完全に数値インデックスからなるテーブルを渡してください。
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onEventFire(player, passedTable)
for k, v in passedTable do
print(k .. " = " .. v)
--> 1 = 剣
--> 2 = 弓
--> CharName = ディーバ・ドラゴンスレイヤー
--> CharClass = ローグ
end
end
-- イベントに関数を接続
remoteEvent.OnServerEvent:Connect(onEventFire)local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- 数値インデックステーブル
local inventoryData = {
"剣", "弓"
}
-- 辞書テーブル
local characterData = {
CharName = "ディーバ・ドラゴンスレイヤー",
CharClass = "ローグ"
}
remoteEvent:FireServer(inventoryData)
remoteEvent:FireServer(characterData)テーブルの同一性
リモートイベント/コールバックに引数として渡されたテーブルはコピーされるため、イベントを発火させたりコールバックを呼び出したりする際に提供されたものと正確に同一ではありません。また、呼び出し元に返されたテーブルも正確に同一ではありません。以下のスクリプトを RemoteFunction で実行し、テーブルの同一性が異なることを確認できます。
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- コールバック関数
local function returnTable(player, passedTable)
-- 呼び出し時のテーブルの同一性を出力
print(tostring(passedTable)) --> table: 0x48eb7aead27563d9
return passedTable
end
-- 関数をリモート関数のコールバックとして設定
remoteFunction.OnServerInvoke = returnTablelocal ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
local inventoryData = {
"剣", "弓"
}
-- 元のテーブルの同一性を出力
print(tostring(inventoryData)) --> table: 0x059bcdbb2b576549
local invokeReturn = remoteFunction:InvokeServer(inventoryData)
-- 戻り値のテーブルの同一性を出力
print(tostring(invokeReturn)) --> table: 0x9fcae7919563a0e9メタテーブル
テーブルにメタテーブルがある場合、すべてのメタテーブル情報は転送中に失われます。以下のコードサンプルでは、NumWheels プロパティは Car メタテーブルの一部です。サーバーが以下のテーブルを受信すると、truck テーブルには Name プロパティはありますが、NumWheels プロパティはありません。
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onEvent(player, param)
print(param) --> {["Name"] = "MyTruck"}
end
-- イベントに関数を接続
remoteEvent.OnServerEvent:Connect(onEvent)local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local Car = {}
Car.NumWheels = 4
Car.__index = Car
local truck = {}
truck.Name = "MyTruck"
setmetatable(truck, Car)
-- メタテーブルを含むテーブルでイベントを発火
remoteEvent:FireServer(truck)複製されないインスタンス
RemoteEvent または RemoteFunction が送信者にのみ表示される値を渡す場合、Robloxはそれをクライアントとサーバーの境界を越えて複製せず、代わりにその値の nil を渡します。例えば、Script が ServerStorage の子孫を渡すと、イベントをリッスンしているクライアントはそのオブジェクトにアクセスできないため、nil 値を受け取ります。
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- サーバーストレージにアクセスできないため "nil" として受信される
local storedPart = Instance.new("Part")
storedPart.Parent = ServerStorage
local function onPlayerAdded(player)
remoteEvent:FireClient(player, storedPart)
end
Players.PlayerAdded:Connect(onPlayerAdded)同様に、LocalScript でパートを作成し、それを Script に渡そうとすると、サーバーはそのパートを知らないため nil を受け取ります。
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- サーバーがこのパートを知らないため "nil" として受信される
local clientPart = Instance.new("Part")
clientPart.Parent = Workspace
remoteEvent:FireServer(clientPart)