遠端事件和回呼

*此內容是使用 AI(Beta 測試版)翻譯,可能含有錯誤。若要以英文檢視此頁面,請按一下這裡

Roblox 體驗的多人模式為預設狀態,因此所有體驗都會天然地通過服務器和玩家連接的客戶端之間通訊。在最簡單的情況下,隨著玩家移動角色,特定的 Humanoid 屬性,例如狀態,會傳送到服務器,該服務器將此信息傳給其他連接的客戶伺服器。

遠端事件和回呼讓您在客戶端與服務器邊界之間通信

  • RemoteEvents 啟用單向通訊(發送請求並 回應)。
  • UnreliableRemoteEvents 啟用持續變更或對遊戲狀態不至關重要的數據的單向通訊這些事件交易訂單並確保可靠性,以提高網絡履約。
  • RemoteFunctions 啟用雙向通訊(向收件人發送請求並等待回應)。

可綁定事件 不同,具有更受限的功能的遠端事件和功能的使用案例太多以至無法列出:

  • 遊戲 - 基本遊遊玩,例如玩家到達等級結束點,可能需要遠端事件。一個客戶端腳本通知伺服器,伺服器腳本重設玩家的位置。
  • 伺服器驗證 - 如果玩家嘗試喝藥水,他們真的有那藥水嗎?為了確保公平,伺服器必須是體驗的真實來源。客戶端腳本可以使用遠端事件通知服務器玩家正在喝藥水,然後服務器腳本可以決定玩家是否擁有該藥水,以及是否應該授予任何好處。
  • 使用者介面更新 - 隨著遊戲狀態變更,服務器腳本可以使用遠端事件通知客戶變更分數、目標等等
  • 體驗內市場購買 - 對於使用遠端功能的示例實裝,請參閱 快速訂閱購買

快速參考

以下表格作為快速參考,用於客戶端和服務伺服器之間通訊的方法 RemoteEventsRemoteFunctions

> > >
客戶端 → 伺服器
客戶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 的 RemoteEvent 視窗中創建新的

  1. 將鼠標懸停在你想要插入 RemoteEvent 的容器上。為了確保服務器和客戶使用權 通行權 存取的兩方都能看到它,它必須在一個地方,兩方都能看到它,例如 ReplicatedStorage , 雖然在某些情況下,將它存儲在 Workspace 或內部的 Tool 中也是適當的。
  2. 點擊容器名稱右側的 按鈕,並插入 遠端事件 個體、實例。
  3. 重命名實例以說明其用途。

一旦您創建了 RemoteEvent,它可以簡化從 客戶到服務器、從 服務器到客戶 或從 服務器到所有客戶 的單向通信。

客戶端 → 伺服器
>

服務器 → 客戶端
>

服務器 → 所有客戶端
>

客戶端→伺服器

您可以使用 來在 伺服器 上啟動事件,呼叫 方法在 上。如果您傳遞參數給 FireServer(),它們會傳到服務器上的事件處理器中,並受到特定的 限制 。請注意,服務器上事件處理器的第一個參數總是客戶端呼叫的 Player 對象,其他參數隨後跟追蹤。

客戶RemoteEvent:FireServer(args)
服務器RemoteEvent.OnServerEvent:Connect(function(player, args))

下列 Script 連接一個事件處理器到 OnServerEvent 創建新的 Part 在服務伺服器上。然後附帶的 LocalScript 會呼叫 FireServer()RemoteEvent 實例上需要的 ColorPosition 對零件。

事件連線 - 腳本

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
-- 取得遠端事件實個體、實例的參考
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onCreatePart(player, partColor, partPosition)
print(player.Name .. " fired the 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))

伺服器 → 客戶

您可以使用 來在 客戶端 上啟動事件,呼叫 方法在 上。FireClient() 的第一個參數是您想回應事件的客戶對象 Player ,其他參數會傳給客戶以某些限制 。請注意,事件處理器不需要包含 Player 對象作為第一個參數,因為您可以使用 Players.LocalPlayer 來在客戶端上確定玩家。

服務器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("[Client] Event received by player", 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("[Server] Firing event to player", player.Name)
remoteEvent:FireClient(player, Players.MaxPlayers, Players.RespawnTime)
end
Players.PlayerAdded:Connect(onPlayerAdded)

伺服器 → 所有客戶

您可以使用 Script 來在所有客戶上啟動事件,稱呼 FireAllClients() 方法在 RemoteEvent 上。與 FireClient() 不同,FireAllClients() 方法不需要 Player 對象,因為它會向所有客戶發射 RemoteEvent

服務器RemoteEvent:FireAllClients(args)
客戶RemoteEvent.OnClientEvent:Connect(function(args))

下列 LocalScript 連接一個事件處理器到輸出剩餘倒計時時間的OnClientEvent事件。然後附帶的 Script 會每秒在循環中呼叫 FireAllClients() 來發射所有客戶的 RemoteEvent

事件連線 - 本地腳本

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 的 RemoteFunction 視窗中創建新的

  1. 將鼠標懸停在你想要插入 RemoteFunction 的容器上。為了確保服務器和客戶使用權 通行權 存取的兩方都能看到它,它必須在一個地方,兩方都能看到它,例如 ReplicatedStorage , 雖然在某些情況下,將它存儲在 Workspace 或內部的 Tool 中也是適當的。
  2. 點擊容器名稱右側的 按鈕,並插入 遠端功能 個體、實例。
  3. 重命名實例以說明其用途。

一旦您創建了 RemoteFunction ,它可以簡化客戶端和服務器服務器和客戶端之間的通信。

客戶端 → 伺服器 → 客戶端
>

服務器 → 客戶端 → 服務器
>

客戶端→伺服器→客戶端

您可以使用 LocalScript 來在 伺服器 上呼叫一個函數,稱為 InvokeServer() 方法在 RemoteFunction 上。與遠端事件不同,呼叫 遠端事件 的 將持續到回調返回為止。您傳給 InvokeServer() 的參數會傳給 OnServerInvokeRemoteFunction 回調,並受到某些 限制 。請注意,如果您定義多個回調到同一個 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 .. " requested a new part")
local newPart = Instance.new("Part")
newPart.Color = partColor
newPart.Position = partPosition
newPart.Parent = Workspace
return newPart
end
-- 將功能設為遠端功能的回調
remoteFunction.OnServerInvoke = createPart
事件呼叫 - 本地腳本

local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- 取得遠端功能實個體、實例的參考
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- 在回調叫回應時傳送顏色和位置
local newPart = remoteFunction:InvokeServer(Color3.fromRGB(255, 0, 0), Vector3.new(0, 25, -20))
-- 輸出返回的零件參考
print("The server created the requested part:", newPart)

服務器 → 客戶端 → 服務伺服器

您可以使用 Script 來呼叫客戶端上的函數,稱為 InvokeClient() 方法在 RemoteFunction 上,但有嚴重的風險如下:

  • 如果客戶端發生錯誤,伺服器也會發生錯誤。
  • 如果客戶在被呼叫時斷開連線,InvokeClient() 將發出錯誤。
  • 如果客戶端沒有返回值,伺服器永遠不會返回。

對於不需要兩向通訊的操作,例如更新 GUI,請使用 RemoteEvent 並從 服務器傳送到客戶端

論述限制

當您發射 RemoteEvent 或呼叫 RemoteFunction 時,它會將您傳給事件或回呼函的任何參數轉發到前方。任何類型的 Roblox 對象,例如 Enum , Instance , 或其他對象,以及 Luau 類型,例如數字、字串和布林,雖然你應該仔細探索以下限制。

非字串指數

如果通過的表中的任何 指數 是非字串類型,例如 Instance用戶資料功能,Roblox 將自動將這些指數轉換為字串。

事件連線 - 本地腳本

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onEventFire(passedTable)
for k, v in passedTable do
print(typeof(k)) --> 字串
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)

通過的函數

包含在 或 作為參數的功能將不會在 客戶端-伺服器 邊界上複製,因此無法遠端傳送功能。相反,接收端的結果論證將是 nil

事件連線 - 本地腳本

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onClientEvent(func)
print(func) --> 零
end
remoteEvent.OnClientEvent:Connect(onClientEvent)
事件發射 - 腳本

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function testFunction()
print("Hello world!")
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 = 弓
--> 角色名稱 = 迪瓦龍殺手
--> CharClass = 惡霸
end
end
-- 連接功能到事件
remoteEvent.OnServerEvent:Connect(onEventFire)
事件發射 - 本地腳本

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- 數字索引表
local inventoryData = {
"Sword", "Bow"
}
-- 字典表
local characterData = {
CharName = "Diva Dragonslayer",
CharClass = "Rogue"
}
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)) --> 表:0x48eb7aead27563d9
return passedTable
end
-- 將功能設為遠端功能的回調
remoteFunction.OnServerInvoke = returnTable
事件呼叫 - 本地腳本

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
local inventoryData = {
"Sword", "Bow"
}
-- 輸出原始表身份
print(tostring(inventoryData)) --> 表: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) --> { ["名稱"] = "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)

非重複的實例

如果 RemoteEventRemoteFunction 傳送值只對發送者可見,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")
-- 會被認為是「零」,因為伺服器不知道這個部分
local clientPart = Instance.new("Part")
clientPart.Parent = Workspace
remoteEvent:FireServer(clientPart)