Hey everyone! Before you continue reading this post, I would like to point out one thing. I have little to no experience with scripting in studio. I’m a builder.
This is the script I have so far. I mostly compiled it from forum posts, and toolbox leaderstat scripts. This probably looks whack to advanced scripters lol.
local players = game:GetService("Players")
local datastores = game:GetService("DataStoreService")
local datastoreMinute = datastores:GetDataStore("DataStoreTime")
local function onPlayerAdded(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local hours = Instance.new("IntValue")
hours.Name = "Hours"
hours.Parent = leaderstats
local minutes = Instance.new("IntValue")
minutes.Name = "Minutes"
minutes.Parent = leaderstats
local success, result = pcall(function()
return datastoreMinute:GetAsync("Minutes_"..player.UserId)
end)
task.spawn(function()
while task.wait(.1) do
minutes.Value += 1
if minutes.Value >= 60 then
minutes.Value = 0
hours.Value += 1
end
end
end)
end
local function onPlayerRemoving(player)
local minutes = player.leaderstats.Minutes
local hours = player.leaderstats.Hours
local success, result = pcall(function()
datastoreMinute:UpdateAsync("Minutes_"..player.UserId, function(old)
return minutes.Value
end)
end)
end
players.PlayerAdded:Connect(onPlayerAdded)
players.PlayerRemoving:Connect(onPlayerRemoving)
Does anyone know why the datastore isn’t saving? Thanks.
Well one, you never even set the value of minutes after getting the data. Also, you never even save Hours, but I assume that is on purpose.
local players = game:GetService("Players")
local datastores = game:GetService("DataStoreService")
local datastoreMinute = datastores:GetDataStore("DataStoreTime")
local function onPlayerAdded(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local hours = Instance.new("IntValue")
hours.Name = "Hours"
hours.Parent = leaderstats
local minutes = Instance.new("IntValue")
minutes.Name = "Minutes"
minutes.Parent = leaderstats
local success, result = pcall(function()
return datastoreMinute:GetAsync("Minutes_"..player.UserId)
end)
if success then
minutes.Value = result
end
task.spawn(function()
while task.wait(.1) do
minutes.Value += 1
if minutes.Value >= 60 then
minutes.Value = 0
hours.Value += 1
end
end
end)
end
local function onPlayerRemoving(player)
local minutes = player.leaderstats.Minutes
local hours = player.leaderstats.Hours
local success, result = pcall(function()
datastoreMinute:UpdateAsync("Minutes_"..player.UserId, function(old)
return minutes.Value
end)
end)
end
players.PlayerAdded:Connect(onPlayerAdded)
players.PlayerRemoving:Connect(onPlayerRemoving)
Ah, alright. This should work for what you are trying to do:
local players = game:GetService("Players")
local datastores = game:GetService("DataStoreService")
local datastore = datastores:GetDataStore("DataStoreTime")
local function onPlayerAdded(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local hours = Instance.new("IntValue")
hours.Name = "Hours"
hours.Parent = leaderstats
local minutes = Instance.new("IntValue")
minutes.Name = "Minutes"
minutes.Parent = leaderstats
local success, result = pcall(function()
return datastore:GetAsync("Time_"..player.UserId)
end)
if success then
minutes.Value = result.minutes
hours.Value = result.hours
end
task.spawn(function()
while task.wait(.1) do
minutes.Value += 1
if minutes.Value >= 60 then
minutes.Value = 0
hours.Value += 1
end
end
end)
end
local function onPlayerRemoving(player)
local minutes = player.leaderstats.Minutes
local hours = player.leaderstats.Hours
local success, result = pcall(function()
datastore:UpdateAsync("Time_"..player.UserId, function(old)
return {minutes = minutes.Value, hours = hours.Value}
end)
end)
end
players.PlayerAdded:Connect(onPlayerAdded)
players.PlayerRemoving:Connect(onPlayerRemoving)
Please don’t increment the hours and minutes after waiting for a certain time. It’s very inaccurate.
Here’s a rewrite:
local playersService = game:GetService("Players");
local datastoreService = game:GetService("DataStoreService");
local timeStore = datastoreService:GetDataStore("time_1");
local function sToHM(s)
local hours = math.floor(s / 3600);
local minutes = math.floor(s / 60) % 60;
return hours, minutes;
end
local function getDelta(t1, t2)
return math.round(t2 - t1);
end
local function makeLeaderstat(player: Player)
local success, data = pcall(timeStore.GetAsync, timeStore, player.UserId);
if not success then
warn("There was an error while loading", tostring(player.UserId) .. "'s", "data");
return;
end
data = tonumber(data) or 0;
local h,m = sToHM(data);
local now = os.time();
local leaderstats = Instance.new("Folder");
leaderstats.Name = "leaderstats";
local hours = Instance.new("IntValue");
hours.Value = h or 0;
hours.Name = "Hours";
local minutes = Instance.new("IntValue");
minutes.Value = m or 0;
minutes.Name = "Minutes";
local joinTime = Instance.new("IntValue");
joinTime.Name = "JoinTimestamp";
joinTime.Value = now;
task.defer(function()
repeat
task.wait(0.25);
hours.Value, minutes.Value = sToHM(getDelta(os.time(), now) + data);
until not player or not player:IsAncestorOf(game);
end);
hours.Parent = leaderstats;
minutes.Parent = leaderstats;
joinTime.Parent = player;
leaderstats.Parent = player;
end
local function save(player)
local secondsSpent = getDelta(os.time(), player.JoinTimestamp.Value);
timeStore:IncrementAsync(player.UserId, secondsSpent);
end
playersService.PlayerAdded:Connect(makeLeaderstat);
for _,p in ipairs(playersService:GetPlayers()) do
makeLeaderstat(p);
end
playersService.PlayerRemoving:Connect(save);
game:BindToClose(function()
for _,p in ipairs(playersService:GetPlayers()) do
save(p);
end
end);
You do realize that you honestly are going against yourself? One, the code you made is much, much longer. Two, task.wait() does not throttle like wait(). That post you referenced is from THREE years ago and is actually quite outdated. In fact, the task wait quite literally does the exact same thing as yours, with much less code. And, as for preventing errors, they could simply add a check to determine whether the player still exists or not.
I’m not going against myself. I’m not against using wait() or task.wait() as a whole, I use them too, but however, using them with time use cases is a very bad practice. I also agree with you that task.wait() is much better than wait(). Timestamp math always yields an accurate result while wait() doesn’t. Even I’m using task.wait() in the code but calculating the time isn’t relying on it at all. I’m simply using it to visually update the time elapsed on the leaderboard.
Also, longer code doesn’t mean inefficient/worse. Better practice is always preferred.
It works perfect when 2 people are in the same server, but when a third person joins, I get this error. Their leaderstats don’t update or save either. Thank you
That’s quite weird, it shouldn’t even run that part of the code if they have no data, but this should be a fix:
local players = game:GetService("Players")
local datastores = game:GetService("DataStoreService")
local datastore = datastores:GetDataStore("DataStoreTime")
local function onPlayerAdded(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local hours = Instance.new("IntValue")
hours.Name = "Hours"
hours.Parent = leaderstats
local minutes = Instance.new("IntValue")
minutes.Name = "Minutes"
minutes.Parent = leaderstats
local success, result = pcall(function()
return datastore:GetAsync("Time_"..player.UserId)
end)
if success and result then
minutes.Value = result.minutes
hours.Value = result.hours
end
task.spawn(function()
while task.wait(.1) do
minutes.Value += 1
if minutes.Value >= 60 then
minutes.Value = 0
hours.Value += 1
end
end
end)
end
local function onPlayerRemoving(player)
local minutes = player.leaderstats.Minutes
local hours = player.leaderstats.Hours
local success, result = pcall(function()
datastore:UpdateAsync("Time_"..player.UserId, function(old)
return {minutes = minutes.Value, hours = hours.Value}
end)
end)
if not success then
warn("Problem saving "..player.Name.."'s data")
end
end
players.PlayerAdded:Connect(onPlayerAdded)
players.PlayerRemoving:Connect(onPlayerRemoving)
game:BindToClose(function()
for i,v in pairs(players:GetPlayers()) do
onPlayerRemoving(v)
end
end)
here is what I did, I made sure it was success and that there was a result on the getting data, and I added a BindToClose for when the server shuts down and PlayerRemoving doesn’t always run.