LeaderStats not saving

Hey everyone! First time posting on the DevForum here.
Just as an FYI, I am more of a beginner scripter, and new modeler too. Sorry if everything looks bad :sweat_smile:

Issue:

My leader stats script isn’t saving:

I am really unsure of why its not saving. It saved when I first only had the “Cash” value. I added “Diamonds” and to be completely honest, I wasn’t super sure what I was doing for making that save too. Here is the script:

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


game.Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local Cash = Instance.new("IntValue")
	Cash.Name = "Cash"
	Cash.Parent = leaderstats
	
	local Diamonds = Instance.new("IntValue")
	Diamonds.Name = "Diamonds"
	Diamonds.Parent = leaderstats
	
	local playerUserId = "Player"..player.UserId

	local data 

	local success, errormessage = pcall(function()
		data = myDataStore:GetAsync(playerUserId) 
	end)


	if success then
		Cash.Value = data--loads data when player joins
		Diamonds.Value = data
	end

	while wait(1) do
		player.leaderstats.Cash.Value = player.leaderstats.Cash.Value + 1
		player.leaderstats.Diamonds.Value = player.leaderstats.Diamonds.Value + 1
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
	local playerUserId = "Player"..player.UserId

	local data1 = player.leaderstats.Cash.Value
	local data2 = player.leaderstats.Diamonds.Value

	myDataStore:SetAsync(playerUserId, data1, data2)           --saves data when player leaves game

end)

Thank you to all in advance! I look forward to the help!

2 Likes

Data saving and getting should be wrapped around a pcall() and repeat until loop since data saving can not work sometimes

3 Likes

I believe SetAsync() only takes 2 parameters - The player and the data being saved. Because of this, it would be best to use tables and simply store your Cash & Diamond values in the table:

game.Players.PlayerRemoving:Connect(function(player)
	local data1 = player.leaderstats.Cash.Value
	local data2 = player.leaderstats.Diamonds.Value

	myDataStore:SetAsync(player.UserId, {
		Cash = data1,
		Diamonds = data2
	})
end)

Noticed how I removed the playerUserId here. The player’s userId itself will suffice as the key for the data, adding an additional string will do you no good.

Now that the data is being properly saved, upon doing GetAsync() on the player’s UserId, this is the data that will be returned:

{
	Cash = 123, -- Example value
	Diamonds = 321
}

It is the exact same table you saved using SetAsync() in the PlayerRemoving event. Now you can use this to set the value of the Cash and Diamonds when the player joins like this:

game.Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local Cash = Instance.new("IntValue")
	Cash.Name = "Cash"
	Cash.Parent = leaderstats

	local Diamonds = Instance.new("IntValue")
	Diamonds.Name = "Diamonds"
	Diamonds.Parent = leaderstats

	local data
	local success, err = pcall(function()
		data = myDataStore:GetAsync(player.UserId) 
	end)

	if success then
		--// Get the saved values and set them as the value of Cash & Diamonds
		Cash.Value = data.Cash
		Diamonds.Value = data.Diamonds
	else
		--// Warn the error. Alternatively, you can also kick the player if you want
		warn(err)
	end

	while true do
		player.leaderstats.Cash.Value += 1
		player.leaderstats.Diamonds.Value += 1
		task.wait(1)
	end
end)

Notice how I also changed the while loop at the end. People say its bad practice to do “while wait do” because it’s just worse on the backend of things, so I did “while true do” and put the wait inside of the loop. Something better to do would be to have one loop that increments everyone’s Cash and Diamonds, but this will suffice here.

You should also use the operators +=, -=, /=, *= to make your calculations faster as I did here.

Keep in mind that data most likely won’t save in Studio, meaning that you’ll need to test data saving & loading by playing the game through the Roblox app.

You can use BindToClose() to save people’s data even when the game shuts down. I won’t be going over this now, but there are tutorials that do.

Hopefully this helps.

2 Likes

So I copied the script and replaced it with my old one, but im receiving an errror.
I have this:
image
and this:


Btw, thanks for the time and details you put into making a great reply :slight_smile:

You forgot to paste the two lines at the top (u actually used that in ur own script just paste them at the top)

local DataStoreService = game:GetService("DataStoreService")
local myDataStore = DataStoreService:GetDataStore("myDataStore")
1 Like

Right, thank you! I did that, and I got this error:


The cash and diamonds isn’t going up each second either.

I forgot to set the data to the table, whoops.

Change this:

if success then
		--// Get the saved values and set them as the value of Cash & Diamonds
		Cash.Value = data.Cash
		Diamonds.Value = data.Diamonds
	else
		--// Warn the error. Alternatively, you can also kick the player if you want
		warn(err)
	end

To this:

if success then
	--// If they don't have the table as a data, then give them it
	if not data or data and typeof(data) ~= "table" then
		data = {
			Cash = 0,
			Diamonds = 0
		}
	end
	
	--// Get the saved values and set them as the value of Cash & Diamonds
	Cash.Value = data.Cash
	Diamonds.Value = data.Diamonds
else
	--// Warn the error. Alternatively, you can also kick the player if you want
	warn(err)
end
1 Like

Great. It fixed the errors.
Unfortunately, it still doesn’t save…

Sometimes you can’t test things on Studio, sometimes you must test in live-game

I tried in studio and in live game, neither work.

Then try this

-- this is getting the data, put data outside the functions as local data 
local success
local playerdata
local attempt = 0

repeat 
	success, playerdata = pcall(function()
		data = myDataStore:GetAsync(player.UserId) 
	end)
	attempt += 1
	if not success then
		warn(playerdata)
		task.wait(3)
	end
until success or attempt == 5
	if success then
		if not playerdata then
			 playerdata = {
			["Cash"] = 0
			["Diamonds"] = 0
			}
		end
		data = playerdata
	else
		warn(err)
	end
	Cash.Value = data.Cash
	Diamonds.Value = data.Diamonds
	Cash.Changed:Connect(function()
		data.Cash = Cash.Value
	end)
	Diamonds.Changed:Connect(function(
		data.Diamonds = Diamonds.Value
	end)

Should I add it to the script?

There is a reason why I wrote that, yes

I meant do you want me to replace the the entire script with it, or just the certain lines of code?

You accidentally set the GetAsync to the wrong variable, change it to this

playerdata = myDataStore:GetAsync(player.UserId)

Edit: Didn’t see the pcall variable lol

No, the second variable is the value it returns

1 Like

Hi there, I posted something similar regarding leaderstats and datastore: Consider checking this out…
It is well written and you can learn more about datastore and the problem you are currently facing if any
Leaderstats Datastore

Don’t you have to put a return before that though?

success, playerdata = pcall(function()
	return myDataStore:GetAsync(player.UserId) 
end)

Yea you usually do but in his way it is a bit different but that way you used is way more efficient

1 Like

Aahh after reading the code you gave, it seems that it does not save when the server is closed (probably how you exit when you are testing the game). You have to consider adding this event:

local Players = game:GetService("Players")

-- fires when the server crashed or closes
game:BindToClose(function()
	for _, player in ipairs(Players:GetPlayers()) do
		save(player) -- create a function save that saves the data of a player (one at a time)
                -- that way you can also use the function save() for when a player leaves the game
	end
end)