I’m trying to make a developer product menu, but every time you buy a product, it gives you more then specified. What happens is(the best example i can make):
Normal amount: 5k,
1 Buy: 5k,
2 Buy 15k,
3 Buy 30k.
It seems to add the bought money to one value and then always gives that to the player for some reason.
Video of it happening:
Also this happens with every product, not just the 500 one. Server sided code: (client just fires a event)
game.ReplicatedStorage.PromptPurchase.OnServerEvent:Connect(function(plr, ID, money)
ms:PromptProductPurchase(plr, ID)
ms.PromptProductPurchaseFinished:Connect(function(plrID, product, purchased)
if plrID == plr.UserId then
if product == ID and purchased == true then
plr.leaderstats.Money.Value += money
end
end
end)
end)
But it does the purchase fully on the server, all the client does is fire a event with the product ID and the amount of money. (Just realized exploiters can use this to their advantage, gotta fix that)
This code is very unreliable and can easily be exploited. For example, a exploiter could just change the “money” value as you rely on the client to determine how much money to give.
Also exploiters can fire the PromptProductPurchaseFinished as purchased without actually purchasing it. Using processReciept is crucial to actually verify that the product was purchased.
In the ProcessReceipt function, once you’ve successfully granted the purchase, you need to return Enum.ProductPurchaseDecision.PurchaseGranted. If something goes wrong like a datastore error and you were not able to give the player it’s reward you should return Enum.ProductPurchaseDecision.NotProcessedYet. This tells Roblox to retry the function later.
Right now, you don’t have a ProcessReceipt function, which means you never returned Enum.ProductPurchaseDecision.PurchaseGranted and Roblox never got confirmation that the purchase was granted. So the next time they buy 500 cash, the function runs twice once for the new purchase and once for the previous one that wasn’t confirmed giving them 1000 cash instead.