Overview
zTimeLib is no longer stand-alone and needs to be embedded to work. This is very easy, and requires only one line in your addons mod file, see below for example.
zTimeLib is an efficient tiered function scheduler. It enables you to run thousands (though most of you shouldn't need more than a few hundred at the very most) of independent schedulers to run functions in the future. All schedulers are independent and can be paused or deleted at any time. zTime's scheduler uses multi-leveling queuing to minimize the number of times the scheduler checks to see if a function needs to run. Example, by default zTime runs with 12 schedule bins, which are given an exponentially increasing 'size'. Schedules are placed in largest bin whose size is not greater than their run time. Each bin is checked for any schedules which need to be run or sorted into a lower bin every time its bin size has passed in seconds. Any schedules which need be moved to lower bins are moved, or run if their run time has passed.
Here are the default bin sizes:
Bin 1 0.10s
Bin 2 0.24s
Bin 3 0.52s
Bin 4 1.14s
Bin 5 2.50s
Bin 6 5.48s
Bin 7 11.98s
Bin 8 26.20s
Bin 9 57.32s
Bin 10 125.40s
Bin 11 274.29s
Bin 12 600.00s
I may tweak these in the future or even allow the scheduler to adaptively change the bin sizes if I can figure a way to calculate the most efficient sizes.
Example Schedules
Scheduling a function to run 12 seconds in the future, it would be placed into bin 7, where it would sit until bin 7 was checked (after 11.98s had passed). It would then be resorted into bin 1, until its run time. At runtime, its function would be executed, and then the schedule would be deleted or reset if it was a repeating schedule.
Another example, if you created a 6.5 second schedule, it would be placed into bin 6 first, until 5.48s had passed. At that point it would then be resorted into bin 3, until 0.52s had passed (leaving 0.5s until runtime), then into bin 2, where it would sit for 2 cycles (0.24x2) and then finally into bin 1 until run time.
The normal scheduler has a max error of 0.1s, so if you need something more precise than that, you should use a frame scheduler, which runs approximately every frame. (I use a frame scheduler in zTweaks to keep track of FPS.)
Frame Schedulers simply hook into the master update and are the same as if you used your own OnUpdate call, except it keeps it in a central location and is automatically terminated if the function throws an error.
zTime also keeps track of the games real world time via chat time stamps, allowing you to easily obtain real world time for your addons.
TODO: I'm considering adding the ability to specify an error handler in the event that a function you schedule returns an error. The handler would then be called allowing a mod that depends on scheduled functions to sort itself out. Though I'm not convinced the coders who would be willing to code an error handler would even need one in the first place.
Usage
Install zTimeLib like any other mod. If you plan on using it with a mod you are working on, you need to add zTimeLib as a file entry in your addon's .mod file. zTimeLib must be loaded before any files which require it to work properly.
<Files>
<File name="YourModsFile.lua" />
<File name="zTimeLib.lua" />
<File name="YourModsFile2.lua" />
</Files>
After that you simply use the API to create schedules / get time information.
Main API:
zTime.AddSchedule
Adds a schedule to the dispatch table, returns id for unscheduling.
zTime.AddSchedule(name, len, func, repete)
name - optional, can be use by outside commands for more logical usage
len - length of time before executing func
func - function to be executed (note there is no way to check if this is valid without running the function, so you won't know until exec time)
repete - optional, number of times schedule will run, defaults to 1, -1 for indefinately
returns - scheduleid used for any other schedule commands (including unscheduling)
zTime.DelSchedule
Removes a schedule from the dispatch table.
Note: This does not check for existence, it simply nils all bins at the key id.
zTime.DelSchedule(id)
id - id of schedule to be removed
returns nothing
zTime.GetSchedule
Returns the schedule table of the schedule at id or false if schedule does not exist.
Note: Name is not returned if its nil.
zTime.GetSchedule(id)
id - id of schedule to be returned
returns - schedule table
ex task = { name = "TimeGrabber", len = 60, repete = -1, pause = false, rtime = 120, func = func }
zTime.GetSchedBin
Returns the bin number of a schedule from that schedules id or false if the schedule does not exist.
zTime.GetSchedBin(id)
id - schedule id whos bin you need
returns - schedule bin number
zTime.PauseSchedule
Pauses the schedule with id from further execution unless resumed. When a function is paused, it's paused entry gets set to the current time so that when its resumed the time difference can be computed and added to keep the exectime correct. It also gets moved into the last schedule bin, which means its only check for exec once every 600s (which doesn't matter really since it won't exec).
zTime.PauseSchedule(id)
id - id of schedule to be paused
returns - true on success (schedule paused), false on failure (schedule is already paused / does not exist)
zTime.UnPauseSchedule
Resumes a paused schedule and updates it exec time.
zTime.UnPauseSchedule(id)
id - id of schedule to be resumed
returns true on success (schedule resumed), false on failure (schedule not paused / does not exist)
zTime.CreateFrameScheduler
Creates a frame scheduler, which is called once per frame.
zTime.CreateFrameScheduler(func)
func - func to be called
returns - id of schedule; required for schedule deletion
zTime.DestroyFrameScheduler
Destroys a frame scheduler
zTime.DestroyFrameScheduler(id)
id - id of frame schduler to be destroyed
returns - true if successful, false if schedule does not exist
zTime.GetFrameSchedule
Allows access to the frame scheduler table, while protecting it from outside manipulation.
zTime.GetFrameSchedule()
returns - entire frames scheduler table, which includes:
key/pair values for frame schedulers, key = schedule id, value = function
zTime.CreatePeriodicLatch
A periodic latch, its a method of preventing a function from being called more than one per period. It guarentees a function will not be called more often then the period, and if the fucntion should be spammed multiple times, it will be called again at the end of the period. Returns the terminate ID.
zTime.CreatePeriodicLatch(period, func)
period - time between func exections
func - function to be called
returns - run, terminate
run - new function with latch builtin
terminate - function used to destroy the latch
ex Lets say you know that SomeFunc get the crap spammed out of it when SomeEvent fires, and it causes you to lag. You could create a latch which would prevent the function from being spammed.
run, terminate = zTime.AddPeriodicLatch(0.5, SomeFunc)
SomeFunc = run -- overwrite the original function with latch
running terminate would make run noop, and effectively unhook it, which would be bad if it was a global ui function, always save a copy if you need this functionality
Now lets say SomeFunc gets called 3 times over 0.3s period. The function would only be called twice. Once for the inital time, then the latch would prevent it from being called for 0.5s, and since it had tried to run while the latch was closed, it would execute one more time at the end fo the 0.5s period.
zTime.GetRealTime
Returns current time in seconds (since midnight). For example, 7200 would be 2:00 AM, 86399 would be 11:59 PM etc. This assumes that the TimeGrabber schedules (in zTime.Init) are running. If not chat messages have been recieved yet, it will return epoch time.
zTime.GetRealTime()
returns - current time in seconds from midnight
Less Used API
zTime.GetEpoch
Allows access to the epoch value, while protecting it from outside manipulation.
zTime.GetEpoch()
returns - ztime's master epoch value (time since ui was last loaded in seconds)
zTime.GetDispatchTable
Allows access to the dispatch table, while protecting it from outside manipulation.
zTime.GetDispatchTable()
returns - entire dispatch table, including:
all schedule bins, allowing access to their subtables, which contain the actual schedules
zTime.GetTimeData
Allows access to the timedata table, while protecting it from outside manipulation.
zTime.GetTimeData()
returns - nothing
zTime.GetTichTable
Allows access to the ticker table, while protecting it from outside manipulation.
zTime.GetTichTable
returns - entire tich table which includes:
epoch time, throttle delay, nextupdate time, last update time, time difference, this updates tich time, unique id ticker
zTime.GetLastStamp
Gets real world time from last timestamp and returns it in a table.
zTime.GetLastStamp()
returns - a table with the time and offset (current epoch time) of the last chat log entry
time = { hour = hr, min = min, sec = sec, offset = currentepochtime }
(for general purpose time tracking, its probably easier to just use zTime.GetRealTime() and convert the seconds)
zTime.UpdateTimeData
Runs GetLastStamp to get current timestamp, then updates the timedata table with current time information.
zTime.UpdateTimeData()
returns - nothing
zTime.TimeSync
Updates current timedata only, recomputing the difference of the timedatas most recent chat time stamp against the current epoch, does not call GetLastStamp.
zTime.TimeSync()
returns - nothing
zTime.SecToHMS
Accepts a number and converts it into hours minutes and seconds, and puts those values into a table.
zTime.SecToHMS(sec)
sec - seconds to be converted
ex 8232.76
returns - table of hr min sec
time = { hour = 2, min = 17, sec = 12.76 }
zTime.HMSToSec
Converts a table with hour min and sec keys into seconds.
zTime.HMSToSec(hms)
ex hms = { hour = 2, min = 17, sec = 12.76 }
returns - seconds
ex 8232.76
zTime.CreateBins
Creates a table of exponientally increasing values based on binsize, where the last bin is always 600
zTime.CreateBins(binsize, numb)
binsize = size tweaker
numb - number of bins
returns - table very similar to one at beginning of this post
zTime.GetBinSlot
Returns the schedule bin a schedule with time len would best be placed in.
zTime.GetBinSlot(len)
len - length of schedule
returns - bin number
zTime.ChangeBin
Moves a schedule from one bin to another.
zTime.ChangeBin(id, source, dest)
id - schedule id
source - source bin number
dest - destination bin number
returns - nothing
zTime.BinCheck
Returns the schedule bin a schedule should be in at this second, given its id and current bin. Differnts from GetBinSlot in that its more heavy duty and checks more than just initial length. GetBinSlot is also for pre-entry into the dispatch table.
zTime.BinCheck(id, key)
id - schedule id
key - current schedules bin id
Notes
With release v0.5r2, the lib is mostly complete. There is only one thing I can thing I'll add, and that's a zero memory scheduler if I can create frames with onupdate handlers via lua. If you have any constructive information (bug reports, problems, errors, fixes, tweaks etc) feel free to email me at zarious@byteblur.com or post here. This is my first lib so I might miss things and I'm always looking for hacks and more efficient ways of doing things. I also idle on freenode #WARUIDev as Zarious.
-z
z00g Requested a schedule status script for debugging so here it is:
local statustabstops = 1
function zTime.ScheduleStatus(id)
local task = zTime.GetSchedule(id)
if task then -- sanity check
local tabstop
if statustabstops == 1 then
statustabstops = 2
tabstop = " "
elseif statustabstops == 2 then
statustabstops = 3
tabstop = " "
elseif statustabstops == 3 then
statustabstops = 1
tabstop = " "
end
local status = "[zTime.ScheduleStatus]\n"
if task["name"] then
status = status .. tabstop .. "Name: " .. task["name"] .. "\n" .. tabstop .. "ID: " .. tostring(id) .. "\n"
else
status = status .. tabstop .. "Name: nil" .. "\n" .. tabstop .. "ID: " .. tostring(id) .. "\n"
end
if task["pause"] then
status = status .. tabstop .. "Status: Paused" .. "\n" .. tabstop .. "Next Exec in: Undef" .. "\n"
else
status = status .. tabstop .. "Status: Running" .. "\n" .. tabstop .. "Next Exec in: " .. string.format("%.1fs", (task["rtime"] - zTime.GetEpoch())) .. "\n"
end
if task["repete"] then
if (task["repete"] > 0) then
status = status .. tabstop .. "Repeat: " .. task["repete"] .. "x"
elseif (task["repete"] == 0) then -- don't think this is possible
status = status .. tabstop .. "Repeat: Delete"
elseif (task["repete"] == -1) then
status = status .. tabstop .. "Repeat: Indef"
end
end
d(status)
end
end
------------------------------------------------------------------------
r28 | zmod | 2008-10-23 02:42:11 +0000 (Thu, 23 Oct 2008) | 1 line
Changed paths:
A /tags/zTime v0.6 (from /trunk:27)
Tagging as zTime v0.6.
------------------------------------------------------------------------
r26 | zmod | 2008-10-23 01:52:19 +0000 (Thu, 23 Oct 2008) | 4 lines
Changed paths:
M /trunk/Changelog.txt
M /trunk/zTimeLib.lua
D /trunk/zTimeLib.mod
*fixed typo which made bin sizes much smaller than intended
*removed mod file for easily embedding; (simple file entry in mod needed to embed)
*fixed bug in periodic latch allowing double execs after the latch is reopened
*better memory usage/cleaned up leftover variables; updated debug messages to be clearer
------------------------------------------------------------------------
r24 | zmod | 2008-10-14 05:47:03 +0000 (Tue, 14 Oct 2008) | 1 line
Changed paths:
M /trunk/zTimeLib.lua
nothing major. its different.
------------------------------------------------------------------------
r23 | zmod | 2008-10-13 09:59:06 +0000 (Mon, 13 Oct 2008) | 1 line
Changed paths:
M /trunk/Changelog.txt
M /trunk/zTimeLib.lua
*.implemented smart miltilevel queueing / schedule bins to reduce overhead on large queues
------------------------------------------------------------------------
r21 | zmod | 2008-10-13 00:28:09 +0000 (Mon, 13 Oct 2008) | 1 line
Changed paths:
M /trunk/zTimeLib.lua
*bugfix for CreatePeriodicLatch
------------------------------------------------------------------------
r20 | zmod | 2008-10-12 13:10:53 +0000 (Sun, 12 Oct 2008) | 2 lines
Changed paths:
M /trunk/Changelog.txt
M /trunk/zTimeLib.lua
M /trunk/zTimeLib.mod
*Added zTime.CreatePeriodicLatch
*Added frame scheduler
------------------------------------------------------------------------
r19 | zmod | 2008-10-12 07:24:22 +0000 (Sun, 12 Oct 2008) | 1 line
Changed paths:
M /trunk/zTimeLib.lua
*added frame scheduler for scheduling functions to run every frame (uses would be fps counter, milisec timer, things that need very precise time etc etc)
------------------------------------------------------------------------
r18 | zmod | 2008-10-11 11:18:57 +0000 (Sat, 11 Oct 2008) | 1 line
Changed paths:
M /trunk
------------------------------------------------------------------------
r16 | zmod | 2008-10-11 09:32:02 +0000 (Sat, 11 Oct 2008) | 1 line
Changed paths:
M /trunk/Changelog.txt
M /trunk/zTimeLib.lua
*typos/minor stuff
------------------------------------------------------------------------
r15 | zmod | 2008-10-11 09:31:11 +0000 (Sat, 11 Oct 2008) | 1 line
Changed paths:
A /trunk/Changelog.txt
A /trunk/License.txt
D /trunk/zTimeLib
A /trunk/zTimeLib.lua
A /trunk/zTimeLib.mod
*proper curse packaging
------------------------------------------------------------------------
r13 | zmod | 2008-10-11 05:57:34 +0000 (Sat, 11 Oct 2008) | 5 lines
Changed paths:
M /trunk/zTimeLib/Changelog.txt
M /trunk/zTimeLib/zTimeLib.lua
M /trunk/zTimeLib/zTimeLib.mod
v0.4r2 Stable
*removed excessive functions to make it more line the traditional model of a lib (this includes any ByName functions as they can be easily implemented in any addon that uses zTime, and some might not use them)
*better debug/error handling
*fixed comments to be consistant
*changed epoch, timedata, and dispatchtable variables to local scope for protection, use zTime.GetEpoch(), zTime.GetTimeData(), and zTime.GetDispatchTable() instead
------------------------------------------------------------------------
r12 | zmod | 2008-10-10 23:27:12 +0000 (Fri, 10 Oct 2008) | 9 lines
Changed paths:
M /trunk/zTimeLib/Changelog.txt
M /trunk/zTimeLib/zTimeLib.lua
M /trunk/zTimeLib/zTimeLib.mod
*fixed a bug causing the time stamp function to break on initial client load
only
*cleaned up a lot of code
*fixed a bug causing repeating timers to gradually become out of sync with
there exec times
*added pause support for schedules
*added callbacks for most functions
*removed excessive functions to make it more line the traditional model of a
lib
------------------------------------------------------------------------
r10 | zmod | 2008-10-10 12:09:45 +0000 (Fri, 10 Oct 2008) | 1 line
Changed paths:
M /trunk/zTimeLib/zTimeLib.lua
full support for getting real world time data, few other changes......servers down again wtf
------------------------------------------------------------------------
r9 | zmod | 2008-10-10 09:46:44 +0000 (Fri, 10 Oct 2008) | 1 line
Changed paths:
M /trunk/zTimeLib/Changelog.txt
M /trunk/zTimeLib/zTimeLib.lua
M /trunk/zTimeLib/zTimeLib.mod
*added full support for getting real time from chat messages and better time handling
------------------------------------------------------------------------
r8 | zmod | 2008-10-10 05:58:12 +0000 (Fri, 10 Oct 2008) | 1 line
Changed paths:
A /trunk/zTimeLib/Changelog.txt
static changelog
------------------------------------------------------------------------
r6 | zmod | 2008-10-10 05:44:25 +0000 (Fri, 10 Oct 2008) | 1 line
Changed paths:
M /trunk/zTimeLib/zTimeLib.lua
M /trunk/zTimeLib/zTimeLib.mod
fixed version numbers
------------------------------------------------------------------------
r5 | zmod | 2008-10-10 05:40:14 +0000 (Fri, 10 Oct 2008) | 11 lines
Changed paths:
M /trunk/zTimeLib/zTimeLib.lua
fixed print/debug printers to accept any valid lua data
fixed bug with AddSchedule when not supplying the repete arg
added lots of debug messages, and three differnt debug levels
added zTime.DumpSchedule for easier outputting of running schedules
added many more comments / info about functions
added time output formatting functions
------------------------------------------------------------------------
r3 | zmod | 2008-10-09 21:25:41 +0000 (Thu, 09 Oct 2008) | 1 line
Changed paths:
D /trunk/zTimeLib.v0.1.zip
Removing unneeded zip
------------------------------------------------------------------------
r2 | zmod | 2008-10-09 21:03:18 +0000 (Thu, 09 Oct 2008) | 1 line
Changed paths:
A /trunk/zTimeLib
A /trunk/zTimeLib/License.txt
A /trunk/zTimeLib/zTimeLib.lua
A /trunk/zTimeLib/zTimeLib.mod
A /trunk/zTimeLib.v0.1.zip
Initial Upload
------------------------------------------------------------------------
r1 | root | 2008-10-09 11:58:26 +0000 (Thu, 09 Oct 2008) | 1 line
Changed paths:
A /branches
A /tags
A /trunk
"ztimelib/mainline: Initial Import"
------------------------------------------------------------------------