MarketplaceService
MarketplaceService : Instance
Overview
MarketplaceService는 월드 내에서의 상품 구매 및 결제 성공에 따른 지급 처리를 담당하는 서비스입니다.
크리에이터는 상품이 판매되었을 때 지급이 누락되지 않도록 반드시 ProcessReceipt 콜백 함수를 정의해야 하며, DataStore 등을 활용하여 정상적으로 지급이 완료되도록 처리할 책임이 있습니다.
Properties
Methods
GetProductInfo
상품 ID(productId)와 상품 타입(Enum.InfoType)에 해당하는 상품 정보를 반환합니다.
Parameters
number
ProductId
상품의 ID입니다.
Enum.InfoType
InfoType
상품의 타입입니다.
Return
Dictionary
상품 정보로 구성된 딕셔너리입니다.
string
Name: 상품 이름string
Description: 상품 설명number
ProductId: 상품 IDstring
ProductType: 상품 종류number
PriceInBLUC: 상품 가격number
Created: 상품이 생성된 시간 (UNIX timestamp)number
Updated: 상품이 수정된 시간 (UNIX timestamp)
Code Samples
local MarketplaceService = game:GetService("MarketplaceService")
local function Request_GetProductInfo(productId)
local success, errorOrProductInfo = pcall(function()
return MarketplaceService:GetProductInfo(productId, Enum.InfoType.Product)
end)
if not success then
print("Error: " .. errorOrProductInfo .. " / ProductId : " .. productId)
else
local productInfo = errorOrProductInfo
print("World Product Name: " .. tostring(productInfo.Name))
print("ProductId: " .. tostring(productInfo.ProductId))
print("ProductType: " .. tostring(productInfo.ProductType))
print("PriceInBLUC: " .. tostring(productInfo.PriceInBLUC))
print("Description: " .. tostring(productInfo.Description))
print("Created: " .. productInfo.Created)
print("Updated: " .. productInfo.Updated)
end
end
GetWorldProductsAsync
모든 월드 상품에 대한 정보를 포함하는 Pages 객체를 반환합니다.
Parameters
Return
Pages
현재 월드의 모든 월드 상품에 대한 정보를 포함하는 객체입니다.
Code Samples
local MarketplaceService = game:GetService("MarketplaceService")
local function Request_GetWorldProductsAsync()
local success, errorOrWorldProducts = pcall(function()
return MarketplaceService:GetWorldProductsAsync()
end)
if not success then
print("Error: " .. errorOrWorldProducts)
else
local worldProducts = errorOrWorldProducts
local pageCount = 1
local dataList = {}
while true do
local currentPage = worldProducts:GetCurrentPage()
-- 마지막 페이지이면 루프 탈출
if worldProducts.IsFinished or currentPage == nil then
print(pageCount .. " page IsFinished : " .. tostring(worldProducts.IsFinished))
break
else
worldProducts:AdvanceToNextPageAsync()
pageCount = pageCount + 1
end
-- 한 페이지에 최대 100개의 상품 정보 구성
for _, productInfo in pairs(currentPage) do
local i = #dataList + 1
print("------ " .. i .. " ------")
print("World Product Name: " .. tostring(productInfo.Name))
print("ProductId: " .. tostring(productInfo.ProductId))
print("ProductType: " .. tostring(productInfo.ProductType))
print("PriceInBLUC: " .. tostring(productInfo.PriceInBLUC))
print("Description: " .. tostring(productInfo.Description))
print("Created: " .. productInfo.Created)
print("Updated: " .. productInfo.Updated)
table.insert(dataList, productInfo)
end
end
end
end
PromptProductPurchase
월드 상품 ID(productId)에 해당하는 상품의 구매를 요청합니다. (시스템 UI로 구매창이 출력됩니다.)
Parameters
Player
Player
상품을 구매할 Player입니다.
number
ProductId
월드의 상품 Id입니다.
Return
void
Code Samples
local MarketplaceService = game:GetService("MarketplaceService")
local function Request_PromptProductPurchase(player, productId)
local success, error = pcall(function()
MarketplaceService:PromptProductPurchase(player, productId)
end)
if not success then
print("Error: " .. error .. " / ProductId : " .. productId)
end
end
Events
PromptProductPurchaseFinished
구매 요청(PromptProductPurchase)을 통해 출력된 구매창이 꺼질 때 이벤트가 호출되며, 구매를 성공하면 isPurchased에 true가 전달되고, 구매를 취소하거나 실패하면 false가 전달됩니다.
이 이벤트는 구매 창을 닫았는지 감지하기 위한 용도로만 사용해야 하며, 구매한 상품에 대한 지급 처리 용도로는 절대 사용하지 않아야 합니다.
Parameters
string
UserId
구매 요청한 Player의 UserId입니다.
number
ProductId
구매 요청한 상품의 Id입니다.
bool
bIsPurchased
구매 성공 여부입니다.
Code Samples
local Players = game:GetService("Players")
local MarketplaceService = game:GetService("MarketplaceService")
local function OnPromptPurchaseFinished(userId, productId, isPurchased)
local player = Players:GetPlayerByUserId(userId)
print(player.Name .. " / ProductID : " .. productId .. " / isPurchased : " .. tostring(isPurchased))
end
MarketplaceService.PromptProductPurchaseFinished:Connect(OnPromptPurchaseFinished)
Callback
ProcessReceipt
구매 성공한 상품 중에서 아직 지급 처리가 되지 않은 영수증 정보를 반환하는 이벤트가 호출됩니다.
호출 조건
월드 상품을 성공적으로 구매했을 때(구매 성공 팝업이 사용자에게 표시되었을 때)
미처리 상품이 있는 상태에서 새로운 상품 구매시, 이전 미처리건도 함께 호출됩니다.
사용자가 서버에 접속(재접속)했을 때
지급 상태 변경 방법
상품 지급 처리 후에, Enum.ProductPurchaseDecision.PurchaseGranted를 반환합니다.
주의사항
ProcessReceipt 이벤트 연결은 서버측 Script에서 한 번만 설정해야 합니다.
이 콜백은 시간 제한 없이 yield 가능하며, 서버가 실행 중인 한 응답이 돌아올 때까지 유효합니다.
미지급된 영수증이 여러개인 경우 각각 호출되며, 콜백 호출 순서는 비결정적(non-deterministic)입니다.
사용자가 서버에 있어야 콜백이 호출됩니다.
단, 콜백의 결과는 사용자가 서버에 없어도 백엔드에 기록될 수 있습니다.
콜백에서 PurchaseGranted를 반환해도 백엔드 기록이 실패할 수 있으며, 이런 경우 영수증의 상태는 변경되지 않습니다. (미지급 상태 유지)
미지급 상태의 상품은 자금이 지급 보류 상태(Escrow)로 보관됩니다.
Parameters
Dictionary
Receipt
구매 성공한 상품의 영수증 정보로 구성된 딕셔너리입니다.
string
PurchaseId: 영수증 Idstring
PlayerId: Player의 UserIdnumber
ProductId: 상품 Idnumber
CurrencySpent: 거래에 사용된 화폐의 양number
PurchaseDateTime: 상품을 결제한시간 (UNIX timestamp)
Return
Enum.ProductPurchaseDecision
월드 상품의 지급 상태입니다.
PurchaseGranted: 상품이 Player에게 성공적으로 지급된 상태
NotProcessedYet: 상품이 지급되지 않은 상태
Code Samples
local Players = game:GetService("Players")
local MarketplaceService = game:GetService("MarketplaceService")
local ProductDeliverer = {}
-----------------------------------------------------------------------------
-- 아래와 같이 테이블에 상품 번호 별로 함수를 구성하여 상품마다 지급 로직을 구현할 수 있습니다.
ProductDeliverer[Enter the product number here.] = function(player)
local success, resultOrError = pcall(function()
-- player에게 상품 지급 및 DataStore를 이용한 저장 처리
-- Tip.
-- DataStore로 상품 정보를 저장할 때는
-- 네트워크 충돌이나 경쟁 상태(race condition)를 방지하기 위해
-- IncrementAsync 또는 UpdateAsync로 처리하는 것을 권장합니다.
-- 지급 및 저장 처리가 성공적으로 완료된 경우 true 반환
return true
end)
if success and resultOrError then
return true
else
return false, resultOrError
end
end
-----------------------------------------------------------------------------
-- 상품 구매 성공시 호출되는 영수증 처리용 콜백
local function OnProcessReceipt(receiptInfo)
-- Receipt information
local success, error = pcall(function()
print("PurchaseId: " .. receiptInfo.PurchaseId)
print("UserId: " .. receiptInfo.PlayerId)
print("ProductId: " .. receiptInfo.ProductId)
print("CurrencySpent: " .. receiptInfo.CurrencySpent)
print("PurchaseDateTime: " .. receiptInfo.PurchaseDateTime)
end)
if not success then
print("Error: " .. tostring(error))
return Enum.ProductPurchaseDecision.NotProcessedYet
end
-- 플레이어가 유효하면
local productId = receiptInfo.ProductId
local userId = receiptInfo.PlayerId
local player = Players:GetPlayerByUserId(userId)
if player == nil then
print("Error: player is nil")
return Enum.ProductPurchaseDecision.NotProcessedYet
end
-- 상품 지급 함수 호출
local delivererFunc = ProductDeliverer[productId]
local success, error = delivererFunc(player)
-- 상품 지급 성공시
if success then
-- 지급 완료 상태 반환
print("Item delivery successful / ProductId : " .. productId)
return Enum.ProductPurchaseDecision.PurchaseGranted
-- 상품 지급 실패시
else
print("Error: " .. tostring(error))
return Enum.ProductPurchaseDecision.NotProcessedYet
end
end
MarketplaceService.ProcessReceipt = OnProcessReceipt
See also
월드 상품 판매Last updated