概要
方法
活动
PromptBulkPurchaseFinished(player: Instance,status: Enum.MarketplaceBulkPurchasePromptStatus,results: Dictionary):RBXScriptSignal |
PromptBundlePurchaseFinished(player: Instance,bundleId: number,wasPurchased: boolean):RBXScriptSignal |
PromptGamePassPurchaseFinished(player: Instance,gamePassId: number,wasPurchased: boolean):RBXScriptSignal |
PromptProductPurchaseFinished(userId: number,productId: number,isPurchased: boolean):RBXScriptSignal |
PromptPurchaseFinished(player: Instance,assetId: number,isPurchased: boolean):RBXScriptSignal |
PromptRobloxSubscriptionPurchaseFinished(user: Player,didTryPurchasing: boolean):RBXScriptSignal |
PromptSubscriptionPurchaseFinished(user: Player,subscriptionId: string,didTryPurchasing: boolean):RBXScriptSignal |
回调
ProcessReceipt(receiptInfo: Dictionary):Enum.ProductPurchaseDecision |
API 参考
方法
BindReceiptHandler
MarketplaceService:BindReceiptHandler(
参数
代码示例
MarketplaceService:BindReceiptHandler
-- 注意:如果您的处理程序授予持久性好处(货币、物品),请使用
-- DataStoreService:UpdateAsync() 针对 TransferRequestId,以防止
-- 当相同收据发送到多个服务器时双重授予。
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")
-- 处理发送者的收据(发送 Robux 的玩家)
MarketplaceService:BindReceiptHandler(
Enum.ReceiptType.RobuxTransferSender,
function(receiptInfo)
local player = Players:GetPlayerByUserId(receiptInfo.PlayerId)
if not player then
-- 玩家不在此服务器上;推迟处理,以便收据被
-- 重新发送到他们当前所在的服务器
return Enum.ReceiptDecision.NotProcessedYet
end
print(
`{player.Name} 发送了 {receiptInfo.CurrencySpent} Robux`
.. ` (TransferRequestId: {receiptInfo.TransferRequestId})`
)
-- 在此授予任何发送者确认或更新用户界面
return Enum.ReceiptDecision.Processed
end
)
-- 处理接收者的收据(接收 Robux 的玩家)
MarketplaceService:BindReceiptHandler(
Enum.ReceiptType.RobuxTransferReceiver,
function(receiptInfo)
local player = Players:GetPlayerByUserId(receiptInfo.PlayerId)
if not player then
return Enum.ReceiptDecision.NotProcessedYet
end
print(
`{player.Name} 收到了 {receiptInfo.CurrencySpent} Robux`
.. ` (TransferRequestId: {receiptInfo.TransferRequestId})`
)
-- 在此授予任何接收者好处或更新用户界面
return Enum.ReceiptDecision.Processed
end
)GetDeveloperProductsAsync
返回
代码示例
市场服务:获取开发者产品异步
local MarketplaceService = game:GetService("MarketplaceService")
local developerProducts = MarketplaceService:GetDeveloperProductsAsync():GetCurrentPage()
for _, developerProduct in pairs(developerProducts) do
for field, value in pairs(developerProduct) do
print(field .. ": " .. value)
end
print(" ")
endGetProductInfo
GetProductInfoAsync
参数
| 默认值:"Asset" |
代码示例
获取产品信息
local MarketplaceService = game:GetService("MarketplaceService")
local ASSET_ID = 125378389
local asset = MarketplaceService:GetProductInfoAsync(ASSET_ID)
print(asset.Name .. " :: " .. asset.Description)显示价格折扣
local MarketplaceService = game:GetService("MarketplaceService")
local PASS_ID = 12345678
local textLabel = script.Parent
local DiscountTypeDisplay = {
RobloxPlusSubscription = "Roblox Plus 折扣",
}
local productInfo = MarketplaceService:GetProductInfoAsync(PASS_ID, Enum.InfoType.GamePass)
print(string.format("原价: %d", productInfo.UserBasePriceInRobux))
for _, discount in ipairs(productInfo.PriceDiscountDetails) do
local displayName = DiscountTypeDisplay[discount.Type] or "其他折扣"
print(string.format("%s (%d%%): -%d", displayName, discount.Percent, discount.AmountInRobux))
end
print(string.format("您支付: %d", productInfo.PriceInRobux))显示可用的定时选项
local MarketplaceService = game:GetService("MarketplaceService")
local info = MarketplaceService:GetProductInfoAsync(105589844216517, Enum.InfoType.Asset)
if info.TimedOptions then
for _, option in info.TimedOptions do
local days = option.Duration / 86400
print(string.format("%d 天 - %d Robux", days, option.Price))
end
endGetRobloxSubscriptionDetailsAsync
参数
代码示例
检查 Roblox 订阅详情
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")
Players.PlayerAdded:Connect(function(player)
local success, details = pcall(function()
return MarketplaceService:GetRobloxSubscriptionDetailsAsync(player)
end)
if success and details.IsSubscribed then
-- 1. 检查忠诚度(例如,订阅超过 60 天)
local threeMonths = 60 * 24 * 60 * 60
if details.StartTime and (os.time() - details.StartTime.UnixTimestamp) > threeMonths then
print("奖励 '3 个月订阅老兵' 皮肤!")
end
-- 2. 检查归因
if details.IsOriginExperience then
print("确认归因:用户通过此体验订阅。")
else
print("用户在其他地方订阅(网站或其他体验)。")
end
end
end)GetSubscriptionProductInfoAsync
参数
GetUsersPriceLevelsAsync
参数
返回
{PriceLevelInfo}
代码示例
获取用户列表的价格等级
-- 获取 MarketplaceService
local MarketplaceService = game:GetService("MarketplaceService")
-- 定义一个函数来获取用户列表的价格等级
local function getPriceLevels(userIds)
local success, result = pcall(function()
return MarketplaceService:GetUsersPriceLevelsAsync(userIds)
end)
if success then
-- 将每个 PriceLevelInfo 映射到 UserId -> PriceLevel 查找表
local lookup = {}
for _, info in ipairs(result) do
lookup[info.UserId] = info.PriceLevel
end
return lookup
else
warn("获取价格等级时出错:", result)
return nil
end
end
-- 使用占位符 ID 的示例
local user1Id = 123456789
local user2Id = 987654321
-- 调用函数并存储结果
local priceLevels = getPriceLevels({user1Id, user2Id})
-- 如果成功,打印每个用户的等级
if priceLevels then
print("用户 1 的价格等级:", priceLevels[user1Id])
print("用户 2 的价格等级:", priceLevels[user2Id])
else
print("无法获取价格等级。")
endGetUserSubscriptionDetailsAsync
GetUserSubscriptionPaymentHistoryAsync
返回
代码示例
市场服务:GetUserSubscriptionPaymentHistoryAsync
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")
local SUBSCRIPTION_ID = "EXP-0"
local function checkSubscriptionHistory(player: Player)
local subscriptionHistory = {}
local success, err = pcall(function()
subscriptionHistory = MarketplaceService:GetUserSubscriptionPaymentHistoryAsync(player, SUBSCRIPTION_ID)
end)
if not success then
warn(`检查订阅历史时出错: {err}`)
return
end
if next(subscriptionHistory) then
-- 用户在过去 12 个月内有一些订阅历史记录。
-- 打印订阅历史中每个付款条目的详细信息。
print(`玩家 {player.Name} 以前订阅过 {SUBSCRIPTION_ID}:`)
for entryNum, paymentEntry in subscriptionHistory do
local paymentStatus = tostring(paymentEntry.PaymentStatus)
local cycleStartTime = paymentEntry.CycleStartTime:FormatLocalTime("LLL", "en-us")
local cycleEndTime = paymentEntry.CycleEndTime:FormatLocalTime("LLL", "en-us")
print(`{entryNum}: {paymentStatus} ({cycleStartTime} - {cycleEndTime})`)
end
else
print(`玩家 {player.Name} 以前从未订阅过 {SUBSCRIPTION_ID}。`)
end
end
-- 对于游戏中已经存在的任何玩家调用 checkSubscriptionHistory
for _, player in ipairs(Players:GetPlayers()) do
checkSubscriptionHistory(player)
end
-- 对于所有未来的玩家调用 checkSubscriptionHistory
Players.PlayerAdded:Connect(checkSubscriptionHistory)GetUserSubscriptionStatusAsync
代码示例
检查用户订阅状态
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")
local subscriptionID = "EXP-00000"
local function checkSubStatus(player)
local subStatus = {}
local success, message = pcall(function()
-- 返回 IsRenewing 和 IsSubscribed
subStatus = MarketplaceService:GetUserSubscriptionStatusAsync(player, subscriptionID)
end)
if not success then
warn("检查玩家是否有订阅时出错: " .. tostring(message))
return
end
if subStatus["IsSubscribed"] then
print(player.Name .. " 订阅了 " .. subscriptionID)
-- 授予与该订阅相关的权限
end
end
Players.PlayerAdded:Connect(checkSubStatus)PlayerOwnsAsset
PlayerOwnsAssetAsync
返回
代码示例
检查物品所有权
local Players = game:GetService("Players")
local MarketplaceService = game:GetService("MarketplaceService")
-- 我们检查的物品: https://www.roblox.com/catalog/30331986/Midnight-Shades
local ASSET_ID = 30331986
local ASSET_NAME = "Midnight Shades"
local function onPlayerAdded(player)
local success, doesPlayerOwnAsset =
pcall(MarketplaceService.PlayerOwnsAssetAsync, MarketplaceService, player, ASSET_ID)
if not success then
local errorMessage = doesPlayerOwnAsset
warn(`检查 {player.Name} 是否拥有 {ASSET_NAME} 时出错: {errorMessage}`)
return
end
if doesPlayerOwnAsset then
print(`{player.Name} 拥有 {ASSET_NAME}`)
else
print(`{player.Name} 不拥有 {ASSET_NAME}`)
end
end
Players.PlayerAdded:Connect(onPlayerAdded)PlayerOwnsBundle
PlayerOwnsBundleAsync
返回
代码示例
检查捆绑物所有权
local Players = game:GetService("Players")
local MarketplaceService = game:GetService("MarketplaceService")
-- 我们正在检查的捆绑包: https://www.roblox.com/bundles/589/Junkbot
local BUNDLE_ID = 589
local BUNDLE_NAME = "Junkbot"
Players.PlayerAdded:Connect(function(player)
local success, doesPlayerOwnBundle = pcall(function()
return MarketplaceService:PlayerOwnsBundleAsync(player, BUNDLE_ID)
end)
if success == false then
print("PlayerOwnsBundleAsync 调用失败: ", doesPlayerOwnBundle)
return
end
if doesPlayerOwnBundle then
print(player.Name .. " 拥有 " .. BUNDLE_NAME)
else
print(player.Name .. " 不拥有 " .. BUNDLE_NAME)
end
end)PromptBulkPurchase
参数
返回
()
代码示例
提示批量购买客户端
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local promptBulkPurchaseEvent = ReplicatedStorage:WaitForChild("PromptBulkPurchaseEvent")
local part = Instance.new("Part")
part.Parent = workspace
local clickDetector = Instance.new("ClickDetector")
clickDetector.Parent = part
clickDetector.MouseClick:Connect(function()
promptBulkPurchaseEvent:FireServer({
{ Type = Enum.MarketplaceProductType.AvatarAsset, Id = "16630147" },
{ Type = Enum.MarketplaceProductType.AvatarBundle, Id = "182" },
})
end)提示批量购买服务器
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local MarketplaceService = game:GetService("MarketplaceService")
local promptBulkPurchaseEvent = Instance.new("RemoteEvent")
promptBulkPurchaseEvent.Name = "PromptBulkPurchaseEvent"
promptBulkPurchaseEvent.Parent = ReplicatedStorage
-- 监听来自客户端的 RemoteEvent 事件,并触发批量购买提示
promptBulkPurchaseEvent.OnServerEvent:Connect(function(player, items)
MarketplaceService:PromptBulkPurchase(player, items, {})
end)提示定时选项购买
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")
local ASSET_ID = 105589844216517
Players.PlayerAdded:Connect(function(player)
local info = MarketplaceService:GetProductInfoAsync(ASSET_ID, Enum.InfoType.Asset)
if info.TimedOptions and #info.TimedOptions > 0 then
-- 查找最短持续时间的选项
local shortest = info.TimedOptions[1]
for _, option in info.TimedOptions do
if option.Duration < shortest.Duration then
shortest = option
end
end
local items = {
{
Type = Enum.MarketplaceProductType.AvatarAsset,
Id = tostring(ASSET_ID),
PurchaseOptions = {
{ Type = Enum.PurchaseOption.TimedOption, Value = shortest.Duration },
},
}
}
MarketplaceService:PromptBulkPurchase(player, items, {})
end
end)PromptBundlePurchase
PromptCancelSubscription
PromptGamePassPurchase
PromptPremiumPurchase
PromptProductPurchase
MarketplaceService:PromptProductPurchase(
):()
参数
| 默认值:true |
| 默认值:"Default" |
返回
()
代码示例
市场服务:提示购买产品
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local productId = 0000000 -- 将此更改为您的开发者产品 ID
-- 提示购买开发者产品的函数
local function promptPurchase()
MarketplaceService:PromptProductPurchase(player, productId)
end
promptPurchase()PromptPurchase
MarketplaceService:PromptPurchase(
):()
参数
| 默认值:true |
| 默认值:"Default" |
返回
()
代码示例
本地脚本 (客户端)
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local promptPurchaseEvent = ReplicatedStorage:WaitForChild("PromptPurchaseEvent")
local part = Instance.new("Part")
part.Parent = workspace
local clickDetector = Instance.new("ClickDetector")
clickDetector.Parent = part
clickDetector.MouseClick:Connect(function()
promptPurchaseEvent:FireServer(16630147)
end)脚本(服务器)
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local MarketplaceService = game:GetService("MarketplaceService")
local promptPurchaseEvent = Instance.new("RemoteEvent")
promptPurchaseEvent.Name = "PromptPurchaseEvent"
promptPurchaseEvent.Parent = ReplicatedStorage
-- 监听来自客户端的 RemoteEvent 触发,然后触发购买提示
promptPurchaseEvent.OnServerEvent:Connect(function(player, id)
MarketplaceService:PromptPurchase(player, id)
end)PromptRobloxSubscriptionPurchase
参数
返回
()
代码示例
提示购买 Roblox Plus 订阅
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")
local teleporter = script.Parent
local showModal = true
local EXCLUSIVE_AREA_POSITION = Vector3.new(1200, 200, 60)
-- 授予奖励并将订阅玩家传送到专属区域
local function grantRewardAndTeleport(player)
player:RequestStreamAroundAsync(EXCLUSIVE_AREA_POSITION)
local character = player.Character
if character and character.Parent then
local currentPivot = character:GetPivot()
character:PivotTo(currentPivot * CFrame.new(EXCLUSIVE_AREA_POSITION))
end
end
-- 检测角色部件触碰传送器
teleporter.Touched:Connect(function(otherPart)
local player = Players:GetPlayerFromCharacter(otherPart.Parent)
if not player then
return
end
if not player:GetAttribute("CharacterPartsTouching") then
player:SetAttribute("CharacterPartsTouching", 0)
end
player:SetAttribute("CharacterPartsTouching", player:GetAttribute("CharacterPartsTouching") + 1)
if player.HasRobloxSubscription then
-- 玩家已经拥有 Roblox Plus,立即授予奖励
grantRewardAndTeleport(player)
else
-- 提示 Roblox Plus 订阅,防抖动每几秒一次
if not showModal then
return
end
showModal = false
task.delay(5, function()
showModal = true
end)
MarketplaceService:PromptRobloxSubscriptionPurchase(player)
end
end)
-- 检测角色部件离开传送器
teleporter.TouchEnded:Connect(function(otherPart)
local player = Players:GetPlayerFromCharacter(otherPart.Parent)
if player and player:GetAttribute("CharacterPartsTouching") then
player:SetAttribute("CharacterPartsTouching", player:GetAttribute("CharacterPartsTouching") - 1)
end
end)
-- 当服务器确认订阅变更时授予奖励
-- 连接每个玩家的 HasRobloxSubscription 变更
Players.PlayerAdded:Connect(function(player)
player:GetPropertyChangedSignal("HasRobloxSubscription"):Connect(function()
if player.HasRobloxSubscription
and player:GetAttribute("CharacterPartsTouching")
and player:GetAttribute("CharacterPartsTouching") > 0
then
grantRewardAndTeleport(player)
end
end)
end)PromptRobuxTransferAsync
返回
代码示例
MarketplaceService:PromptRobuxTransferAsync
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")
-- 示例:当玩家触发 RemoteEvent 时转移 Robux
local transferEvent = game.ReplicatedStorage:WaitForChild("RequestTransfer")
transferEvent.OnServerEvent:Connect(function(sender, receiverUserId, amount)
-- 验证输入
if not sender or not sender:IsA("Player") then
return
end
if typeof(receiverUserId) ~= "number" or receiverUserId <= 0 then
warn("无效的 receiverUserId")
return
end
if typeof(amount) ~= "number" or amount <= 0 then
warn("无效的金额")
return
end
local success, result = pcall(function()
return MarketplaceService:PromptRobuxTransferAsync(sender, receiverUserId, amount)
end)
if success then
print(`转账已启动,TransferRequestId: {result}`)
else
warn(`转账失败: {result}`)
end
end)PromptSubscriptionPurchase
RankProductsAsync
参数
返回
{RankedItem}
代码示例
根据提供的产品 ID 获取排名产品列表
-- 获取 MarketplaceService
local MarketplaceService = game:GetService("MarketplaceService")
-- 创建要排名的产品数组
local productIdentifiers = {
{InfoType = Enum.InfoType.GamePass, Id = 123},
{InfoType = Enum.InfoType.Product, Id = 456},
{InfoType = Enum.InfoType.Product, Id = 789}
}
-- 以受保护的调用处理错误
local success, rankedProducts = pcall(function()
return MarketplaceService:RankProductsAsync(productIdentifiers)
end)
if not success then
error("排名产品失败")
end
-- 将返回的项目加载到商店中。
for i, rankedItem in ipairs(rankedProducts) do
local productIdentifier = rankedItem.ProductIdentifier
local productInfo = rankedItem.ProductInfo
-- ...
-- 将产品添加到商店的逻辑
endRecommendTopProductsAsync
参数
返回
{RankedItem}
代码示例
获取您体验内商店中的顶级产品的排名列表
-- 获取 MarketplaceService
local MarketplaceService = game:GetService("MarketplaceService")
-- 创建要包含的产品类型数组。在这种情况下包括游戏通行证和开发者产品
local productTypes = {Enum.InfoType.GamePass, Enum.InfoType.Product}
-- 以受保护的调用来处理错误 gracefully
local success, topRankedItems = pcall(function()
return MarketplaceService:RecommendTopProductsAsync(productTypes)
end)
if not success then
error("未能对产品进行排名")
end
-- 将返回的项目加载到商店中。确保过滤掉 topRankedItems 中任何不符合条件的项目,例如用户无法再购买的开发者产品
for i, rankedItem in ipairs(topRankedItems) do
local productIdentifier = rankedItem.ProductIdentifier
local productInfo = rankedItem.ProductInfo
-- ...
-- 将产品添加到商店的逻辑
end活动
PromptBulkPurchaseFinished
MarketplaceService.PromptBulkPurchaseFinished(
参数
PromptBundlePurchaseFinished
PromptGamePassPurchaseFinished
MarketplaceService.PromptGamePassPurchaseFinished(
代码示例
处理游戏通行证购买完成
local MarketplaceService = game:GetService("MarketplaceService")
local function gamepassPurchaseFinished(...)
-- 打印提示的所有详细信息,例如:
-- PromptGamePassPurchaseFinished PlayerName 123456 false
print("PromptGamePassPurchaseFinished", ...)
end
MarketplaceService.PromptGamePassPurchaseFinished:Connect(gamepassPurchaseFinished)PromptProductPurchaseFinished
PromptPurchaseFinished
MarketplaceService.PromptPurchaseFinished(
代码示例
处理 PromptPurchaseFinished 事件
local MarketplaceService = game:GetService("MarketplaceService")
local function onPromptPurchaseFinished(player, assetId, isPurchased)
if isPurchased then
print(player.Name, "购买了物品,AssetID:", assetId)
else
print(player.Name, "没有购买物品,AssetID:", assetId)
end
end
MarketplaceService.PromptPurchaseFinished:Connect(onPromptPurchaseFinished)PromptRobloxSubscriptionPurchaseFinished
MarketplaceService.PromptRobloxSubscriptionPurchaseFinished(
代码示例
处理 PromptRobloxSubscriptionPurchaseFinished 事件
local MarketplaceService = game:GetService("MarketplaceService")
local function onPromptRobloxSubscriptionPurchaseFinished(player, didTryPurchasing)
if didTryPurchasing then
-- 玩家尝试订阅;等待 HasRobloxSubscription 更改以确认
print(player.Name, "尝试订阅 Roblox Plus")
else
print(player.Name, "在未购买的情况下关闭了 Roblox Plus 订阅提示")
end
end
MarketplaceService.PromptRobloxSubscriptionPurchaseFinished:Connect(onPromptRobloxSubscriptionPurchaseFinished)回调
ProcessReceipt
参数
代码示例
处理收据回调
local MarketplaceService = game:GetService("MarketplaceService")
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
-- 数据存储设置,用于跟踪成功处理的购买
local purchaseHistoryStore = DataStoreService:GetDataStore("PurchaseHistory")
local productIdByName = {
fullHeal = 123123,
gold100 = 456456,
}
-- 一个字典,用于查找与产品 ID 相对应的授予购买的处理函数
-- 如果购买成功授予,则这些函数返回 true
-- 这些函数绝不能让出,因为它们稍后在 UpdateAsync() 回调中被调用
local grantPurchaseHandlerByProductId = {
[productIdByName.fullHeal] = function(_receipt, player)
local character = player.Character
local humanoid = character and character:FindFirstChild("Humanoid")
-- 确保玩家拥有可以治疗的类人角色
if not humanoid then
return false
end
-- 将玩家治愈到满生命值
humanoid.Health = humanoid.MaxHealth
-- 表示成功授予
return true
end,
[productIdByName.gold100] = function(_receipt, player)
local leaderstats = player:FindFirstChild("leaderstats")
local goldStat = leaderstats and leaderstats:FindFirstChild("Gold")
if not goldStat then
return false
end
-- 为玩家的金币统计添加 100 金币
goldStat.Value += 100
-- 表示成功授予
return true
end,
}
-- 核心 ProcessReceipt 回调函数
-- 该实现处理大多数失败场景,但并不能完全减轻跨服务器数据失败场景
local function processReceipt(receiptInfo)
local success, result = pcall(
purchaseHistoryStore.UpdateAsync,
purchaseHistoryStore,
receiptInfo.PurchaseId,
function(isPurchased)
if isPurchased then
-- 此购买已被记录为授予,因此它必须之前已被处理
-- 避免在此调用授予购买的处理程序,以防止重复授予购买
-- 尽管数据存储中的值已经为 true,但由于 pcall 结果变量也将为 true,因此再次返回 true
-- 这将稍后用于从收据处理器返回 PurchaseGranted
return true
end
local player = Players:GetPlayerByUserId(receiptInfo.PlayerId)
if not player then
-- 如果玩家不在服务器中,避免授予购买
-- 当他们重新加入时,此收据处理器将被再次调用
return nil
end
local grantPurchaseHandler = grantPurchaseHandlerByProductId[receiptInfo.ProductId]
if not grantPurchaseHandler then
-- 如果没有为此产品 ID 定义处理程序,则无法处理购买
-- 只要为体验中销售的每个产品 ID 设置了处理程序,这种情况就不会发生
warn(`没有为产品 ID '{receiptInfo.ProductId}' 定义购买处理程序`)
return nil
end
local handlerSucceeded, handlerResult = pcall(grantPurchaseHandler, receiptInfo, player)
if not handlerSucceeded then
local errorMessage = handlerResult
warn(
`在处理来自 '{player.Name}' 的产品 ID '{receiptInfo.ProductId}' 购买时,授予购买处理程序出现错误:{errorMessage}`
)
return nil
end
local didHandlerGrantPurchase = handlerResult == true
if not didHandlerGrantPurchase then
-- 处理程序未授予购买,因此将其记录为未授予
return nil
end
-- 购买现在已授予给玩家,因此将其记录为已授予
-- 这将在稍后用于从收据处理器返回 PurchaseGranted
return true
end
)
if not success then
local errorMessage = result
warn(`由于数据存储错误而未能处理收据:{errorMessage}`)
return Enum.ProductPurchaseDecision.NotProcessedYet
end
local didGrantPurchase = result == true
return if didGrantPurchase
then Enum.ProductPurchaseDecision.PurchaseGranted
else Enum.ProductPurchaseDecision.NotProcessedYet
end
-- 设置回调;这只能由服务器上的一个脚本执行一次
MarketplaceService.ProcessReceipt = processReceipt