vanilla-wow-addons – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | --[[--------------------------------------------------------------------------------- |
2 | AceHook Library by Cladhaire (cladhaire@gmail.com) |
||
3 | |||
4 | This first section is the standard embedded library stub declaration. This code |
||
5 | manages the versioning between different instances of the AceHooks library. |
||
6 | |||
7 | See http://www.iriel.org/wow/addondev/embedlibrary1.html for more information |
||
8 | ----------------------------------------------------------------------------------]] |
||
9 | |||
10 | local protFuncs = { |
||
11 | CameraOrSelectOrMoveStart = true, CameraOrSelectOrMoveStop = true, |
||
12 | TurnOrActionStart = true, TurnOrActionStop = true, |
||
13 | PitchUpStart = true, PitchUpStop = true, |
||
14 | PitchDownStart = true, PitchDownStop = true, |
||
15 | MoveBackwardStart = true, MoveBackwardStop = true, |
||
16 | MoveForwardStart = true, MoveForwardStop = true, |
||
17 | Jump = true, StrafeLeftStart = true, |
||
18 | StrafeLeftStop = true, StrafeRightStart = true, |
||
19 | StrafeRightStop = true, ToggleMouseMove = true, |
||
20 | ToggleRun = true, TurnLeftStart = true, |
||
21 | TurnLeftStop = true, TurnRightStart = true, |
||
22 | TurnRightStop = true, |
||
23 | } |
||
24 | |||
25 | --[[--------------------------------------------------------------------------------- |
||
26 | AceHooks Library implementation. |
||
27 | -----------------------------------------------------------------------------------]] |
||
28 | |||
29 | local MAJOR_VERSION = "1.4" |
||
30 | local MINOR_VERSION = 2006042401 |
||
31 | local AceHook = {} |
||
32 | |||
33 | -- This is a compatability change for AceHook 1.3 upgrade |
||
34 | if AceHookLib and not AceHookLib.NewVersion then |
||
35 | function AceHookLib:NewVersion(version, minor) |
||
36 | local versionData = self.versions[version] |
||
37 | if not versionData or versionData.minor < minor then return true end |
||
38 | end |
||
39 | end |
||
40 | |||
41 | -- Only declare this class if necessary |
||
42 | if not AceHookLib or AceHookLib:NewVersion(MAJOR_VERSION, MINOR_VERSION) then |
||
43 | |||
44 | function AceHook:GetLibraryVersion() |
||
45 | return MAJOR_VERSION, MINOR_VERSION |
||
46 | end |
||
47 | |||
48 | function AceHook:LibActivate(stub, oldLib, oldList) |
||
49 | local maj, min = self:GetLibraryVersion() |
||
50 | |||
51 | if oldLib then |
||
52 | for i,namespace in pairs(oldLib.embedList or {}) do |
||
53 | self:Embed(namespace) |
||
54 | end |
||
55 | end |
||
56 | |||
57 | -- Return nil to force the instance copy. |
||
58 | return nil |
||
59 | end |
||
60 | |||
61 | function AceHook:HookDebug(msg) |
||
62 | local maj,min = MAJOR_VERSION, MINOR_VERSION |
||
63 | if DEFAULT_CHAT_FRAME then |
||
64 | DEFAULT_CHAT_FRAME:AddMessage("[|cffffff00AceHook "..maj.."|r] " .. tostring(msg)) |
||
65 | else |
||
66 | print("[AceHook "..maj.."] " .. tostring(msg)) |
||
67 | end |
||
68 | end |
||
69 | |||
70 | --[[---------------------------------------------------------------------- |
||
71 | AceHook:Hook |
||
72 | self:Hook("functionName", ["handlerName" | handler]) |
||
73 | self:Hook(ObjectName, "Method", ["Handler" | handler]) |
||
74 | -------------------------------------------------------------------------]] |
||
75 | function AceHook:Hook(arg1, arg2, arg3) |
||
76 | if not self.Hooks then self.Hooks = {} end |
||
77 | if type(arg1)== "string" then |
||
78 | if protFuncs[arg1] then |
||
79 | local name = self.name |
||
80 | |||
81 | if not name then |
||
82 | local g = getfenv(0) |
||
83 | |||
84 | for k,v in pairs(g) do |
||
85 | if v == self then |
||
86 | name = k |
||
87 | break |
||
88 | end |
||
89 | end |
||
90 | end |
||
91 | |||
92 | if name then |
||
93 | error(tostring(name) .. " tried to hook " .. arg1 .. ", which is a Blizzard protected function.",3) |
||
94 | else |
||
95 | self:HookDebug("An Addon tried to hook " .. arg1 .. ", which is a Blizzard protected function.") |
||
96 | end |
||
97 | else |
||
98 | self:HookFunc(arg1, arg2) |
||
99 | end |
||
100 | else |
||
101 | self:HookMeth(arg1, arg2, arg3) |
||
102 | end |
||
103 | end |
||
104 | |||
105 | function AceHook:HookScript(arg1, arg2, arg3) |
||
106 | if not self.Hooks then self.Hooks = {} end |
||
107 | |||
108 | self:HookMeth(arg1, arg2, arg3, true) |
||
109 | end |
||
110 | |||
111 | --[[---------------------------------------------------------------------- |
||
112 | AceHook:IsHooked() |
||
113 | self:Hook("functionName") |
||
114 | self:Hook(ObjectName, "Method") |
||
115 | |||
116 | Returns whether or not the given function is hooked in the current |
||
117 | namespace. A hooked, but inactive function is considered NOT |
||
118 | hooked in this context. |
||
119 | -------------------------------------------------------------------------]] |
||
120 | function AceHook:IsHooked(obj, method) |
||
121 | if method and obj then |
||
122 | if self.Hooks and self.Hooks[obj] and self.Hooks[obj][method] and self.Hooks[obj][method].active then |
||
123 | return true |
||
124 | end |
||
125 | else |
||
126 | if self.Hooks and self.Hooks[obj] and self.Hooks[obj].active then |
||
127 | return true |
||
128 | end |
||
129 | end |
||
130 | |||
131 | return false |
||
132 | end |
||
133 | |||
134 | --[[---------------------------------------------------------------------- |
||
135 | AceHook:Unhook |
||
136 | self:Unhook("functionName") |
||
137 | self:Unhook(ObjectName, "Method") |
||
138 | -------------------------------------------------------------------------]] |
||
139 | function AceHook:Unhook(arg1, arg2) |
||
140 | if type(arg1) == "string" then |
||
141 | self:UnhookFunc(arg1) |
||
142 | else |
||
143 | self:UnhookMeth(arg1, arg2) |
||
144 | end |
||
145 | end |
||
146 | |||
147 | --[[---------------------------------------------------------------------- |
||
148 | AceHook:UnhookAll - Unhooks all active hooks from the calling source |
||
149 | -------------------------------------------------------------------------]] |
||
150 | function AceHook:UnhookAll(script) |
||
151 | if not self.Hooks then return end |
||
152 | for key, value in pairs(self.Hooks) do |
||
153 | if type(key) == "table" then |
||
154 | for method in pairs(value) do |
||
155 | if (self.Hooks[key][method].script == script) then |
||
156 | self:Unhook(key, method) |
||
157 | end |
||
158 | end |
||
159 | else |
||
160 | self:Unhook(key) |
||
161 | end |
||
162 | end |
||
163 | end |
||
164 | |||
165 | function AceHook:UnhookAllScripts() |
||
166 | self:UnhookAll(true) |
||
167 | end |
||
168 | |||
169 | --[[---------------------------------------------------------------------- |
||
170 | AceHook:Print - Utility function for HookReport, for embedding |
||
171 | AceHook:HookReport - Lists registered hooks from this source |
||
172 | -------------------------------------------------------------------------]] |
||
173 | |||
174 | function AceHook:HookReport() |
||
175 | self:HookDebug("This is a list of all active hooks for this object:") |
||
176 | if not self.Hooks then self:HookDebug("No registered hooks.") return end |
||
177 | |||
178 | for key, value in pairs(self.Hooks) do |
||
179 | if type(key) == "table" then |
||
180 | for method in pairs(value) do |
||
181 | self:HookDebug("key: "..tostring(key).." method: "..tostring(method)..((self.Hooks[key][method].active and "|cff00ff00 Active" or "|cffffff00 Inactive"))) |
||
182 | end |
||
183 | else |
||
184 | self:HookDebug("key: " .. tostring(key) .. " value: " .. tostring(value) .. ((self.Hooks[key].active and "|cff00ff00 Active" or "|cffffff00 Inactive"))) |
||
185 | end |
||
186 | end |
||
187 | end |
||
188 | |||
189 | --[[---------------------------------------------------------------------- |
||
190 | AceHook:CallHook("functionName" [, arg1, arg2, arg3, ...]) |
||
191 | AceHook:CallHook(ObjectName, "Method" [, arg1, arg2, arg3, ...]) |
||
192 | |||
193 | DEPRECATED: This function has been deprecated and replaced by a direct |
||
194 | call from the self.Hooks table. This avoids function calls and decreases |
||
195 | the overhead from a CallHook. The new wrapper functions limit any |
||
196 | CallHook to 20 arguments. The new forms are as follows: |
||
197 | |||
198 | self.Hooks.functionName.orig(arg1, arg2, arg3) |
||
199 | self.Hooks[ObjectName].MethodName.orig(ObjectName, arg1, arg2, arg3) |
||
200 | -------------------------------------------------------------------------]] |
||
201 | |||
202 | function AceHook:CallHook(obj,meth,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
203 | if type(obj) == "string" then |
||
204 | -- Function Call |
||
205 | if not self.Hooks or not self.Hooks[obj] then |
||
206 | self:HookDebug( "Attempt to CallHook when no hook exists for " .. obj) |
||
207 | return |
||
208 | else |
||
209 | local func = obj |
||
210 | return self.Hooks[func].orig(meth,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
211 | end |
||
212 | else |
||
213 | if not self.Hooks[obj] or not self.Hooks[obj][meth] then |
||
214 | self:HookDebug( "Attempt to CallHook when no hook exists for " .. tostring(meth)) |
||
215 | return |
||
216 | else |
||
217 | return self.Hooks[obj][meth].orig(obj,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
218 | end |
||
219 | end |
||
220 | end |
||
221 | |||
222 | --[[---------------------------------------------------------------------- |
||
223 | AceHook:HookFunc - internal method. |
||
224 | o You can only hook each function once from each source. |
||
225 | o If there is an inactive hook for this func/handler pair, we reactivate it |
||
226 | o If there is an inactive hook for another handler, we error out. |
||
227 | o Looks for handler as a method of the calling class, error if not available |
||
228 | o If handler is a function, it just uses it directly through the wrapper |
||
229 | -------------------------------------------------------------------------]] |
||
230 | function AceHook:HookFunc(func, handler) |
||
231 | local f = getglobal(func) |
||
232 | |||
233 | if not f or type(f) ~= "function" then |
||
234 | self:HookDebug("Attempt to hook a non-existant function '"..func.."'.",3) |
||
235 | return |
||
236 | end |
||
237 | |||
238 | if not handler then handler = func end |
||
239 | |||
240 | if self.Hooks[func] then |
||
241 | -- We have an active hook from this source. Don't multi-hook |
||
242 | if self.Hooks[func].active then |
||
243 | self:HookDebug( func .. " already has an active hook from this source.") |
||
244 | return |
||
245 | end |
||
246 | -- The hook is inactive, so reactivate it |
||
247 | if self.Hooks[func].handler == handler then |
||
248 | self.Hooks[func].active = true |
||
249 | return |
||
250 | else |
||
251 | error( "There is a stale hook for " .. func .. " can't hook or reactivate.",3) |
||
252 | end |
||
253 | end |
||
254 | |||
255 | local methodHandler |
||
256 | |||
257 | if type(handler) == "string" then |
||
258 | if self[handler] then |
||
259 | methodHandler = true |
||
260 | else |
||
261 | error( "Could not find the the handler " ..handler.." when hooking function " .. func,3) |
||
262 | end |
||
263 | elseif type(handler) ~= "function" then |
||
264 | error( "Could not find the handler you supplied when hooking " .. func,3) |
||
265 | end |
||
266 | |||
267 | self.Hooks[func] = {} |
||
268 | self.Hooks[func].orig = f |
||
269 | self.Hooks[func].active = true |
||
270 | self.Hooks[func].handler = handler |
||
271 | self.Hooks[func].func = self:_getFunctionHook(func, handler, methodHandler) |
||
272 | setglobal(func, self.Hooks[func].func) |
||
273 | end |
||
274 | |||
275 | --[[---------------------------------------------------------------------- |
||
276 | AceHook:UnhookFunc - internal method |
||
277 | o If you attempt to unhook a function that has never been hooked, or to unhook in a |
||
278 | system that has never had a hook before, the system will error with a stack trace |
||
279 | o If we own the global function, then put the original back in its place and remove |
||
280 | all references to the Hooks[func] structure. |
||
281 | o If we don't own the global function (we've been hooked) we deactivate the hook, |
||
282 | forcing the handler to passthrough. |
||
283 | -------------------------------------------------------------------------]] |
||
284 | function AceHook:UnhookFunc(func) |
||
285 | if not self.Hooks or not self.Hooks[func] then |
||
286 | self:HookDebug("Tried to unhook '" ..func .. "' which is not currently hooked.") |
||
287 | return |
||
288 | end |
||
289 | if self.Hooks[func].active then |
||
290 | -- See if we own the global function |
||
291 | if getglobal(func) == self.Hooks[func].func then |
||
292 | setglobal(func, self.Hooks[func].orig) |
||
293 | self.Hooks[func] = nil |
||
294 | -- Magically all-done |
||
295 | else |
||
296 | self.Hooks[func].active = nil |
||
297 | end |
||
298 | end |
||
299 | end |
||
300 | |||
301 | --[[---------------------------------------------------------------------- |
||
302 | AceHook:_getFunctionHook- internal method |
||
303 | -------------------------------------------------------------------------]] |
||
304 | |||
305 | function AceHook:_getFunctionHook(func, handler, methodHandler) |
||
306 | if methodHandler then |
||
307 | -- The handler is a method, need to self it |
||
308 | return |
||
309 | function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
310 | if self.Hooks[func].active then |
||
311 | return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
312 | else |
||
313 | return self.Hooks[func].orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
314 | end |
||
315 | end |
||
316 | else |
||
317 | -- The handler is a function, just call it |
||
318 | return |
||
319 | function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
320 | if self.Hooks[func].active then |
||
321 | return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
322 | else |
||
323 | return self.Hooks[func].orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
324 | end |
||
325 | end |
||
326 | end |
||
327 | end |
||
328 | |||
329 | --[[---------------------------------------------------------------------- |
||
330 | AceHook:HookMeth - Takes an optional fourth argument |
||
331 | o script - Signifies whether this is a script hook or not |
||
332 | -------------------------------------------------------------------------]] |
||
333 | |||
334 | function AceHook:HookMeth(obj, method, handler, script) |
||
335 | if not handler then handler = method end |
||
336 | if (not obj or type(obj) ~= "table") then |
||
337 | error("The object you supplied could not be found, or isn't a table.", 3) |
||
338 | end |
||
339 | |||
340 | if self.Hooks[obj] and self.Hooks[obj][method] then |
||
341 | -- We have an active hook from this source. Don't multi-hook |
||
342 | if self.Hooks[obj][method].active then |
||
343 | self:HookDebug( method .. " already has an active hook from this source.") |
||
344 | return |
||
345 | end |
||
346 | -- The hook is inactive, so reactivate it. |
||
347 | if self.Hooks[obj][method].handler == handler then |
||
348 | self.Hooks[obj][method].active = true |
||
349 | return |
||
350 | else |
||
351 | error( "There is a stale hook for " .. method .. " can't hook or reactivate.",3) |
||
352 | end |
||
353 | end |
||
354 | -- We're clear to try the hook, let's make some checks first |
||
355 | local methodHandler |
||
356 | if type(handler) == "string" then |
||
357 | if self[handler] then |
||
358 | methodHandler = true |
||
359 | else |
||
360 | error( "Could not find the handler ("..handler..") you supplied when hooking method " .. method,3) |
||
361 | end |
||
362 | elseif type(handler) ~= "function" then |
||
363 | error( "Could not find the handler you supplied when hooking method " .. method,3) |
||
364 | end |
||
365 | -- Handler has been found, so now try to find the method we're trying to hook |
||
366 | local orig, setscript |
||
367 | -- Script |
||
368 | if script then |
||
369 | if not obj.GetScript then |
||
370 | error("The object you supplied does not have a GetScript method.", 3) |
||
371 | end |
||
372 | if not obj:HasScript(method) then |
||
373 | error("The object you supplied doesn't allows the " .. method .. " method.", 3) |
||
374 | end |
||
375 | -- Sometimes there is not a original function for a script. |
||
376 | orig = obj:GetScript(method) or function () end |
||
377 | -- Method |
||
378 | else |
||
379 | orig = obj[method] |
||
380 | end |
||
381 | if not orig then |
||
382 | error("Could not find the method or script ("..method..") you are trying to hook.",3) |
||
383 | end |
||
384 | if not self.Hooks[obj] then self.Hooks[obj] = {} end |
||
385 | self.Hooks[obj][method] = {} |
||
386 | self.Hooks[obj][method].orig = orig |
||
387 | self.Hooks[obj][method].active = true |
||
388 | self.Hooks[obj][method].handler = handler |
||
389 | self.Hooks[obj][method].script = script |
||
390 | self.Hooks[obj][method].func = self:_getMethodHook(obj, method, handler, methodHandler) |
||
391 | if script then |
||
392 | obj:SetScript(method, self.Hooks[obj][method].func) |
||
393 | else |
||
394 | obj[method] = self.Hooks[obj][method].func |
||
395 | end |
||
396 | end |
||
397 | |||
398 | --[[---------------------------------------------------------------------- |
||
399 | AceHook:UnhookMeth - Internal method |
||
400 | o If you attempt to unhook a method that has never been hooked, or to unhook in a |
||
401 | system that has never had a hook before, the system will error with a stack trace |
||
402 | o If we own the global method, then put the original back in its place and remove |
||
403 | all references to the Hooks[obj][method] structure. |
||
404 | o If we don't own the global method (we've been hooked) we deactivate the hook, |
||
405 | forcing the handler to passthrough. |
||
406 | -------------------------------------------------------------------------]] |
||
407 | function AceHook:UnhookMeth(obj, method) |
||
408 | if not self.Hooks or not self.Hooks[obj] or not self.Hooks[obj][method] then |
||
409 | self:HookDebug("Attempt to unhook a method ("..method..") that is not currently hooked.") |
||
410 | return |
||
411 | end |
||
412 | if self.Hooks[obj][method].active then |
||
413 | -- If this is a script |
||
414 | if self.Hooks[obj][method].script then |
||
415 | if obj:GetScript(method) == self.Hooks[obj][method].func then |
||
416 | -- We own the global function. Kill it. |
||
417 | obj:SetScript(method, self.Hooks[obj][method].orig) |
||
418 | self.Hooks[obj][method] = nil |
||
419 | return |
||
420 | else |
||
421 | self.Hooks[obj][method].active = nil |
||
422 | end |
||
423 | else |
||
424 | if obj[method] == self.Hooks[obj][method].func then |
||
425 | -- We own the global function. Kill it. |
||
426 | obj[method] = self.Hooks[obj][method].orig |
||
427 | self.Hooks[obj][method] = nil |
||
428 | return |
||
429 | else |
||
430 | self.Hooks[obj][method].active = nil |
||
431 | end |
||
432 | end |
||
433 | end |
||
434 | if not next(self.Hooks[obj]) then |
||
435 | -- Spank the table |
||
436 | self.Hooks[obj] = nil |
||
437 | end |
||
438 | end |
||
439 | |||
440 | --[[---------------------------------------------------------------------- |
||
441 | AceHook:_getMethodHook - Internal Method |
||
442 | -------------------------------------------------------------------------]] |
||
443 | function AceHook:_getMethodHook(obj, method, handler, methodHook) |
||
444 | if methodHook then |
||
445 | -- The handler is a method, need to self it |
||
446 | return |
||
447 | function(o,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
448 | if self.Hooks[obj][method].active then |
||
449 | return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
450 | elseif self.Hooks[obj][method].orig then |
||
451 | return self.Hooks[obj][method].orig(obj, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
452 | end |
||
453 | end |
||
454 | else |
||
455 | -- The handler is a function, just call it |
||
456 | return |
||
457 | function(o,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
458 | if self.Hooks[obj][method].active then |
||
459 | return handler(o,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
460 | elseif self.Hooks[obj][method].orig then |
||
461 | return self.Hooks[obj][method].orig(obj,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
462 | end |
||
463 | end |
||
464 | end |
||
465 | end |
||
466 | |||
467 | --[[---------------------------------------------------------------------- |
||
468 | AceHook:Embed - Called to embed the vital methods into another object |
||
469 | -------------------------------------------------------------------------]] |
||
470 | function AceHook:Embed(object) |
||
471 | object.Hook = self.Hook |
||
472 | object.Unhook = self.Unhook |
||
473 | object.UnhookAll = self.UnhookAll |
||
474 | object.CallHook = self.CallHook |
||
475 | object.HookFunc = self.HookFunc |
||
476 | object.HookMeth = self.HookMeth |
||
477 | object.UnhookFunc = self.UnhookFunc |
||
478 | object.UnhookMeth = self.UnhookMeth |
||
479 | object._getFunctionHook = self._getFunctionHook |
||
480 | object._getMethodHook = self._getMethodHook |
||
481 | object.HookReport = self.HookReport |
||
482 | object.IsHooked = self.IsHooked |
||
483 | |||
484 | object.HookScript = self.HookScript |
||
485 | object.UnhookScript = self.Unhook |
||
486 | object.UnhookAllScripts = self.UnhookAllScripts |
||
487 | object.CallScript = self.CallHook |
||
488 | |||
489 | if object.debug then |
||
490 | object.HookDebug = object.debug |
||
491 | else |
||
492 | object.HookDebug = self.HookDebug |
||
493 | end |
||
494 | end |
||
495 | end -- End conditional declaration |
||
496 | |||
497 | --[[--------------------------------------------------------------------------------- |
||
498 | This is the stub declaration for non-Ace environments |
||
499 | ----------------------------------------------------------------------------------]] |
||
500 | |||
501 | if not AceLibStub then |
||
502 | AceLibStub = {} |
||
503 | |||
504 | -- Instance replacement method. Handles "upgrading" to a new version |
||
505 | function AceLibStub:ReplaceInstance(old,new) |
||
506 | for k,v in pairs(old) do old[k]=nil end |
||
507 | for k,v in pairs(new) do old[k]=v end |
||
508 | end |
||
509 | |||
510 | -- Returns a new stub. This allows multiple libraries to use the same stub |
||
511 | function AceLibStub:NewStub(name) |
||
512 | local newStub = {} |
||
513 | self:ReplaceInstance(newStub, self) |
||
514 | newStub.versions = {} |
||
515 | newStub.libName = name |
||
516 | return newStub |
||
517 | end |
||
518 | |||
519 | -- Returns true if the supplied version would be an upgrade to the current version |
||
520 | -- This allows for bypass code in library declaration. |
||
521 | |||
522 | function AceLibStub:NewVersion(version, minor) |
||
523 | local versionData = self.versions[version] |
||
524 | if not versionData or versionData.minor < minor then return true end |
||
525 | end |
||
526 | |||
527 | -- Handles referencing methods in the calling namespace itself, to accomplish |
||
528 | -- inheritance instead of composition. This will not be used in every library |
||
529 | -- but its important to track what namespaces have used :Embed() since |
||
530 | -- :ReplaceInstance() won't update those references. |
||
531 | |||
532 | function AceLibStub:Embed(namespace, version) |
||
533 | local lib = self:GetInstance(version) |
||
534 | if not lib.Embed then return end |
||
535 | |||
536 | lib:Embed(namespace) |
||
537 | |||
538 | if not lib.embedList then |
||
539 | lib.embedList = setmetatable({}, {__mode="v"}) |
||
540 | end |
||
541 | |||
542 | table.insert(lib.embedList, namespace) |
||
543 | lib = nil |
||
544 | end |
||
545 | |||
546 | -- Returns the most recent version of the given major library |
||
547 | function AceLibStub:GetInstance(version) |
||
548 | if not version then |
||
549 | error("You must specify a version when requesting a library instance" ,2) |
||
550 | end |
||
551 | |||
552 | local versionData = self.versions[version] |
||
553 | if not versionData then |
||
554 | error("Cannot find " .. self.libName .. " instance with version '" .. version .. "'",2) |
||
555 | return |
||
556 | end |
||
557 | return versionData.instance |
||
558 | end |
||
559 | |||
560 | -- Registers a new version of a given library. Takes the library object. |
||
561 | function AceLibStub:Register(newInstance) |
||
562 | if not newInstance.GetLibraryVersion then return end |
||
563 | local version,minor = newInstance:GetLibraryVersion() |
||
564 | local versionData = self.versions[version] |
||
565 | if not versionData then |
||
566 | -- This is new |
||
567 | versionData = { instance=newInstance, minor=minor, old={}} |
||
568 | self.versions[version] = versionData |
||
569 | newInstance:LibActivate(self) |
||
570 | return newInstance |
||
571 | end |
||
572 | if minor <= versionData.minor then |
||
573 | -- This one is already obsolete |
||
574 | if newInstance.LibDiscard then |
||
575 | newInstance:LibDiscard() |
||
576 | end |
||
577 | return versionData.instance |
||
578 | end |
||
579 | |||
580 | -- This is an update |
||
581 | local oldInstance = versionData.instance |
||
582 | local oldList = versionData.old |
||
583 | versionData.instance = newInstance |
||
584 | versionData.minor = minor |
||
585 | local skipCopy = newInstance:LibActivate(self, oldInstance, oldList) |
||
586 | table.insert(oldList, oldInstance) |
||
587 | if not skipCopy then |
||
588 | for i,old in ipairs(oldList) do |
||
589 | self:ReplaceInstance(old, newInstance) |
||
590 | end |
||
591 | end |
||
592 | return newInstance |
||
593 | end |
||
594 | end |
||
595 | |||
596 | --[[--------------------------------------------------------------------------------- |
||
597 | Stub and Library registration |
||
598 | ----------------------------------------------------------------------------------]] |
||
599 | |||
600 | -- Bind a stub in the global namespace if it doesn't already exist |
||
601 | if not AceHookLib then |
||
602 | AceHookLib = AceLibStub:NewStub("AceHook") |
||
603 | end |
||
604 | |||
605 | -- Register this library version with the global stub |
||
606 | AceHookLib:Register(AceHook) |
||
607 | AceHook = nil |