So, I am trying to make a leaderboard for minutes that saves, but upon looking for tutorials they only teach you about how to make a data store with the ‘cash’ leader and not how to script a actual data saving minute leaderboard. If you could help me, I would greatly appreciate it.
The tutorials shows you how to save a variable which is most common cash. You need to take that concept of saving a variable and make that variable track time in minutes I would assume.
But I have no idea how to ‘track time’
After you create the stats, do a while loop with the condition as wait(60) and inside it, increment minutes by one and save it. (I suggest DS2 tho…)
Just do a wait
local minutes = 0
while wait(60) do
minutes = minutes + 1
end
game.Players.ChildAdded:connect(function(Player)
local Lead = Instance.new("IntValue",Player)
Lead.Name = "leaderstats"
local Cash = Instance.new("IntValue",Lead)
Cash.Name = "Minutes Played"
Cash.Value = 0
DataStore = game:GetService("DataStoreService"):GetDataStore("MinutesPlayed")
local Key = Player.userId
local Data = DataStore:GetAsync(Key)
if Data then
Cash.Value = Data
end
end)
game.Players.ChildRemoved:connect(function(Player)
local Key = Player.userId
DataStore:SetAsync(Key,Player.leaderstats.Cash.Value)
end)
while wait(60) do
minutes = minutes + 1
end
Would that work
No, you need to move the loop inside the PlayerAdded event.
You will need to move the loop in to the PlayerAdded function so each individual player has their own counter and not a server shared one.
Here:
game.Players.PlayerAdded:Connect(function(player)
local leaderstats = Instance.new("Folder", player)
leaderstats.Name = "leaderstats"
local Minutes = Instance.new("IntValue", leaderstats)
Minutes.Name = "Minutes"
Minutes.Value = 0
while true do
wait(60)
Minutes.Value = Minutes.Value + 1
end
end)
Most of the other solutions here use wait(60)
, which is not a reliable solution. wait(60)
can take much longer than a minute depending on what other scripts are running at the end of that period. Doing a tick-based approach is much simpler and more reliable. For example:
local datastore = game:GetService("DataStoreService"):GetService("MinutesPlayed")
-- since the datastore isn't based on the player, only the keys are,
-- there's no reason to define the datastore instead the PlayerAdded event
local joinTimes = {} -- store a table of when players joined
game:GetService("Players").PlayerAdded:Connect(function(player)
local leaderstats = Instance.new("Folder", player)
-- folders are meant for storing stuff, no need to use an intvalue
leaderstats.Name = "leaderstats"
local playTime = Instance.new("IntValue", leaderstats)
playTime.Name = "Time Played"
local key = player.UserId
local success, data = pcall(datastore.GetAsync, datastore, key)
-- make sure you handle errors properly, otherwise your code will break
if success then -- if it worked,
playTime.Value = data or 0 -- set it to whatever was saved (or 0 if nothing was saved)
joinTimes[player] = {data or 0, tick()} -- keep track of when the player joined and what they had saved
else
warn(data) -- put the error in the console as a warning
-- ... you can do better error handling here too
end
end)
game:GetService("Players").PlayerRemoving:Connect(function(player)
-- when a player leaves,
local key = player.UserId
local success, error = pcall(datastore.IncrementAsync, datastore, math.floor((tick() - joinTimes[player][2])/ 60))
-- add onto the saved data the amount of time between when they joined and now in minutes
if not success then -- if it errors,
warn("UpdateAsync failed for", player, ":", error)
-- retry or whatever error handling you want
end
end)
game:GetService("RunService").Heartbeat:Connect(function()
-- every frame, for every player, update their time played
local now = tick()
for player, times in pairs(joinTimes) do
local leaderstats = player:FindFirstChild("leaderstats")
if leaderstats and leaderstats:FindFirstChild("Time Played") then
leaderstats["Time Played"].Value = times[1] + math.floor((now - times[2]) / 60)
-- set their time played to what was saved + how long it's been since they've joined (in min)
end
end
end)
Edit: It’s not really simpler, I’m not sure what I was thinking.
Is there another way to do the math at the very bottom of the script? An error message about attempting to do arithmetic gets spammed in the output when I try it.