Mercurial > wow > hansgar_and_franzok_assist
comparison Libs/AceTimer-3.0/AceTimer-3.0.lua @ 4:1c3534391efb
- Added timeout for stampers.
| author | Tercio |
|---|---|
| date | Mon, 02 Mar 2015 21:28:33 -0300 |
| parents | |
| children | 0682d738499b |
comparison
equal
deleted
inserted
replaced
| 3:4a3ffc2ee399 | 4:1c3534391efb |
|---|---|
| 1 --- **AceTimer-3.0** provides a central facility for registering timers. | |
| 2 -- AceTimer supports one-shot timers and repeating timers. All timers are stored in an efficient | |
| 3 -- data structure that allows easy dispatching and fast rescheduling. Timers can be registered | |
| 4 -- or canceled at any time, even from within a running timer, without conflict or large overhead.\\ | |
| 5 -- AceTimer is currently limited to firing timers at a frequency of 0.01s as this is what the WoW timer API | |
| 6 -- restricts us to. | |
| 7 -- | |
| 8 -- All `:Schedule` functions will return a handle to the current timer, which you will need to store if you | |
| 9 -- need to cancel the timer you just registered. | |
| 10 -- | |
| 11 -- **AceTimer-3.0** can be embeded into your addon, either explicitly by calling AceTimer:Embed(MyAddon) or by | |
| 12 -- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object | |
| 13 -- and can be accessed directly, without having to explicitly call AceTimer itself.\\ | |
| 14 -- It is recommended to embed AceTimer, otherwise you'll have to specify a custom `self` on all calls you | |
| 15 -- make into AceTimer. | |
| 16 -- @class file | |
| 17 -- @name AceTimer-3.0 | |
| 18 -- @release $Id: AceTimer-3.0.lua 1119 2014-10-14 17:23:29Z nevcairiel $ | |
| 19 | |
| 20 local MAJOR, MINOR = "AceTimer-3.0", 17 -- Bump minor on changes | |
| 21 local AceTimer, oldminor = LibStub:NewLibrary(MAJOR, MINOR) | |
| 22 | |
| 23 if not AceTimer then return end -- No upgrade needed | |
| 24 AceTimer.activeTimers = AceTimer.activeTimers or {} -- Active timer list | |
| 25 local activeTimers = AceTimer.activeTimers -- Upvalue our private data | |
| 26 | |
| 27 -- Lua APIs | |
| 28 local type, unpack, next, error, select = type, unpack, next, error, select | |
| 29 -- WoW APIs | |
| 30 local GetTime, C_TimerAfter = GetTime, C_Timer.After | |
| 31 | |
| 32 local function new(self, loop, func, delay, ...) | |
| 33 if delay < 0.01 then | |
| 34 delay = 0.01 -- Restrict to the lowest time that the C_Timer API allows us | |
| 35 end | |
| 36 | |
| 37 local timer = {...} | |
| 38 timer.object = self | |
| 39 timer.func = func | |
| 40 timer.looping = loop | |
| 41 timer.argsCount = select("#", ...) | |
| 42 timer.delay = delay | |
| 43 timer.ends = GetTime() + delay | |
| 44 | |
| 45 activeTimers[timer] = timer | |
| 46 | |
| 47 -- Create new timer closure to wrap the "timer" object | |
| 48 timer.callback = function() | |
| 49 if not timer.cancelled then | |
| 50 if type(timer.func) == "string" then | |
| 51 -- We manually set the unpack count to prevent issues with an arg set that contains nil and ends with nil | |
| 52 -- e.g. local t = {1, 2, nil, 3, nil} print(#t) will result in 2, instead of 5. This fixes said issue. | |
| 53 timer.object[timer.func](timer.object, unpack(timer, 1, timer.argsCount)) | |
| 54 else | |
| 55 timer.func(unpack(timer, 1, timer.argsCount)) | |
| 56 end | |
| 57 | |
| 58 if timer.looping and not timer.cancelled then | |
| 59 -- Compensate delay to get a perfect average delay, even if individual times don't match up perfectly | |
| 60 -- due to fps differences | |
| 61 local time = GetTime() | |
| 62 local delay = timer.delay - (time - timer.ends) | |
| 63 -- Ensure the delay doesn't go below the threshold | |
| 64 if delay < 0.01 then delay = 0.01 end | |
| 65 C_TimerAfter(delay, timer.callback) | |
| 66 timer.ends = time + delay | |
| 67 else | |
| 68 activeTimers[timer.handle or timer] = nil | |
| 69 end | |
| 70 end | |
| 71 end | |
| 72 | |
| 73 C_TimerAfter(delay, timer.callback) | |
| 74 return timer | |
| 75 end | |
| 76 | |
| 77 --- Schedule a new one-shot timer. | |
| 78 -- The timer will fire once in `delay` seconds, unless canceled before. | |
| 79 -- @param callback Callback function for the timer pulse (funcref or method name). | |
| 80 -- @param delay Delay for the timer, in seconds. | |
| 81 -- @param ... An optional, unlimited amount of arguments to pass to the callback function. | |
| 82 -- @usage | |
| 83 -- MyAddOn = LibStub("AceAddon-3.0"):NewAddon("MyAddOn", "AceTimer-3.0") | |
| 84 -- | |
| 85 -- function MyAddOn:OnEnable() | |
| 86 -- self:ScheduleTimer("TimerFeedback", 5) | |
| 87 -- end | |
| 88 -- | |
| 89 -- function MyAddOn:TimerFeedback() | |
| 90 -- print("5 seconds passed") | |
| 91 -- end | |
| 92 function AceTimer:ScheduleTimer(func, delay, ...) | |
| 93 if not func or not delay then | |
| 94 error(MAJOR..": ScheduleTimer(callback, delay, args...): 'callback' and 'delay' must have set values.", 2) | |
| 95 end | |
| 96 if type(func) == "string" then | |
| 97 if type(self) ~= "table" then | |
| 98 error(MAJOR..": ScheduleTimer(callback, delay, args...): 'self' - must be a table.", 2) | |
| 99 elseif not self[func] then | |
| 100 error(MAJOR..": ScheduleTimer(callback, delay, args...): Tried to register '"..func.."' as the callback, but it doesn't exist in the module.", 2) | |
| 101 end | |
| 102 end | |
| 103 return new(self, nil, func, delay, ...) | |
| 104 end | |
| 105 | |
| 106 --- Schedule a repeating timer. | |
| 107 -- The timer will fire every `delay` seconds, until canceled. | |
| 108 -- @param callback Callback function for the timer pulse (funcref or method name). | |
| 109 -- @param delay Delay for the timer, in seconds. | |
| 110 -- @param ... An optional, unlimited amount of arguments to pass to the callback function. | |
| 111 -- @usage | |
| 112 -- MyAddOn = LibStub("AceAddon-3.0"):NewAddon("MyAddOn", "AceTimer-3.0") | |
| 113 -- | |
| 114 -- function MyAddOn:OnEnable() | |
| 115 -- self.timerCount = 0 | |
| 116 -- self.testTimer = self:ScheduleRepeatingTimer("TimerFeedback", 5) | |
| 117 -- end | |
| 118 -- | |
| 119 -- function MyAddOn:TimerFeedback() | |
| 120 -- self.timerCount = self.timerCount + 1 | |
| 121 -- print(("%d seconds passed"):format(5 * self.timerCount)) | |
| 122 -- -- run 30 seconds in total | |
| 123 -- if self.timerCount == 6 then | |
| 124 -- self:CancelTimer(self.testTimer) | |
| 125 -- end | |
| 126 -- end | |
| 127 function AceTimer:ScheduleRepeatingTimer(func, delay, ...) | |
| 128 if not func or not delay then | |
| 129 error(MAJOR..": ScheduleRepeatingTimer(callback, delay, args...): 'callback' and 'delay' must have set values.", 2) | |
| 130 end | |
| 131 if type(func) == "string" then | |
| 132 if type(self) ~= "table" then | |
| 133 error(MAJOR..": ScheduleRepeatingTimer(callback, delay, args...): 'self' - must be a table.", 2) | |
| 134 elseif not self[func] then | |
| 135 error(MAJOR..": ScheduleRepeatingTimer(callback, delay, args...): Tried to register '"..func.."' as the callback, but it doesn't exist in the module.", 2) | |
| 136 end | |
| 137 end | |
| 138 return new(self, true, func, delay, ...) | |
| 139 end | |
| 140 | |
| 141 --- Cancels a timer with the given id, registered by the same addon object as used for `:ScheduleTimer` | |
| 142 -- Both one-shot and repeating timers can be canceled with this function, as long as the `id` is valid | |
| 143 -- and the timer has not fired yet or was canceled before. | |
| 144 -- @param id The id of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer` | |
| 145 function AceTimer:CancelTimer(id) | |
| 146 local timer = activeTimers[id] | |
| 147 | |
| 148 if not timer then | |
| 149 return false | |
| 150 else | |
| 151 timer.cancelled = true | |
| 152 activeTimers[id] = nil | |
| 153 return true | |
| 154 end | |
| 155 end | |
| 156 | |
| 157 --- Cancels all timers registered to the current addon object ('self') | |
| 158 function AceTimer:CancelAllTimers() | |
| 159 for k,v in pairs(activeTimers) do | |
| 160 if v.object == self then | |
| 161 AceTimer.CancelTimer(self, k) | |
| 162 end | |
| 163 end | |
| 164 end | |
| 165 | |
| 166 --- Returns the time left for a timer with the given id, registered by the current addon object ('self'). | |
| 167 -- This function will return 0 when the id is invalid. | |
| 168 -- @param id The id of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer` | |
| 169 -- @return The time left on the timer. | |
| 170 function AceTimer:TimeLeft(id) | |
| 171 local timer = activeTimers[id] | |
| 172 if not timer then | |
| 173 return 0 | |
| 174 else | |
| 175 return timer.ends - GetTime() | |
| 176 end | |
| 177 end | |
| 178 | |
| 179 | |
| 180 -- --------------------------------------------------------------------- | |
| 181 -- Upgrading | |
| 182 | |
| 183 -- Upgrade from old hash-bucket based timers to C_Timer.After timers. | |
| 184 if oldminor and oldminor < 10 then | |
| 185 -- disable old timer logic | |
| 186 AceTimer.frame:SetScript("OnUpdate", nil) | |
| 187 AceTimer.frame:SetScript("OnEvent", nil) | |
| 188 AceTimer.frame:UnregisterAllEvents() | |
| 189 -- convert timers | |
| 190 for object,timers in pairs(AceTimer.selfs) do | |
| 191 for handle,timer in pairs(timers) do | |
| 192 if type(timer) == "table" and timer.callback then | |
| 193 local newTimer | |
| 194 if timer.delay then | |
| 195 newTimer = AceTimer.ScheduleRepeatingTimer(timer.object, timer.callback, timer.delay, timer.arg) | |
| 196 else | |
| 197 newTimer = AceTimer.ScheduleTimer(timer.object, timer.callback, timer.when - GetTime(), timer.arg) | |
| 198 end | |
| 199 -- Use the old handle for old timers | |
| 200 activeTimers[newTimer] = nil | |
| 201 activeTimers[handle] = newTimer | |
| 202 newTimer.handle = handle | |
| 203 end | |
| 204 end | |
| 205 end | |
| 206 AceTimer.selfs = nil | |
| 207 AceTimer.hash = nil | |
| 208 AceTimer.debug = nil | |
| 209 elseif oldminor and oldminor < 17 then | |
| 210 -- Upgrade from old animation based timers to C_Timer.After timers. | |
| 211 AceTimer.inactiveTimers = nil | |
| 212 AceTimer.frame = nil | |
| 213 local oldTimers = AceTimer.activeTimers | |
| 214 -- Clear old timer table and update upvalue | |
| 215 AceTimer.activeTimers = {} | |
| 216 activeTimers = AceTimer.activeTimers | |
| 217 for handle, timer in pairs(oldTimers) do | |
| 218 local newTimer | |
| 219 -- Stop the old timer animation | |
| 220 local duration, elapsed = timer:GetDuration(), timer:GetElapsed() | |
| 221 timer:GetParent():Stop() | |
| 222 if timer.looping then | |
| 223 newTimer = AceTimer.ScheduleRepeatingTimer(timer.object, timer.func, duration, unpack(timer.args, 1, timer.argsCount)) | |
| 224 else | |
| 225 newTimer = AceTimer.ScheduleTimer(timer.object, timer.func, duration - elapsed, unpack(timer.args, 1, timer.argsCount)) | |
| 226 end | |
| 227 -- Use the old handle for old timers | |
| 228 activeTimers[newTimer] = nil | |
| 229 activeTimers[handle] = newTimer | |
| 230 newTimer.handle = handle | |
| 231 end | |
| 232 | |
| 233 -- Migrate transitional handles | |
| 234 if oldminor < 13 and AceTimer.hashCompatTable then | |
| 235 for handle, id in pairs(AceTimer.hashCompatTable) do | |
| 236 local t = activeTimers[id] | |
| 237 if t then | |
| 238 activeTimers[id] = nil | |
| 239 activeTimers[handle] = t | |
| 240 t.handle = handle | |
| 241 end | |
| 242 end | |
| 243 AceTimer.hashCompatTable = nil | |
| 244 end | |
| 245 end | |
| 246 | |
| 247 -- --------------------------------------------------------------------- | |
| 248 -- Embed handling | |
| 249 | |
| 250 AceTimer.embeds = AceTimer.embeds or {} | |
| 251 | |
| 252 local mixins = { | |
| 253 "ScheduleTimer", "ScheduleRepeatingTimer", | |
| 254 "CancelTimer", "CancelAllTimers", | |
| 255 "TimeLeft" | |
| 256 } | |
| 257 | |
| 258 function AceTimer:Embed(target) | |
| 259 AceTimer.embeds[target] = true | |
| 260 for _,v in pairs(mixins) do | |
| 261 target[v] = AceTimer[v] | |
| 262 end | |
| 263 return target | |
| 264 end | |
| 265 | |
| 266 -- AceTimer:OnEmbedDisable(target) | |
| 267 -- target (object) - target object that AceTimer is embedded in. | |
| 268 -- | |
| 269 -- cancel all timers registered for the object | |
| 270 function AceTimer:OnEmbedDisable(target) | |
| 271 target:CancelAllTimers() | |
| 272 end | |
| 273 | |
| 274 for addon in pairs(AceTimer.embeds) do | |
| 275 AceTimer:Embed(addon) | |
| 276 end |
