远程事件和回调

*此内容使用人工智能(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 对象可以在客户端-服务器边界之间进行异步一方通信,无需为响应。

要创建一个新的 RemoteEvent 通过 Studio 中的 Explorer 窗口

  1. 将鼠标悬停在你想要插入RemoteEvent的容器上。为了确保服务器和客户端都可以1) 使用权 2)通行证 3)访问权限问,它必须位于两个方面都能看到的地方,例如ReplicatedStorage,尽管在一些情况下它的存储在Workspace或1> Class.Workspace1>内也可以。
  2. 点击容器名称右侧的 按钮,然后插入一个 RemoteEvent 实例。
  3. 重命名实例以反映其目的。

一旦您创建了一个 RemoteEvent,它可以从客户端到服务器通信,从服务器到客户端通信或从服务器到所有客户端通信。

客户端 → 服务器
服务器 → 客户端
服务器 → 所有客户

客户端 → 服务器

您可以使用一个 LocalScript 来在 服务器 上触发事件,调用 Class.RemoteEvent:FireServer()|FireServer() 2>Class.RemoteEvent

客户RemoteEvent:FireServer(args)
服务器RemoteEvent.OnServerEvent:Connect(function(player, args))

下列 Script 连接一个服务器件处理器到 OnServerEvent ,该创建一个新的 Class.

事件连接 - 脚本

local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- 获取远程事件实例的引用
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))

服务器 → 客户

您可以使用一个 Script 来在

服务器RemoteEvent:FireClient(player, args)
客户RemoteEvent.OnClientEvent:Connect(function(args))

下列 LocalScript 连接一个事件处理器到 OnClientEvent 事件。 随后,Script 列出来的玩家来到服务器,并调用 1> Class.RemoteEvent:FireClient()|FireClient()1> 为每个有任意数据的玩家。

事件连接 - 本地脚本

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() 方法在 Class.RemoteEvent

服务器RemoteEvent:FireAllClients(args)
客户RemoteEvent.OnClientEvent:Connect(function(args))

下列 LocalScript 连接一个事件处理器到 OnClientEvent 事件,该事件输出剩余的倒计时时间。随后的 Script 调用每秒钟 1> Class.RemoteEvent:FireAllClients()|FireAllClients()1>

事件连接 - 本地脚本

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 对象可以在客户端-服务器边界上进行同步的两向通信。发送远程函数的发件人会直到收到从收件人收人那里获得的回应。

要创建一个新的 RemoteFunction 通过 Studio 中的 Explorer 窗口

  1. 将鼠标悬停在你想要插入RemoteFunction的容器上。为了确保工作间务器和客户端都可以1) 使用权 2)通行证 3)访问权限问,它必须位于两个方面都能看到的地方,例如ReplicatedStorage,尽管在一些情况下它的存储在Workspace或1> Class.Workspace1>内也可以。
  2. 点击容器名称右侧的 按钮,然后插入一个 RemoteFunction 实例。
  3. 重命名实例以反映其目的。

当您创建了一个 RemoteFunction 时,它可以在 客户端和服务器服务器和客户端 之间的两向通信中提供帮助。

客户端 → 服务器 → 客户端
服务器 → 客户端 → 服务器

客户端 → 服务器 → 客户端

您可以使用一个 LocalScript 来调用服务器上的函数,通过在 Class.RemoteFunction:ExecuteServer()|ExecuteServer() 方法上调用 Class.RemoteFunction:

客户RemoteFunction:InvokeServer(args)
服务器RemoteFunction.OnServerInvoke = function(player, args)

下列 Script 定义了回调函数通过 OnServerInvoke 调用,并且通过其 Part 值返回要求的 2>Class.Part2> 。 跟随的 5>Class.LocalScript5> 然后调用 8>Class

回调连接 - 脚本

local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- 获取远程函数实例的引用
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 、一个 1> Class.Instance1> 或其他类型的对象

非字符索引

如果传入的表中的任何 索引 为非字符串类型,例如Instanceuserdata或1>函数1>,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 remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- 监听进入的玩家并将远程事件发送到每个
local function onPlayerAdded(player)
remoteEvent:FireClient(player,
{
[workspace.Baseplate] = true
}
)
end
Players.PlayerAdded:Connect(onPlayerAdded)

已通过的函数

包含在 RemoteEventRemoteFunction 作为参数的函数将不会在客户端-服务器边界上复制,因此无法远程传递函数。相反,在接收端的参数将为 8>nil8> 。

事件连接 - 本地脚本

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 = 弓
--> CharName = Diva 拖动器
--> 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)
-- 输出表达式 I回传
print(tostring(invokeReturn)) --> table: 0x9fcae7919563a0e9

金属表

如果表有一个 metatable,所有的 metatable 信息都会在转换中丢失。在以下代码示例中, NumWheels 属性是 Car 的 metatable 的一部分。当服务器收到下表时,truck 表有 1> Name1> 属性,但

事件连接 - 脚本

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)
-- 带有 metatable 的火焰事件
remoteEvent:FireServer(truck)

非复制实例

如果 RemoteEventRemoteFunction 通过一个只对发件人可见的值,Roblox 不会在客户端-服务器边界上复制它,而是将 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 remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- 因为服务器不知道这部分的存在
local clientPart = Instance.new("Part")
clientPart.Parent = workspace
remoteEvent:FireServer(clientPart)