DataStore not working

So I originally made a datastore for my game and gave it to my friend to help me out with it. Because it was not working. He then in turn made it better but for some reason it still does not save

 local datastore = game:GetService("DataStoreService")
local singleStorage = datastore:GetDataStore("PlayerSaves") 

game.Players.PlayerAdded:connect(function(plr)
    
    local folder = Instance.new("Folder")
    folder.Name = "leaderstats"
    folder.Parent = plr
    

    
    local coins = Instance.new("IntValue")
    coins.Name = "Coins"
    coins.Parent = folder
	coins.Value = 50
    
    local gems = Instance.new("IntValue")
    gems.Name = "Gems"
    gems.Parent = folder
	gems.Value = 10
    
    local kills = Instance.new("IntValue") 
    kills.Name = "Kills"
    kills.Parent = folder    
    
    local rank = Instance.new("IntValue")
    rank.Name = "Rank"
    rank.Value = 1
    rank.Parent = folder
        
    local data = singleStorage:GetAsync(plr.UserId)
        
    if data then 
        coins.Value = data[1]
        gems.Value = data[2] 
        kills.Value = data[3] 
        rank.Value = data[4]
    end 

end)

game.Players.PlayerRemoving:Connect(function(plr)
    local leaderstats = plr:FindFirstChild('leaderstats')
    if leaderstats then
        local saveData = {
            leaderstats['Coins'].Value,
            leaderstats['Gems'].Value,
            leaderstats['Kills'].Value,
            leaderstats['Rank'].Value
        }
    end
end)

could you pls help

2 Likes

I’m pretty sure that you(or your friend) aren’t saving anything at all in the player removing event, there is no saving method there from
what I can see (SetAsync, UpdateAsync etc).

If you wanted to use UpdateAsync, you could do something like this in your player removing event

singleStorage:UpdateAsync(plr.UserId, function(PreviousData)
  return saveData
end)

game.Players.PlayerRemoving:Connect(function(plr)
    local leaderstats = plr:FindFirstChild('leaderstats')
    if leaderstats then
        local saveData = {
            leaderstats['Coins'].Value,
            leaderstats['Gems'].Value,
            leaderstats['Kills'].Value,
            leaderstats['Rank'].Value
        }
 
    singleStorage:UpdateAsync(plr.UserId,function(PreviousData)
         return saveData
    end)

    end
end)
2 Likes

so what do i need to change in order to have the leaderstates saved?

EDIT: I’m new to scripting lua, so some of my questions may sound dumb

1 Like

For data to be saved you need to add in a saving method, like UpdateAsync for example, the one I provided above. Try replacing the player removing event with the one I provided and see if that works.

Hiya, I have a few tips for you that I would recommend taking into consideration.

  1. Use Connect over connect because the one with a lowercase c is deprecated and can be removed at any time which results in breaking your script altogether.
  2. Wrap your DataStore functions in pcalls, here is an article to assist you in adding them. Pcalls can prevent data loss which is a win for both you and your players.
2 Likes

I agree that pcalls should be used, not to be nit-picky but I think it is slightly misleading to say that they prevent dataloss just in general, I think it’s more that they are something that some one can use to help someone prevent data loss. They dont prevent data loss on their own, pcalls really just isolate or “quarantine” whatever is wrapped in them and you can use them to your advantage to “validate” stuff.

1 Like

cc: @COUNTYL1MITS, @Jaycbee05

The reason why you use pcall with data stores is because data store requests often fail at no fault of the developer. Pcall allows you to catch the error and do something with that error like doing a custom retry method. Roblox uses DynamoDB for data stores so web calls have to be preformed to access it so pcall should be used.


The reason why your script ins’t working is because you aren’t actually using any saving method in the PlayerRemoving function. This means the data wont save to a data store because you havn’t told it to. To fix this you should use either SetAsync() or UpdateAsync() to save data. I would recommend UpdateAsync() because the developers hub recommends it over SetAsync() and because of this community tutorial: Stop using SetAsync() to save player data.

As I mentioned above you should always wrap your data store requests in pcall because they often fail at no fault of the developer. Having your requests in a pcall will allow you to catch the error and do something when the request fails.

Here is your script with the changes that I mentioned above.:

local datastore = game:GetService("DataStoreService")
local singleStorage = datastore:GetDataStore("PlayerSaves") 

game.Players.PlayerAdded:connect(function(plr)
    local folder = Instance.new("Folder")
    folder.Name = "leaderstats"
    folder.Parent = plr
    
    local coins = Instance.new("IntValue")
    coins.Name = "Coins"
    coins.Parent = folder
	coins.Value = 50
    
    local gems = Instance.new("IntValue")
    gems.Name = "Gems"
    gems.Parent = folder
	gems.Value = 10
    
    local kills = Instance.new("IntValue") 
    kills.Name = "Kills"
    kills.Parent = folder    
    
    local rank = Instance.new("IntValue")
    rank.Name = "Rank"
    rank.Value = 1
    rank.Parent = folder
	
	local Success, data = pcall(function() -- Added a pcall
		return singleStorage:GetAsync(plr.UserId)
	end)
	
	if not Success then -- The data failed to load
		-- Do something if the data faield
	else -- The data loaded successfully
		if data then 
        	coins.Value = data[1]
			gems.Value = data[2] 
        	kills.Value = data[3] 
        	rank.Value = data[4]
		else
			-- Give the player the default data
    	end 
	end
end)

game.Players.PlayerRemoving:Connect(function(plr)
    local leaderstats = plr:FindFirstChild('leaderstats')
	
	if leaderstats then
		local saveData = {
            leaderstats['Coins'].Value,
            leaderstats['Gems'].Value,
            leaderstats['Kills'].Value,
            leaderstats['Rank'].Value
        }
		
		local Success, Error = pcall(function() -- Added pcall
			singleStorage:UpdateAsync(plr.UserId, function(OldData) -- Calls the UpdateAsync() function
				return saveData
			end)
		end)
		
		if not Success then
			-- Do something if the save failed
		end
	end
end)

You should modify this script to fit your use case and where I have left comments. For further improvements you should add BindToClose() for saving data: BindToClose & Data Loss Risk - #2 by Tiffblocks

Thank you for this script but I have one more question,
so at this part what would I put as the default data?

else -- The data loaded successfully
		if data then 
       	coins.Value = data[1]
			gems.Value = data[2] 
       	kills.Value = data[3] 
       	rank.Value = data[4]
		else
			-- Give the player the default data
   	end 
	end
end)

The default data refers to the stats the player starts out with when they join your game for the first time. For your game you could create a table that stores all the default stats and you can reference it when you need to:

local DefaultStats = {
	coins = 0;
	gems = 0;
	kills = 0;
	rank = "Default";
}

if not Success then -- The data failed to load
	-- Do something if the data faield
else -- The data loaded successfully
	if data then 
       	coins.Value = data[1]
		gems.Value = data[2] 
       	kills.Value = data[3] 
       	rank.Value = data[4]
	else
		-- Give the player the default data
		coins.Value = DefaultStats.coins
		gems.Value = DefaultStats.gems
		kills.Value = DefaultStats.kills
		rank.Value = DefaultStats.rank
   	end 
end
2 Likes

Would I put

local DefaultStats = {
	coins = 0;
	gems = 0;
	kills = 0;
	rank = "Default";
}

At the end of the script or between

local datastore = game:GetService("DataStoreService")
local singleStorage = datastore:GetDataStore("PlayerSaves") 

and

game.Players.PlayerAdded:connect(function(plr)

You can put it anywhere in the script as long as you put it where you can reference it. For your case I would put it where you said to put it:

1 Like