Minute Counter Bug!

G’day fellow Robloxians! I’d like some help on a little bug I’ve found. Any feedback is truly appreciated. Thank you for your time!

I have a piece of Lua code for a Minute Leadboard Counter, and it works perfectly fine except, THE MINUTES DON’T SAVE! Please help!

  1. What I would like to achieve? I’d like for the minutes to save after rejoining.
  2. What have I tried? I’ve looked for answers on the Forum, looked for tutorials, and tried to debug it.

The code is below.
game.Players.PlayerAdded:Connect(function(player)

local leaderboard = Instance.new("IntValue", player)
leaderboard.Name = "leaderstats"


local time = Instance.new("IntValue", leaderboard)
time.Name = "Minutes Played"
time.Value = 0

while true do
	wait(60) -------- how long you have to wait until it gives you one point
	time.Value = time.Value + 1
end

end)

1 Like

You will have to save the minutes in a datastore.

1 Like

You need to use DataStoreService, your script should look something like this:

local DataStoreService = game:GetService("DataStoreService")
local MinutesDataStore = DataStoreService:GetDataStore("MinutesPlayed")

game.Players.PlayerAdded:Connect(function(player)
	local leaderboard = Instance.new("IntValue", player)
	leaderboard.Name = "leaderstats"

	local time = Instance.new("IntValue", leaderboard)
	time.Name = "Minutes Played"

	-- load the saved mins
	local success, savedMinutes = pcall(function()
		return MinutesDataStore:GetAsync(player.UserId)
	end)

	if success and savedMinutes then
		time.Value = savedMinutes
	else
		time.Value = 0
	end

	while true do
		task.wait(1)
		time.Value = time.Value + 1

		-- Save the updated minutes
		local success, errorMessage = pcall(function()
			MinutesDataStore:SetAsync(player.UserId, time.Value)
		end)

		if not success then
			-- it did not save the minutes (should do it though)
		end
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
	local minutes = player:FindFirstChild("leaderstats"):FindFirstChild("Minutes Played")
	if minutes then
		local success, errorMessage = pcall(function()
			MinutesDataStore:SetAsync(player.UserId, minutes.Value)
		end)

		if not success then

		end
	end
end)

3 Likes

also, change the “task.wait(1)” back to 60, I did it for testing purposes

2 Likes

use task.wait. wait is deprecated.

1 Like

I’m very new, sorry, where would I put that?

1 Like

Instead of using “wait()”, use “task.wait()” by just replacing it

1 Like

Makes sense! I’ll try that when I log on, and let you know how it works! Thank you for all your help, all of you!

2 Likes

The following is not related to your question, however it is to your code.

Having an infinite loop with a task.wait() inside is far from precise/accurate when it comes to timing stuff, sometimes it might be a little under a minute and sometimes a little over a minute. While you a lot of times don’t require things to happen with milliseconds precision, sometimes you want to be precise. I personally feel that all games that counts and rewards players every X seconds should be precise.

You can achieve such precision by using RunService, let me show you!

local RunService = game:GetService("RunService")

local total = 0
local speed = 1

RunService.Heartbeat:Connect(function(deltaTime)
	total += deltaTime
	
	while total >= speed do
		print(os.clock())
		total -= speed
	end
end)

To start off we declare two variables, one to keep track of the total time, in this case ‘total’, and one for how often we want our code to execute, in this case ‘speed’. The ‘speed’ variable is not required however it makes it faster to change the time in the future if we’d like.
After that, connect a Heartbeat event to a function and add the parameter ‘deltaTime’ (can be named anything but it provides the deltaTime). DeltaTime is amount of elapsed seconds between the previous rendered frame and the current one. If we are running at 60 FPS (frames per second), then our DeltaTime would be 1/60, which is approximately 0.017 seconds, however the FPS is not constant and will fluctuate.

To start of our heartbeat function we want to add out deltaTime to our total time, after that we create a while loop that will run if our total time is greater than or equal to our speed (how often we want to specified code to run).
After that we can add our code to execute, in the example I just print the os.clock() so that you can see how precise this way of looping is. You could do the same thing in a normal while loop with a task.wait() to see how “precise” that one is, the answer would be not very.

Finally we subtract our ‘speed’ from our ‘total’. You might be asking why we’re not setting the ‘total’ to zero, that has to do with our deltaTime. Let us imagine that our ‘total’ is equal to 0.99, if our deltaTime for the upcoming heartbeat is, for instance, 0.018, then our ‘total’ would become 1.008, which is more than our ‘speed’ in the example. If we were to straight up set ‘total’ to zero, then we would miss out on eight whole milliseconds, which will quickly build up when using RunService, resulting in a very non-accurate loop.

EDIT: To clarify “miss out on eight whole milliseconds, which will quickly build up” what I meant was that those milliseconds will shift our loop out of sync as those ms won’t ever be counted towards the total time, meaning that it will take longer that in should to execute the next iteration and so on.

I did not add it in the example but remember to save the RBXScriptConnection that the :Connect() returns and :Disconnect() it when the player leaves. This is because the code in this case runs on server, it won’t automatically be removed when the player leaves, unlike local scripts.

2 Likes

Now, my piece of code not including the precision looks like this. local leaderboard = Instance.new(“IntValue”, player)
leaderboard.Name = “leaderstats”

local time = Instance.new("IntValue", leaderboard)
time.Name = "Minutes Played"
time.Value = 0


while true do
	task.wait(60) -------- how long you have to wait until it gives you one point
	time.Value = time.Value + 1
end

end)
I’m wondering if this is all I need for it not be precise, I could always add that later.

1 Like

Use Heartbeat or BindToRenderStep. Here is the code:

local time = Instance.new("IntValue", leaderboard)
time.Name = "Minutes Played"
time.Value = 0

local RunService = game:GetService("RunService")
local Heartbeat = RunService.Heartbeat --Event

Heartbeat:Connect(function()
	task.wait(60) -------- how long you have to wait until it gives you one point
	time.Value = time.Value + 1
end)
2 Likes

Remember, the code works in my server, but as @dotinfo mentioned, I need the minutes to save for each player. The minutes count but when I leave and rejoin, I reset to 0 for some reason. I have used multiple tutorials, they both had different code, and none worked fully. could someone tell me if the code I used above will work. I haven’t tested it yet. Thank you.

Do you want to save the minutes?

1 Like

I deleted my original code and used the code you listed @Omnipotent_Corrupted, but the actual leaderboard for the minutes disappeared! And yes, I need to save the minutes. I don’t get it, the leaderboard disappeared, and the minute counter vanished into thin air! I need a Lua code block that fully covers how it can save and how the minutes can be added, exact preciseness is not required as of now. Thank you for any feedback, suggestions, etc.

1 Like

@StealthBloxxer150 Use the code this bro provided.

1 Like

The code @D7L14 provided? Or… Because I tried the code only @Omnipotent_Corrupted, provided and it didn’t work, you’re saying I need to use the code @D7L14 provided only?

1 Like
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)
1 Like

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)

1 Like

no, it won’t work as a datastore, I suppose.

1 Like

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.

1 Like