Timer Module with Debugging Errors

Well basically, when you code a few timers such as timer.Create and timer.Simple and you slip up with a bit of code and it errors and you can’t figure out which timer caused it, I modified the code to show which function ran the code and on what line alongside the timers name.

2 Examples, timer.Create and timer.Simple:

http://puu.sh/fNjN

Example code used:
[lua]function Test()
timer.Create( “test”, 1, 1, function()
print( table.Random( nil, 10 ) )
end )
end

function Test2()
timer.Simple( 1, function()
print( table.Random( nil, 10 ) )
end )
end[/lua]

How do I install this?:
Go into your lua/includes/modules/ folder and copy paste this code over the original

Go into your cfg/nosend.txt file and remove the line which has includes\modules imer.lua or else if you have ScriptEnfocer enabled, your gamemodes/addons will break clientside
Restart the map and if you have fastdl, update your cache file.

The code:
[lua]require( “hook” )

// Globals that we need.
local CurTime = CurTime
local UnPredictedCurTime = UnPredictedCurTime
local unpack = unpack
local pairs = pairs
local table = table
local pcall = pcall
local ErrorNoHalt = ErrorNoHalt
local hook = hook
local tostring = tostring
local debug = debug
local Format = Format

/---------------------------------------------------------
Name: timer
Desc: A module implementing timed execution of functions.
---------------------------------------------------------
/
module( “timer” )

// Some definitions
local PAUSED = -1
local STOPPED = 0
local RUNNING = 1

// Declare our locals
local Timer = {}
local TimerSimple = {}

local function CreateTimer( name )
if Timer[ name ] == nil then
Timer[ name ] = {}
Timer[ name ].Status = STOPPED

	return true
end

return false

end

/---------------------------------------------------------
Name: IsTimer( name )
Desc: Returns boolean whether or not name is a timer.
---------------------------------------------------------
/
function IsTimer( name ) return Timer[ name ] ~= nil end

/---------------------------------------------------------
Name: Create( name, delay, reps, func, … )
Desc: Setup and start a timer by name.
---------------------------------------------------------
/
function Create( name, delay, reps, func, … )
if IsTimer( name ) then
Destroy( name )
end

CreateTimer( name )
Timer[ name ].Delay = delay
Timer[ name ].Repetitions = reps
Timer[ name ].Debug = debug.getinfo( 2 )
if func ~= nil then Timer[ name ].Func = func end
Timer[ name ].Args = { ... }

Start( name )

end

/---------------------------------------------------------
Name: Start( name )
Desc: (Re)start the timer by name.
---------------------------------------------------------
/
function Start( name )
if not IsTimer( name ) then return false end

Timer[ name ].n = 0
Timer[ name ].Status = RUNNING
Timer[ name ].Last = CurTime()

return true

end

/---------------------------------------------------------
Name: Adjust( name, delay, reps, func, … )
Desc: Adjust a running, stopped or paused timer by name.
---------------------------------------------------------
/
function Adjust( name, delay, reps, func, … )
CreateTimer( name )
Timer[ name ].Delay = delay
Timer[ name ].Repetitions = reps
Timer[ name ].Debug = debug.getinfo( 2 )
if func ~= nil then Timer[ name ].Func = func end
Timer[ name ].Args = { … }

return true

end

/---------------------------------------------------------
Name: Pause( name )
Desc: Pause a running timer by name.
---------------------------------------------------------
/
function Pause( name )
if not IsTimer( name ) then return false end

if Timer[ name ].Status == RUNNING then
	Timer[ name ].Diff = CurTime() - Timer[ name ].Last
	Timer[ name ].Status = PAUSED

	return true
end

return false

end

/---------------------------------------------------------
Name: UnPause( name )
Desc: Unpause a paused timer by name.
---------------------------------------------------------
/
function UnPause( name )
if not IsTimer( name ) then return false end

if Timer[ name ].Status == PAUSED then
	Timer[ name ].Diff = nil
	Timer[ name ].Status = RUNNING

	return true
end

return false

end

/---------------------------------------------------------
Name: Toggle( name )
Desc: Toggle a timer’s pause state by name.
---------------------------------------------------------
/
function Toggle( name )
if not IsTimer( name ) then return false end

return Timer[ name ].Status == PAUSED and UnPause( name ) or Pause( name )

end

/---------------------------------------------------------
Name: Stop( name )
Desc: Stop a running or paused timer by name.
---------------------------------------------------------
/
function Stop( name )
if not IsTimer( name ) then return false end

if Timer[ name ].Status ~= STOPPED then
	Timer[ name ].Status = STOPPED

	return true
end

return false

end

/---------------------------------------------------------
Name: Check()
Desc: Check all timers and complete any tasks needed.
This should be run every frame.
---------------------------------------------------------
/
function Check()
for key, value in pairs( Timer ) do
if value.Status == PAUSED then
value.Last = CurTime() - value.Diff
elseif value.Status == RUNNING and ( value.Last + value.Delay ) <= CurTime() then
value.Last = CurTime()
value.n = value.n + 1

		local b, e = pcall( value.Func, unpack( value.Args ) )
		if not b then
			ErrorNoHalt( Format( "Timer (%s) error: %s
Defined: [%s:%i]

", key, tostring( e ), value.Debug.source, value.Debug.currentline or 0 ) )
end

		if value.n &gt;= value.Repetitions and value.Repetitions ~= 0 then
			Stop( key )
		end
	end
end

// Run Simple timers
for key, value in pairs( TimerSimple ) do
	if value.Finish &lt;= CurTime() then
		local b, e = pcall( value.Func, unpack( value.Args ) )
		if not b then
			ErrorNoHalt( Format( "Simple Timer error: %s
Defined: [%s:%i]

", tostring( e ), value.Debug.source, value.Debug.currentline or 0 ) )
end

		TimerSimple[ key ] = nil			// Kill Timer
	end
end

end

/---------------------------------------------------------
Name: Destroy( name )
Desc: Destroy the timer by name and remove all evidence.
---------------------------------------------------------
/
function Destroy( name )
Timer[ name ] = nil
end

Remove = Destroy

/---------------------------------------------------------
Name: Simple( delay, func, … )
Desc: Make a simple “create and forget” timer
---------------------------------------------------------
/
function Simple( delay, func, … )
local new_timer = {}

new_timer.Finish = UnPredictedCurTime() + delay

if func ~= nil then new_timer.Func = func end
new_timer.Args = { ... }
new_timer.Debug = debug.getinfo( 2 )

table.insert( TimerSimple, new_timer )

return true

end

hook.Add( “Think”, “CheckTimers”, Check )[/lua]

thank god, not sure why this isn’t done by default.

Kind of was wondering when someone makes something like this. Metastruct has had timer overrides for a long time too ( http://www.facepunch.com/threads/1019531
) since the errors were indeed too over the head to debug easily.
Oh and our version requires no nosend.txt edits although we do that through huge hacks which break in beta without more of my hacks, but oh well…
Oh and, our timer module also has some extra error checks so you shouldn’t be able to break all timers with incorrect parameters on timer.Create :slight_smile:

Now to get Garry to ship ours or your so everyone would benefit.