chess123mate

Script for ScriptingHelpers

Sep 17th, 2017
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 6.65 KB | None | 0 0
  1. local marketplaceService = game:GetService("MarketplaceService")
  2. local Players = game:GetService("Players")
  3.  
  4. local replicatedStorage = game:GetService("ReplicatedStorage")
  5. local eventsFolder = replicatedStorage:WaitForChild("EventsFolder")
  6. local purchaseEvent = eventsFolder:WaitForChild("PurchaseEvent")
  7. local savePlayerProfile = eventsFolder:WaitForChild("SavePlayerProfile") -- TODO make this a BindableFunction. Make sure that in your Datastore script, you save when this is called. It will be given the 'player' whose data to save.
  8.  
  9. local products = {} --keys: name and IDs; value has .Name, .Offers, .ApplyOffer
  10. local idToProduct = {}
  11. local idToAmount = {}
  12. function CreateProduct(name, offers, applyOffer)
  13.     --  offers: dictionary between amount offered (the key) and cost to user (the value)
  14.     --  applyOffer: function(player, amount)
  15.     if products[name] then error("Already have a product with name " .. name .."!") end -- Make sure we don't make a mistake (ex having 2 "Gold" products, which would break this algorithm)
  16.     -- We need to be able to look up each offer by Amount, so turn 'offers' into a dictionary
  17.     local offerDict = {}
  18.     for i = 1, #offers do
  19.         offerDict[offers[i].Amount] = offers[i]
  20.     end
  21.     local product = {Name = name, Offers = offerDict, ApplyOffer = applyOffer}
  22.     products[name] = product
  23.     for i = 1, #offers do
  24.         idToProduct[offers[i].ID] = product
  25.         idToAmount[offers[i].ID] = offers[i].Amount
  26.     end
  27. end
  28. CreateProduct("Gold", {
  29.     {ID = 100122331, Amount = 50, Price = 50},
  30.     {ID = 111111111, Amount = 100, Price = 100},
  31.     --etc
  32. }, _G.awardGold)
  33.  
  34. -- ALTERNATIVE to above (starting at CreateProduct):
  35.  
  36. function CreateProduct(name, offers, applyOffer)
  37.     --  offers: dictionary between amount offered (the key) and cost to user (the value)
  38.     --  applyOffer: function(player, amount)
  39.     if products[name] then error("Already have a product with name " .. name .."!") end -- Make sure we don't make a mistake (ex having 2 "Gold" products, which would break this algorithm)
  40.     local product = {Name = name, Offers = offers, ApplyOffer = applyOffer}
  41.     products[name] = product
  42.     for i = amount, offer in pairs(offers) do
  43.         idToProduct[offer.ID] = product
  44.         idToAmount[offer.ID] = amount
  45.     end
  46. end
  47. CreateProduct("Gold", {
  48.     [50] = {ID = 100122331, Price = 50},
  49.     [100] = {ID = 111111111, Price = 100},
  50.     --etc
  51. }, _G.awardGold)
  52.  
  53. -- END OF ALTERNATIVE. The alternative is simpler, but the "[50]" is not as descriptive as Amount=50.
  54.  
  55. purchaseEvent.OnServerEvent:connect(function(player, name, amount)
  56.     local product = products[name]
  57.     if not product then error(string.format("Player %s attempted to purchase amount %s of non-existent %s", player.Name, amount, name)) end
  58.     local offer = product.Offers[amount]
  59.     if not offer then error(string.format("Player %s attempted to purchase non-existent amount %s of %s", player.Name, amount, name)) end
  60.     marketplaceService:PromptPurchase(player, offer.ID, false)
  61. end)
  62.  
  63. --System to record purchases temporarily (in case datastores aren't working or have slown down)
  64. local recentPurchases = {} -- Dictionary<player, Dictionary<PurchaseId, value>>. values:
  65. local IN_PROGRESS = 0 -- Player purchased it and was given reward, but it wasn't saved yet
  66. local COMPLETE = 1 -- Purchase complete and fully saved
  67. Players.PlayerAdded:Connect(function(player)
  68.     recentPurchases[player] = {}
  69. end)
  70. Players.PlayerRemoving:Connect(function(player)
  71.     recentPurchases[player] = nil
  72. end)
  73. function PlayerMadePurchase(player, purchaseID) -- True if the player at least started a purchase
  74.     return recentPurchases[player][purchaseID]
  75. end
  76. function PlayerPurchaseComplete(player, purchaseID) -- True if the player finished the purchase
  77.     return recentPurchases[player][purchaseID] == COMPLETE
  78. end
  79. function RecordPlayerPurchaseInProgress(player, purchaseID)
  80.     recentPurchases[player][purchaseID] = IN_PROGRESS
  81. end
  82. function RecordPlayerPurchaseComplete(player, purchaseID)
  83.     recentPurchases[player][purchaseID] = COMPLETE
  84.     delay(300, function() -- Release memory after a while (but give enough time for Roblox to fire ProcessReceipt incorrectly, as suggested might happen by wiki)
  85.         if recentPurchases[player] then -- if player is still around
  86.             recentPurchases[player][purchaseID] = nil -- release memory
  87.         end
  88.     end)
  89. end
  90.  
  91. --ProcessReceipt
  92. function marketplaceService.ProcessReceipt(receiptInfo)
  93.     -- find the player based on the PlayerId in receiptInfo
  94.     local player = Players:GetPlayerByUserId(receiptInfo.PlayerId)
  95.     -- player left? don't process it:
  96.     if not player then return Enum.ProductPurchaseDecision.NotProcessedYet end
  97.     local purchaseID = receiptInfo.PurchaseId
  98.     if PlayerMadePurchase(player, purchaseID) then
  99.         if PlayerPurchaseComplete(player, purchaseID) then
  100.             return Enum.ProductPurchaseDecision.PurchaseGranted --We already granted it.
  101.         end
  102.         --Attempt to save profile again
  103.         return AttemptToFinishPurchase(player, purchaseID)
  104.     end
  105.  
  106.     -- Get information required to give the player what they purchased
  107.    
  108.     local product = idToProduct[receiptInfo.ProductId]
  109.     local amount = idToAmount[receiptInfo.ProductId]
  110.  
  111.     -- call ApplyOffer safely with pcall to catch any error
  112.     local suc, err = pcall(product.ApplyOffer, player, amount)
  113.     if not suc then -- log it to the output
  114.         warn("An error occured while processing a product purchase")
  115.         print("\tProduct name:", product.Name)
  116.         print("\tProduct amount:", amount)
  117.         print("\tProductId:",receiptInfo.ProductId)
  118.         print("\tPlayer:",player)
  119.         print("\tError message:",err)
  120.         return Enum.ProductPurchaseDecision.NotProcessedYet
  121.     end
  122.  
  123.     -- if the function didn't error, 'err' will be whatever the function returned
  124.     -- if our handler didn't return anything (or it returned false/nil), it means
  125.     -- that the purchase failed for some reason, so we have to cancel it
  126.     if not err then
  127.         return Enum.ProductPurchaseDecision.NotProcessedYet
  128.     end
  129.     RecordPlayerPurchaseInProgress(player, receiptInfo.PurchaseId)
  130.     return AttemptToFinishPurchase(player, purchaseID)
  131. end
  132. function AttemptToFinishPurchase()
  133.     -- Ask for the player's profile to be saved
  134.     if not savePlayerProfile:Invoke(player) then
  135.         -- Save failed, try again later
  136.         return Enum.ProductPurchaseDecision.NotProcessedYet
  137.     end
  138.     RecordPlayerPurchaseComplete(player, receiptInfo.PurchaseId)
  139.     -- tell ROBLOX that we have successfully handled the transaction (required)
  140.     return Enum.ProductPurchaseDecision.PurchaseGranted
  141. end
Advertisement
Add Comment
Please, Sign In to add comment