Which of these is a better way of counting player minutes?

Greetings,

I am currently trying to decide on the best way to track how many minutes the players have played the game. I’ve got 2 ways of doing this and i am not sure which is better. Keep in mind that the game will have a max of 50-75 players per server.

my first solution is a simple while player loop that would wait 60 seconds before adding 1 minute
(WaitCalculator is a module that replaces wait() function)


--first solution

Players.PlayerAdded:Connect(function(player)

	local Minutes = player:WaitForChild("leaderstats").Minutes

	while Players:FindFirstChild(player.Name) do

		WaitCalculator(60)

		Minutes.Value += 1		

	end

end)

my second solution is to have a table of all players that tracks their seconds, adding 1 to each currently online player and then adding 1 minute when they gather 60 seconds

--second solution

local PlayerSeconds = {}

Players.PlayerAdded:Connect(function(player)

	PlayerSeconds[player.Name] = 0

end)


Players.PlayerRemoving:Connect(function(player)

	PlayerSeconds[player.Name] = nil

end)

while true do
	
	for i,v in pairs(PlayerSeconds) do
		
		v += 1
		
		if v == 60 then 
			
			Players:FindFirstChild(v):WaitForChild("leaderstats").Minutes.Value += 1 
			
			v = 0
			
		end
				
	end
	
        WaitCalculator(1)	

end

Perhaps you know of an even better way of doing this, if so i’d be grateful if you shared it with me.

Thank you for your time

1 Like

Quick reply possibly you can also look into using os.time here
By doing so you will be removing the loop.

Hope this helps.

Yep like @CrazySnoopylove said os.time() is so much better because it offers an event based approach where code runs at required controllable times rather than polling where the code runs continuously no matter what happens. While wait() do is notorious for promoting this practice although you can say if it works it works.

Here is a service style module thanks to Sleitnick for teaching me this style of coding from aero game framework to get the players time only when the function runs which should be on the server or you can implement a remote event method sync to sync the join times on client and server.

-- Player Time Service Module
-- Dthecoolest
-- March 17, 2021

local Players = game:GetService("Players")

local PlayerTimeService = {}

local PlayerJoinTimeDictionary = {}
PlayerTimeService.PlayerJoinTimeDictionary = PlayerJoinTimeDictionary

local function onJoin(player)
	PlayerJoinTimeDictionary[player] = os.clock()
end

Players.PlayerAdded:Connect(onJoin)

for _, player in pairs(Players:GetPlayers()) do
	coroutine.wrap(function()
		onJoin(player)
	end)()
end

Players.PlayerRemoving:Connect(function(player)
	PlayerJoinTimeDictionary[player] = nil
end)

function PlayerTimeService:GetPlayerTimePlayedInCurrentGame(player: Player)
	local playerJoinTime = self.PlayerJoinTimeDictionary[player]
	local timeElapsedSinceFirstJoin = os.clock() - playerJoinTime

	return timeElapsedSinceFirstJoin
end

return PlayerTimeService
2 Likes

Add the value by whatever delta time wait(1) yields for and convert it to minutes.

Players.PlayerAdded:Connect(function(player
	local Minutes = player:WaitForChild("leaderstats").Minutes

	while player:IsDescendantOf(game) do 
        Minutes.Value += wait(60) / 60
	end
end)

You could use repeat to help you with this:

game.Players.PlayerAdded:Connect(function(plr)
local timeByMinute = plr:WaitForChild("leaderstats").Time
local minute = 60
local char = plr.Character
wait(minute)
timeByMinute.Value = timeByMinute.Value + 1
repeat until char == nil
  end
 end)
end

why use a module for this? Isn’t a single server script more than sufficient for the whole code? More importantly, how and under what conditions do you require this module? What did you put in the server script that requires it?

The usage of a module is so that any script can read the PlayerJoinTimeDictionary, so you can have a script like a weapons giver script read it, or a round manager script get the player join times.

These scripts will both require this module and use the PlayerTimeService:GetPlayerTimePlayedInCurrentGame function to do stuff like check the time the moment a gui is popped up to allow the player to purchase a weapon.

Moreover, os.clock() is accurate as well. However you can still use the wait(n) approach just make sure the use the delta time wait(n) returns cuz it might wait 60.14 seconds, even RunService:HeartBeat:Wait() is no exception to this issue.

I’ve never encountered delta time, i’ll look into it. However I do not use wait() i use

the fast wait module made by CloneTrooper. I can’t claim to fully understand it but some of the best programmers in the community recommend it and i’ve been using it without any issues for a long time now. I am hoping in the end my original solution will suffice then.

https://gist.github.com/CloneTrooper1019/4ae7113f6ccfa666caa0c3991398e21a

You can store the timestamp they join the game using os.time() and subtract it from the current timestamp when they leave. To get their play time while playing, just subtract their join time from the current timestamp. You could do this on a loop using the RunService events.

well seeing as FastWait uses run service anyway it seems that i’ve already done what you suggest with my current solution