So I’m new to using developer products and want to figure out how to make one of the developer products show up on screen when the player has no lives left. I have a script to record how much lives the player has, and how it loses them. I’m trying to get something like the death mechanic in “Rickey Rat” and “Us Are Toys” by @UmmmOkayWhat . Like after you loose your lives It’ll show the developer product. If you buy it, you will get more lives and continue playing. But if you don’t you will get kicked from the game.
script.Parent.Humanoid.Died:Connect(function()
local plr = game.Players:GetPlayerFromCharacter(script.Parent)
plr.Lives.Value -= 1
if plr.Lives.Value == 0 then
plr:Kick("you lost all your lives")
end
end)
I’ve tried looking at videos on a way to get this to work. But I have gotten no luck. I’d appreciate some help!
(This is my first topic so i’m not sure if this is how you properly do them)
You would first have to make a prompt before you kick them that says “Would you like to buy more lives” with a yes and no button. If they click yes, then you would have to prompt the product and then give the player the lives should they should to purchase it. If they click no, then you kick them.
The local script (found from the DevHub) under the “Yes” Button that prompts the purchase:
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")
local productID = 0000000 -- Change this to your developer product ID
-- Function to prompt purchase of the developer product
local function promptPurchase()
local player = Players.LocalPlayer
MarketplaceService:PromptProductPurchase(player, productID)
end
script.Parent.Mouse1ButtonClick:Connect(promptPurchase)
Then create server script in ServerScriptService and paste this code (also found from the DevHub) inside:
local MarketplaceService = game:GetService("MarketplaceService")
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
-- Data store for tracking purchases that were successfully processed
local purchaseHistoryStore = DataStoreService:GetDataStore("PurchaseHistory")
-- Table setup containing product IDs and functions for handling purchases
local productFunctions = {}
-- Replace the 000000 with your developer product ID
productFunctions[000000] = function(receipt, player)
local Lives = player:FindFirstChild("LivesValue")
if Lives then
Lives.Value += 3
-- Indicate a successful purchase
return true
end
end
-- The core 'ProcessReceipt' callback function
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, 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
-- 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 Enum.ProductPurchaseDecision.NotProcessedYet
end
-- Look up handler function from 'productFunctions' table above
local handler = productFunctions[receiptInfo.ProductId]
-- Call the handler function and catch any errors
local success, result = pcall(handler, receiptInfo, player)
if not success or not result then
warn("Error occurred while processing a product purchase")
print("\nProductId:", receiptInfo.ProductId)
print("\nPlayer:", player)
return Enum.ProductPurchaseDecision.NotProcessedYet
end
-- Record transaction in data store so it isn't granted again
local success, errorMessage = pcall(function()
purchaseHistoryStore:SetAsync(playerProductKey, true)
end)
if not success then
error("Cannot save purchase data: " .. errorMessage)
end
-- IMPORTANT: Tell Roblox that the game successfully handled the purchase
return Enum.ProductPurchaseDecision.PurchaseGranted
end
-- Set the callback; this can only be done once by one script on the server!
MarketplaceService.ProcessReceipt = processReceipt
Here’s a relatively primitive approach to your problem, it makes use of a single RemoteFunction instance placed inside the ReplicatedStorage container.
--LOCAL
local replicated = game:GetService("ReplicatedStorage")
local remote = replicated:WaitForChild("RemoteFunction")
script.Parent.Humanoid.Died:Connect(function()
local plr = game.Players:GetPlayerFromCharacter(script.Parent)
plr.Lives.Value -= 1
if plr.Lives.Value == 0 then
local value = remote:InvokeServer()
if not value then
plr:Kick("server timed out")
end
task.wait(60) --60 seconds to purchase more lives.
if plr.Lives.Value == 0 then
plr:Kick("you lost all your lives")
end
end
end)
--SERVER
local players = game:GetService("Players")
local marketplace = game:GetService("MarketplaceService")
local replicated = game:GetService("ReplicatedStorage")
local remote = replicated:WaitForChild("RemoteFunction")
local productId = 0 --Change to ID of product.
marketplace.ProcessReceipt = function(receiptInfo)
local player = players:GetPlayerByUserId(receiptInfo.PlayerId)
if player then
if receiptInfo.ProductId == productId then
player.Lives.Value += 3
end
return Enum.ProductPurchaseDecision.PurchaseGranted
end
return Enum.ProductPurchaseDecision.NotProcessedYet
end
remote.OnServerInvoke = function(player)
marketplace:PromptProductPurchase(player, productId)
return true
end
The server script would go inside the ServerScriptService container.
Thank you, it works perfectly. Well until you buy more lives. Once you buy extra lives it’ll add on to how much it had previously. The “Lives” script adds 3 at the beginning, then after buying it adds 3 more. Thus giving the player 6 lives. And it keeps adding on after dying those 6 times (thus resulting to 9 lives).
To explain your issue in depth, the player’s lives stat is being set by the client which means that its changes aren’t being replicated to the server (from the server’s perspective the player still has 3 lives, so 3 + 3 = 6 lives), we can circumvent this issue by setting the player’s “lives” stat on the server whenever they die (instead of letting the client decrement the lives stat by 1).
--LOCAL
local replicated = game:GetService("ReplicatedStorage")
local remote = replicated:WaitForChild("RemoteFunction")
local remote2 = replicated:WaitForChild("RemoteEvent")
local players = game:GetService("Players")
local character = script.Parent
local player = players:GetPlayerFromCharacter(character)
local humanoid = character:WaitForChild("Humanoid")
humanoid.Died:Connect(function()
remote2:FireServer()
if player.Lives.Value == 0 then
local value = remote:InvokeServer()
if not value then
player:Kick("server timed out")
end
task.wait(60) --60 seconds to purchase more lives.
if player.Lives.Value == 0 then
player:Kick("you lost all your lives")
end
end
end)
--SERVER
local players = game:GetService("Players")
local marketplace = game:GetService("MarketplaceService")
local replicated = game:GetService("ReplicatedStorage")
local remote = replicated:WaitForChild("RemoteFunction")
local remote2 = replicated:WaitForChild("RemoteEvent")
local productId = 0 --Change to ID of product.
marketplace.ProcessReceipt = function(receiptInfo)
local player = players:GetPlayerByUserId(receiptInfo.PlayerId)
if player then
if receiptInfo.ProductId == productId then
player.Lives.Value += 3
end
return Enum.ProductPurchaseDecision.PurchaseGranted
end
return Enum.ProductPurchaseDecision.NotProcessedYet
end
remote.OnServerInvoke = function(player)
marketplace:PromptProductPurchase(player, productId)
return true
end
remote2.OnServerEvent:Connect(function(player)
player.Lives.Value -= 1
end)
For this implementation we’ll need a RemoteEvent instance placed inside ReplicatedStorage.