Saving "Time Played" Leaderstats

I have been trying to make a script where there would be a leaderstat that updates to show the amount of minutes the player has played, and it saves so when the player leaves and rejoins, their time will still be there. The problem is that the leaderstat wouldn’t save, and sometimes when I try to fix the script, it won’t update the amount of minutes played. I have looked on YouTube and in the toolbox for help, but nothing worked.

Can anyone help?

1 Like

Can I see the leaderstats script, and DS?

If you are saving it every minute, don’t. Make a local stat where you count the minutes in the server, then when the player leaves, save the stat.
I don’t know the actual script though, so I don’t know if this is what you want.

Look into DataStores, these will allow you to save things. Save the data linked to a player when they leave, which is a much better way of saving.

To save data linked to a player, you can do :SetAsync(player.UserId, player.leaderstats.Time)

You can load it in using PlayerAdded, pcalls and :GetAsync

Hope this helped :slight_smile:

local players = game:GetService("Players")
local datastores = game:GetService("DataStoreService")
local datastore = datastores:GetDataStore("DataStore")

local function onPlayerAdded(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player
	
	local minutes = Instance.new("IntValue")
	minutes.Name = "Minutes"
	minutes.Parent = leaderstats
	
	local success, result = pcall(function()
		return datastore:GetAsync("Minutes_"..player.UserId)
	end)
	
	if success then
		if result then
			minutes.Value = result
		end
	else
		warn(result)
	end
	
	task.spawn(function()
		while task.wait(60) do
			minutes.Value += 1
		end
	end)
end

local function onPlayerRemoving(player)
	local minutes = player.leaderstats.Minutes
	local success, result = pcall(function()
		datastore:UpdateAsync("Minutes_"..player.UserId, function(old)
			return minutes.Value
		end)
	end)
	
	if success then
		if result then
			print(result)
		end
	else
		warn(result)
	end
end

players.PlayerAdded:Connect(onPlayerAdded)
players.PlayerRemoving:Connect(onPlayerRemoving)

This is working for me.

Server script placed inside the ServerScriptService container.

8 Likes

Wouldn’t it be better to use :BindToClose instead of PlayerRemoving?

“:BindToClose()” executes when the server shuts down, you’d need to use the “.PlayerRemoving” event to store individual player stats (players will leave before “:BindToClose()” executes).

1 Like

BindToClose is useful when testing in studio, you need both functions to run the datastore well. If you don’t have BindToClose, most of the time the leaderstats won’t save. (This is because studio shuts down faster than it can save)

1 Like

I’m aware of what “:BindToClose” is. “:BindToClose()” is only going to prove beneficial when testing in studio (as sometimes the local server closes before the “.PlayerRemoving” event has a chance to fire).

For me, both help. If I don’t have one, my code doesn’t work.

Ontop of this, I like to also get the variables for the values being saved the second the player leaves. If I don’t the value normally goes down and doesn’t save correctly. :slight_smile:

You’ll get drop request warnings if you use both, indexing a ValueBase’s “Value” property can be done in less than a frame (if that’s resulting in loss of data for you then there’s likely some other unrelated issue with your code). You should be testing/debugging your DataStores in a live session as that is ultimately where they are going to be used most frequently.

1 Like

Maybe the ProfileService module would be helpful. I normally use it for things like this, and its easy to use.

1 Like