You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Roblox Lua脚本GamePass检测异常 购买后仍反复提示购买排查

问题根因

UserOwnsGamePassAsync始终返回false、重复弹出购买提示的问题由以下几个原因共同导致:

  • GamePass ID填写错误:Roblox创作者后台创建GamePass后,页面地址栏默认显示的是资产ID,并非UserOwnsGamePassAsync接口要求传入的GamePass ID,你当前填写的48752534大概率是资产ID而非实际生效的GamePass ID,这是接口返回false的最常见诱因。
  • 接口调用未做错误兜底:UserOwnsGamePassAsync属于网络请求接口,遇到限流、网络波动时会抛出错误,你没有用pcall包裹调用逻辑,一旦请求报错整个循环逻辑会直接异常中断。
  • 轮询逻辑设计缺陷:用while wait(3)做无限轮询时,每3秒直接触发PromptGamePassPurchase,会在玩家已经打开购买弹窗时重复触发弹窗调用,导致界面逻辑异常;同时轮询方案性能差,还容易触发接口限流。
  • 引用失效问题:脚本开头直接获取Player.Character下的Humanoid实例,玩家每次重生角色都会生成新的Humanoid,旧引用会直接失效,后续修改WalkSpeed的逻辑不会作用在新角色上。
  • 校验逻辑位置错误:将权限判断、速度修改逻辑全部放在客户端执行,不仅容易被作弊工具篡改绕过,客户端和服务端的状态同步延迟也会导致状态判断异常。
修复步骤

1 获取正确的GamePass ID

打开Roblox Studio命令栏,运行以下代码,将打印出的正确GamePass ID替换原脚本中的48752534:

local MPS = game:GetService("MarketplaceService")
local inputAssetId = 48752534 -- 你当前脚本中填写的ID
local success, productInfo = pcall(function()
    return MPS:GetProductInfo(inputAssetId, Enum.InfoType.GamePass)
end)
if success then
    print("接口要求传入的正确GamePass ID为:", productInfo.TargetId)
else
    print("查询失败,请确认输入的ID属于GamePass类型资产")
end

2 部署服务端校验逻辑

在ServerScriptService下新建服务端脚本,所有权限判断、角色属性修改逻辑全部放在服务端执行,避免被客户端作弊篡改:

local MPS = game:GetService("MarketplaceService")
local GAMEPASS_ID = 0 -- 替换为上一步获取到的正确GamePass ID
-- 速度参数按需调整
local LOCKED_WALKSPEED = 0
local LOCKED_JUMPPOWER = 0
local UNLOCKED_WALKSPEED = 18.5
local UNLOCKED_JUMPPOWER = 50

game.Players.PlayerAdded:Connect(function(player)
    local ownsPass = false
    -- 加错误兜底调用持有状态查询接口
    local querySuccess, queryResult = pcall(function()
        return MPS:UserOwnsGamePassAsync(player.UserId, GAMEPASS_ID)
    end)
    if querySuccess then
        ownsPass = queryResult
    end

    -- 玩家每次重生角色时重新设置速度
    player.CharacterAdded:Connect(function(character)
        local humanoid = character:WaitForChild("Humanoid")
        if ownsPass then
            humanoid.WalkSpeed = UNLOCKED_WALKSPEED
            humanoid.JumpPower = UNLOCKED_JUMPPOWER
        else
            humanoid.WalkSpeed = LOCKED_WALKSPEED
            humanoid.JumpPower = LOCKED_JUMPPOWER
        end
    end)

    -- 监听购买完成事件,购买成功后立刻解锁权限,不需要轮询
    MPS.PromptGamePassPurchaseFinished:Connect(function(buyer, passId, purchaseSuccess)
        if buyer == player and passId == GAMEPASS_ID and purchaseSuccess then
            ownsPass = true
            if player.Character and player.Character:FindFirstChild("Humanoid") then
                player.Character.Humanoid.WalkSpeed = UNLOCKED_WALKSPEED
                player.Character.Humanoid.JumpPower = UNLOCKED_JUMPPOWER
            end
        end
    end)
end)

3 部署客户端弹窗逻辑

在StarterPlayerScripts下新建本地脚本,客户端只负责处理购买弹窗交互,不做权限判断和属性修改:

local MPS = game:GetService("MarketplaceService")
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local GAMEPASS_ID = 0 -- 和服务端填写相同的正确GamePass ID

-- 等待角色加载、服务端状态同步完成
player.CharacterAdded:Wait()
task.wait(1)

-- 查询一次持有状态,未持有则弹出一次购买窗,不做循环轮询
local querySuccess, ownsPass = pcall(function()
    return MPS:UserOwnsGamePassAsync(player.UserId, GAMEPASS_ID)
end)
if querySuccess and not ownsPass then
    MPS:PromptGamePassPurchase(player, GAMEPASS_ID)
end

-- 监听购买结果
MPS.PromptGamePassPurchaseFinished:Connect(function(buyer, passId, purchaseSuccess)
    if buyer == player and passId == GAMEPASS_ID and purchaseSuccess then
        print("GamePass购买成功,移动权限已解锁")
    end
end)
注意事项
  • 禁止使用无限轮询的方式检测购买状态,Roblox提供了专门的PromptGamePassPurchaseFinished事件做购买结果监听,轮询不仅浪费性能,还容易触发接口限流导致请求失败。
  • 所有涉及玩家权限、角色属性的修改逻辑必须放在服务端执行,客户端的任何数值都可以被作弊工具随意篡改,纯客户端校验没有安全可言。
  • Studio环境下测试时,创作者账号的GamePass持有状态会被接口正确识别,不需要额外做模拟;如果需要测试未持有状态,可以临时将判断逻辑取反调试。

内容的提问来源于stack exchange,提问作者rml1310

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 23:51:35