note: what I understand from this comes from AI, so correct me if I’m wrong
Ok this snippet is from the Roblox page itself about marketplace service callback. the focus part is the first Pcall function followed by the if statement. I don’t understand because if the player has never bought the product then it will always result in the ((elseif not success then error(“Data store error:” … errorMessage)end)) snippet meaning that if the player has never bought the product the function will always be exited meaning they actually cant.
Also apparently this code: ((return Enum.ProductPurchaseDecision.PurchaseGranted)) will also exit the function so ((again i got this info from AI so correct me if I’m wrong)) doesn’t that mean the rest of the code after is useless
– T
--local function processReceipt(receiptInfo)
Determine if the product was already granted by checking the data store
local playerProductKey = receiptInfo.PlayerId .. "_" .. receiptInfo.PurchaseId
local purchased = false
local success, result, errorMessage
success, errorMessage = pcall(function()
purchased = purchaseHistoryStore:GetAsync(playerProductKey)
end)
-- If purchase was recorded, the product was already granted
if success and purchased then
return Enum.ProductPurchaseDecision.PurchaseGranted
elseif not success then
error("Data store error:" .. errorMessage)
end
-- Determine if the product was already granted by checking the data store
local playerProductKey = receiptInfo.PlayerId .. "_" .. receiptInfo.PurchaseId
local success, isPurchaseRecorded = pcall(function()
return purchaseHistoryStore:UpdateAsync(playerProductKey, function(alreadyPurchased)
if alreadyPurchased then
return true
end
-- Find the player who made the purchase in the server
local player = Players:GetPlayerByUserId(receiptInfo.PlayerId)
if not player then
-- The player probably left the game
-- If they come back, the callback will be called again
return nil
end
local handler = productFunctions[receiptInfo.ProductId]
local success, result = pcall(handler, receiptInfo, player)
-- If granting the product failed, do NOT record the purchase in datastores.
if not success or not result then
error("Failed to process a product purchase for ProductId: " .. tostring(receiptInfo.ProductId) .. " Player: " .. tostring(player) .. " Error: " .. tostring(result))
return nil
end
-- Record the transcation in purchaseHistoryStore.
return true
end)
end)
if not success then
error("Failed to process receipt due to data store error.")
return Enum.ProductPurchaseDecision.NotProcessedYet
elseif isPurchaseRecorded == nil then
-- Didn't update the value in data store.
return Enum.ProductPurchaseDecision.NotProcessedYet
else
-- IMPORTANT: Tell Roblox that the game successfully handled the purchase
return Enum.ProductPurchaseDecision.PurchaseGranted
end
end
I think you are mistaking the success variable returned for the purchased which is what tells you if its been bought or not. So if the player has never bought the product before, it first checks if the datastore didn’t error (which is why there’s a pcall) and then it checks if purchased was already granted, and if it was it returns and does nothing so the program doesn’t have to recheck.
But if the purchase variable returns false (which means you haven’t bought it yet) then it skips the first if statement and the second elseif because success should still return true. Then it records the purchase in the datastore
((it returns and does nothing )) by this you mean the function will be exited right meaning nothing after the return will run?
I want to make it 100% because AI and and some other guy has told me if purchase equals false then success also does. So what the variable Purchase equals to has no effect on what SUCCESS equals to is that right?
Using Enum.ProductPurchaseDecision.PurchaseGranted is useful for making sure the purchase is guaranteed to be recorded into the datastore. If for any reason the datastores fail (roblox is down) or something else happens, you have to return Enum.ProductPurchaseDecision.NotProcessedYet. The difference is that if you return not processed yet, when the player rejoins the game or buys the product again it runs the function again until it returns PurchaseGranted.
Example:
A player buys an item in game, but when you try to save the purchase in the datastore it fails because roblox is down so you return Enum.ProductPurchaseDecision.NotProcessedYet.
Then when the player rejoins the game, if datastores are back up again it tries to save that exact purchase again into the datastores
Now that i think about what does the ((Enum.ProductPurchaseDecision.NotProcessedYet)) do in the first place how I understand it is that it just tells Roblox itself the current state of the proccess
I also have some other questions if you don’t mind.
Enum.ProductPurchaseDecision.NotProcessedYet just tells roblox that something happened on your end where the purchase could not be completed/recorded in the datastore. So if you return that, roblox runs the function again (when you join and if you buy the product again) until you return PurchaseGranted meaning everything was good and you don’t need to run the function again. I put an example how how it would work in a real game scenario in the previous reply
so its all automatic, what I mean is like for example Enum.ProductPurchaseDecision.PurchaseGranted automatically gets the purchaseID and the playerID and checks it off as PurchaseGranted Specifically for that player and product
Not sure what you mean by automatic? Enum.ProductPurchaseDecision.PurchaseGranted is just a purchase decision that lets roblox know that everything on your end was successful and they don’t have to rerun the function. All the rest of that information is upto you to provide. But the function that it retries if you return NotProcessedYet contains the relevant information you need
when Enum.ProductPurchaseDecision.PurchaseGranted gets called there is no mention of the playerID or ProductID; leading me to assume that you know Enum.ProductPurchaseDecision.PurchaseGranted automatically stores that data of that specific purchase for that player somewhere behind the scenes.
Also in the whole code I intially provided there is no mention of ‘setAsync’ or ‘UpdateAsync’ after the player gets granted the product which i don’t understand
local success, isPurchaseRecorded = pcall(function()
return purchaseHistoryStore:UpdateAsync(playerProductKey, function(alreadyPurchased)
if alreadyPurchased then
return true
end
I need a explanation on this overall I got info from AI which already confirmed got multiple things wrong so I’m going off AI’s explanation of some of these. Instead of telling you what I learnt. can you explain over all how this works with the ‘function(alreadyPurchased)’ inside. Also how the line of code works in relative to ‘return’.