Timer Module - Manage timers and their states at no cost!

Sorry for the trouble. I’ll look into it when I’m home.

[Update 1.0.5]

  • Addressed issues of @Sweet_Smoothies
  • Updated IncrementTime to work properly
  • Added alias for IncrementTime - IncrementRemaining
  • Added Reset method: resets the time left the TimerObject has, resetting it back to the timer’s starter length.
  • Updated docs
3 Likes

I may have found a bug. OnFinished will not fire while another timer is running. In this example t1 and t2 will trigger OnFinished simultaneously.

local Timer2 = require(workspace.Timer)
local t1 = Timer2.new(3)
local t2 = Timer2.new(5)
local t3 = Timer2.new(7)

t1:OnFinished(function()
	print("t1 Finished")
end)
t2:OnFinished(function()
	print("t2 Finished")
end)
t3:OnFinished(function()
	print("t3 Finished")
end)

t1:Start()
t2:Start() 
t3:Start()
2 Likes

I found the solution.

local CenterIdx = math.ceil((LeftIdx + RightIdx) / 2)

This line originally used math.floor but needs a math.ceil. Otherwise when a second timer is added to TimerArrays, CenterIdx will still be equal ‘0’.

--// Thank you CntKillMe
local function FindBestSpot(CompletionTime)
	local LeftIdx = 0
	local RightIdx = #TimerArrays

	if RightIdx == 0 then
		return 1
	end
	while (LeftIdx <= RightIdx) do
		local CenterIdx = math.ceil((LeftIdx + RightIdx) / 2)
		local CenterTimer = TimerArrays[CenterIdx]

		if CenterTimer == nil then
			return RightIdx + 1
		end
		if (CompletionTime > CenterTimer:GetRemaining()) then
			RightIdx = CenterIdx - 1
		elseif (CompletionTime < CenterTimer:GetRemaining()) then
			LeftIdx = CenterIdx + 1
		else
			LeftIdx = CenterIdx
			break
		end
	end

	return LeftIdx	
end

Here’s another fix

local function RemoveFromArray(TimerObj)
     table.remove(TimerArrays, table.find(TimerArrays, TimerObj))
end

If :Stop() or :Pause() is accidentally called on a timer that was never started then this function will remove the last item from the TimerArrays table. Needs to look like this instead.

local function RemoveFromArray(TimerObj)
	local index = table.find(TimerArrays, TimerObj)
	if index then
		table.remove(TimerArrays, index)
	end
end
1 Like

@Dued1 Good catches, especially for the latter ones.
I’m unsure regarding the binary search algorithm since it was provided to be by CntKillMe, and after looking through other sources they use math.floor too. I’ll do some extra research before properly taking care of the issue.

[Update 1.0.6]

  • Validates that the timer object has been started before removing it from the priority queue.

  • Fixed issues with binary search algorithm; the issue lied in the fact that since the binary search algorithm was translated from roblox-ts in which arrays start at 0 rather than 1, I forgot to add a + 1 within the code where I grab the middle timer. I have rewritten the algorithm function to function on a 1-based index rather than a 0-based index (thank you CntKillMe again).

2 Likes

I have the same issue as @Sweet_Smoothies. Am I doing something wrong? Here is my code

local timer = Timer.new(5)

print("starting timer")

timer:Start()

timer:Wait()

print("timer ended")

“timer ended” never prints

1 Like

When updating the module previously I didn’t properly make sure yielding worked. This issue should be addressed now.

1 Like

100% will use this module in my game!
Timers are pretty cool since i never could make one lol

1 Like

Would this timer be useful for Hourly/Daily rewards? as a 2 hour timer as an example

Do the timer objects created garbage collect themselves or do they just get removed when the timer ends? I don’t see a method to destroy or otherwise set the timer object to nil in the documentation, is that by deign?

How can we be sure they are cleaned up and not causing memory leaks?

1 Like

I noticed that the callbacks for the states “Died” and “Dead” do not fire. This may be intended, but if so I am not sure how to fire a function if it is Stopped. We can fire a function if it is Finished yes, but what if we kill it before its finished.

Update [1.0.7]

  • Put the whole source and documentation on my GitHub repository. I will no longer be updating the uploaded Roblox asset.
  • Addressed issue where OnDied | OnDead would not fire. cc @Planet_Dad
2 Likes

Sorry, I’m not well-versed in this area of expertise, and no one I knew was available to help me determine whether this would cause any memory leaks. I’ve been using it fine for a while without any noticeable memory increases, though.

1 Like

There doesn’t appear to be anything in his code that would cause a memory leak, it looks like if you want to get rid of a timer object that you should cancel it’s timer if it is active and set any references you have to it to nil and it will garbage collect.

1 Like

how would i restart the time because ive tried timer:stop() timer:start()

1 Like

Is it possible to change the timer mid time? like I have 50 seconds and be able to change it to 6 or something like that

Could you use this similar to a stop watch, or is it only for waiting 5 seconds for example?

That’s what I’ve been hoping to see since I began learning Roblox Studio. Previously, I was a Unity developer and wanted to learn something way beyond it. When I started to learn Roblox Studio, it was really hard to get used to using wait instead of a timer. Thank you!