[Solved] Dev Products Only Work When Handled Through A Single Callback

Hi. I have two remote functions. When I invoke the one in the code below all of it works, and when I invoke the other one, it prompts the marketplace service and reads the code on my other script. How is this possible? If I don’t get an answer on this I’m submitting a bug report.

local button = script.Parent

button.MouseButton1Click:Connect(function()
game.ReplicatedStorage.DevProducts.SpeedCoil:InvokeServer()
end)
local button = script.Parent

button.MouseButton1Click:Connect(function()
game.ReplicatedStorage.DevProducts.GravityCoil:InvokeServer() --Invokes speed coil despite it all being named Gravity Coil in the other script
end)
local MarketplaceService = game:GetService("MarketplaceService")
local toolFolder = game.ServerStorage:WaitForChild("Tools")
local TOOL_PRODUCT_ID = 1231231234 --Example
local TOOL_NAME = "SpeedCoil"

local function giveToolToPlayer(player)
local tool = toolFolder:FindFirstChild(TOOL_NAME)
if tool and not player.Backpack:FindFirstChild(TOOL_NAME) then
local clonedTool = tool:Clone()
clonedTool.Parent = player.Backpack
else
print("You already have the speed coil")
end
end

game.ReplicatedStorage.DevProducts.SpeedCoil.OnServerInvoke = function(player)
MarketplaceService:PromptProductPurchase(player, TOOL_PRODUCT_ID)
end

MarketplaceService.ProcessReceipt = function(receiptInfo)
local player = game.Players:GetPlayerByUserId(receiptInfo.PlayerId)
if not player then
return Enum.ProductPurchaseDecision.NotProcessedYet
end

if receiptInfo.ProductId == TOOL_PRODUCT_ID then
giveToolToPlayer(player)

return Enum.ProductPurchaseDecision.PurchaseGranted
end

end
1 Like

Bumping this since it’s a pretty serious issue

I don’t quite get what your issue is. Can you paraphrase it? Where is your other script?

1 Like

I have two completely separate remote functions. They both do the exact same thing. One of them works. The other one doesn’t. The marketplace processes the purchase, takes your robux, and gives you absolutely nothing and doesn’t even read the code inside of the marketplace receipt yet somehow it still processes the purchase.

The other script is identical to this one, it is useless for me to paste the code here I’ve reviewed it multiple times. It’s the same exact everything just with different names and a different badge ID. Trust me when I tell you I am good at looking through code. I always spot small things. There’s nothing wrong with it. No errors. It returns no errors when you purchase the item. It refuses to work.

Send it anyway; it doesn’t hurt for me to take a look

1 Like

Actually, the fact that you said it’s identical already sets off alarms. MarketplaceService.ProcessReceipt, like RemoteFunction.OnServerInvoke is a callback. Unlike events, only a single function can be assigned as a callback. Depending on which script runs second, it will override the previous callback you assigned to ProcessReceipt, leading all developer product purchases to be put through that callback. This is why the other developer product fails as it can never match the single asset ID you’re checking against

2 Likes

I was just going to send it :joy: It’s all good lol. What do I need to do to fix it?

local MarketplaceService = game:GetService("MarketplaceService")
local toolFolder = game.ServerStorage:WaitForChild("Tools")
local TOOL_PRODUCT_ID = 4324324321
local TOOL_NAME = "GravityCoil"

local function giveToolToPlayer(player)
local tool = toolFolder:FindFirstChild(TOOL_NAME)
if tool and not player.Backpack:FindFirstChild(TOOL_NAME) then
local clonedTool = tool:Clone()
clonedTool.Parent = player.Backpack
else
print("You already have the gravity coil")
end
end

game.ReplicatedStorage.DevProducts.GravityCoil.OnServerInvoke = function(player)
MarketplaceService:PromptProductPurchase(player, TOOL_PRODUCT_ID)
end

MarketplaceService.ProcessReceipt = function(receiptInfo)
local player = game.Players:GetPlayerByUserId(receiptInfo.PlayerId)
if not player then
return Enum.ProductPurchaseDecision.NotProcessedYet
end

if receiptInfo.ProductId == TOOL_PRODUCT_ID then
giveToolToPlayer(player)

return Enum.ProductPurchaseDecision.PurchaseGranted
end

end

You need to handle all developer products through a single callback. The documentation I referenced for MarketplaceService.ProcessReceipt shows you how to do that. I developed a pipeline for handling all things monetized in my game which demonstrates this. Feel free to take inspiration from it. You can fork the code here. I abstract my developer products, game-passes, and the like into ModuleScripts. I have found it more convenient to register them to the pipeline via a function so things stay connected with their relevant part of the codebase, but the pipeline version I’m giving you does not do this

1 Like

I would really prefer to do it the way I am but you are saying it’s impossible to salvage this code?

This is my third time solving this same problem:
https://devforum.roblox.com/t/studio-processreceipt-question/3292301/2?u=lava_shield

1 Like

It is impossible to handle things your way

1 Like

Thank you guys so much for helping me! I really appreciate it :smiley_cat:

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