Issues when saving donations

I made a donation GUI and leaderboard in my game but there are some issues. Whenever you donate robux, the amount you donated gets added to a NumberValue in the player. When the player leaves the game the value is supposed to be saved but sometimes when I rejoin the game the value is 0 again.

Theres another issue. If you choose to donate 5 robux, it says the DevProduct is not currently for sale although it is: image
The product id in the donation script is correct though.

1 Like

what are you using to save how much they have donated? are you using data stores?

Yes.

local DataStoreService = game:GetService("DataStoreService")
local SaveData = DataStoreService:GetDataStore("SaveData")

local function onPlayerJoin(plr)

	local donated = Instance.new("NumberValue")
	donated.Name = "Donated"
	donated.Parent = plr
	
	local playerUserId = "Player_"..plr.UserId
	local data = SaveData:GetAsync(playerUserId)
	if data then
		donated.Value = data["Donated"]
	else
		donated.Value = false
	end	
end

local function create_table(plr)
	local player_stats = {}
	for _, stat in pairs(plr:GetChildren()) do
		if stat.Name ==  "Donated" then
			player_stats[stat.Name] = stat.Value
		end
	end
	return player_stats
end

local function onPlayerRemoving(plr)
	local player_stats = create_table(plr)
	local success, err = pcall(function()
		local playerUserId = "Player_"..plr.UserId
		SaveData:SetAsync(playerUserId,player_stats)
	end)
	if not success then
		warn(err)
	end
end

game.Players.PlayerAdded:Connect(onPlayerJoin)
game.Players.PlayerRemoving:Connect(onPlayerRemoving)



I’m saving multiple values to this datastore, thats why there’s a create table function.

1 Like

i know now, are you only testing this in studio? if yes it may be because you’re only the player and the server close before it ever saves the data, also studio close fast unlike normal servers (Roblox). add bindtoclose() to delay the server closing and let is save the data before closing, more info here DataModel | Roblox Creator Documentation

It happened outside of studio in the actual game. Do I need BindToClose for that too?

where do you use marketplaceservice

There are 3 scripts in total. The one above saves data, this one here makes the player purchase the donation:

local num
local plr = game.Players.LocalPlayer
local mar = game:GetService("MarketplaceService")
script.Parent.MouseButton1Click:Connect(function()
	num = tonumber(script.Parent.Parent.Show.Text)
	if num == 5 then
		mar:PromptProductPurchase(plr,1218195662)
	elseif num == 10 then
		mar:PromptProductPurchase(plr,1218195748)
	elseif num == 50 then
		mar:PromptProductPurchase(plr,1218196108)
	elseif num == 100 then
		mar:PromptProductPurchase(plr,1218195860)
	elseif num == 500 then
		mar:PromptProductPurchase(plr,1218195911)
	elseif num == 1000 then
		mar:PromptProductPurchase(plr,1218195946)
	end
	script.Parent.Parent.Show.Text = 0
	script.Parent.Parent.Visible = false
end)

and this one:

local MarketplaceService = game:GetService("MarketplaceService")

local d5 = 1218195662
local d10 = 1218195748
local d50 = 1218196108
local d100 = 1218195860
local d500 = 1218195911
local d1000 = 1218195946

local function processReciept(recieptInfo)
	local player = game.Players:GetPlayerByUserId(recieptInfo.PlayerId)
	if not player then
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end
	
	if recieptInfo.ProductId == d5 then
		if player then
			player.Donated.Value = player.Donated.Value + 5
		end
	end
	
	if recieptInfo.ProductId == d10 then
		if player then
			player.Donated.Value = player.Donated.Value + 10
		end
	end
	
	if recieptInfo.ProductId == d50 then
		if player then
			player.Donated.Value = player.Donated.Value + 50
		end
	end
	
	if recieptInfo.ProductId == d100 then
		if player then
			player.Donated.Value = player.Donated.Value + 100
		end
	end
	
	if recieptInfo.ProductId == d500 then
		if player then
			player.Donated.Value = player.Donated.Value + 500
		end
	end
	
	if recieptInfo.ProductId == d1000 then
		if player then
			player.Donated.Value = player.Donated.Value + 1000
		end
	end
	wait(5)
	game.ReplicatedStorage.Remotes.DisableDialogueEvent:FireAllClients()
	return Enum.ProductPurchaseDecision.PurchaseGranted
end

MarketplaceService.ProcessReceipt = processReciept

increases the ‘donated’ value when someone purchased the donation

do all sameKeyDataStoreActions in one datastore script

sameKeyDataStoreActions

i mean by this all actions that uses the same key

The script that makes the player purchase the products is a LocalScript, I can’t do that. Also they all work fine it’s just that sometimes the datastorescript doesnt save data everytime

yes because it maybe that the server closes before it saves your data, so you need to delay it

1 Like

Get data:
Everytime a user joins the game.

Save data:

  1. Every x minutes on an interval
  2. BindToClose
  3. PlayerRemoving.

You should also use pcall when dealing with async calls.
More information here: Data Stores | Roblox Creator Documentation

Also, you can use elseif instead of checking if they bought every product, because ProcessReciept only returns one product at a time, not multiple.

if ProductId == 1 then
   print(1)
elseif ProductId == 2 then
   print(2)
end
1 Like

Thank you! I added that to my game but this is to make sure that the data saves. But sometimes the value is 0 when a player joins even though it was saved before.

local DataStoreService = game:GetService("DataStoreService")
local SaveData = DataStoreService:GetDataStore("SaveData")

local function onPlayerJoin(plr)

	local donated = Instance.new("NumberValue")
	donated.Name = "Donated"
	donated.Parent = plr
	
	local playerUserId = "Player_"..plr.UserId
	local data = SaveData:GetAsync(playerUserId)
	if data then
		donated.Value = data["Donated"]
	else
		donated.Value = 0
	end	
end

game.Players.PlayerAdded:Connect(onPlayerJoin)

here’s the code that gets the data.

@Qin2007

maybe you are overwrithing data. the best way to avoid that is

or datastoreservice has errored