zTimeLib

This project has become inactive.

This project is inactive and its default file will likely not work with the most recent version of Warhammer Online: Age of Reckoning. The author may have abandoned it, or it may have outlived its usefulness.

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




You must login to post a comment. Don't have an account? Register to get one!

  • 5 comments
  • Avatar of zMod zMod Fri, 10 Oct 2008 13:40:46

    Now 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.

  • Avatar of solariz solariz Fri, 10 Oct 2008 13:27:26

    I'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. :(


  • Avatar of zMod zMod Fri, 10 Oct 2008 12:17:28

    I 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.

  • Avatar of z00g z00g Thu, 09 Oct 2008 21:55:43

    Wanted to ask the very same question.

  • Avatar of solariz solariz Thu, 09 Oct 2008 21:34:24

    Hmm just a question... what is the difference between this and LibTimer ?

  • 5 comments