Hi Guys, so I basically made a script where if a player buys a specific product, there stats named Skips increase. Basically I have 5 types of skips -
+1 Skip
+5 Skip
+10 skip
+25 skip
+100 skip
Basically whenever someone buys any product, it changes the value in table.
Script -
MS.ProcessReceipt = function(receipt)
if receipt.PlayerId == player.UserId then
if receipt.ProductId == 1358881369 then
data.Skips1 += 1
print(data.Skips1)
end
if receipt.ProductId == 1361212065 then
data.Skips5 += 1
print(data.Skips5)
end
if receipt.ProductId == 1361212655 then
data.Skips10 += 1
print(data.Skips10)
end
if receipt.ProductId == 1361268917 then
data.Skips100 += 1
print(data.Skips100)
end
end
end
(Data is just the table)
But for some reason it is really kind of multiplying. Lets say you purchase a product first time, it increments normally as 1. But slowly skips increase by 2, 3, 4,5 etc. I don’t really know the reason behind. Any help is appreciated!
Ok, the whole script is long but you have asked for it so I’ll show you.
local BS = game:GetService("BadgeService")
local DS = game:GetService("DataStoreService"):GetDataStore("Stage")
local MS = game:GetService("MarketplaceService")
local module = require(game.ReplicatedStorage.Modules.DataModule)
local bans = {}
local function awardBadge(player, id)
if not BS:UserHasBadgeAsync(player.UserId, id) then
BS:AwardBadge(player.UserId, id)
end
end
local function duplicateGui(player, amount, value)
local clone = game.ReplicatedStorage.SkipButton
clone.TextLabel = "+"..clone.Value.." Skips ".."(x"..clone.Amount..")"
clone.Parent = player.PlayerGui.ScreenGui1.Inventory.Scroll
end
local checkpoints = workspace.Checkpoints
game.Players.PlayerAdded:Connect(function(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local Stage = Instance.new("IntValue")
Stage.Name = "Stage"
Stage.Value = 0
Stage.Parent = leaderstats
data = module:Load(player)
Stage.Value = data.Stage
player.CharacterAdded:Connect(function(char)
print("Loaded")
local hum = char:WaitForChild("Humanoid")
wait()
char:MoveTo(checkpoints[Stage.Value].Checkpoint.Position)
hum.Touched:Connect(function(hit)
if hit.Name == "Checkpoint" and hit.Parent.Parent == checkpoints then
if tonumber(hit.Parent.Name) == Stage.Value + 1 then
Stage.Value += 1
data.Stage = Stage.Value
end
end
end)
end)
awardBadge(player, 2130439793)
if table.find(bans, player.Name) then
print(bans)
player:Kick()
end
MS.ProcessReceipt = function(receipt)
if receipt.PlayerId == player.UserId then
if receipt.ProductId == 1358881369 then
print(data.Skips1 + 1)
elseif receipt.ProductId == 1361212065 then
data.Skips5 += 1
print(data.Skips5)
elseif receipt.ProductId == 1361212655 then
data.Skips10 += 1
print(data.Skips10)
elseif receipt.ProductId == 1361268917 then
data.Skips100 += 1
print(data.Skips10)
end
end
end
end)
game.Players.PlayerRemoving:Connect(function(player)
module:Save(player, data)
end)
game:BindToClose(function()
for i, plr in pairs(game.Players:GetPlayers()) do
module:Save(plr, data)
end
end)
If you want me to share the module as well, let me know.
Create the process receipt in a server script inside server script service. You can already get the player data with the function. Theres no need to create a different event for every player that joins
It’s true that you’re creating the callback repeatedly and this is how to solve it:
local BS = game:GetService("BadgeService")
local DS = game:GetService("DataStoreService"):GetDataStore("Stage")
local MS = game:GetService("MarketplaceService")
local module = require(game.ReplicatedStorage.Modules.DataModule)
local bans = {}
local function awardBadge(player, id)
if not BS:UserHasBadgeAsync(player.UserId, id) then
BS:AwardBadge(player.UserId, id)
end
end
local function duplicateGui(player, amount, value)
local clone = game.ReplicatedStorage.SkipButton
clone.TextLabel = "+"..clone.Value.." Skips ".."(x"..clone.Amount..")"
clone.Parent = player.PlayerGui.ScreenGui1.Inventory.Scroll
end
local checkpoints = workspace.Checkpoints
game.Players.PlayerAdded:Connect(function(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local Stage = Instance.new("IntValue")
Stage.Name = "Stage"
Stage.Value = 0
Stage.Parent = leaderstats
data = module:Load(player)
Stage.Value = data.Stage
player.CharacterAdded:Connect(function(char)
print("Loaded")
local hum = char:WaitForChild("Humanoid")
wait()
char:MoveTo(checkpoints[Stage.Value].Checkpoint.Position)
hum.Touched:Connect(function(hit)
if hit.Name == "Checkpoint" and hit.Parent.Parent == checkpoints then
if tonumber(hit.Parent.Name) == Stage.Value + 1 then
Stage.Value += 1
data.Stage = Stage.Value
end
end
end)
end)
awardBadge(player, 2130439793)
if table.find(bans, player.Name) then
print(bans)
player:Kick()
end
end)
game.Players.PlayerRemoving:Connect(function(player)
module:Save(player, data)
end)
MS.ProcessReceipt = function(receipt)
if receipt.PlayerId == player.UserId then
if receipt.ProductId == 1358881369 then
print(data.Skips1 + 1)
elseif receipt.ProductId == 1361212065 then
data.Skips5 += 1
print(data.Skips5)
elseif receipt.ProductId == 1361212655 then
data.Skips10 += 1
print(data.Skips10)
elseif receipt.ProductId == 1361268917 then
data.Skips100 += 1
print(data.Skips10)
end
end
end
game:BindToClose(function()
for i, plr in pairs(game.Players:GetPlayers()) do
module:Save(plr, data)
end
end)
Your script is incorrect. You can’t check the player userid inside the process receipt because theres no player value. Instead get the player value and increase the skips data when player makes a purchase
I found a way to get the correct player and their data now:
local BS = game:GetService("BadgeService")
local DS = game:GetService("DataStoreService"):GetDataStore("Stage")
local MS = game:GetService("MarketplaceService")
local module = require(game.ReplicatedStorage.Modules.DataModule)
local bans = {}
local function awardBadge(player, id)
if not BS:UserHasBadgeAsync(player.UserId, id) then
BS:AwardBadge(player.UserId, id)
end
end
local function duplicateGui(player, amount, value)
local clone = game.ReplicatedStorage.SkipButton
clone.TextLabel = "+"..clone.Value.." Skips ".."(x"..clone.Amount..")"
clone.Parent = player.PlayerGui.ScreenGui1.Inventory.Scroll
end
local checkpoints = workspace.Checkpoints
game.Players.PlayerAdded:Connect(function(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local Stage = Instance.new("IntValue")
Stage.Name = "Stage"
Stage.Value = 0
Stage.Parent = leaderstats
data = module:Load(player)
Stage.Value = data.Stage
player.CharacterAdded:Connect(function(char)
print("Loaded")
local hum = char:WaitForChild("Humanoid")
wait()
char:MoveTo(checkpoints[Stage.Value].Checkpoint.Position)
hum.Touched:Connect(function(hit)
if hit.Name == "Checkpoint" and hit.Parent.Parent == checkpoints then
if tonumber(hit.Parent.Name) == Stage.Value + 1 then
Stage.Value += 1
data.Stage = Stage.Value
end
end
end)
end)
awardBadge(player, 2130439793)
if table.find(bans, player.Name) then
print(bans)
player:Kick()
end
end)
game.Players.PlayerRemoving:Connect(function(player)
module:Save(player, data)
end)
MS.ProcessReceipt = function(receipt)
local data = module:Load(game.Players:GetPlayerByUserId(receipt.PlayerId))
if receipt.ProductId == 1358881369 then
print(data.Skips1 + 1)
elseif receipt.ProductId == 1361212065 then
data.Skips5 += 1
print(data.Skips5)
elseif receipt.ProductId == 1361212655 then
data.Skips10 += 1
print(data.Skips10)
elseif receipt.ProductId == 1361268917 then
data.Skips100 += 1
print(data.Skips10)
end
end
game:BindToClose(function()
for i, plr in pairs(game.Players:GetPlayers()) do
module:Save(plr, data)
end
end)
It’s strange that the issue is still happening for you even when removing that line though, I’ll see if I can find the cause
Edit: @Moneypro456789 Can I see the module as well please? I can’t seem to find something in the code that might cause the problem to happen now so I suspect it’s being caused by the module
local DataModule = {}
local DS = game:GetService("DataStoreService"):GetDataStore("Stage")
local defaultData = {
Stage = 0,
Skips1 = 0,
Skips5 = 0,
Skips10 = 0,
Skips25 = 0,
Skips100 = 0,
Robux = 0,
}
function DataModule:Load(plr)
local data
local success, err = pcall(function()
data = DS:GetAsync(plr.UserId)
if typeof(data) ~= "table" then
local stage = data
local newData = {
Stage = stage,
Skips1 = 0,
Skips5 = 0,
Skips10 = 0,
Skips25 = 0,
Skips100 = 0,
Robux = 0,
}
DS:SetAsync(plr.UserId, newData)
data = newData
else
return true
end
end)
if success then
return data
end
end
function DataModule:Save(plr, data)
local success, err = pcall(function()
DS:SetAsync(plr.UserId, data)
end)
if success then
print("Saved Data")
end
end
function DataModule:UpdateRobuxSpent(plr, amount, data)
data.Robux += amount
local success, err = pcall(function()
DS:SetAsync(plr.UserId, data)
end)
end
return DataModule
The DataModule:Load is quite unusual, I don’t know why you’re setting the Skips back to 0 and resaving the data retrieved by it. All the function should need to do really is to attempt to retrieve the player’s data in an error-protected way and return the data result
Basically the game is quite old and I decided to shift on table saving recently. But the problem with that is if I directly set tables, it will overwrite and reset the old data. So I’m firstly seeing if it was a table or not, if it’s not, then it’s old, and I’m putting inside the tables.
if receipt.ProductId == 1358881369 then
data.Skips1 += 1
print(data.Skips1)
Plus @D1CEL is correct in saying that you’ll need to:
And also I suspect that when testing in Studio the data doesn’t have enough time to save properly before the server closes so you’ll need to replace the game:BindToClose section like so:
if game:GetService("RunService"):IsStudio() then
game:BindToClose(function()
task.wait(1)
end)
else
game:BindToClose(function()
local x, y = 0, 0
for _, player in game:GetService("Players"):GetPlayers() do
x += 1
task.spawn(function()
module:Save(player, data)
y += 1
end)
end
repeat task.wait() until y == x
end)
end
It’s rather complicated because there’s a lot of stuff that can go wrong even if your code works as intended (things can fail on Roblox’s end or the user could join another server before your callback returns). The docs for ProcessReceipt give you an example and some notes on stuff that could possibly go wrong as well as guarantees you have to work with.