Trouble with leaderstats saving

Hey, so recently I’ve been trying to make a leaderstats saver using datastore.
However, it’s not working. So I thought I better come here.

This is my code:

local dataStoreService = game:GetService("DataStoreService")
local myDataStore = dataStoreService:GetDataStore("myDataStore")
local players = game:GetService("Players")

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

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

  local success, data = pcall(myDataStore.GetAsync, myDataStore, player.UserId)

  if success then
    cash.Value = data
  else
    print("There was an error whilst getting your data.")
    warn(data)
  end
end)

players.PlayerRemoving:Connect(function(player)
  local success, errormessage = pcall(myDataStore.SetAsync, myDataStore, player.UserId, player.leaderstats.Coins.Value)

      if success then
       print("Player data successfully saved!")
  else
    print("There was an error saviing data.")
    warn(errormessage)
  end
end)

This is my current output: 23:29:27.079 - ServerScriptService.myDataStore:5: attempt to index nil with 'PlayerAdded'

2 Likes

You should have players.PlayerAdded instead of player.PlayerAdded as thats what you have defined earlier in your code @Disparrel

2 Likes

Should this fix my problem?
(3030)

It should as thats the only error I have seen in your code, if not just reach back here and we can help

1 Like

Just my luck Anyways, code isn’t working. But the output seems fine, nothing is wrong… From what I can tell.

So I am unsure of what to do from here.

Have you turned on API services in game settings, please turn it on and then publish your game and try again.

1 Like

I have had API Services on, for a few weeks now. I am still, unsure of what’s happening.

You said the code is not working that’s very vague. What part of your code is not working? Could be more descriptive in your remarks?

The leaderstats just aren’t saving. So in whole, the code isn’t working, yet there’s nothing in the output. And I have API services on.

He is perfectly fine doing it his way. I assume he read this article and learned that way of using pcalls. Also, pcall’s 2nd variable can return data if you are using a GET method.

1 Like

I have inserted your script into a blank baseplate, it works perfectly. Could it be that the server is closing before all the data is saved? I would read this article and try using it to see if your data saves afterward.

I had the same as well

but i recommend switching to DataStore2 if u dont want complexity but if u want tho ill give you a chance

lets say u have coins in your leaderstats
lets add bindtoclose

local dataStoreService = game:GetService("DataStoreService")
local myDataStore = dataStoreService:GetDataStore("myDataStore")
local players = game:GetService("Players")
local plrsLeft = 0

player.PlayerAdded:Connect(function(player)
plrsLeft = plrsLeft + 1  
local leaderstats = Instance.new("Folder")
  leaderstats.Name = "leaderstats"
  leaderstats.Parent = player

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

local success, errormessage = pcall(function()
        myDataStore:GetAsync(player.UserId) -- No need for "User-"
end)

-- if it was success then run this
if success then
     Coins = success[1] -- Means they are stored in the first table
else
     warn("Error Failed to receive")
end

-- auto save (optional)

while wait(30) do
       myDataStore:UpdateAsync(player.UserId, {Coins.Value} -- in this table is where u want to save)
end

end)
local BindEvent = Instance.new("BindableEvent")
player.PlayerRemoving:Connect(function(player)
     plrsLeft = plrsLeft - 1

    pcall(function()
        myDataStore:UpdateAsync(player.UserId, {player.leaderstats.Coins.Value})
        BindEvent:Fire()
end

end)

game:BindToClose(function()
while plrsLeft > 0 do
     BindEvent.Event:Wait()
end

end

Never use SetAsync because it sets the value

But UpdateAsync reconsiders the old value before making changes

and bindable events to prevent data loss

1 Like

I would recommend properly indenting your code for readability and it is also a good practice to indent your code.

i cant use studio rn so i used dev forum code

That’s not how UpdateAsync works. The problem with telling people blindly to use UpdateAsync over SetAsync without actually explaining the benefits is that you get code like this. UpdateAsync’s second argument is a transformation function that takes the old data that’s saved as an argument. For something like Coins, where the value may go up or down throughout a play-session, it’s much harder to sanity-check the old value to make sure what you’re saving makes sense.

Saying “never” is also not particularly helpful, as there are absolutely times you may want to completely overwrite data. I’d recommend reading this post where I give some example situations of when UpdateAsync should be used.

Pcall can return values. It is generlaly better practice to return the result from GetAsync() rather than assining the result to a variable outside the pcall. This is what you should do when you are using GetAsync() with pcall:

local Success, Result = pcall(function()
   return DataStore:GetAsync(tostring(Player.UserId))
end)

The reason why you are getting this error is because I am assuming you made a small typo with player.PlayerAdded. player should be changed to players. This is what the line should be:

players.PlayerAdded:Connect(function(player)

Instead of using SetAsync() when saving data you should use UpdateAsync() because according to the developers hub it is more reliable. Also according to to the developers hub it states using SetAsync() can be hazardous because it forces the save onto the key without taking into account previously saved data. You should read over this community tutorial because it explains why and how you should use UpdateAsync():

Other than that I can’t see anything else wrong with your script other than changing how you use pcall. The code below should work perfectly fine because I have tested it and it works:

local dataStoreService = game:GetService("DataStoreService")
local myDataStore = dataStoreService:GetDataStore("myDataStore")
local players = game:GetService("Players")

players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player
	
	local cash = Instance.new("IntValue")
	cash.Name = "Coins"
	cash.Parent = leaderstats
	
	local success, data = pcall(function()
		return myDataStore:GetAsync(tostring(player.UserId))
	end)
	
	if success then
		cash.Value = data
	else
		print("There was an error whilst getting your data.")
		warn(data)
	end
end)

players.PlayerRemoving:Connect(function(player)
	local success, errormessage = pcall(function()
		myDataStore:UpdateAsync(tostring(player.UserId), function(OldData)
			return player.leaderstats.Coins.Value
		end)
	end)

	if success then
		print("Player data successfully saved!")
	else
		print("There was an error saviing data.")
		warn(errormessage)
	end
end)

If you are changing your coins on the client it wont replicate to the server. This means when the server saves the data it will assume you haven’t changed the coins so it will save the default value. To fix this you should always update players leaderstats values on the server.

1 Like

Is there a way to make leaderstat saving, without having to wait so much time?

Just change the 30 in while wait(30) do assuming you are using FerbZides’s code. I do not recommend changing it though due to limits. Otherwise, I do not know what you mean by without having to wait so much time, so if you mean something else please explain.

By using FerbZide’s code, I am getting this output:
[09:52:22.916 - ServerScriptService.myDataStore:33: Expected ')' (to close '(' at line 30), got 'end']