Dev Product Purchase Repeats?

Hi all

I made dev products for my zombie game to spawn a soldier.

I understand it is meant to support multiple purchases.

However upon purchasing 1 soldier, it continues to spawn in a new separate game session.

The intention is to have player purchase just 1 soldier for that single game session.

Am I doing anything wrong?

Much appreciated.

2 Likes

I think you did something wrong in the stored datas. You probably add a solidier everytimes the player join because you saved he bought the solidier with robux.

1 Like

We can’t really know what is wrong with it because we cannot see the script.

1 Like

I had this same issue, I resolved it by creating a table in my DataStore and each developer product purchase gives you a unique ID that you can save to your DataStore and when you are processing the receipt, you can check if the players data table already contains that unique Id, if it does, do not give them what they already received.

1 Like

Or just when the player buy a solidier, save his solidier amount with one more (and before he leave, add his solidier). When the player rejoin, he will get the good amount of solidiers.

what, that doesn’t make sense?

Please provide some code so we can help you.

Dear all this is my code… thanks for the time taken to help . .

local productFunctions = {}
productFunctions[XXX] = function(receipt, player)
add marine code
end

productFunctions[YYY] = function(receipt, player)
add combat engineer code
end

local function processReceipt(receiptInfo)

local handler = productFunctions[receiptInfo.ProductId]

local success, result = pcall(handler, receiptInfo, receiptInfo.PlayerId)
if not success or not result then
	warn("Error occurred while processing a product purchase")
	print("\nProductId:", receiptInfo.ProductId)
	print("\nPlayer:", player)
	return Enum.ProductPurchaseDecision.NotProcessedYet
end
	return Enum.ProductPurchaseDecision.PurchaseGranted

end

MarketplaceService.ProcessReceipt = processReceipt

can you kindly share more? i have still having trouble with it . . my only ref is the example given by roblox . .

  1. local MarketplaceService = game:GetService(“MarketplaceService”)
  2. local DataStoreService = game:GetService(“DataStoreService”)
  3. local Players = game:GetService(“Players”)
  • – Data store for tracking purchases that were successfully processed
  1. local purchaseHistoryStore = DataStoreService:GetDataStore(“PurchaseHistory”)
  • – Table setup containing product IDs and functions for handling purchases
  1. local productFunctions = {}
  2. – ProductId 123123 for a full heal
  3. productFunctions[123123] = function(receipt, player)
  4. – Logic/code for player buying a full heal (may vary)
  5. if player.Character and player.Character:FindFirstChild(“Humanoid”) then
  6. – Heal the player to full health
  7. player.Character.Humanoid.Health = player.Character.Humanoid.MaxHealth
  8. – Indicate a successful purchase
  9. return true
  10. end
  11. end
  12. – ProductId 456456 for 100 gold
  13. productFunctions[456456] = function(receipt, player)
  14. – Logic/code for player buying 100 gold (may vary)
  15. local stats = player:FindFirstChild(“leaderstats”)
  16. local gold = stats and stats:FindFirstChild(“Gold”)
  17. if gold then
  18. gold.Value = gold.Value + 100
  19. – Indicate a successful purchase
  20. return true
  21. end
  22. end
  • – The core ‘ProcessReceipt’ callback function
  1. local function processReceipt(receiptInfo)
  • – Determine if the product was already granted by checking the data store
  1. local playerProductKey = receiptInfo.PlayerId … “_” … receiptInfo.PurchaseId
  2. local purchased = false
  3. local success, errorMessage = pcall(function()
  4. purchased = purchaseHistoryStore:GetAsync(playerProductKey)
  5. end)
  6. – If purchase was recorded, the product was already granted
  7. if success and purchased then
  8. return Enum.ProductPurchaseDecision.PurchaseGranted
  9. elseif not success then
  10. error(“Data store error:” … errorMessage)
  11. end
  • – Find the player who made the purchase in the server
  1. local player = Players:GetPlayerByUserId(receiptInfo.PlayerId)
  2. if not player then
  3. – The player probably left the game
  4. – If they come back, the callback will be called again
  5. return Enum.ProductPurchaseDecision.NotProcessedYet
  6. end
  • – Look up handler function from ‘productFunctions’ table above
  1. local handler = productFunctions[receiptInfo.ProductId]
  • – Call the handler function and catch any errors
  1. local success, result = pcall(handler, receiptInfo, player)
  2. if not success or not result then
  3. warn(“Error occurred while processing a product purchase”)
  4. print(“\nProductId:”, receiptInfo.ProductId)
  5. print(“\nPlayer:”, player)
  6. return Enum.ProductPurchaseDecision.NotProcessedYet
  7. end
  • – Record transaction in data store so it isn’t granted again
  1. local success, errorMessage = pcall(function()
  2. purchaseHistoryStore:SetAsync(playerProductKey, true)
  3. end)
  4. if not success then
  5. error("Cannot save purchase data: " … errorMessage)
  6. end
  • – IMPORTANT: Tell Roblox that the game successfully handled the purchase
  1. return Enum.ProductPurchaseDecision.PurchaseGranted
  2. end
  • – Set the callback; this can only be done once by one script on the server!
  1. MarketplaceService.ProcessReceipt = processReceipt

You just need to save the transaction Id that is returned in the product receipt using DataStores.

Ok. Why am I saving it ? Because it is meant to be only for that game session. Thank you.

You are saving it because it will repeat the purchase. Let’s say you have bought it once, and want to buy a product again. The script then thinks it is the same ID, and uses that to repeat the purchase. However, you will not receive the robux from the second one! (this have I personally tried out).

One way to fix this is by creating a table in your datastore. For every purchase within this product, creates an unique ID.

Yes just like @Schedency said, you need to save it to check for it when they rejoin and make sure to not give them the product.

Hi!

i fixed up the code. However it seems to be failing at the pcall for the handler . . i always get not success although the soldier was spawned successfully. This results in the sales not saving into datastore

local DS = game:GetService(“DataStoreService”)
local MarketplaceService = game:GetService(“MarketplaceService”)
local purchaseHistoryStore = DS:GetDataStore(“PurchaseHistory”)

local productFunctions = {}
productFunctions[1085506706] = function(receipt, player)
Code to give a soldier
return true
end

productFunctions[1085506610] = function(receipt, player)
Code to give a repair man
return true
end

productFunctions[1085506705] = function(receipt, player)
Code to reload turrets
return true
end

local function processReceipt(receiptInfo)
local playerProductKey = receiptInfo.PlayerId … “_” … receiptInfo.PurchaseId
local purchased = false
local success, errorMessage = pcall(function()
purchased = purchaseHistoryStore:GetAsync(playerProductKey)
end)
if success and purchased then
return Enum.ProductPurchaseDecision.PurchaseGranted
elseif not success then
error(“Data store error:” … errorMessage)
end
local player = game:GetService(“Players”):GetPlayerByUserId(receiptInfo.PlayerId)
if not player then
return Enum.ProductPurchaseDecision.NotProcessedYet
end

local handler = productFunctions[receiptInfo.ProductId]

local success, result = pcall(handler, receiptInfo, receiptInfo.PlayerId)
if not success or not result then
	warn("Error occurred while processing a product purchase")
	print("\nProductId:", receiptInfo.ProductId)
	print("\nPlayer:", player)
	return Enum.ProductPurchaseDecision.NotProcessedYet
end

local success, errorMessage = pcall(function()
	purchaseHistoryStore:SetAsync(playerProductKey, true)
end)
if not success then
	error("Cannot save purchase data: " .. errorMessage)
end
	return Enum.ProductPurchaseDecision.PurchaseGranted

end

MarketplaceService.ProcessReceipt = processReceipt

i fixed up the code. However it seems to be failing at the pcall for the handler . . i always get not success although the soldier was spawned successfully. This results in the sales not saving into datastore
:frowning:

Show me the code. (())30------

local DS = game:GetService(“DataStoreService”)
local MarketplaceService = game:GetService(“MarketplaceService”)
local purchaseHistoryStore = DS:GetDataStore(“PurchaseHistory”)

local productFunctions = {}
productFunctions[1085506706] = function(receipt, player)
Code to give a soldier
return true
end

productFunctions[1085506610] = function(receipt, player)
Code to give a repair man
return true
end

productFunctions[1085506705] = function(receipt, player)
Code to reload turrets
return true
end

local function processReceipt(receiptInfo)
local playerProductKey = receiptInfo.PlayerId … “_” … receiptInfo.PurchaseId
local purchased = false
local success, errorMessage = pcall(function()
purchased = purchaseHistoryStore:GetAsync(playerProductKey)
end)
if success and purchased then
return Enum.ProductPurchaseDecision.PurchaseGranted
elseif not success then
error(“Data store error:” … errorMessage)
end
local player = game:GetService(“Players”):GetPlayerByUserId(receiptInfo.PlayerId)
if not player then
return Enum.ProductPurchaseDecision.NotProcessedYet
end

local handler = productFunctions[receiptInfo.ProductId]

local success, result = pcall(handler, receiptInfo, receiptInfo.PlayerId)
if not success or not result then
warn(“Error occurred while processing a product purchase”)
print(“\nProductId:”, receiptInfo.ProductId)
print(“\nPlayer:”, player)
return Enum.ProductPurchaseDecision.NotProcessedYet
end

local success, errorMessage = pcall(function()
purchaseHistoryStore:SetAsync(playerProductKey, true)
end)
if not success then
error("Cannot save purchase data: " … errorMessage)
end
return Enum.ProductPurchaseDecision.PurchaseGranted

end

MarketplaceService.ProcessReceipt = processReceipt

Well you don’t wanna make a new key for the player each time…

Just make the “PlayerProductKey” the player’s UserId and then you can use GetAsync to get their data. I also suggesting using a table inside your datastore called Purchases or something and then do table.insert(myDataStore[playerUserId].Purchases, transactionId) then you can use table.find(table, value) to see if they have already gotten the product before.

thank you for the advice. appreciate the time taken.

1 Like