I don’t see how the use case described by OP can’t be accomplished right now. Why do you even need to invoke ProcessReceipt (by giving an asset to the player) when you can just apply the developer product’s effect directly to the player once s/he enters the code?
As for gamepasses, why not use developer products instead and make a check to make sure that the player can’t purchase the developer product if a) they have already purchased it or b) they’ve already redeemed its effect via code?
For both of these cases, the implementation shouldn’t be too complicated. For the first one, you should properly organize your code such that the function that awards the player the bonus is separated from your ProcessReceipt callback.:
-- In a server-side module.
-- Function that gives the player 1K points
function AwardPoints(player)
-- This is a stub.
-- Awarding function goes here.
end
-- In a server-side script.
-- Receipt-processing code
function MarketplaceService.ProcessReceipt(receiptInfo)
local player = game:GetService("Players"):GetPlayerByUserId(receiptInfo.PlayerId)
if receiptInfo.ProductId == 1234 then
AwardPoints(player)
end
end
-- In a localscript in the player's gui.
-- This is the text box for the code form.
TextBox.FocusLost:Connect(function()
-- Fire a remote event that will send the input of this field to the server.
-- The server will validate it on their side.
CodeRemote:FireServer(TextBox.Text)
end)
-- In a server script.
-- This is the code for the server script that will listen to the remote event.
CodeRemote.OnServerEvent:Connect(function(player, code)
if code == "YourCodeHere" then
AwardPoints(player)
end
end)
If MarketplaceService:AwardAssetToUser(id UserId, id AssetId)
were to be implemented, we would replace the code of the remote event listener to:
CodeRemote.OnServerEvent:Connect(function(player, code)
if code == "YourCodeHere" then
MarketplaceService:AwardAssetToUser(player, 1234)
end
end)
Which actually ends up making the code longer.
As for the second one (using a developer product to simulate game pass behavior) you could implement it the following way:
function PlayerHasBeenAwarded(player)
-- This is a stub.
-- Retrieves a boolean in the player's datastore which indicates whether or not the
-- pseudo-game pass has been awarded.
end
function AwardPlayer(player)
-- This is a stub.
-- Awards the player 1K points.
-- In addition, the bool that indicates that the award has been given is set in the datastore.
end
-- Tries to award the player.
-- Will do nothing if the award has already been awarded in the past.
function TryToAwardPlayer(player)
if not PlayerHasBeenAwarded(player) then
AwardPlayer(player)
return true
end
return false
end
-- For ProcessReceipt, the previous code is fine.
-- Ditto for the code entry, but instead of AwardPlayer, do TryToAwardPlayer instead.
-- Maybe even present a message to the player if the code has already been redeemed?
-- Code for the in-game buy button.
-- Assume that the appropriate remotes are in place.
BuyButton.Mouse1Click:Connect(function()
-- If the player has already obtained this award, whether via code
-- or via dev product, then do not let them purchase this.
-- Optimally, if the player already received the award, they wouldn't even see this button.
if PlayerHasBeenAwarded(localplayer) then
print("You already have this!")
else
-- Otherwise, go ahead and allow them to buy it.
PromptPurchase(localplayer, 1234)
end
end