Beginner with leaderstats datastore

If you are one of the few people struggling with the datastore concept or just a beginner in general, I will share my understanding of datastore…
First of all, you have to enable API services: simply by going to game settings → security → Enable API Service and save

The next few codes are commented on so you can refer back to them when coding. It has also been designed so that you can edit three variables namely VERSION, and data_table which are self-explanatory in themselves:

-- PublicDS
-- handles all the data store that is seen publicly
-- aka all items in the leaderstats

-- services needed
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")

-- constants variables
-- Changeable Values
-- change the version (will make a new datastore for each new version)
local VERSION = "v2"
-- add or remove elements from this table that you want to put into leaderstats
-- format: [dataName] = defaultValue
local data_table = {
	["Money"] = 1000,
	["Diamond"] = 50
}


-- handles leaderstats when player joins game
local LeaderstatsHandler_in = (function(player)
	-- functions
	-- get stats from the data store
	local getStats = (function(statName)
		local userId = Players:GetUserIdFromNameAsync(player.Name)
		local temp = DataStoreService:GetDataStore(VERSION)
		
		local success, currentStatValue = pcall(function()
			local value = temp:GetAsync(userId..statName)
			if value == nil then
				return data_table[statName]
			end
			
			return value
		end)
		
		if success then
			return currentStatValue
		else
			print("Error retrieving " .. statName)
		end
	end)
	
	-- creates leaderstats folder to player
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player
	
	-- sets the values under leaderstats folder
	-- statName: string represents the name of the stat
	local set_leaderstats = (function(statName)
		local temp = Instance.new("IntValue")
		temp.Name = statName
		temp.Value = getStats(statName)
		temp.Parent = leaderstats
	end)
	
	
	-- gets the values to set in leaderstats 
	-- by calling function set_leaderstats
	for data, v in data_table do
		set_leaderstats(data)
	end
end)

-- Event when a player joined a game
Players.PlayerAdded:Connect(function(player)
	print("Player " .. player.Name .. " has joined the game!")
	LeaderstatsHandler_in(player)	-- initiate the leaderstats for the player
	
end)

-- handles leaderstats when player want to save the datas
-- either by leaving the game or when server crashes
local LeaderstatsHandler_out = (function(player)
	local leaderstats = player:WaitForChild("leaderstats")
	-- functions
	--set stats into the data store
	local setStats = (function(statName)
		local userId = Players:GetUserIdFromNameAsync(player.Name)
		local temp = DataStoreService:GetDataStore(VERSION)
		local value = leaderstats:WaitForChild(statName).Value
		
		repeat
			local success, errorMessage = pcall(function()
				temp:SetAsync(userId..statName, value)
			end)
		until success
	end)	
	
	-- saves the stats into data store by calling function setStats
	for data, v in data_table do
		setStats(data)
	end
end)

-- to be called if and only if player is leaving the game or
-- when server crashed or closed
local save = (function(player)
	LeaderstatsHandler_out(player)
end)

-- Event when a player left the game
Players.PlayerRemoving:Connect(function(player)
	print("Player " .. player.Name .. " has left the game")
	save(player)
end)

-- Event when server crashed or closed
game:BindToClose(function()
	print("Server closed")
	for _, player in ipairs(Players:GetPlayers()) do
		save(player)
	end
end)

Now you can create a currency, level but I will leave that to you however you want to implement it. :smiley:

7 Likes

The problem in your repeat until loop is that you are waiting for success, the problem can be that it will never be successful so it will run infinitely, you should probably add a threshold of maybe 5 loops

2 Likes