关于 roblox-remote-events
面向 Roblox 开发者的 Remote Events 与 Functions 技能,说明客户端和服务器之间的通信方式及部署位置,并强调服务端校验与安全防护。
主要功能
- 01对比 RemoteEvent、RemoteFunction 与 UnreliableRemoteEvent
- 02说明 Remote 的存放位置与创建顺序
- 03提供客户端和服务器的调用示例
- 04总结参数校验、限流与防重放方法
适用场景
- 01选择适合通知、请求返回或高频同步的 Remote 类型
- 02搭建客户端与服务器间的消息传递
- 03检查 Remote 处理逻辑中的安全风险
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ sentinelcore/ roblox-skills --skill roblox-remote-events安装后在 Claude Code 中输入/roblox-remote-events确认已加载。
详细介绍
Roblox 远程事件与函数
RemoteEvent 与 RemoteFunction
| 类型 | 方向 | 是否返回值? | 使用场景 |
|---|---|---|---|
RemoteEvent | 任意方向 | 否(发送后不等待) | 通知服务器玩家执行了操作、广播状态 |
RemoteFunction | 客户端→服务器 | 是(调用方会挂起) | 客户端需要获取返回结果(例如获取背包) |
UnreliableRemoteEvent | 任意方向 | 否 | 高频更新且允许丢包的场景 |
默认使用 RemoteEvent。 避免使用服务器→客户端的 RemoteFunction——利用漏洞的玩家可以冻结回调,导致服务器线程无限期阻塞。
Remotes 的存放位置
始终将 Remotes 存放在 ReplicatedStorage 中。由服务器 Script 创建,并确保它在任何 LocalScript 运行之前执行。
ReplicatedStorage/
Remotes/
DealDamage (RemoteEvent)
GetInventory (RemoteFunction)
SyncPosition (UnreliableRemoteEvent)
-- Script in ServerScriptService
local folder = Instance.new("Folder")
folder.Name = "Remotes"
folder.Parent = game:GetService("ReplicatedStorage")
local function make(class, name)
local r = Instance.new(class)
r.Name = name
r.Parent = folder
return r
end
make("RemoteEvent", "DealDamage")
make("RemoteFunction", "GetInventory")
make("UnreliableRemoteEvent", "SyncPosition")
触发模式
客户端 → 服务器(FireServer)
-- LocalScript
local DealDamage = game:GetService("ReplicatedStorage").Remotes:WaitForChild("DealDamage")
DealDamage:FireServer({ targetId = 12345, amount = 50 })
-- First arg on server is always the firing Player (injected automatically, cannot be spoofed)
-- Script (server) — VALIDATE everything in the payload
DealDamage.OnServerEvent:Connect(function(player, data)
-- player identity is trustworthy; data contents are not
end)
服务器 → 单个客户端
local Notify = game:GetService("ReplicatedStorage").Remotes:WaitForChild("Notify")
Notify:FireClient(player, { message = "Welcome!" })
-- LocalScript
Notify.OnClientEvent:Connect(function(data)
print(data.message)
end)
服务器 → 所有客户端
AnnounceEvent:FireAllClients({ text = "Game starting in 10 seconds!" })
RemoteFunction(客户端调用,服务器返回)
-- Script (server)
GetInventory.OnServerInvoke = function(player)
return getPlayerInventory(player.UserId)
end
-- LocalScript
local inventory = GetInventory:InvokeServer() -- yields until server returns
UnreliableRemoteEvent(高频同步)
-- LocalScript
RunService.Heartbeat:Connect(function()
SyncPosition:FireServer(character.HumanoidRootPart.CFrame)
end)
-- Script (server) — still validate
SyncPosition.OnServerEvent:Connect(function(player, cframe)
if typeof(cframe) ~= "CFrame" then return end
-- apply with sanity bounds check
end)
关键:服务器端安全
客户端不可信。将每个参数都视为不可信输入。
local MAX_DAMAGE = 100
local COOLDOWNS = {}
local COOLDOWN_SECONDS = 0.5
DealDamage.OnServerEvent:Connect(function(player, data)
-- 1. Rate limit
local now = tick()
if COOLDOWNS[player.UserId] and now - COOLDOWNS[player.UserId] < COOLDOWN_SECONDS then
return
end
COOLDOWNS[player.UserId] = now
-- 2. Type checks
if type(data) ~= "table" then return end
if type(data.targetId) ~= "number" then return end
if type(data.amount) ~= "number" then return end
-- 3. Range clamp
local amount = math.clamp(data.amount, 0, MAX_DAMAGE)
-- 4. Server-side weapon lookup — never trust client-provided Instance
local weapon = getEquippedWeapon(player)
if not weapon then return end
-- 5. Server-side target lookup
local target = getPlayerByUserId(data.targetId)
if not target then return end
applyDamage(target, amount, player)
end)
攻击模式与防御措施
| 攻击 | 攻击者的操作 | 防御措施 |
|---|---|---|
| 参数注入 | 发送意外类型的数据,导致处理程序崩溃 | 检查所有参数的类型 |
| 伤害放大 | 发送 amount = math.huge | 将数值限制在合理上限内 |
| Remote 滥用 | 每秒触发数千次 | 为每位玩家设置冷却时间 |
| 伪造目标 | 发送另一位玩家的 UserId | 由服务器根据自身状态确定目标 |
| 无限等待 | OnClientEvent 回调始终不返回 | 避免使用服务器→客户端的 RemoteFunction |
| 重复操作 | 重放有效请求,以便重复购买 | 执行操作前检查状态/消耗令牌 |
快速参考
FireServer(args) LocalScript → server
FireClient(player, args) server → one client
FireAllClients(args) server → every client
InvokeServer(args) LocalScript → server, waits for return
OnServerEvent server-side listener for FireServer
OnClientEvent client-side listener for FireClient/FireAllClients
OnServerInvoke server-side function assigned for InvokeServer
常见错误
| 错误 | 修正方法 |
|---|---|
在 LocalScript 中使用 OnServerEvent | 客户端使用 OnClientEvent;OnServerEvent 仅供服务器使用 |
| 将 Remotes 放在 ServerStorage 中 | 移至 ReplicatedStorage |
| 除玩家身份外,信任载荷中的其他内容 | 验证载荷中的每个字段 |
| 使用服务器→客户端的 RemoteFunction | 使用 RemoteEvent;冻结的客户端会阻塞服务器线程 |
在 LocalScript 中未使用 WaitForChild | Remotes 可能尚不存在;始终使用 WaitForChild |
多次赋值给 OnServerInvoke | 只有最后一次赋值生效;将其放在同一处 |
| 在紧密循环中触发且不做限流 | 使用 UnreliableRemoteEvent 或累积时间增量 |
评论
支持 Markdown