关于 roblox-teleport
roblox-teleport 是面向 Roblox 开发者的传送系统参考技能,说明如何在体验中的地点和服务器之间移动玩家。内容涵盖服务器端传送、预留服务器、数据传递、匹配模式及安全处理。
主要功能
- 01使用 TeleportAsync 进行服务器端传送
- 02指定目标服务器或预留服务器
- 03跨传送传递数据与加载界面
- 04传送失败处理与重试
- 05大厅、比赛和服务器浏览器模式
- 06请求验证与传送安全
适用场景
- 01将大厅玩家送入比赛地点
- 02为私人比赛创建预留服务器
- 03构建活动服务器列表供玩家选择
- 04安全处理玩家发起的传送请求
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ nonlooped/ roblox-suite --skill roblox-teleport安装后在 Claude Code 中输入/roblox-teleport确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/matchmaking.mdteleport-options.mdscripts/TeleportHelper.luatests/TeleportHelper.spec.lua详细介绍
roblox-teleport
官方来源:
- https://create.roblox.com/docs/en-us/reference/engine/classes/TeleportService
- https://create.roblox.com/docs/en-us/projects/teleport
- https://create.roblox.com/docs/en-us/reference/engine/classes/TeleportOptions
- https://create.roblox.com/docs/en-us/reference/engine/classes/TeleportAsyncResult
- https://create.roblox.com/docs/projects/teleport(多地点架构)
TeleportService 可在不同地点和服务器之间传送玩家。现代入口是 TeleportAsync(仅限服务器);旧版的 Teleport(客户端)、TeleportPartyAsync、TeleportToPlaceInstance、TeleportToPrivateServer 和 TeleportToSpawnByName 方法均已弃用。请改用 TeleportAsync()。对于由客户端发起的传送,请向服务器触发 RemoteEvent,并由服务器调用 TeleportAsync();即使地点配置为“Fully Open”,新功能也不要从客户端调用 Teleport()。请参阅迁移到安全传送指南。
交叉参考:
- roblox-datastores/SKILL.md:传送期间玩家数据的交接模式。
- roblox-networking/SKILL.md:服务器权威、速率限制,以及传送请求的安全模型。
- roblox-core/SKILL.md:服务和脚本上下文。
多地点架构
一个宇宙(体验)可以包含多个地点。每个地点都有自己的 PlaceId;宇宙有一个 UniverseId(以 game.GameId 的形式公开)。主地点是玩家从 Roblox 应用的主入口加入的地点。
- 在 Creator Dashboard 中的体验 → Places 下创建其他地点。
- 每个地点都必须已发布,并且(要允许玩家加入)可见或已启用。
game.PlaceId是当前地点;game.GameId是宇宙 ID(有时称为 UniverseId)。- 同一宇宙中的地点共享 DataStore、MemoryStore 和 Asset 权限。
- 默认情况下,跨宇宙(跨体验)传送受到限制。请参阅下文的“跨体验传送”。
TeleportAsync(现代方法)
TeleportService:TeleportAsync(placeId, players, teleportOptions?) 是统一的单一方法。它可以将玩家传送到不同地点、特定服务器或预留服务器。仅限服务器。从客户端调用会报错。Teleport() 和其他旧版方法现在会显示弃用提示,引导你使用 TeleportAsync()(请参阅地点之间传送)。
--!strict
local TeleportService = game:GetService("TeleportService")
local Players = game:GetService("Players")
local DESTINATION_PLACE_ID = 1234567890
local function teleportToPlace(player: Player)
local options = Instance.new("TeleportOptions")
-- options.ServerInstanceId = "..." -- to target a specific server
-- options.ReservedServerAccessCode = "..." -- to join a reserved server
-- options.ShouldReserveServer = true -- to create+join a new reserved server
options:SetTeleportData({ reason = "lobby_choice", mode = "classic" })
local ok, result = pcall(function()
return TeleportService:TeleportAsync(DESTINATION_PLACE_ID, { player }, options)
end)
if not ok then
warn("TeleportAsync failed:", tostring(result))
return false
end
-- result is a TeleportAsyncResult with info about the destination
return true
end
群组传送限制
- 群组只能在同一体验内传送(同一宇宙)。
- 每次
TeleportAsync调用最多可传送 50 名玩家。
冲突的 TeleportOptions
以下组合会导致“参数不兼容”错误:
ReservedServerAccessCode+ServerInstanceIdShouldReserveServer+ServerInstanceIdShouldReserveServer+ReservedServerAccessCode
TeleportOptions
| 属性 | 用途 |
|---|---|
ServerInstanceId | 通过 JobId 指定目标服务器。 |
ReservedServerAccessCode | 使用访问代码加入现有的预留服务器。 |
ShouldReserveServer | 创建新的预留服务器并传送到其中。 |
SetTeleportData(data) / GetTeleportData() | 将数据传递到目标地点(通过 GetLocalPlayerTeleportData 获取)。 |
TeleportAsyncResult
传入 TeleportOptions 时,TeleportAsync 会返回一个 TeleportAsyncResult,其中包含最终传送目的地的信息。可用于确认玩家最终到达的位置。
TeleportInitFailed(错误处理)
当传送无法启动时,会触发 TeleportService.TeleportInitFailed。连接到此事件以显示重试界面。失败原因包括无效的 place ID、玩家列表为空、实例不是 Player、传送选项类型错误、由客户端调用 TeleportAsync,以及参数冲突。
TeleportService.TeleportInitFailed:Connect(function(
player: Player,
reason: Enum.TeleportResult,
errMsg: string,
placeId: number,
options: TeleportOptions
)
warn(`Teleport failed for {player.Name} to {placeId}: {reason.Name} - {errMsg}`)
-- Show retry UI, log options, etc.
end)
保留服务器
TeleportService:ReserveServerAsync(placeId)(仅限服务器端,会让出执行权)会返回访问码和一个 PrivateServerId。玩家只能通过该访问码加入保留服务器,无法通过常规匹配加入。
- 首次使用访问码时,服务器会启动。
- 访问码会一直有效;即使当前没有服务器运行,也可以重新加入保留服务器(系统会启动一个新服务器)。
- 检测是否处于保留服务器环境:
local isReserved = game.PrivateServerId ~= "" and game.PrivateServerOwnerId == 0。 - 同一访问码对应的不同服务器实例,其
PrivateServerId相同;JobId则不同。 - **跨平台注意事项:**关闭跨平台联机的 Xbox/PlayStation 玩家会进入与启用跨平台联机的玩家不同的服务器。多个服务器可以共用一个
PrivateServerId。使用game.MatchmakingType进行区分。
--!strict
local TeleportService = game:GetService("TeleportService")
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
-- Reserve a candidate, then atomically publish-or-use the winner.
local store = DataStoreService:GetDataStore("ReservedServerAllocations_v2")
local reserveOk, candidateCode = pcall(function()
return select(1, TeleportService:ReserveServerAsync(game.PlaceId))
end)
local code: string? = nil
if reserveOk and typeof(candidateCode) == "string" then
local now = os.time()
local candidate = { accessCode = candidateCode, expiresAt = now + 3600, state = "allocated" }
local publishOk, winner = pcall(function()
return store:UpdateAsync("DungeonRoom_1", function(current)
if type(current) == "table" and type(current.accessCode) == "string" and current.expiresAt > now then
return current
end
return candidate
end)
end)
if publishOk and type(winner) == "table" then
code = winner.accessCode -- every racing allocator uses the same winner
end
end
local function sendToDungeon(player: Player)
if not code then return end
local options = Instance.new("TeleportOptions")
options.ReservedServerAccessCode = code
options:SetTeleportData({ room = 1 })
pcall(function()
TeleportService:TeleportAsync(game.PlaceId, { player }, options)
end)
end
跨传送传递数据
有两种机制,安全性各不相同:
TeleportOptions:SetTeleportData / GetLocalPlayerTeleportData
在源服务器上(通过 TeleportOptions)设置,然后在目标客户端上通过 TeleportService:GetLocalPlayerTeleportData() 获取。**只能在客户端获取。**可以传递任何可序列化的值。
**安全性:**利用漏洞的用户可以伪造传送数据。敏感数据(货币、权益)应通过 DataStoreService 发送;传送数据仅用于非敏感提示(所选游戏模式、外观装备偏好)。
SetTeleportSetting / GetTeleportSetting
仅限客户端,在本地存储,并在同一游戏内的传送过程中保留。适用于无需服务器信任的客户端偏好设置(蹲伏状态、UI 标签页)。此数据也可被伪造。任何影响游戏玩法的内容都应在服务器端验证。
自定义加载界面
TeleportService:SetTeleportGui(gui)(客户端)会设置一个在传送过程中显示的 ScreenGui。TeleportService:GetArrivingTeleportGui()(客户端,在目标位置调用)会获取该界面,以便你将其设为 PlayerGui 的子对象并运行自定义过渡效果。传送 GUI 不会跨越到不同的游戏(universe),也不会在多次传送之间保留。每次传送前都要设置。
--!strict
-- At the destination, in ReplicatedFirst
local TeleportService = game:GetService("TeleportService")
local Players = game:GetService("Players")
local ReplicatedFirst = game:GetService("ReplicatedFirst")
local customLoadingScreen = TeleportService:GetArrivingTeleportGui()
if customLoadingScreen then
local playerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
ReplicatedFirst:RemoveDefaultLoadingScreen()
customLoadingScreen.Parent = playerGui
task.wait(5)
customLoadingScreen:Destroy()
end
跨体验传送
默认情况下,从你的体验传送到其他人拥有的体验会失败。如需启用跨体验传送,请按照官方地点之间的传送文档中的步骤操作。在你自己的 universe 内部(跨地点)传送无需额外设置即可使用。
TeleportService:PromptExperienceDetailsAsync(player, universeId)(仅限客户端,会让出执行权)会向玩家显示体验详情和加入按钮。如果玩家不符合加入目标体验的资格,该按钮会被禁用。在 Studio 中进行游戏测试时,加入按钮始终处于禁用状态。
匹配模式
模式 1:大厅 → 对局(简单轮询)
大厅地点收集玩家;准备就绪的玩家达到一定数量后,TeleportAsync 会将他们发送到游戏地点。如果有多个大厅,请使用 MessagingService 在不同的大厅服务器之间协调。
模式 2:每场对局使用一个保留服务器
适用于副本地下城或私人对局:ReserveServerAsync → 将访问码按对局 ID 存入 DataStore → 使用 ReservedServerAccessCode 传送队伍 → 玩家进入隔离服务器。
模式 3:通过 MemoryStoreService 实现服务器浏览器
维护一个 MemoryStoreService 排序映射,其中记录活跃服务器(以 JobId 为键,玩家人数/模式/延迟为值)。大厅列出这些条目;玩家选中某个服务器后,设置 TeleportOptions.ServerInstanceId = jobId 并调用 TeleportAsync。每个游戏服务器在玩家加入/离开时更新排序映射。与服务器数量较多时使用 MessagingService 相比,这种方式的扩展性更好。
模式 4:外部匹配服务
对于复杂的匹配(基于技能、队伍队列),使用外部 HTTP 服务作为匹配器。它会返回 placeId + JobId,或一个新的预留服务器访问代码;随后由大厅调用 TeleportAsync 传送整个队伍。有关 HttpService 安全模型和游戏内 Open Cloud 调用,请参阅 roblox-networking 和 roblox-open-cloud。
所有匹配都必须遵守每次 TeleportAsync 最多传送 50 名玩家的限制;更大的队伍需拆分成多次调用。
通过传送交接 DataStore 数据
要在不同地点之间转移玩家状态:
- **源服务器:**触发事件时,通过
UpdateAsync保存玩家档案(参阅 roblox-datastores)。然后进行传送。 - **目标服务器:**在
PlayerAdded时,通过GetAsync加载档案(如果刚刚保存过,可考虑使用UseCache=false以获取最新数据)。 - **竞态条件:**如果目标服务器加载时保存尚未写入完成,你会得到过时数据。可通过以下方式缓解:(a)如果数据很重要,在传送前等待保存确认;或(b)在传送数据中传入“加载此版本”的提示,并重试加载,直到版本匹配。
- **绝不要将传送数据视为权威状态。**传送数据只是提示;DataStore 才是真实数据源。
安全性
- **
TeleportAsync只能由服务器调用。**客户端不能直接调用它。如果需要由客户端发起传送,客户端应发送 RemoteEvent,由服务器验证后再调用TeleportAsync。旧版客户端方法Teleport()现已弃用(请在服务器上使用TeleportAsync());请参阅上文的迁移指南。 - **对每位玩家的传送请求进行速率限制。**恶意客户端反复发送“传送我”的 RemoteEvent,可能扰乱服务器流程;如果每次触发都会保存数据,还会消耗 DataStore 预算。
- **验证目标地点。**不要未经清理就让客户端提供的地点 ID 决定传送目标。在服务器端将允许的目标地点列入白名单。
- **传送数据可被伪造。**将其视为提示;在目标服务器上通过 DataStore 重新验证任何会影响游戏的声明。
GetLocalPlayerTeleportData只能由客户端调用,且返回由客户端控制的数据。不要在服务器上将其用于权威决策。
Studio 限制
**TeleportService 在 Studio 游戏测试期间无法使用。**你必须发布体验,并在 Roblox 应用程序中测试传送。请在测试工作流中考虑这一点。传送逻辑只能在线上验证。
注意事项
- 玩家传送后会失去角色状态(新地点会生成新角色)。请通过 DataStore 保存/加载数据;不要尝试保留实时角色状态。
- 源服务器上的
BindToClose可能与传送发生竞态。如果数据很重要,请在触发传送前完成保存。 - 默认传送加载消息已移除;
CustomizedTeleportUI已弃用且不起作用。 - 跨平台情况下(关闭跨平台游戏的 Xbox/PS),一个预留服务器可能会被拆分为多个具有相同
PrivateServerId的服务器。 - 队伍传送仅限同一 universe;你无法通过
TeleportAsync将队伍传送到其他体验。 - 50 名玩家的限制按每次调用计算。更大的队伍需要多次调用;若要确保“同时抵达”,调用顺序很重要。
- 跟随好友:
Players.PlayerAdded→ 检查player.FollowUserId→GetPlayerPlaceInstanceAsync(followId)→TeleportToPlaceInstance。注意,GetPlayerPlaceInstanceAsync返回的是JobId,而不是预留服务器访问代码,因此无法用于跟随好友进入预留服务器。
脚本
scripts/TeleportHelper.lua:经过审查的服务端示例,展示了原子化发布预留代码、过期处理、分配结果不明确时的协调,以及分开的teleporting/arrived状态。
后续步骤
- 确定你的场所架构:在同一个 universe 中设置主场所和子场所。
- 跨场所传送时,使用
TeleportAsync(服务端)和TeleportOptions。 - 对于预留服务端,先预留一个候选项,再通过
UpdateAsync发布;使用最终胜出的分配结果。分别跟踪传送的发起和抵达目的地。 - 通过传送数据传递非敏感提示;通过 DataStores 传递权威状态。
- 连接
TeleportInitFailed,以提供重试 UI。 - 验证并限制任何由客户端发起的传送 Remote 的调用频率。
- 使用已发布的体验,在 Roblox 应用中(而非 Studio)进行测试。
参考索引
- matchmaking.md:协调大厅、预留服务端、分配竞争或玩家数据交接。
- teleport-options.md:选择目标服务端或检查传送结果。