요약
메서드
이벤트
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})`
)
-- 여기에서 송신자 측 확인 또는 UI 업데이트를 진행하세요.
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})`
)
-- 여기에서 수신자 측 혜택을 부여하거나 UI 업데이트를 진행하세요.
return Enum.ReceiptDecision.Processed
end
)GetDeveloperProductsAsync
반환
코드 샘플
MarketplaceService: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
매개 변수
코드 샘플
로블록스 구독 세부정보 확인
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
반환
코드 샘플
MarketplaceService: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
매개 변수
반환
()
코드 샘플
로블록스 플러스 구독 구매 안내
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
-- 플레이어는 이미 로블록스 플러스를 가지고 있습니다; 즉시 보상을 제공합니다
grantRewardAndTeleport(player)
else
-- 로블록스 플러스 구독을 안내합니다, 몇 초마다 한 번 반복됩니다
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}
-- 오류를 우아하게 처리하기 위해 보호된 호출에서 실행합니다.
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, "bought an item with AssetID:", assetId)
else
print(player.Name, "didn't buy an item with 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() 콜백 내에서 나중에 호출되므로 결코 yield하지 않아야 합니다.
local grantPurchaseHandlerByProductId = {
[productIdByName.fullHeal] = function(_receipt, player)
local character = player.Character
local humanoid = character and character:FindFirstChild("Humanoid")
-- 플레이어가 치유할 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인 경우, true가 다시 반환되어 pcall 결과 변수도 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