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
- 5 comments
- 5 comments
Facts
- Date created
- 09 Oct 2008
- Category
- Last update
- 23 Oct 2008
- Development stage
- Inactive
- Language
- enUS
- License
- BSD License
- Curse link
- zTimeLib
- Recent files
- R: zTime v0.6 for Beta 3.0 on 23 Oct 2008
- B: zTime v0.5 for Beta 3.0 on 23 Oct 2008
- R: zTime v0.5r2 for Beta 3.0 on 14 Oct 2008
- R: zTime v0.4r3 for Beta 3.0 on 11 Oct 2008
- R: zTime v0.4 for Beta 3.0 on 11 Oct 2008
- #6
zMod Fri, 10 Oct 2008 13:40:46Now you wonder why I didn't bother asking. Please get on irc sometime so I can talk about merging or adding some features to TimerLib or something. I wouldn't really judge this until it's mostly finished though. A lot of those functions can be removed once I get everything I want in it.
I'm on freenode in #WARUIDev as zarious.
- #5
solariz Fri, 10 Oct 2008 13:27:26I'm the author of libtimer and nobody asked for anything so I'm a freind of many open source mods but I'`m totaly against doing similar things twice instead of working on one project. This is nowadays the reason why big Opensource projects fails. For the mods here it don't bug me but the general way I do not like.
So now we have two mods doing similar things. My intention was to have a slightmod lib only doing what it's suposed to be. You now have a blown up library with INT conversion and other stuff, I already have other dev libs doing exactly the same. Its the same XXXX like in good old wow with chronous and timex. At the end it leads people to have both libs installed and keep them updated fillling their ram with unnecesry stuff... this is the actual pain in the ass. :(
- #4
zMod Fri, 10 Oct 2008 12:17:28I wanted more functionality than LibTimer. I guess I could've talked to the author about adding things but I didn't. From #WARUIDev it sounded like it needed updates and was being neglected. I'm not against merging or instead working on LibTimer or something similar, it just seemed like adding all the things I want to do with zTime might not fly with some people using LibTimer.
- #2
z00g Thu, 09 Oct 2008 21:55:43Wanted to ask the very same question.
- #1
solariz Thu, 09 Oct 2008 21:34:24Hmm just a question... what is the difference between this and LibTimer ?