local DataStoreService = game:GetService("DataStoreService")
local leaderboardsDataStore = DataStoreService:GetDataStore("Leaderboards")
local time = Instance.new("IntValue", leaderboard)
time.Name = "Minutes Played"
time.Value = 0
local increment = 1
local success, err = pcall(function()
timeValue = leaderboardsDataStore:GetAsync("Minutes Played") or 0
end)
if not success then
warn("Failed to load MinutesPlayed from datastore: ".. err)
end
local function saveTimeValue()
local success, err = pcall(function()
leaderboardsDataStore:SetAsync("Minutes Played", time.Value)
end)
if not success then
warn("Failed to save MinutesPlayed to datastore: ".. err)
end
end
while task.wait(60) do
time.Value += increment
saveTimeValue()
end
game:BindToClose(saveTimeValue)
Ok. I’ll test that code momentarily, on another ServerScriptStorage Local Script I have this code below, is this needed? game.Players.PlayerAdded:Connect(function(plr)
wait()
local plrkey = “id”…plr.UserId
local savevalue = plr:WaitForChild(“leaderstats”):WaitForChild(“Time”)
local getsaved = DS:GetAsync(plrkey)
if getsaved then
savevalue.Value = getsaved[1]
else
local NumbersForSaving = (savevalue.value)
DS:GetAsync(plrkey, NumbersForSaving)
end
end)
game.Players.PlayerRemoving:Connect(function(plr)
DS:SetAsync(“id”…plr.UserId, {plr.leaderstats.Time.Value})
end)
no, it won’t work as a datastore, I suppose.
I tested @Omnipotent_Corrupted’s code with the code I posted above, asking if it was necessary, in my game, and the leaderboard wouldn’t show up. This is frustrating, but I won’t give up.
Wait real quick, I’ll check in Studio.
DOing all of that inside Devforum is really annoying XD
XD. I deleted the unnecessary code, if it proves perfect on your end, I’ll proceed to test it on mine. Hope I can fix it! Thanks for all your help, y’all! EDIT; Tested it in my end and didn’t work, leaderboard for minutes disappeared once again.
Add a Server Script called Leaderboard in ServerScriptService, and paste this:
local plrs = game:GetService("Players")
local added = plrs.PlayerAdded
local removing = plrs.PlayerRemoving
local DSS = game:GetService("DataStoreService")
local experiencestore = DSS:GetDataStore("MinutesPlayed")
added:Connect(function(plr)
local leaderboard = Instance.new("Folder", plr)
leaderboard.Name = "Leaderboard"
local time = Instance.new("IntValue", leaderboard)
time.Name = "Minutes Played"
time.Value = 0
local suc, result = pcall(function()
return experiencestore:GetAsync(plr.UserId)
end)
if not suc then
warn("Data Store Failed: ".. result)
time.Value = 0
else
if result then
time.Value = result
end
end
end)
-- Save the player's time value before leaving
removing:Connect(function(plr)
local time = plr:WaitForChild("Leaderboard"):WaitForChild("Minutes Played")
experiencestore:SetAsync(plr.UserId, time.Value)
end)
Add another Server Script in ServerScriptService named AddMinute and paste that:
local plrs = game:GetService("Players")
local added = plrs.PlayerAdded
added:Wait()
for i, v in pairs(plrs:GetChildren()) do
local leaderboard = v:WaitForChild("Leaderboard")
local timevalue = leaderboard:WaitForChild("Minutes Played")
while task.wait(60) do
timevalue.Value += 1
end
end
Enable Studio Access to API Services inside Game Settings → Security → Enable Studio Access to API Services
According to your code, the “Leaderboard” Script under ServerScriptService consists of X. According to your code the “AddMinute” Script under ServerScriptService consists of Y. The code is below.
X. local plrs = game:GetService(“Players”)
local added = plrs.PlayerAdded
local removing = plrs.PlayerRemoving
local DSS = game:GetService(“DataStoreService”)
local experiencestore = DSS:GetDataStore(“MinutesPlayed”)
added:Connect(function(plr)
local leaderboard = Instance.new(“Folder”, plr)
leaderboard.Name = “Leaderboard”
local time = Instance.new("IntValue", leaderboard)
time.Name = "Minutes Played"
time.Value = 0
local suc, result = pcall(function()
return experiencestore:GetAsync(plr.UserId)
end)
if not suc then
warn("Data Store Failed: ".. result)
time.Value = 0
else
if result then
time.Value = result
end
end
end)
– Save the player’s time value before leaving
removing:Connect(function(plr)
local time = plr:WaitForChild(“Leaderboard”):WaitForChild(“Minutes Played”)
experiencestore:SetAsync(plr.UserId, time.Value)
end)
Y. local plrs = game:GetService(“Players”)
local added = plrs.PlayerAdded
added:Wait()
for i, v in pairs(plrs:GetChildren()) do
local leaderboard = v:WaitForChild(“Leaderboard”)
local timevalue = leaderboard:WaitForChild(“Minutes Played”)
while task.wait(60) do
timevalue.Value += 1
end
end
This doesn’t work on studio, I have API enabled. Did it work for you?
On mobile at the moment, I haven’t checked the first datastore reply in this thread but I’ll just assume that it works. Assuming that it works, then what’s missing is a game:BindToClose(function()
–code to save
end)
This is because Roblox studio shuts down the local server too fast for it to register and execute the save code when the server shuts down. Although you should set up a more proper way for the future, for quick testing of your code you should be able to save by just adding a task.wait(5) inside BindToClose.
Note that the server might shut down while on Roblox too, so it is crucial to add a game:BindToClose() function.
*I very much dislike typing on mobile, but hope you got something out of it *
Sorry to bother you @dotinfo, but do you know where I’d put the game:BindToClose(function()? I’d also like to know where to put the task.wait(5). Thanks!
You could place the BindToClose at the end of the script, add task.wait(5) inside the BindToClose function.
wait() is not deprecated but its marked as a legacy
It worked for me. I recommend checking if it really didn’t work, because it is supposed to, as it did for me.
Could you reply to me with the final code? I’d appreciate it!
I already sent the final code to you. What is the problem you’re facing now?
You don’t need to count the seconds as the computer already does it for you. On Roblox you can use UNIX timestamp, which is the amount of seconds that have elapsed since 00:00:00 UTC on 1 January 1970. You can obtain a UNIX timestamp by using the built-in library os
and calling its time
method.
print(os.time()) -- 1714940821
-- 1 second later
print(os.time()) -- 1714940822
-- To obtain the elapsed time
print(1714940822 - 1714940821) -- 1
Now using this method you can obtain the amount of seconds player has been playing your game. When player joins your game you want to obtain the timestamp, and once the player leaves the game, you will want to obtain another timestamp and subtract the first timestamp from the newer one to obtain the amount of seconds that the player has been in your game.
local Players = game:GetService("Players")
local join_time: { [Player]: number } = {}
local function player_joined(player: Player)
join_time[player] = os.time()
end
local function player_leaving(player: Player)
if join_time[player] then
local elapsed = os.time() - join_time[player]
print(`{player.Name} has played the game for {elapsed} seconds`)
join_time[player] = nil -- Cleanup, or there will be a memory leak!
end
end
for _, player in Players:GetPlayers() do
player_joined(player)
end
Players.PlayerAdded:Connect(player_joined)
Players.PlayerRemoving:Connect(player_leaving)
Now all you need to do is update the amount of seconds that the player has played your game for. There is many ways to save data, but for the sake of simplicity of this guide, I will show the simplest method. When player joins we will read their play time for debugging purposes, we might get nil
which means that the key doesn’t exist, so player never had their play time recorded and we will treat it as 0
. When player leaves, we will take their elapsed time, and add it to their total elapsed time which is saved in the data store, we will achieve this by using IncrementAsync
method.
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local play_time_store = DataStoreService:GetDataStore("play_time")
local join_time: { [Player]: number } = {}
local function save_play_time(player: Player, elapsed: number)
local success = pcall(function()
play_time_store:IncrementAsync(tostring(player.UserId), elapsed, { player.UserId })
end)
if success then
print(`Successfully saved {player.Name}'s play time`);
else
warn(`Failed to save {player.Name}'s play time`)
end
end
local function read_play_time(player: Player): number?
local success, data = pcall(function()
return play_time_store:GetAsync(tostring(player.UserId))
end)
if success then
-- If data is nil, that means the key doesn't exist
-- if the key doesn't exist, the player's play time will be 0
return if data == nil then 0 else data
end
return
end
local function player_joined(player: Player)
join_time[player] = os.time()
local play_time = read_play_time(player)
if play_time then
print(`{player.Name} has play time of {play_time} seconds`)
else
warn(`Failed to read {player.Name}'s play time`)
end
end
local function player_leaving(player: Player)
if join_time[player] then
local elapsed = os.time() - join_time[player]
print(`{player.Name} has played the game for {elapsed} seconds`)
save_play_time(player, elapsed)
join_time[player] = nil -- Cleanup, or there will be a memory leak!
end
end
for _, player in Players:GetPlayers() do
player_joined(player)
end
Players.PlayerAdded:Connect(player_joined)
Players.PlayerRemoving:Connect(player_leaving)
This is what you will see in your output window when you join for the first time, and leave:
Daw588 has play time of 0 seconds
Daw588 has played the game for 2 seconds
Successfully saved Daw588's play time
When you join again, and leave, this is what you will see:
Daw588 has play time of 2 seconds
Daw588 has played the game for 3 seconds
Successfully saved Daw588's play time
All we are doing essentially boils down to this:
local play_time = 0
local function simulate_session()
local join_time = os.time()
task.wait(math.random(1, 3))
local leave_time = os.time()
local elapsed = leave_time - join_time
play_time += elapsed
end
-- First session
simulate_session()
print(play_time) -- 1
-- Second session
simulate_session()
print(play_time) -- 4
-- Third session
simulate_session()
print(play_time) -- 7
One last thing: If you want to display minutes to the player, you can convert seconds to minutes.
local play_time = 120 -- 120 seconds
-- Note: We are using math.floor to get rid of decimals because some numbers will produce non integer result
-- Note: There is 60 seconds in one minute
local minutes = math.floor(play_time / 60) -- 2 minutes
print(minutes) -- 2
This should get you started on the developing your play time saving feature. One thing to note is that the data saving solution is very simple and doesn’t account for situations when server crashes, or when player joins another server while their data is still saving in the previous one. Those situations can cause data loss! You will need to implement mechanisms like periodical data saves, and session locking. Though I wouldn’t recommend writing such system yourself, instead you should choose a battle tested data store solutions like DataStore2, and ProfileService.
Thank you so much. That was very much informative, just to clarify I should put all of that code inside of one ServerScriptService Script?
Yes, it has to be on the server. Additionally, I forgot to include logic for removing join time when the player leaves, so make sure to do that unless you want to have a memory leak.
-- When player leaves remove their join time
join_time[player] = nil
Got it, I’m not on studio right now, but I’ll check when I get on. Thanks for all your help, y’all!