This logic makes no sense

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
4 Likes

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

1 Like

((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?

1 Like

Yes the function will exit and not retry

Yea, purchased has no effect on what success equals, but if success is false, purchased will always be false. So it’s a 1 way relationship

4 Likes

Goddamit thank you, that actually makes sense so the Roblox page wasn’t wrong after all.

1 Like

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

1 Like

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.

1 Like

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

2 Likes

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

1 Like

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

1 Like

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.

1 Like

If you want to store the purchase data, you need to do that yourself into a datastore. Roblox doesn’t record purchases

1 Like

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

What do you mean by that? Looking at the original code I can see UpdateAsync being called

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’.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.