vanilla-wow-addons – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | local weakK_mt = {__mode="k"}; |
2 | local weakV_mt = {__mode="v"}; |
||
3 | |||
4 | local TIMEX_UPDATE = 1; |
||
5 | local TIMEX_EVENT = 2; |
||
6 | local FUNCTION = 4; |
||
7 | |||
8 | local TT_UPDATE = "doTimexEvent"; |
||
9 | |||
10 | local TT_UPDATE_EVENT = "TIMEX_UPDATE"; |
||
11 | |||
12 | local function ARG_ID(t) return t.schedule.id; end; |
||
13 | local function ARG_COUNT(t) return t.schedule.c; end; |
||
14 | local function ARG_ELAPSED(t) return t.schedule.elapsed; end; |
||
15 | |||
16 | local DEBUG_DB = "Debug"; |
||
17 | local timexDebug = nil; |
||
18 | |||
19 | local getTime = GetTime; |
||
20 | |||
21 | --<< ================================================= >>-- |
||
22 | -- Section I: Initialize the AddOn Object. -- |
||
23 | --<< ================================================= >>-- |
||
24 | |||
25 | Timex = AceAddon:new({ |
||
26 | name = TimexLocals.Title, |
||
27 | version = TimexLocals.Version, |
||
28 | description = TimexLocals.Desc, |
||
29 | author = "Rowne/facboy", |
||
30 | aceCompatible = "100", |
||
31 | category = ACE_CATEGORY_OTHERS, |
||
32 | cmd = AceChatCmd:new(TimexLocals.ChatCmd, (TimexLocals.ChatOpt or {})), |
||
33 | db = AceDatabase:new("TimexDB"), |
||
34 | |||
35 | TT_UPDATE = TT_UPDATE, |
||
36 | ARG_ID = ARG_ID, |
||
37 | ARG_COUNT = ARG_COUNT, |
||
38 | ARG_ELAPSED = ARG_ELAPSED, |
||
39 | |||
40 | weakV_mt = weakV_mt, |
||
41 | }) |
||
42 | |||
43 | -- make all this stuff local...there should only be one Timex instance anyway, this will effectively make it a singleton |
||
44 | local scheduleDB = {}; |
||
45 | local scheduleMap = setmetatable({}, weakV_mt); |
||
46 | |||
47 | local timerDB = {}; |
||
48 | |||
49 | local initDB = {}; |
||
50 | |||
51 | local onUpdateDB = {}; |
||
52 | local onUpdateMap = setmetatable({}, weakV_mt); |
||
53 | |||
54 | --<< ================================================= >>-- |
||
55 | -- Section II: Private utility functions. -- |
||
56 | --<< ================================================= >>-- |
||
57 | |||
58 | -------------------- |
||
59 | -- table management |
||
60 | -------------------- |
||
61 | |||
62 | local getn = table.getn; |
||
63 | local setn = table.setn; |
||
64 | local tinsert = table.insert; |
||
65 | local tremove = table.remove; |
||
66 | |||
67 | local unusedTables = setmetatable({}, weakK_mt); |
||
68 | |||
69 | local function newTable() |
||
70 | local new = next(unusedTables); |
||
71 | if new then |
||
72 | unusedTables[new] = nil; |
||
73 | else |
||
74 | new = {}; |
||
75 | end |
||
76 | return new; |
||
77 | end |
||
78 | |||
79 | local function deleteTable(deleteTable) |
||
80 | unusedTables[deleteTable] = true; |
||
81 | end |
||
82 | |||
83 | -------------------- |
||
84 | -- argument stuff |
||
85 | -------------------- |
||
86 | local args_switch = {}; |
||
87 | args_switch[ARG_ID] = ARG_ID; |
||
88 | args_switch[ARG_COUNT] = ARG_COUNT; |
||
89 | args_switch[ARG_ELAPSED] = ARG_ELAPSED; |
||
90 | |||
91 | local function buildArgs(args, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) |
||
92 | local sub = args.sub; |
||
93 | local f = args_switch[a20]; args[20], sub[20] = not f and a20 or nil, f; |
||
94 | f = args_switch[a19]; args[19], sub[19] = not f and a19 or nil, f; |
||
95 | f = args_switch[a18]; args[18], sub[18] = not f and a18 or nil, f; |
||
96 | f = args_switch[a17]; args[17], sub[17] = not f and a17 or nil, f; |
||
97 | f = args_switch[a16]; args[16], sub[16] = not f and a16 or nil, f; |
||
98 | f = args_switch[a15]; args[15], sub[15] = not f and a15 or nil, f; |
||
99 | f = args_switch[a14]; args[14], sub[14] = not f and a14 or nil, f; |
||
100 | f = args_switch[a13]; args[13], sub[13] = not f and a13 or nil, f; |
||
101 | f = args_switch[a12]; args[12], sub[12] = not f and a12 or nil, f; |
||
102 | f = args_switch[a11]; args[11], sub[11] = not f and a11 or nil, f; |
||
103 | f = args_switch[a10]; args[10], sub[10] = not f and a10 or nil, f; |
||
104 | f = args_switch[a9]; args[9], sub[9] = not f and a9 or nil, f; |
||
105 | f = args_switch[a8]; args[8], sub[8] = not f and a8 or nil, f; |
||
106 | f = args_switch[a7]; args[7], sub[7] = not f and a7 or nil, f; |
||
107 | f = args_switch[a6]; args[6], sub[6] = not f and a6 or nil, f; |
||
108 | f = args_switch[a5]; args[5], sub[5] = not f and a5 or nil, f; |
||
109 | f = args_switch[a4]; args[4], sub[4] = not f and a4 or nil, f; |
||
110 | f = args_switch[a3]; args[3], sub[3] = not f and a3 or nil, f; |
||
111 | f = args_switch[a2]; args[2], sub[2] = not f and a2 or nil, f; |
||
112 | f = args_switch[a1]; args[1], sub[1] = not f and a1 or nil, f; |
||
113 | end |
||
114 | |||
115 | local args_mt = { |
||
116 | __index = function(t, k) |
||
117 | local f = t.sub[k]; |
||
118 | if f then return f(t); end |
||
119 | end, |
||
120 | } |
||
121 | |||
122 | local function newArgs(schedule) |
||
123 | local args = newTable(); |
||
124 | args.schedule, args.sub = schedule, newTable(); |
||
125 | setmetatable(args, args_mt); |
||
126 | return args; |
||
127 | end |
||
128 | |||
129 | -------------------- |
||
130 | -- schedule heap management |
||
131 | -------------------- |
||
132 | |||
133 | -------------------- |
||
134 | -- sifting functions |
||
135 | local function hSiftUp(heap, pos, schedule) |
||
136 | schedule = schedule or heap[pos]; |
||
137 | local scheduleD = schedule.d; |
||
138 | |||
139 | local curr, i = pos, floor(pos/2); |
||
140 | local parent = heap[i]; |
||
141 | while i > 0 and scheduleD < parent.d do |
||
142 | heap[curr], parent.i = parent, curr; |
||
143 | curr, i = i, floor(i/2); |
||
144 | parent = heap[i]; |
||
145 | end |
||
146 | heap[curr], schedule.i = schedule, curr; |
||
147 | return pos ~= curr; |
||
148 | end |
||
149 | |||
150 | local function hSiftDown(heap, pos, schedule, size) |
||
151 | schedule, size = schedule or heap[pos], size or getn(heap); |
||
152 | local scheduleD = schedule.d; |
||
153 | |||
154 | local curr = pos; |
||
155 | repeat |
||
156 | local child, childD, c; |
||
157 | -- determine the child to compare with |
||
158 | local j = 2 * curr; |
||
159 | if j > size then |
||
160 | break; |
||
161 | end |
||
162 | local k = j + 1; |
||
163 | if k > size then |
||
164 | child = heap[j]; |
||
165 | childD, c = child.d, j; |
||
166 | else |
||
167 | local childj, childk = heap[j], heap[k]; |
||
168 | local jD, kD = childj.d, childk.d; |
||
169 | if jD < kD then |
||
170 | child, childD, c = childj, jD, j; |
||
171 | else |
||
172 | child, childD, c = childk, kD, k; |
||
173 | end |
||
174 | end |
||
175 | -- do the comparison |
||
176 | if scheduleD <= childD then |
||
177 | break; |
||
178 | end |
||
179 | heap[curr], child.i = child, curr; |
||
180 | curr = c; |
||
181 | until false; |
||
182 | heap[curr], schedule.i = schedule, curr; |
||
183 | return pos ~= curr; |
||
184 | end |
||
185 | |||
186 | -------------------- |
||
187 | -- heap functions |
||
188 | local function hMaintain(heap, pos, schedule, size) |
||
189 | schedule, size = schedule or heap[pos], size or getn(heap); |
||
190 | if not hSiftUp(heap, pos, schedule) then |
||
191 | hSiftDown(heap, pos, schedule, size); |
||
192 | end |
||
193 | end |
||
194 | |||
195 | local function hPush(heap, schedule) |
||
196 | tinsert(heap, schedule); |
||
197 | hSiftUp(heap, getn(heap), schedule); |
||
198 | end |
||
199 | |||
200 | local function hPop(heap) |
||
201 | local head, tail = heap[1], tremove(heap); |
||
202 | local size = getn(heap); |
||
203 | |||
204 | if size == 1 then |
||
205 | heap[1], tail.i = tail, 1; |
||
206 | elseif size > 1 then |
||
207 | hSiftDown(heap, 1, tail, size); |
||
208 | end |
||
209 | return head; |
||
210 | end |
||
211 | |||
212 | local function hDelete(heap, pos) |
||
213 | local size = getn(heap); |
||
214 | local tail = tremove(heap); |
||
215 | if pos < size then |
||
216 | local size = size - 1; |
||
217 | if size == 1 then |
||
218 | heap[1], tail.i = tail, 1; |
||
219 | elseif size > 1 then |
||
220 | heap[pos] = tail; |
||
221 | hMaintain(heap, pos, tail, size); |
||
222 | end |
||
223 | end |
||
224 | end |
||
225 | |||
226 | -------------------- |
||
227 | -- schedule management |
||
228 | -------------------- |
||
229 | |||
230 | local unusedSchedules = setmetatable({}, weakK_mt); |
||
231 | |||
232 | local function newSchedule() |
||
233 | local schedule = next(unusedSchedules); |
||
234 | if schedule then |
||
235 | unusedSchedules[schedule] = nil; |
||
236 | else |
||
237 | schedule = newTable(); |
||
238 | schedule.a = newArgs(schedule); |
||
239 | end |
||
240 | return schedule; |
||
241 | end |
||
242 | |||
243 | -- schedule should already have been removed from the heap |
||
244 | local function deleteSchedule(schedule) |
||
245 | schedule.del = nil; |
||
246 | scheduleMap[schedule.id] = nil; |
||
247 | unusedSchedules[schedule] = true; |
||
248 | end |
||
249 | |||
250 | local function deleteOnUpdate(onUpdate) |
||
251 | onUpdate.del = nil; |
||
252 | onUpdateMap[onUpdate.id] = nil; |
||
253 | unusedSchedules[onUpdate] = true; |
||
254 | end |
||
255 | |||
256 | -------------------- |
||
257 | -- function callers |
||
258 | -------------------- |
||
259 | |||
260 | local function callFunction(schedule) |
||
261 | local a = schedule.a; |
||
262 | local status, err = pcall(schedule.f, a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], a[16], a[17], a[18], a[19], a[20]); |
||
263 | if not status then |
||
264 | Timex.cmd:msg("Scheduled function '%s' failed with error: %s", tostring(schedule.id), tostring(err)); |
||
265 | end |
||
266 | return err; |
||
267 | end |
||
268 | |||
269 | local function triggerEvent(schedule) |
||
270 | local a = schedule.a; |
||
271 | local status, err = pcall(schedule.f, self, schedule.e, a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], a[16], a[17], a[18], a[19], a[20]); |
||
272 | if not status then |
||
273 | Timex.cmd:msg("Scheduled function '%s' failed with error: %s", tostring(schedule.id), tostring(err)); |
||
274 | end |
||
275 | return err; |
||
276 | end |
||
277 | |||
278 | local function triggerDeprecatedEvent(schedule) |
||
279 | local a = schedule.a; |
||
280 | local status, err = pcall(schedule.f, self, schedule.e, a, schedule.c, schedule.id, schedule.elapsed); |
||
281 | if not status then |
||
282 | Timex.cmd:msg("Scheduled function '%s' failed with error: %s", tostring(schedule.id), tostring(err)); |
||
283 | end |
||
284 | return err; |
||
285 | end |
||
286 | |||
287 | local function runMultiple(schedule, runCount) |
||
288 | local runFunc = schedule.runF; |
||
289 | local result = runFunc(schedule); |
||
290 | if runCount > 1 then |
||
291 | local autoRemove = schedule.aR; |
||
292 | schedule.elapsed = 0; |
||
293 | for i = 2, runCount do |
||
294 | result = runFunc(schedule); |
||
295 | if autoRemove and result then break; end |
||
296 | end |
||
297 | end |
||
298 | return result; |
||
299 | end |
||
300 | |||
301 | -------------------- |
||
302 | -- other stuff |
||
303 | -------------------- |
||
304 | |||
305 | local function handleFrame() |
||
306 | local runCount = getn(scheduleDB) + getn(onUpdateDB); |
||
307 | if (runCount == 1) then |
||
308 | TimexUpdateFrame:Show(); |
||
309 | elseif (runCount == 0) then |
||
310 | TimexUpdateFrame:Hide(); |
||
311 | end |
||
312 | end |
||
313 | |||
314 | local function runStartupFunctions() |
||
315 | for k, v in pairs(initDB) do |
||
316 | if v.f then |
||
317 | v.f(v.a1, v.a2, v.a3, v.a4, v.a5, v.a6, v.a7, v.a8, v.a9, v.a10, v.a11, v.a12, v.a13, v.a14, v.a15, v.a16, v.a17, v.a18, v.a19, v.a20); |
||
318 | end |
||
319 | -- delete the table |
||
320 | v.f, v.a = nil, nil; |
||
321 | v.a1, v.a2, v.a3, v.a4, v.a5 = nil, nil, nil, nil, nil; |
||
322 | v.a6, v.a7, v.a8, v.a9, v.a10 = nil, nil, nil, nil, nil; |
||
323 | v.a11, v.a12, v.a13, v.a14, v.a15 = nil, nil, nil, nil, nil; |
||
324 | v.a16, v.a17, v.a18, v.a19, v.a20 = nil, nil, nil, nil, nil; |
||
325 | deleteTable(v); |
||
326 | initDB[k] = nil; |
||
327 | end |
||
328 | end |
||
329 | |||
330 | local function togOpt(timex, var) |
||
331 | return timex.db:toggle(timex.profilePath, var) |
||
332 | end |
||
333 | |||
334 | local function getOpt(timex, var) |
||
335 | return timex.db:get(timex.profilePath, var) |
||
336 | end |
||
337 | |||
338 | local function getNumber(n) |
||
339 | local num = tonumber(n); |
||
340 | if not num then |
||
341 | error("'" .. n .. "' is not a number."); |
||
342 | end |
||
343 | return num; |
||
344 | end |
||
345 | |||
346 | --<< ================================================= >>-- |
||
347 | -- Section III: The Timex System Functions. -- |
||
348 | --<< ================================================= >>-- |
||
349 | |||
350 | function Timex:Enable() |
||
351 | TimexBar:Enable(); |
||
352 | timexDebug = getOpt(self, DEBUG_DB); |
||
353 | TimexBar:Debug(timexDebug); |
||
354 | runStartupFunctions(self); |
||
355 | end |
||
356 | |||
357 | function Timex:AddStartupFunc(f, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) |
||
358 | local init = newTable(); |
||
359 | init.f, init.a = f, arg; |
||
360 | init.a1, init.a2, init.a3, init.a4, init.a5 = a1, a2, a3, a4, a5; |
||
361 | init.a6, init.a7, init.a8, init.a9, init.a10 = a6, a7, a8, a9, a10; |
||
362 | init.a11, init.a12, init.a13, init.a14, init.a15 = a11, a12, a13, a14, a15; |
||
363 | init.a16, init.a17, init.a18, init.a19, init.a20 = a16, a17, a18, a19, a20; |
||
364 | tinsert(initDB, init); |
||
365 | end |
||
366 | |||
367 | function Timex:Update(dt) |
||
368 | local now = getTime(); |
||
369 | |||
370 | for k, onUpdate in pairs(onUpdateDB) do |
||
371 | onUpdate.del = true; |
||
372 | local a = onUpdate.a; |
||
373 | local ret = onUpdate.f(a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], a[16], a[17], a[18], a[19], a[20]); |
||
374 | if ret and onUpdate.aR and onUpdate.del then |
||
375 | onUpdateDB[k] = nil; |
||
376 | onUpdateMap[onUpdate.id] = nil; |
||
377 | unusedSchedules[onUpdate] = true; |
||
378 | end |
||
379 | onUpdate.del = nil; |
||
380 | end |
||
381 | |||
382 | local schedule = scheduleDB[1]; |
||
383 | while schedule and now >= schedule.d do |
||
384 | local elapsed = now - schedule.l; |
||
385 | schedule.elapsed = elapsed; |
||
386 | |||
387 | local runCount; |
||
388 | |||
389 | local count, t = schedule.c, schedule.t; |
||
390 | local runCount; |
||
391 | if count then |
||
392 | runCount = t > 0 and floor((now - schedule.s)/t) or 1; |
||
393 | runCount = runCount < count and runCount or count; |
||
394 | count = count - runCount; |
||
395 | schedule.c = count; |
||
396 | if (count <= 0) then |
||
397 | -- mark schedule for deletion |
||
398 | schedule.del = true; |
||
399 | else |
||
400 | schedule.l, schedule.s, schedule.d = now, schedule.d, schedule.d + t; |
||
401 | hSiftDown(scheduleDB, 1, schedule); |
||
402 | end |
||
403 | elseif schedule.r then |
||
404 | schedule.l, schedule.s, schedule.d = now, schedule.d, schedule.d + t; |
||
405 | hSiftDown(scheduleDB, 1, schedule); |
||
406 | else |
||
407 | -- mark schedule for deletion |
||
408 | schedule.del = true; |
||
409 | end |
||
410 | -- run the function |
||
411 | local run = schedule.run; |
||
412 | if run then |
||
413 | local ret = run(schedule, runCount); |
||
414 | if ret and schedule.aR then |
||
415 | schedule.del = true; |
||
416 | end |
||
417 | end |
||
418 | if schedule.del then |
||
419 | -- remove from heap |
||
420 | hPop(scheduleDB); |
||
421 | if schedule.u then |
||
422 | deleteOnUpdate(schedule); |
||
423 | else |
||
424 | deleteSchedule(schedule); |
||
425 | end |
||
426 | end |
||
427 | schedule = scheduleDB[1]; |
||
428 | end |
||
429 | handleFrame(); |
||
430 | end |
||
431 | |||
432 | function Timex:Debug() |
||
433 | togOpt(self, DEBUG_DB); |
||
434 | timexDebug = getOpt(self, DEBUG_DB); |
||
435 | TimexBar:Debug(timexDebug); |
||
436 | if timexDebug then |
||
437 | self.cmd:msg("Debug: ON"); |
||
438 | else |
||
439 | self.cmd:msg("Debug: OFF"); |
||
440 | end |
||
441 | end |
||
442 | |||
443 | --<< ================================================= >>-- |
||
444 | -- Section IV: The Timex Schedule Functions. -- |
||
445 | --<< ================================================= >>-- |
||
446 | |||
447 | -- changed to support max of 20 arguments (to prevent table creation) |
||
448 | function Timex:AddSchedule(id, t, r, c, f, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) |
||
449 | if id or t then |
||
450 | local now = getTime(); |
||
451 | -- look for named schedule |
||
452 | local schedule; |
||
453 | if id then |
||
454 | schedule = scheduleMap[id]; |
||
455 | end |
||
456 | |||
457 | if not schedule then |
||
458 | -- create |
||
459 | schedule = newSchedule(); |
||
460 | if id then |
||
461 | scheduleMap[id] = schedule; |
||
462 | end |
||
463 | tinsert(scheduleDB, schedule); |
||
464 | schedule.i = getn(scheduleDB); |
||
465 | end |
||
466 | schedule.id = id or this:GetName() or scheduleDB; |
||
467 | t = t and getNumber(t) or 0; |
||
468 | t = t >= 0 and t or 0; |
||
469 | schedule.t, schedule.r, schedule.c = t, r, c and getNumber(c) or nil; |
||
470 | if f then |
||
471 | local fType = type(f); |
||
472 | if fType == "function" then |
||
473 | schedule.f, schedule.run = f, callFunction; |
||
474 | elseif fType == "string" then |
||
475 | schedule.f = self.TriggerEvent; |
||
476 | if f == TT_UPDATE then |
||
477 | schedule.e, schedule.run = TT_UPDATE_EVENT, triggerDeprecatedEvent; |
||
478 | else |
||
479 | schedule.e, schedule.run = f, triggerEvent; |
||
480 | end |
||
481 | else |
||
482 | error("Timex:AddSchedule: param f is not a function or an event name"); |
||
483 | end |
||
484 | |||
485 | -- check for multi |
||
486 | if c then |
||
487 | schedule.runF, schedule.run = schedule.run, runMultiple; |
||
488 | end |
||
489 | else |
||
490 | schedule.run = nil; |
||
491 | end |
||
492 | buildArgs(schedule.a, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); |
||
493 | -- last update, start time, due time |
||
494 | schedule.l, schedule.s, schedule.d = now, now, now + t; |
||
495 | |||
496 | -- clear deletion, auto-remove (for onUpdate) flag |
||
497 | schedule.del = nil; |
||
498 | schedule.aR = nil; |
||
499 | |||
500 | -- onupdate flag; |
||
501 | schedule.u = nil; |
||
502 | |||
503 | -- place in scheduleDB |
||
504 | hMaintain(scheduleDB, schedule.i, schedule); |
||
505 | |||
506 | handleFrame(); |
||
507 | end |
||
508 | end |
||
509 | |||
510 | function Timex:DeleteSchedule(id) |
||
511 | local schedule = scheduleMap[id]; |
||
512 | if schedule then |
||
513 | hDelete(scheduleDB, schedule.i); |
||
514 | deleteSchedule(schedule); |
||
515 | handleFrame(); |
||
516 | end |
||
517 | end |
||
518 | |||
519 | function Timex:CheckSchedule(id, r) |
||
520 | local schedule = scheduleMap[id]; |
||
521 | if schedule then |
||
522 | if r then |
||
523 | -- shows the time remaining |
||
524 | return schedule.d - getTime(); |
||
525 | else |
||
526 | return true; |
||
527 | end |
||
528 | end |
||
529 | end |
||
530 | |||
531 | function Timex:ElapsedScheduleTime(id) |
||
532 | local now = getTime(); |
||
533 | local schedule = scheduleMap[id]; |
||
534 | if schedule then |
||
535 | -- show the time elapsed |
||
536 | return now - schedule.s, schedule.s, now; |
||
537 | else |
||
538 | return 0, 0, now; |
||
539 | end |
||
540 | end |
||
541 | |||
542 | function Timex:RemainingScheduleTime(id) |
||
543 | local now = getTime(); |
||
544 | local schedule = scheduleMap[id]; |
||
545 | if schedule then |
||
546 | -- show the time remaining |
||
547 | return schedule.d - now, schedule.d, now; |
||
548 | else |
||
549 | return 0, 0, now; |
||
550 | end |
||
551 | end |
||
552 | |||
553 | function Timex:ChangeScheduleDuration(id, t) |
||
554 | local schedule = scheduleMap[id]; |
||
555 | if schedule and t then |
||
556 | schedule.t, schedule.d = t, schedule.s + t; |
||
557 | hMaintain(scheduleDB, schedule.i, schedule); |
||
558 | end |
||
559 | end |
||
560 | |||
561 | function Timex:ChangeScheduleDue(id, d) |
||
562 | local schedule = scheduleMap[id]; |
||
563 | if schedule then |
||
564 | schedule.d = d or getTime(); |
||
565 | hMaintain(scheduleDB, schedule.i, schedule); |
||
566 | end |
||
567 | end |
||
568 | |||
569 | --<< ================================================= >>-- |
||
570 | -- Section V: The Timex Timer Functions. -- |
||
571 | --<< ================================================= >>-- |
||
572 | -- largely for Chronos compatibility - plus it's a pretty cool idea! |
||
573 | |||
574 | function Timex:AddTimer(id) |
||
575 | local now = getTime(); |
||
576 | id = id or this:GetName(); |
||
577 | local timer = timerDB[id]; |
||
578 | if not timer then |
||
579 | timer = newTable(); |
||
580 | timerDB[id] = timer; |
||
581 | end |
||
582 | tinsert(timer, now); |
||
583 | end |
||
584 | |||
585 | function Timex:DeleteTimer(id) |
||
586 | local now = getTime(); |
||
587 | id = id or this:GetName(); |
||
588 | local timer = timerDB[id]; |
||
589 | local start; |
||
590 | if timer then |
||
591 | local start = tremove(timer); |
||
592 | -- delete timer if it is empt |
||
593 | if getn(timer) == 0 then |
||
594 | deleteTable(timer); |
||
595 | timerDB[id] = nil; |
||
596 | end |
||
597 | return now - start, start, now; |
||
598 | else |
||
599 | return 0, 0, now; |
||
600 | end |
||
601 | end |
||
602 | |||
603 | function Timex:GetTimer(id) |
||
604 | local now = getTime(); |
||
605 | id = id or this:GetName(); |
||
606 | local timer = timerDB[id]; |
||
607 | local start; |
||
608 | if timer then |
||
609 | local start = timer[getn(timer)]; |
||
610 | return now - start, start, now; |
||
611 | else |
||
612 | return 0, 0, now; |
||
613 | end |
||
614 | end |
||
615 | |||
616 | function Timex:CheckTimer(id) |
||
617 | id = id or this:GetName(); |
||
618 | if timerDB[id] then |
||
619 | return true; |
||
620 | else |
||
621 | return false; |
||
622 | end |
||
623 | end |
||
624 | |||
625 | --<< ================================================= >>-- |
||
626 | -- Section VI: The Timex OnUpdate Functions. -- |
||
627 | --<< ================================================= >>-- |
||
628 | |||
629 | local function insertOnUpdate(onUpdate) |
||
630 | -- find first empty spot |
||
631 | local i, v = 1, onUpdateDB[1]; |
||
632 | while v ~= nil do |
||
633 | i = i + 1; |
||
634 | v = onUpdateDB[i]; |
||
635 | end |
||
636 | onUpdateDB[i], onUpdate.i = onUpdate, i; |
||
637 | end |
||
638 | |||
639 | -- moves the onUpdate to the correct table based on the new rate |
||
640 | local function maintainOnUpdate(onUpdate, rate) |
||
641 | if rate then |
||
642 | if not onUpdate.t then |
||
643 | -- remove from onUpdateDB |
||
644 | onUpdateDB[onUpdate.i] = nil; |
||
645 | -- add to scheduleDB |
||
646 | tinsert(scheduleDB, onUpdate); |
||
647 | onUpdate.i = getn(scheduleDB); |
||
648 | end |
||
649 | elseif onUpdate.t then |
||
650 | -- remove from scheduleDB and add to onUpdateDB |
||
651 | hDelete(scheduleDB, onUpdate.i, onUpdate); |
||
652 | insertOnUpdate(onUpdate); |
||
653 | end |
||
654 | end |
||
655 | |||
656 | local function setOnUpdateRate(onUpdate, rate, now) |
||
657 | if rate then |
||
658 | -- last update, start time, due time |
||
659 | onUpdate.t, onUpdate.l, onUpdate.s, onUpdate.d = rate, now, now, now + rate; |
||
660 | |||
661 | -- place in scheduleDB |
||
662 | hMaintain(scheduleDB, onUpdate.i, onUpdate); |
||
663 | else |
||
664 | onUpdate.t, onUpdate.l, onUpdate.s, onUpdate.d = nil, nil, nil, nil; |
||
665 | end |
||
666 | end |
||
667 | |||
668 | function Timex:AddOnUpdate(id, rate, autoRemove, f, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) |
||
669 | if f then |
||
670 | local now = getTime(); |
||
671 | -- look for named onUpdate |
||
672 | local onUpdate; |
||
673 | if id then |
||
674 | onUpdate = onUpdateMap[id]; |
||
675 | end |
||
676 | |||
677 | if rate then |
||
678 | rate = getNumber(rate); |
||
679 | rate = rate > 0 and rate or nil; |
||
680 | end |
||
681 | |||
682 | if not onUpdate then |
||
683 | -- create |
||
684 | onUpdate = newSchedule(); |
||
685 | if id then |
||
686 | onUpdateMap[id] = onUpdate; |
||
687 | end |
||
688 | |||
689 | -- insert into scheduleDB or onUpdateDB, depending on whether a rate is specced or not |
||
690 | if rate then |
||
691 | tinsert(scheduleDB, onUpdate); |
||
692 | onUpdate.i = getn(scheduleDB); |
||
693 | else |
||
694 | insertOnUpdate(onUpdate); |
||
695 | end |
||
696 | else |
||
697 | maintainOnUpdate(onUpdate, rate); |
||
698 | end |
||
699 | onUpdate.id = id or this:GetName() or onUpdateDB; |
||
700 | onUpdate.aR, onUpdate.f, onUpdate.r, onUpdate.del = autoRemove, f, true, nil; |
||
701 | |||
702 | -- maintain scheduleDB if necessary |
||
703 | setOnUpdateRate(onUpdate, rate, now); |
||
704 | |||
705 | -- flag as an update schedule |
||
706 | onUpdate.u = true; |
||
707 | |||
708 | buildArgs(onUpdate.a, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); |
||
709 | handleFrame(); |
||
710 | end |
||
711 | end |
||
712 | |||
713 | function Timex:DeleteOnUpdate(id) |
||
714 | local onUpdate = onUpdateMap[id]; |
||
715 | if onUpdate then |
||
716 | if onUpdate.t then |
||
717 | hDelete(scheduleDB, onUpdate.i); |
||
718 | deleteOnUpdate(onUpdate); |
||
719 | else |
||
720 | onUpdate.del = nil; |
||
721 | onUpdateDB[onUpdate.i] = nil; |
||
722 | onUpdateMap[id] = nil; |
||
723 | unusedSchedules[onUpdate] = true; |
||
724 | end |
||
725 | handleFrame(); |
||
726 | end |
||
727 | end |
||
728 | |||
729 | function Timex:ChangeOnUpdateRate(id, rate) |
||
730 | local onUpdate = onUpdateMap[id]; |
||
731 | if onUpdate then |
||
732 | local now = getTime(); |
||
733 | if rate then |
||
734 | rate = getNumber(rate); |
||
735 | rate = rate > 0 and rate or nil; |
||
736 | end |
||
737 | |||
738 | maintainOnUpdate(onUpdate, rate); |
||
739 | |||
740 | setOnUpdateRate(onUpdate, rate, now); |
||
741 | end |
||
742 | end |
||
743 | |||
744 | --<< ================================================= >>-- |
||
745 | -- Section Omega: Register the AddOn Object. -- |
||
746 | --<< ================================================= >>-- |
||
747 | |||
748 | Timex:RegisterForLoad() |