How do I make a datastore that saves a leaderstat?

I don’t know if I understand what you said, but it automatically will save your progress when you leave the game.

Well that code you sent is hard for me to read, and I don’t trust it because it looks like it’s missing some things

There’s no DataStore1, there is the simple datastore, here’s an example:

local dss = game:GetService("DataStoreService")
local saveData = dss:GetDataStore("putanythinghere")


game.Players.PlayerAdded:Connect(function(player)
      local leaderstats = Instance.new(“Folder”,player)
      leaderstats.Name = “leaderstats”

      local Cash = Instance.new(“IntValue”,leaderstats)
      Cash.Name = “Cash”
      Cash.Value = 0
      
      local data = saveData:GetAsync(player.UserId)
      if data ~= nil then
          Cash.Value = data[1]
          else
          Cash.Value = 0
    end
end)

game.Players.PlayerRemoving(player)
      local dataToSave = {
          player.leaderstats.Cash.Value
      }

      saveData:SetAsync(player.UserId, dataToSave)
end)

I don’t need to create a leaderstat because I already did that in another script. Does it affect anything in this script? Datastore is new to me and I’m not good at reading it either.

1 Like

You need to do the first part of the datastore inside of the leaderstats, format it how I did.

And also put the whole datastore in the same script as the leaderstats.

I don’t know what that means, sorry.

Another thing to add, wouldn’t you need to put pcall functions around the datastore stuff? I saw on devhub that you always need to put pcalls around datastore.

Also here is the code that I currently have in the game, maybe we can improve the already existing one?

local DS = game:GetService("DataStoreService"):GetDataStore("Wins")

game:GetService("Players").PlayerAdded:Connect(function(plr)
	wait()
	local plrkey = "id_"..plr.userId
	local save1 = plr.leaderstats.Wins
	
	local GetSaved = nil
	local success, errorMessage = pcall(function()
		GetSaved = DS:GetAsync(plrkey)
	end)
	if not success then
		warn(errorMessage)
	end
	if GetSaved ~= nil then
		save1.Value = GetSaved[1]
	else
		local NumberForSaving = {save1.Value}
		local success, errorMessage = pcall(function()
			DS:GetAsync{plrkey, NumberForSaving}
		end)
		if not success then
			warn(errorMessage)
		end
	end
end)

game:GetService("Players").PlayerRemoving:Connect(function(plr)
	local success, errorMessage = pcall(function()
		DS:SetAsync("id_"..plr.userId, {plr.leaderstats.Wins.Value})
	end)
	if not success then
		warn(errorMessage)
	end
end)

Just use DataStore2 like I said, you don’t have to worry about data not saving etc as it handles it all for you. As I said, as long as you aren’t using ordered datastores its perfect for your usecase.

Well I don’t know what DataStore2 is and idk how to use it.

Read the documentation like everyone else.

Hey there! So, in essence, modules are just tables, which are returned to you by “requiring” them. Luau, however, is unique in the fact that it can store functions in tables and dictionaries. Because of this, people commonly use modules to neatly store functions. For example:

local Module = {}

function Module.Example()
     print("Cool, it works!")
     return
end

return Module

This “module”, would return a dictionary (a table that stores values with names/strings and other values instead of numbers indexing from 1+), and you can execute the function in it with

local Module = require(Path.To.Module)

Module.Example() -- This would print out "Cool, it works!"
return

This special property is why a lot of very popular utilities and libraries for use in ROBLOX are made with modules, because any script can access them and they are neatly organized!

So back to the original topic, the values in leaderstats are essentially just instances that store values. For example, a “NumberValue” stores a number that you can access by doing

NumberValue.Value

Then, you can use this value to save a player’s data! Here’s a quick example of a datastore system using ROBLOX’s built in datastores (but feel free to use a module, they’re great!)

local Datastore = { 
    Cache = {}, -- The currently saved datastore data!
    Default = { -- The default data a player with no saved data gets!
        Wins = 0,
        Losses = 0,
        Statistics = {}
    }
}

local datastoreService = game:GetService("DatastoreService")

local datastore = datastoreService:GetDataStore("Game")

local function cloneTable(target)
	if typeof(target) ~= "table" then
		return target
	end
	
	local clone = {}
	
	for index, value in pairs(target) do
		clone[cloneTable(index)] = cloneTable(value)
	end
	
	return clone
end


function Datastore.Get(player)
    local userId = tostring(player.UserId)
    local cached = Datastore.Cache[userId]

    if (cached ~= nil) then
         return cached
    end

    local attempts = 0
    local success = false
    local data = nil

    while true do
        if (success ~= false or attempts >= 3) then
            break
        end

        data = datastore:GetAsync(userId)
        attempts += 1

        if (data ~= nil) then 
            success = true break
        end

        wait(0.125)
    end

    if (data ~= nil) then
        Datastore.Cache[userId] = data        
        return data
    end
    
    data = cloneTable(Datastore.Default)
    
    Datastore.Cache[userId] = data        
    return data
end

function Datastore.Save(player)
     local data = Datastore.Get(player)

     local attempts = 0
     local success = false
     local data = nil

     while true do
         if (success ~= false or attempts >= 3) then
             break
         end

         success = pcall(function() datastore:SetAsync(userId, data) end)
         attempts += 1

         wait(0.125)
     end
end

return Datastore

You can then use this “module”, require it , and load data in a process similar to this:

-- The datastore module to get and save player data!
local Datastore = require(Path.To.Module)

-- The players service for all the important events we need!
local players = game:GetService("Players")

-- The event for when a player joins, so we can print out their wins/losses!
players.PlayerAdded(function(player)
    local data = Datastore.Get(player)

    print("The player has " .. data.Wins .. " wins, and " .. data.Losses .. " losses!")
    return
end)

-- The event for when a player leaves, so we can save their data!
players.PlayerRemoving:Conncet(function(player)
    Datastore.Save(player)
    return
end)

But you may be wondering, where do leaderstats tie in with all this stuff? Well here’s the magic of modules, instead of rewriting the datastore saving code each time to set the player’s datastore values, you can use the following code to update the cached value, and then it’ll save automatically! (Assuming you are also using the previous script(s) I mentioned)

local Datastore = require(Path.To.Module)

Datastore.Get(player).Wins = leaderstats.Wins.Value
return

Please note, I wrote all of this in this text box, so I’m not quite sure if its 100% bug-free, but I’d be happy to help through any issues :slight_smile:

Hope this helps! Have a wonderful day! :wave:

1 Like

Documentation really doesn’t work when conveying the information of how to use something when the person doesn’t know enough about the base of what that utility is made of. Even if you read the documentation, you still need to have a decent understanding of modules to really understand what’s going on with your code. Luckily, there are tons of tutorials about modules all over the developer forums! :smiley:

Hope you have a great day!
Hope this helps! :wave:

This thread is already way too long but I’ll just put in my post.

For the most direct answer follow Post 12

Post 12

Only thing you should add is a pcall surrounding the web calls (Async)


If you want to use a Data Storage module, I would highly recommend ProfileService over any other modules like DataStore2. DataStore2’s single purpose has been deprecated since the release of DataStore v2 and DS2 is unsupported.

ProfileService is fully supported and gets constant updates, as well as having many vital features like session locking.

Try this script:


local DataStoreService = game:GetService("DataStoreService")
local DataStore = DataStoreService:GetDataStore("DataStoreValues") --Name the DataStore whatever you want

game.Players.PlayerAdded:Connect(function(player)

    local leaderstats = Instance.new("Folder", player)
    leaderstats.Name = "leaderstats"

	local Wins = Instance.new('NumberValue', leaderstats)
	Wins.Name = "Wins"
	Wins.Value = 0

	local value1Data = Wins

	local s, e = pcall(function()
		value1Data = DataStore:GetAsync(player.UserId.."-Value1") or 0 --check if they have data, if not it'll be "0"
	end)

	if s then
	Wins.Value = value1Data --setting data if its success
	else
		game:GetService("TestService"):Error(e)  --if not success then we error it to the console
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
local s, e = pcall(function()
	DataStore:SetAsync(player.UserId.."-Value1", player.leaderstats.Wins.Value) --setting data
	end)
	if not s then game:GetService("TestService"):Error(e) 
	end
end)

I haven’t read the full thread yet. But does it change the value on the server or client? If it does on the client then it wont say since data stores are on the server. Make sure to check

Check out my script that i posted in the thread. It should save your wins.

That is the exact same script I was using… I think the other tutorial I watched just copied this one

That script didn’t work, sorry :confused:

Alright I figured it out. All I did was use a free model. I checked the model for viruses and read through the whole script. The script had some errors and typos so I changed a few things. This is what I have so far and it seems to be working:

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

game.Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player
	
	local wins = Instance.new("StringValue")
	wins.Name = "Wins"
	wins.Value = 0
	wins.Parent = leaderstats
	
	local data = nil
	local success, errormessage = pcall(function()
		data = playerData:GetAsync(player.userId.."-wins") 
	end)
	
	if success and data ~= nil then 
		wins.Value = data
	else
		print("Error while getting your data")
		warn(errormessage)
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
	
	local success, errormessage = pcall(function()
		playerData:SetAsync(player.userId.."-wins", player.leaderstats.Wins.Value)
	end)
	
	if success then
		print("Data successfully saved!")
	else
		print("There was an error while saving the data")
		warn(errormessage)
	end
	
end)

I will study this script. I’ll give an update if something happens again.

2 Likes