Marketplace

๊ฐœ์š”

ํฌ๋ฆฌ์—์ดํ„ฐ๋Š” Marketplace ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜์—ฌ ๊ณจ๋“œ, ํฌ๋ฆฌ์Šคํƒˆ๊ณผ ๊ฐ™์€ ๊ฒŒ์ž„ ๋‚ด ์žฌํ™”๋‚˜ ์ด, ํƒ„์•ฝ, ํšŒ๋ณต ๋ฌผ์•ฝ ๋“ฑ์˜ ์•„์ดํ…œ์„ ์›”๋“œ ์ƒํ’ˆ์œผ๋กœ ๊ตฌ์„ฑํ•˜์—ฌ ์‚ฌ์šฉ์ž์—๊ฒŒ ํŒ๋งคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํŒ๋งค์ž์˜ ์˜๋ฌด

ํฌ๋ฆฌ์—์ดํ„ฐ๋Š” ํŒ๋งคํ•œ ์ƒํ’ˆ์ด ๊ตฌ๋งค์ž์—๊ฒŒ ์ •์ƒ์ ์œผ๋กœ ์ง€๊ธ‰๋˜๋„๋ก ์ฒ˜๋ฆฌํ•  ์˜๋ฌด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ง€๊ธ‰ ๋ˆ„๋ฝ์ด๋‚˜ ์„ค๋ช…๊ณผ ๋‹ค๋ฅธ ์ƒํ’ˆ ๊ตฌ์„ฑ, ๊ตฌ๋งคํ•œ ์ƒํ’ˆ์˜ ๊ฐ€์น˜ ํ›ผ์† ๋“ฑ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ, ๋ฐ˜๋“œ์‹œ ์ด์— ๋Œ€ํ•œ ์ ์ ˆํ•œ ํ•ด๊ฒฐ ์กฐ์น˜๋ฅผ ์„ฑ์‹คํžˆ ์ดํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ง€๊ธ‰ ์˜๋ฌด๋ฅผ ๋ถˆ์„ฑ์‹คํ•˜๊ฒŒ ์ดํ–‰ํ•˜๊ฑฐ๋‚˜ ๊ด€๋ จ ์‹ ๊ณ ๊ฐ€ ๋ฐ˜๋ณต์ ์œผ๋กœ ์ ‘์ˆ˜๋  ๊ฒฝ์šฐ, ์ •์‚ฐ ๋ณด๋ฅ˜, ์›”๋“œ ์ œ์žฌ, ๋‚˜์•„๊ฐ€ ๊ณ„์ • ๋น„ํ™œ์„ฑํ™” ๋“ฑ์˜ ๋ถˆ์ด์ต์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ž์„ธํžˆ ์•Œ์•„๋ณด๊ธฐ

์›”๋“œ ์ƒํ’ˆ ๊ฐ€์ด๋“œ๋ผ์ธ

์ƒํ’ˆ ์ข…๋ฅ˜

์ƒํ’ˆ ์ข…๋ฅ˜
์šฉ๋„
์˜ˆ์‹œ

World Product

1ํšŒ์„ฑ์œผ๋กœ ์ง€๊ธ‰๋˜๋Š” ์žฌํ™”, ์•„์ดํ…œ ๋“ฑ์˜ ์ƒํ’ˆ

์žฌํ™” ์ง€๊ธ‰(๊ณจ๋“œ, ํฌ๋ฆฌ์Šคํƒˆ ๋“ฑ)

์•„์ดํ…œ ์ง€๊ธ‰(๊ฒ€, ๋„๋ผ, ํšŒ๋ณต ํฌ์…˜ ๋“ฑ)

์†Œ๋ชจ์„ฑ ์•„์ดํ…œ(๋ถ€ํ™œ, ๊ฑด๋ฌผ ์ฆ‰์‹œ ์„ค์น˜๊ถŒ ๋“ฑ)

์ƒํ’ˆ ๊ด€๋ฆฌ

์ƒํ’ˆ์€ ์›”๋“œ๋ณ„๋กœ ๊ตฌ์„ฑ๋˜๋ฉฐ, ๊ฐ๊ฐ ๊ฐœ๋ณ„์ ์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒํ’ˆ์„ ๋“ฑ๋กํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋ ค๋ฉด ์›”๋“œ๋ฅผ ๋จผ์ € Publishํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์›”๋“œ๋ฅผ Publish ํ•  ๋•Œ Owner group์„ ๊ทธ๋ฃน์œผ๋กœ ์„ค์ •ํ•˜๋ฉด ๊ทธ๋ฃน์›๊ณผ ํ•จ๊ป˜ ์ƒํ’ˆ์„ ๊ด€๋ฆฌํ•˜๊ณ  ์ˆ˜์ต์„ ๋ถ„๋ฐฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ถŒํ•œ๋ณ„ ๊ธฐ๋Šฅ

๊ถŒํ•œ
์ƒํ’ˆ ์กฐํšŒ/๋“ฑ๋ก
์ƒํ’ˆ ์ˆ˜์ •
์ˆ˜์ต ๋ถ„๋ฐฐ

์›”๋“œ์ œ์ž‘์ž(๊ฐœ์ธ ์›”๋“œ)

O

O

O

Group Owner(๊ทธ๋ฃน ์›”๋“œ)

O

O

O

Group Member(๊ทธ๋ฃน ์›”๋“œ)

O

X

X

์ƒํ’ˆ ๋ชฉ๋ก ํ™•์ธ

Dashboard์˜ World ํƒญ์—์„œ ์›”๋“œ๋ฅผ ํด๋ฆญํ•˜์—ฌ ์›”๋“œ ํŽ˜์ด์ง€์— ์ง„์ž…ํ•œ ๋‹ค์Œ, World Product ํƒญ์„ ํด๋ฆญํ•˜๋ฉด ๋“ฑ๋กํ•œ ์ƒํ’ˆ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒํ’ˆ ๋“ฑ๋ก

+ Create World Product ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ์ƒˆ๋กœ์šด ์ƒํ’ˆ์„ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒํ’ˆ ID ๋ณต์‚ฌํ•˜๊ธฐ

๊ฐ ์ƒํ’ˆ ์ด๋ฆ„ ์˜†์— ํ‘œ์‹œ๋˜๋Š” ... ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅธ ๋‹ค์Œ, Copy Product Id๋ฅผ ํด๋ฆญํ•ด์„œ ์ƒํ’ˆ ID๋ฅผ ๋ณต์‚ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒํ’ˆ ์ˆ˜์ •

์ƒํ’ˆ ์ด๋ฏธ์ง€๋‚˜ ์ด๋ฆ„ ์˜์—ญ์„ ํด๋ฆญํ•˜์—ฌ ์ƒํ’ˆ์˜ ์ด๋ฏธ์ง€, ์ด๋ฆ„, ๊ฐ€๊ฒฉ ๋“ฑ์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒํ’ˆ ํŒ๋งค๋ฅผ ์œ„ํ•œ ์Šคํฌ๋ฆฝํŠธ ์ฒ˜๋ฆฌ

Marketplace๋ฅผ ํ†ตํ•œ ์ƒํ’ˆ ๊ตฌ๋งค ๊ธฐ๋Šฅ์€ ์œ ์ €์˜ ์žฌํ™”๋ฅผ ์†Œ๋ชจํ•˜๋Š” ์ค‘์š” ๊ธฐ๋Šฅ์ด๋ฏ€๋กœ, pcall ๋“ฑ์„ ํ™œ์šฉํ•œ ์—„๊ฒฉํ•œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ์™€ ๋””๋ฒ„๊น…์ด ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๋‚˜ ๋„คํŠธ์›Œํฌ ์ง€์—ฐ ๋“ฑ์˜ ์ƒํ™ฉ์—์„œ๋„ ์‹œ์Šคํ…œ์˜ ์•ˆ์ •์„ฑ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์•„์ดํ…œ ๋ฏธ์ง€๊ธ‰๊ณผ ๊ฐ™์€ ์น˜๋ช…์ ์ธ ๋ฌธ์ œ๋ฅผ ์‚ฌ์ „์— ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ๋Šฅ ๋ชฉ๋ก

๊ธฐ๋Šฅ
์„ค๋ช…

GetProductInfo(productId, productType)

ํŠน์ • ์ƒํ’ˆ ์ •๋ณด ์š”์ฒญ

GetWorldProductsAsync()

๋ชจ๋“  ์›”๋“œ ์ƒํ’ˆ ์ •๋ณด ์š”์ฒญ

PromptProductPurchase(player, productId)

๊ตฌ๋งค ์š”์ฒญ

PromptProductPurchaseFinished

๊ตฌ๋งค์ฐฝ์ด ๊บผ์งˆ ๋•Œ ํ•„์š”ํ•œ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ

ProcessReceipt

๊ตฌ๋งค ์„ฑ๊ณต์‹œ ์ƒํ’ˆ ์ง€๊ธ‰ ์ฒ˜๋ฆฌ ํ›„, ์ •์ƒ ์ง€๊ธ‰๊ฑด์˜ ์˜์ˆ˜์ฆ ์ƒํƒœ๋ฅผ ์™„๋ฃŒ๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•œ ์ด๋ฒคํŠธ

ํŠน์ • ์ƒํ’ˆ ์ •๋ณด ์š”์ฒญ(GetProductInfo)

์ƒํ’ˆ ID(productId)์™€ ์ƒํ’ˆ ํƒ€์ž…(Enum.InfoType)์— ํ•ด๋‹นํ•˜๋Š” ์ƒํ’ˆ ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

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)
        
        -- UI์— ์ถœ๋ ฅ
    end
end

๋ชจ๋“  ์›”๋“œ ์ƒํ’ˆ ์ •๋ณด ์š”์ฒญ(GetWorldProductsAsync)

๋ชจ๋“  ์›”๋“œ ์ƒํ’ˆ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๋Š” Pages ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

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)
		
                -- UI์— ์ถœ๋ ฅ
            end
        end
    end
end

๊ตฌ๋งค ์š”์ฒญ(PromptProductPurchase)

์›”๋“œ ์ƒํ’ˆ ID(productId)์— ํ•ด๋‹นํ•˜๋Š” ์ƒํ’ˆ์˜ ๊ตฌ๋งค๋ฅผ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค. (์‹œ์Šคํ…œ UI๋กœ ๊ตฌ๋งค์ฐฝ์ด ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.)

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

๊ตฌ๋งค์ฐฝ ๊บผ์งˆ ๋•Œ(PromptProductPurchaseFinished)

๊ตฌ๋งค ์š”์ฒญ(PromptProductPurchase)์„ ํ†ตํ•ด ์ถœ๋ ฅ๋œ ๊ตฌ๋งค์ฐฝ์ด ๊บผ์งˆ ๋•Œ ์ด๋ฒคํŠธ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉฐ, ๊ตฌ๋งค๋ฅผ ์„ฑ๊ณตํ•˜๋ฉด isPurchased์— true๊ฐ€ ์ „๋‹ฌ๋˜๊ณ , ๊ตฌ๋งค๋ฅผ ์ทจ์†Œํ•˜๊ฑฐ๋‚˜ ์‹คํŒจํ•˜๋ฉด false๊ฐ€ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.

์ด ์ด๋ฒคํŠธ๋Š” ๊ตฌ๋งค ์ฐฝ์„ ๋‹ซ์•˜๋Š”์ง€ ๊ฐ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ์šฉ๋„๋กœ๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋ฉฐ, ๊ตฌ๋งคํ•œ ์ƒํ’ˆ์— ๋Œ€ํ•œ ์ง€๊ธ‰ ์ฒ˜๋ฆฌ ์šฉ๋„๋กœ๋Š” ์ ˆ๋Œ€ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

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)

๊ตฌ๋งค ์„ฑ๊ณต์‹œ ์ง€๊ธ‰ ์ฒ˜๋ฆฌ(ProcessReceipt)

๊ตฌ๋งค ์„ฑ๊ณตํ•œ ์ƒํ’ˆ ์ค‘์—์„œ ์•„์ง ์ง€๊ธ‰ ์ฒ˜๋ฆฌ๊ฐ€ ๋˜์ง€ ์•Š์€ ์˜์ˆ˜์ฆ ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ด๋ฒคํŠธ๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

์˜์ˆ˜์ฆ ์ƒํƒœ

์ƒํƒœ
์„ค๋ช…
์žฌํ˜ธ์ถœ ์—ฌ๋ถ€

NotProcessedYet

์ƒํ’ˆ ๋ฏธ์ง€๊ธ‰ ์ƒํƒœ

ํ˜ธ์ถœ ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋‹ค์‹œ ํ˜ธ์ถœ๋  ์ˆ˜ ์žˆ์Œ

PurchaseGranted

์ƒํ’ˆ ์ง€๊ธ‰ ์™„๋ฃŒ ์ƒํƒœ

๋‹ค์‹œ ํ˜ธ์ถœ๋˜์ง€ ์•Š์Œ

ํ˜ธ์ถœ ์กฐ๊ฑด

  • ์›”๋“œ ์ƒํ’ˆ์„ ์„ฑ๊ณต์ ์œผ๋กœ ๊ตฌ๋งคํ–ˆ์„ ๋•Œ(๊ตฌ๋งค ์„ฑ๊ณต ํŒ์—…์ด ์‚ฌ์šฉ์ž์—๊ฒŒ ํ‘œ์‹œ๋˜์—ˆ์„ ๋•Œ)

    • ๋ฏธ์ฒ˜๋ฆฌ ์ƒํ’ˆ์ด ์žˆ๋Š” ์ƒํƒœ์—์„œ ์ƒˆ๋กœ์šด ์ƒํ’ˆ ๊ตฌ๋งค์‹œ, ์ด์ „ ๋ฏธ์ฒ˜๋ฆฌ๊ฑด๋„ ํ•จ๊ป˜ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

  • ์‚ฌ์šฉ์ž๊ฐ€ ์„œ๋ฒ„์— ์ ‘์†(์žฌ์ ‘์†)ํ–ˆ์„ ๋•Œ

์ง€๊ธ‰ ์ƒํƒœ ๋ณ€๊ฒฝ ๋ฐฉ๋ฒ•

  • ์ƒํ’ˆ ์ง€๊ธ‰ ์ฒ˜๋ฆฌ ํ›„์—, Enum.ProductPurchaseDecision.PurchaseGranted๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ

  • ProcessReceipt ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ์€ ์„œ๋ฒ„์ธก Script์—์„œ ํ•œ ๋ฒˆ๋งŒ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • ์ด ์ฝœ๋ฐฑ์€ ์‹œ๊ฐ„ ์ œํ•œ ์—†์ด yield ๊ฐ€๋Šฅํ•˜๋ฉฐ, ์„œ๋ฒ„๊ฐ€ ์‹คํ–‰ ์ค‘์ธ ํ•œ ์‘๋‹ต์ด ๋Œ์•„์˜ฌ ๋•Œ๊นŒ์ง€ ์œ ํšจํ•ฉ๋‹ˆ๋‹ค.

  • ๋ฏธ์ง€๊ธ‰๋œ ์˜์ˆ˜์ฆ์ด ์—ฌ๋Ÿฌ๊ฐœ์ธ ๊ฒฝ์šฐ ๊ฐ๊ฐ ํ˜ธ์ถœ๋˜๋ฉฐ, ์ฝœ๋ฐฑ ํ˜ธ์ถœ ์ˆœ์„œ๋Š” ๋น„๊ฒฐ์ •์ (non-deterministic)์ž…๋‹ˆ๋‹ค.

  • ์‚ฌ์šฉ์ž๊ฐ€ ์„œ๋ฒ„์— ์žˆ์–ด์•ผ ์ฝœ๋ฐฑ์ด ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

    • ๋‹จ, ์ฝœ๋ฐฑ์˜ ๊ฒฐ๊ณผ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์„œ๋ฒ„์— ์—†์–ด๋„ ๋ฐฑ์—”๋“œ์— ๊ธฐ๋ก๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ฝœ๋ฐฑ์—์„œ PurchaseGranted๋ฅผ ๋ฐ˜ํ™˜ํ•ด๋„ ๋ฐฑ์—”๋“œ ๊ธฐ๋ก์ด ์‹คํŒจํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Ÿฐ ๊ฒฝ์šฐ ์˜์ˆ˜์ฆ์˜ ์ƒํƒœ๋Š” ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. (๋ฏธ์ง€๊ธ‰ ์ƒํƒœ ์œ ์ง€)

  • ๋ฏธ์ง€๊ธ‰ ์ƒํƒœ์˜ ์ƒํ’ˆ์€ ์ž๊ธˆ์ด ์ง€๊ธ‰ ๋ณด๋ฅ˜ ์ƒํƒœ(Escrow)๋กœ ๋ณด๊ด€๋ฉ๋‹ˆ๋‹ค.

local Players = game:GetService("Players")
local MarketplaceService = game:GetService("MarketplaceService")

local ProductDeliverer = {}

-----------------------------------------------------------------------------
-- ์•„๋ž˜์™€ ๊ฐ™์ด ํ…Œ์ด๋ธ”์— ์ƒํ’ˆ ๋ฒˆํ˜ธ ๋ณ„๋กœ ํ•จ์ˆ˜๋ฅผ ๊ตฌ์„ฑํ•˜์—ฌ ์ƒํ’ˆ๋งˆ๋‹ค ์ง€๊ธ‰ ๋กœ์ง์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ProductDeliverer[์—ฌ๊ธฐ์— ์ƒํ’ˆ ๋ฒˆํ˜ธ๋ฅผ ๋„ฃ์œผ์„ธ์š”.] = 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)	
    -- ์˜์ˆ˜์ฆ ์ •๋ณด
    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

ํ…Œ์ŠคํŠธ ๊ตฌ๋งค

์ŠคํŠœ๋””์˜ค์˜ ํ…Œ์ŠคํŠธ ํ”Œ๋ ˆ์ด ํ™˜๊ฒฝ์—์„œ๋„ ์ƒํ’ˆ ๊ตฌ๋งค ๋ฐ ์ง€๊ธ‰ ์ฒ˜๋ฆฌ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (์žฌํ™”๊ฐ€ ์ฐจ๊ฐ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.)

ํŒ๋งค ํ†ต๊ณ„

๊ณง ์ง€์›๋  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

์ˆ˜์ต

์ˆ˜์ต ๋ถ„๋ฐฐ

๊ณง ์ง€์›๋  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

์ˆ˜์ต ์ •์‚ฐ

๊ณง ์ง€์›๋  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

ํ™œ์šฉ ์˜ˆ์‹œ

  • ์ธ๊ฒŒ์ž„ ์žฌํ™”๋ฅผ ๋ฌด๋ฃŒ/์œ ๋ฃŒ๋กœ ๊ตฌ๋ถ„ํ•œ ๋’ค, ์œ ๋ฃŒ ์žฌํ™”์˜ ๊ฐ€์น˜๋ฅผ ๋†’์ด๊ณ  ์›”๋“œ ์ƒํ’ˆ์œผ๋กœ ํŒ๋งคํ•˜์—ฌ ์‚ฌ์šฉ์ž ๊ตฌ๋งค๋ฅผ ์œ ๋„ํ•˜๊ณ  ์ˆ˜์ต์„ ์ด‰์ง„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ผ๋ฐ˜ ์Šคํ‚จ๋ณด๋‹ค ๋” ๋†’์€ ํ€„๋ฆฌํ‹ฐ์˜ ์Šคํ‚จ์„ ์›”๋“œ ์ƒํ’ˆ์œผ๋กœ ๊ตฌ์„ฑํ•˜๋ฉด, ํ”Œ๋ ˆ์ด์–ด์˜ ๊ฐœ์„ฑ๊ณผ ๊พธ๋ฏธ๊ธฐ ์š•๊ตฌ๋ฅผ ์ž๊ทนํ•˜์—ฌ ๊ตฌ๋งค๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋ฌด๊ธฐ, ํฌ์…˜, ์žฌํ™” ๋“ฑ์„ ๋ฌถ์€ ํŒจํ‚ค์ง€ ์ƒํ’ˆ์„ ๊ตฌ์„ฑํ•˜๋ฉด, ๊ฐœ๋ณ„ ์•„์ดํ…œ ๋Œ€๋น„ ๋†’์€ ๊ฐ€์„ฑ๋น„๋ฅผ ํ†ตํ•ด ๊ตฌ๋งค ์ „ํ™˜์œจ์„ ๋†’์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ „ํˆฌ ์ค‘ ์‚ฌ๋งํ–ˆ์„ ๋•Œ ์ฆ‰์‹œ ๋ถ€ํ™œํ•  ์ˆ˜ ์žˆ๋Š” ์†Œ๋ชจ์„ฑ ์•„์ดํ…œ์„ ์›”๋“œ ์ƒํ’ˆ์œผ๋กœ ๊ตฌ์„ฑํ•˜๋ฉด, ๊ฒŒ์ž„ ํ๋ฆ„์„ ์œ ์ง€ํ•˜๋ฉด์„œ ์ž์—ฐ์Šค๋Ÿฌ์šด ๊ตฌ๋งค๋ฅผ ์œ ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์‹œ์ฆŒ ํŒจ์Šค์™€ ๊ฐ™์€ ์ง€์†ํ˜• ์ƒํ’ˆ์„ ํ†ตํ•ด ์žฅ๊ธฐ์ ์ธ ์‚ฌ์šฉ์ž ๋ฆฌํ…์…˜๊ณผ ์ˆ˜์ต์„ ๋™์‹œ์— ํ™•๋ณดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์œ ๋ฃŒ ์ƒํ’ˆ ์œ„์ฃผ์˜ ๊ณผ๋„ํ•œ ๊ตฌ์„ฑ๋ณด๋‹ค๋Š”, ์ผ์ • ์ˆ˜์ค€์˜ ๋ฌด๋ฃŒ ์ƒํ’ˆ์„ ์ ์ ˆํžˆ ์ œ๊ณตํ•˜์—ฌ ์‚ฌ์šฉ์ž ๋งŒ์กฑ๋„๋ฅผ ๋†’์ด๊ณ , ์‹ ๋ขฐ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ํ•œ ์ž๋ฐœ์ ์ธ ๊ตฌ๋งค๋ฅผ ์œ ๋„ํ•˜๋Š” ๊ฒƒ์ด ๋”์šฑ ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค.

Last updated