vanilla-wow-addons – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | --[[ |
2 | |||
3 | Sea Hooks (mostly Sea.util) |
||
4 | |||
5 | A Mini-Library for standardized function and frame script element hooks. |
||
6 | |||
7 | Compiler: |
||
8 | AnduinLothar (karlkfi@cosmosui.org) |
||
9 | |||
10 | Contributors: |
||
11 | Thott (thott@thottbot.com) |
||
12 | Legorol (legorol@cosmosui.org) |
||
13 | Mugendai (mugekun@gmail.com) |
||
14 | |||
15 | |||
16 | ==Installation/Utilization== |
||
17 | |||
18 | Embedding: |
||
19 | - Drop the SeaHooks folder into your Interface\AddOns\YourAddon\ folder |
||
20 | - Add Sea and SeaHooks as optional dependancies |
||
21 | - Add the following line to the end of your TOC file, before your addon files: |
||
22 | SeaHooks\SeaHooks.lua |
||
23 | |||
24 | Standard: |
||
25 | - Drop the SeaHooks folder into your Interface\AddOns\ directory |
||
26 | - Add SeaHooks a required dependancy |
||
27 | |||
28 | |||
29 | Change Log: |
||
30 | v0.6 |
||
31 | - Fixed bug preventing propper unhooking |
||
32 | - Synced with Sea v1.11 |
||
33 | v0.5 |
||
34 | - Only one replace hook is now called for each hook call, unless it returns true as arg1 |
||
35 | - Old style table passing of return arguments as a table is again honored, but not encouraged. All other return value must be nil except fro arg1 (non-nil) and arg2 (argument table) |
||
36 | v0.4
- Optimized split, getValue and setValue for speed and GC (thanks Iriel and krka)
- Removed cleanArgs. Slow and pointless.
- Changed internal SeaHooks_debugErrorPrint syntax to match Sea.io.dprintfc syntax for easy conversion to Sea
- Code Synced with Sea 1.07
v0.3
- Fixed Bug: causing no return from hooked functions where no return replacement was supplied
- Fixed Oversight: causing a return to Frame Script Elements (which don't take any)
- Fixed Oversight: sloppy Sea.util.unhook mirroring
- Hook definitions now use an object refrence rather than a name to save on indexing (Thanks Iriel for suggestion)
- Added Feature: You can now modify return values from either a 'replace' that hides the orig func or an 'after' hook
- Added Feature: Added Error Debug and Vebose Debug by hook function name
/script Sea.util.debugHooks(enabled, verboseHookName)
enabled - boolean, verboseHookName - string equal to 'orig' passed to hook function (nil to disable)
Note: enabling debug usually incurs a heavier proc load and can cause slow down when used with OnUpdate hooks.
- Added Feature: current return values from a hooked function are availible to 'after' hooks via global return variables: Sea.util.returnArgs[1-20]
Note: These arguments are only availible for the durration of the 'after' hook call.
Also, if you call any function within the 'after' hook that would lead to the call of another 'after' hook call then the global Sea.util.returnArgs would most likely change.
Thus it is highly recommend you grab whatever return arguments you need at the beginning of the function call and assign them to local variables.
This method preserves reverse compatibility as well as avoids table creation and thus does not effect GC.
You can also use Sea.util.getReturnArgs() to unpack them for you. Ex: local arg1, arg2 = Sea.util.getReturnArgs();
- Cleaned up comments and code readability
- Added Feature: Sea.util.cleanArgs eliminates trailing nils in a list of arguments. Used in the hook functions to mask the 20 arguments utilized to avoid GC.
Ex: Sea.util.cleanArgs("a", nil, "b", nil, nil) == "a", nil, "b"
- Now stores a refrence of the hooked function handler in the database to facilitate future overhook recognition |
||
37 | v0.2
- Added input argument modification using a 'before' hook.
If you return true as the the first arg from a before hook function
the subsequent arguments will be the arguments fed to each hook function called afterwards as well as the orig function.
EX: if your before hook returned (true, nil, 10) then the next hook would be called as func(nil, 10), as would the orig(nil, 10)
This allows you to modify a function output without destroying or hiding the orig function, allowing additional hooks to be called without conflicting functionality. |
||
38 | v0.1 (Alpha)
- SeaHooks Forked into Mini-Library from the main Sea. Still backwards compatible. |
||
39 |
|
||
40 |
|
||
41 | $LastChangedBy: karlkfi $ |
||
42 | $Rev: 2577 $ |
||
43 | $Date: 2005-10-10 14:44:01 -0700 (Mon, 10 Oct 2005) $ |
||
44 | ]]-- |
||
45 |
|
||
46 | local SEA_HOOKS_VERSION = 0.60; |
||
47 | local loadThisEmbeddedInstance; |
||
48 | local SeaHooks_hookInit, SeaHooks_getDynamicHookHandler, SeaHooks_hookHandler, SeaHooks_hookHandlerQuick, SeaHooks_hookHandlerDebug, SeaHooks_assignReturnArgs, SeaHooks_debugErrorPrint; |
||
49 | SEA_HOOKS_DEBUG = nil; |
||
50 | SEA_HOOKS_DEBUG_VERBOSE = nil; |
||
51 |
|
||
52 | ------------------------------------------------------------------------------ |
||
53 | --[[ Embedded Sub-Library Load Algorithm ]]-- |
||
54 | ------------------------------------------------------------------------------ |
||
55 |
|
||
56 | if(not Sea) then |
||
57 | Sea = {}; |
||
58 | Sea.versions = {}; |
||
59 | Sea.versions.SeaHooks = SEA_HOOKS_VERSION; |
||
60 | loadThisEmbeddedInstance = true; |
||
61 | Sea.util = {}; |
||
62 | Sea.util.Hooks = {}; |
||
63 | Sea.util.valueTable = {}; |
||
64 | Sea.util.returnArgs = {}; |
||
65 | else |
||
66 | if(not Sea.versions) then |
||
67 | Sea.versions = {}; |
||
68 | end |
||
69 | |||
70 | |||
71 | loadThisEmbeddedInstance = true; |
||
72 | end |
||
73 | if(not Sea.util) then |
||
74 | Sea.util = {}; |
||
75 | |||
76 | if(not Sea.util.Hooks) then |
||
77 | --Is preserved from any previously loaded embedded SeaHook to so that OnLoad triggered hooks from already loaded addons are not lost. |
||
78 | Sea.util.Hooks = {}; |
||
79 | end |
||
80 | if ( not Sea.util.valueTable ) then |
||
81 | |||
82 | end |
||
83 | if ( not Sea.util.returnArgs ) then |
||
84 | Sea.util.returnArgs = {}; |
||
85 | |||
86 | end |
||
87 |
|
||
88 | if (loadThisEmbeddedInstance) then |
||
89 | loadThisEmbeddedInstance = nil; |
||
90 |
|
||
91 |
|
||
92 | ------------------------------------------------------------------------------ |
||
93 | --[[ Function and Frame Script Element Hooking - User Functions ]]-- |
||
94 | ------------------------------------------------------------------------------ |
||
95 |
|
||
96 | -- |
||
97 | -- Sea.util.hook( string originalFunctionNameOrFrameName, string newFunction, string hooktype, string scriptElementName ) |
||
98 | -- |
||
99 | -- Hooks a function. |
||
100 | -- |
||
101 | -- Example: |
||
102 | -- Sea.util.hook("some_function","my_function","hide|before|replace|after"); |
||
103 | -- Sea.util.hook("some_frame_name","my_function","hide|before|replace|after", "some_script_element_name"); |
||
104 | -- |
||
105 | -- Hook types :
-- "hide" - call "my_function" instead of "some_function". If you return true, subsequent hooks will be called afterwards, otherwise no further hooks nor the orig function will be called.
-- "before" - call "my_function" before "some_function". If you return true, the subsequent args will be fed into the calls of the orig function as well as any other functions that hook "some_function".
-- "replace" - call instead of "some_function". If you return true, the orig function will be called afterwards, otherwise subsequent args will be returned by the hooked function call.
-- "after" - called after "some_function". If you return true subsequent args will be returned by the hooked function call. |
||
106 | -- |
||
107 | -- |
||
108 | -- Written by Thott (thott@thottbot.com) |
||
109 | -- Rewritten by AnduinLothar (karlkfi@cosmosui.org) |
||
110 | Sea.util.hook = function ( orig, new, hooktype, scriptElementName ) |
||
111 | if(not hooktype) then |
||
112 | hooktype = "before"; |
||
113 | end |
||
114 | local compoundOrig = orig; |
||
115 | if (scriptElementName) then |
||
116 | compoundOrig = orig.."."..scriptElementName; |
||
117 | |||
118 | SeaHooks_debugErrorPrint((SEA_HOOKS_DEBUG and (SEA_HOOKS_DEBUG_VERBOSE==compoundOrig)), nil, NORMAL_FONT_COLOR, "SeaHooks Progress: Hooking ", orig, " to ", new, ", hooktype ", hooktype, ", scriptElementName ", scriptElementName); |
||
119 | local newFunc = new; |
||
120 | |||
121 | |||
122 | end |
||
123 |
|
||
124 | local hookObj = Sea.util.Hooks[compoundOrig]; |
||
125 | |||
126 | hookObj = SeaHooks_hookInit(orig, compoundOrig, scriptElementName); |
||
127 | else |
||
128 | for key,value in hookObj[hooktype] do |
||
129 | -- NOTE THIS SHOULD BE VALUE! VALUE! *NOT* KEY! (checking if the functions are the same, even if the names are different) |
||
130 | -- If the function is found previously inserted, it will not rehook |
||
131 | -- If the function is not found, the new function will be inserted at the end |
||
132 | if(value == newFunc) then |
||
133 | SeaHooks_debugErrorPrint((SEA_HOOKS_DEBUG and (SEA_HOOKS_DEBUG_VERBOSE==compoundOrig)), nil, NORMAL_FONT_COLOR, "SeaHooks Progress: Already hooked '", compoundOrig, "' with '", new, "' skipping."); |
||
134 | return; |
||
135 | end |
||
136 | end |
||
137 | end |
||
138 | -- intentionally will error if bad hooktype is passed |
||
139 | local currKey = table.getn(hookObj[hooktype])+1; |
||
140 | table.insert(hookObj[hooktype], currKey, newFunc); |
||
141 | hookObj.count = hookObj.count + 1; --increment hook counter |
||
142 |
|
||
143 | -- Adds a ["#Info"] table for preserving reverse compatibility while passing the frame name of the frame that called the hook, for debug. |
||
144 | local infoKey = currKey.."Info"; |
||
145 | local embeddedTable = hookObj[hooktype][infoKey]; |
||
146 | if (type(embeddedTable) ~= "table") then |
||
147 | embeddedTable = {}; |
||
148 | end |
||
149 | if (this) and (this:GetName()) then |
||
150 | embeddedTable.parent = this:GetName(); |
||
151 | else |
||
152 | embeddedTable.parent = 'unknown'; |
||
153 | end |
||
154 | embeddedTable.name = new; |
||
155 | hookObj[hooktype][infoKey] = embeddedTable; --repackage current hook info into hookObj |
||
156 |
|
||
157 | |||
158 | end |
||
159 |
|
||
160 | -- |
||
161 | -- Sea.util.unhook( string originalFunctionNameOrFrameName, string newFunction, string hooktype, string scriptElementName ) |
||
162 | -- |
||
163 | -- Unhooks a function |
||
164 | -- |
||
165 | -- Example: |
||
166 | -- Sea.util.unhook("some_blizzard_function","my_function","before|after|hide|replace"); |
||
167 | -- Sea.util.unhook("some_frame_name","my_function","before|after|hide|replace", "some_script_element_name"); |
||
168 | -- |
||
169 | -- This will remove a function hooked by Sea.util.hook. |
||
170 | -- |
||
171 | -- Written by Thott (thott@thottbot.com) |
||
172 | -- Rewritten by AnduinLothar (karlkfi@cosmosui.org) |
||
173 | Sea.util.unhook = function ( orig, new, hooktype, scriptElementName ) |
||
174 | if(not hooktype) then |
||
175 | hooktype = "before"; |
||
176 | |||
177 | local compoundOrig = orig; |
||
178 | if (scriptElementName) then |
||
179 | compoundOrig = orig.."."..scriptElementName; |
||
180 | end |
||
181 | SeaHooks_debugErrorPrint((SEA_HOOKS_DEBUG and (SEA_HOOKS_DEBUG_VERBOSE==compoundOrig)), nil, NORMAL_FONT_COLOR, "SeaHooks Progress: Unhooking ", orig, " to ", new, ", hooktype ", hooktype, ", scriptElementName ", scriptElementName); |
||
182 | local newFunc = new; |
||
183 | if ( type(new) ~= "function" ) then |
||
184 | newFunc = Sea.util.getValue(new); |
||
185 | end |
||
186 | local hookObj = Sea.util.Hooks[compoundOrig]; |
||
187 | if(not hookObj) then |
||
188 | hookObj = SeaHooks_hookInit(orig, compoundOrig, scriptElementName); |
||
189 | else |
||
190 | |||
191 | for key,value in hookObj[hooktype] do |
||
192 | -- NOTE THIS SHOULD BE VALUE! VALUE! *NOT* KEY! (checking if the functions are the same, even if the names are different) |
||
193 | |||
194 | if(value == newFunc) then |
||
195 | foundIt = true; |
||
196 | break; |
||
197 | --exit loop since found hook |
||
198 | end |
||
199 | end |
||
200 | if (not foundIt) then |
||
201 | SeaHooks_debugErrorPrint((SEA_HOOKS_DEBUG and (SEA_HOOKS_DEBUG_VERBOSE==compoundOrig)), nil, NORMAL_FONT_COLOR, "SeaHooks Progress: '", compoundOrig, "' not hooked with '", new, "' skipping."); |
||
202 | --hooked function not found so nothing to do |
||
203 | return; |
||
204 | end |
||
205 | end |
||
206 | local info = hookObj[hooktype]; --Sea.util.Hooks[compoundOrig][hooktype] |
||
207 | for key,value in info do |
||
208 | if (type(value) == "function") and (value == newFunc) then |
||
209 | info[key] = nil; |
||
210 | local embeddedTable = info[key.."Info"]; |
||
211 | if (type(embeddedTable) == "table") then |
||
212 | embeddedTable.parent = nil; |
||
213 | embeddedTable.name = nil; |
||
214 | end |
||
215 | info[key.."Info"] = embeddedTable; |
||
216 | hookObj[hooktype] = info; |
||
217 | hookObj.count = hookObj.count - 1; --decrement hook counter |
||
218 | Sea.util.Hooks[compoundOrig] = hookObj --repackage all hook types |
||
219 | SeaHooks_debugErrorPrint((SEA_HOOKS_DEBUG and (SEA_HOOKS_DEBUG_VERBOSE==compoundOrig)), nil, NORMAL_FONT_COLOR, "SeaHooks Progress: Found and unhooked '", new, "' from '", compoundOrig, "'."); |
||
220 | return; |
||
221 | end |
||
222 | end |
||
223 | -- No Complete Unhooking - Incompatible with Frame Script Element Hooks - Also liable to erase function hooks loaded after the first hook. |
||
224 |
|
||
225 | Sea.util.Hooks[compoundOrig] = hookObj --repackage all hook types |
||
226 | end |
||
227 |
|
||
228 | -- |
||
229 | -- Sea.util.getReturnArgs() |
||
230 | -- |
||
231 | -- Get the current return values of a hooked function from within an 'after' hook. |
||
232 | -- |
||
233 | -- Example: |
||
234 | -- local arg1, arg2 = Sea.util.getReturnArgs(); |
||
235 | -- |
||
236 | -- This will return nil if called outside of an 'after' hook. |
||
237 | -- Also, if you call any function within the 'after' hook that would lead to the call of another 'after' hook call then the global Sea.util.returnArgs would most likely change. |
||
238 | -- Thus it is highly recommend you grab whatever return arguments you need at the beginning of the function call and assign them to local variables. |
||
239 | -- This method preserves reverse compatibility as well as avoids table creation and thus does not effect GC. |
||
240 | -- |
||
241 | -- Written by AnduinLothar (karlkfi@cosmosui.org) |
||
242 | Sea.util.getReturnArgs = function() |
||
243 | return unpack(Sea.util.returnArgs); |
||
244 | end |
||
245 |
|
||
246 | -- |
||
247 | -- Sea.util.debugHooks( boolean enable , string verboseFunctionName ) |
||
248 | -- |
||
249 | -- Enable standard or verbose error logging. (Prints to the default chat frame) |
||
250 | -- |
||
251 | -- Examples: |
||
252 | -- On: Sea.util.debugHooks(1); |
||
253 | -- Verbose: Sea.util.debugHooks(1, "ChatFrame_OnLoad"); |
||
254 | -- Off: Sea.util.debugHooks(); |
||
255 | -- |
||
256 | -- Args: |
||
257 | -- (boolean) enable - true/false |
||
258 | |||
259 | -- |
||
260 | -- /script Sea.util.debugHooks(enabled, verboseHookName) |
||
261 | |||
262 | -- Note: enabling debug usually incurs a heavier proc load and can cause slow down when used with OnUpdate hooks. |
||
263 | -- |
||
264 | -- Written by AnduinLothar (karlkfi@cosmosui.org), |
||
265 | Sea.util.debugHooks = function ( enable, verboseFunctionName ) |
||
266 | if (enable) then |
||
267 | SEA_HOOKS_DEBUG = true; |
||
268 | if (verboseFunctionName) then |
||
269 | SEA_HOOKS_DEBUG_VERBOSE = verboseFunctionName; |
||
270 | else |
||
271 | SEA_HOOKS_DEBUG_VERBOSE = nil; |
||
272 | end |
||
273 | else |
||
274 | SEA_HOOKS_DEBUG = nil; |
||
275 | SEA_HOOKS_DEBUG_VERBOSE = nil; |
||
276 | end |
||
277 | end |
||
278 |
|
||
279 | |||
280 | --[[ String Parsing - User Functions ]]-- |
||
281 | ------------------------------------------------------------------------------ |
||
282 |
|
||
283 | -- |
||
284 | -- Sea.util.split(string text, string separator [, table oldTable [, boolean noPurge] ] ) |
||
285 | -- |
||
286 | -- Efficiently splits a string into a table by separators |
||
287 | -- |
||
288 | -- Args: |
||
289 | -- (string text, string separator, table oldTable, boolean noPurge) |
||
290 | -- text - string containing input |
||
291 | -- separator - separators |
||
292 | -- oldTable (optional) - table to fill with the results |
||
293 | -- noPurge (optional) - do not clear extraneous entries in oldTable |
||
294 | -- |
||
295 | -- Returns: |
||
296 | -- (table) |
||
297 | -- table - the table containing the exploded strings, which is freshly |
||
298 | -- created if oldTable wasn't passed |
||
299 | -- |
||
300 | -- Aliases: |
||
301 | -- Sea.string.split |
||
302 | -- |
||
303 | -- Notes: |
||
304 | -- In the interests of avoiding garbage generation, whenever possible pass |
||
305 | -- a table for split to reuse. Also, dont use [ or % in the separator as it |
||
306 | -- will conflict with the regex. |
||
307 | -- |
||
308 | -- Written by Thott (thott@thottbot.com) |
||
309 | -- Modified by Legorol (legorol@cosmosui.org) |
||
310 | -- Optimized by AnduinLothar (with suggestions from Iriel and krka) |
||
311 | Sea.util.split = function ( text, separator, t, noPurge ) |
||
312 | |||
313 | local mstart, mend = 1; |
||
314 | local oldn, numMatches = 0, 0; |
||
315 | local regexKey = "([^"..separator.."]+)"; |
||
316 | |||
317 |
|
||
318 | if ( not t ) then |
||
319 | t = {}; |
||
320 | else |
||
321 | oldn = table.getn(t); |
||
322 | end |
||
323 |
|
||
324 | -- Using string.find instead of string.gfind to avoid garbage generation |
||
325 | mstart, mend, value = sfind(text, regexKey, mstart); |
||
326 | while (value) do |
||
327 | numMatches = numMatches + 1; |
||
328 | t[numMatches] = value |
||
329 | mstart = mend + 1; |
||
330 | mstart, mend, value = sfind(text, regexKey, mstart); |
||
331 | end |
||
332 |
|
||
333 | if ( not noPurge ) then |
||
334 | for i = numMatches+1, oldn do |
||
335 | t[i] = nil; |
||
336 | end |
||
337 | end |
||
338 |
|
||
339 | table.setn(t, numMatches); |
||
340 |
|
||
341 | return t; |
||
342 | end |
||
343 |
|
||
344 | -- Aliasing |
||
345 | if (not Sea.string) then |
||
346 | Sea.string = {}; |
||
347 | end |
||
348 | Sea.string.split = Sea.util.split; |
||
349 | Sea.string.explode = Sea.util.split; |
||
350 |
|
||
351 | |||
352 | ------------------------------------------------------------------------------ |
||
353 | --[[ Indexed Variable Referencing - User Functions ]]-- |
||
354 | ------------------------------------------------------------------------------ |
||
355 |
|
||
356 | -- |
||
357 | |||
358 | -- |
||
359 | -- Obtains the value of a variable given its name. |
||
360 | -- |
||
361 | -- Examples: |
||
362 | -- Sea.util.getValue("ChatFrame_OnLoad"); |
||
363 | -- Sea.util.getValue("Class.subclass.element"); |
||
364 | -- |
||
365 | -- Args: |
||
366 | |||
367 | -- |
||
368 | -- Returns: |
||
369 | -- value - the value that variable has |
||
370 | -- |
||
371 | -- This function obtains the value that variableName contains. |
||
372 | |||
373 | -- the element of a table. If variableName doesn't exist, it returns nil. |
||
374 | |||
375 | -- Concept by Mugendai |
||
376 | -- Written by Legorol (legorol@cosmosui.org) |
||
377 | |||
378 | Sea.util.getValue = function ( variableName ) |
||
379 | if ( type(variableName) ~= "string" ) then |
||
380 | return; |
||
381 | end |
||
382 |
|
||
383 | local sfind = strfind; |
||
384 | |||
385 | |||
386 | local sstart = 2; |
||
387 | local value; |
||
388 | -- Split the variable name at ".", first field is a global name |
||
389 | |||
390 | if ( match ) then |
||
391 | value = getglobal(strsub(variableName, 0, match-1)); |
||
392 | else |
||
393 | return getglobal(variableName); |
||
394 | end |
||
395 |
|
||
396 | while true do |
||
397 | if (type(value) ~= "table") then |
||
398 | -- Returns nil rather than trying to index a non-table |
||
399 | return; |
||
400 | end |
||
401 | sstart = match + 1; |
||
402 | match = sfind(variableName, '.', sstart, true); |
||
403 |
|
||
404 | if ( match ) then |
||
405 | -- next one (there are more) |
||
406 | value = value[strsub(variableName, sstart, match-1)]; |
||
407 | else |
||
408 | -- last one |
||
409 | return value[strsub(variableName, sstart)]; |
||
410 | end |
||
411 | end |
||
412 | end |
||
413 |
|
||
414 | -- |
||
415 | -- Sea.util.setValue( string variableName, value ) |
||
416 | |||
417 | -- Sets the value of a variable given its name. |
||
418 | -- |
||
419 | |||
420 | -- Sea.util.setValue("ChatFrame_OnLoad", MyChatFrame_OnLoad); |
||
421 | -- Sea.util.setValue("Class.subclass.element", 5); |
||
422 | -- Sea.util.setValue("Class.subclass.function", function() dostuff; end); |
||
423 | -- Args: |
||
424 | -- (string) variableName - the name of the variable to change |
||
425 | -- value - the new value of the variable |
||
426 | -- |
||
427 | -- Returns: |
||
428 | -- (boolean) success - true if the operation succeeded |
||
429 | |||
430 | -- This function sets the value of variableName. |
||
431 | -- It is able to set the value for both a global variable or for |
||
432 | -- the element of a table, including functions. If variableName |
||
433 | -- already exists, it is overwritten. |
||
434 | -- |
||
435 | -- Concept by Mugendai |
||
436 | -- Written by Legorol (legorol@cosmosui.org) |
||
437 | |||
438 | Sea.util.setValue = function ( variableName, newValue ) |
||
439 | if ( type(variableName) ~= "string" ) then |
||
440 | return; |
||
441 | end |
||
442 |
|
||
443 | local sfind = strfind; |
||
444 | local strsub = strsub; |
||
445 |
|
||
446 | local sstart = 2; |
||
447 | |||
448 | -- Split the variable name at ".", first field is a global name |
||
449 | local match = sfind(variableName, '.', sstart, true); |
||
450 | if ( match ) then |
||
451 | value = getglobal(strsub(variableName, 0, match-1)); |
||
452 | else |
||
453 | setglobal(variableName, newValue); |
||
454 | return true; |
||
455 | end |
||
456 |
|
||
457 | while true do |
||
458 | if (type(value) ~= "table") then |
||
459 | -- Returns nil rather than trying to index a non-table |
||
460 | return false; |
||
461 | end |
||
462 | sstart = match + 1; |
||
463 | match = sfind(variableName, '.', sstart, true); |
||
464 |
|
||
465 | if ( match ) then |
||
466 | -- next one (there are more) |
||
467 | value = value[strsub(variableName, sstart, match-1)]; |
||
468 | else |
||
469 | -- last one |
||
470 | value[strsub(variableName, sstart)] = newValue; |
||
471 | return true; |
||
472 | end |
||
473 | end |
||
474 |
|
||
475 | -- Error occured, subtable is not a table |
||
476 | |||
477 | end |
||
478 |
|
||
479 | |||
480 | ------------------------------------------------------------------------------ |
||
481 | --[[ Function and Frame Script Element Hooking - Internal Functions ]]-- |
||
482 | ------------------------------------------------------------------------------ |
||
483 |
|
||
484 | -- |
||
485 | -- Hook Initialization |
||
486 | -- |
||
487 | -- Create a database instantiation the first time a hook is registered for a function. Stores the original function and establishes hook tables. |
||
488 | -- |
||
489 | -- Written by AnduinLothar (karlkfi@cosmosui.org) |
||
490 | |||
491 | SeaHooks_debugErrorPrint((SEA_HOOKS_DEBUG and (SEA_HOOKS_DEBUG_VERBOSE==compoundOrig)), nil, NORMAL_FONT_COLOR, "SeaHooks Progress: Hook Init - storing '", compoundOrig, "' orig and replacing with hookHandler."); |
||
492 | local hookObj = { |
||
493 | name = compoundOrig; |
||
494 | count = 0; |
||
495 | before = {}; |
||
496 | after = {}; |
||
497 | hide = {}; |
||
498 | |||
499 | }; |
||
500 | -- Set up the hook the first time |
||
501 | if (scriptElementName) then |
||
502 | local origFrame = Sea.util.getValue(orig); |
||
503 | hookObj.orig = origFrame:GetScript(scriptElementName); |
||
504 | hookObj.hookFunction = SeaHooks_getDynamicHookHandler(compoundOrig); |
||
505 | origFrame:SetScript(scriptElementName, hookObj.hookFunction); |
||
506 | Sea.util.setValue(orig, origFrame); --Reasign refrenced and modified origFrame |
||
507 | else |
||
508 | |||
509 | hookObj.hookFunction = SeaHooks_getDynamicHookHandler(compoundOrig); |
||
510 | Sea.util.setValue(orig, hookObj.hookFunction); |
||
511 | end |
||
512 | |||
513 | |||
514 |
|
||
515 | SeaHooks_getDynamicHookHandler = function ( databaseID ) |
||
516 | return function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) return SeaHooks_hookHandler(databaseID,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) end; |
||
517 | |||
518 |
|
||
519 | -- |
||
520 | -- Hook Handler |
||
521 | -- |
||
522 | -- Handles the name and the argument table. |
||
523 | -- An instantiated copy of this function is set to all hooked functions, passing the name of the original function staticly and any arguments dynamicly. |
||
524 | -- |
||
525 | -- Written by Thott (thott@thottbot.com) |
||
526 | -- Rewritten by AnduinLothar (karlkfi@cosmosui.org) |
||
527 | SeaHooks_hookHandler = function (hookInfo,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
528 | hookInfo = Sea.util.Hooks[hookInfo] --hookInfo passed in as string, exported as table on demand. |
||
529 | if (SEA_HOOKS_DEBUG) then |
||
530 | return SeaHooks_hookHandlerDebug(hookInfo,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); |
||
531 | end |
||
532 | return SeaHooks_hookHandlerQuick(hookInfo,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); |
||
533 | end |
||
534 |
|
||
535 | --Quick (non-debug) Hook Handler. Called for each hook function to iterate over hook functions and original. |
||
536 | SeaHooks_hookHandlerQuick = function (hookObj,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
537 | if (type(hookObj) ~= "table") then |
||
538 | hookObj = Sea.util.Hooks[hookObj]; |
||
539 | if (not hookObj) then |
||
540 | return; |
||
541 | end; |
||
542 | end |
||
543 | if (hookObj.count == 0) then |
||
544 | if (hookObj.orig) then |
||
545 | return hookObj.orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); |
||
546 | end |
||
547 | return; |
||
548 | |||
549 | local ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14,ra15,ra16,ra17,ra18,ra19,ra20; --return args |
||
550 | local toggle; |
||
551 | for key, value in hookObj.hide do |
||
552 | |||
553 | toggle,ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14,ra15,ra16,ra17,ra18,ra19,ra20 = value(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); |
||
554 | if(not toggle) then |
||
555 | return ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14,ra15,ra16,ra17,ra18,ra19,ra20; |
||
556 | end |
||
557 | end |
||
558 | end |
||
559 | local ta1,ta2,ta3,ta4,ta5,ta6,ta7,ta8,ta9,ta10,ta11,ta12,ta13,ta14,ta15,ta16,ta17,ta18,ta19,ta20; --temp args |
||
560 | for key, value in hookObj.before do |
||
561 | if(type(value) == "function") then |
||
562 | toggle,ta1,ta2,ta3,ta4,ta5,ta6,ta7,ta8,ta9,ta10,ta11,ta12,ta13,ta14,ta15,ta16,ta17,ta18,ta19,ta20 = value(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); |
||
563 | if(toggle) then |
||
564 | a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20 = ta1,ta2,ta3,ta4,ta5,ta6,ta7,ta8,ta9,ta10,ta11,ta12,ta13,ta14,ta15,ta16,ta17,ta18,ta19,ta20; |
||
565 | end |
||
566 | end |
||
567 | end |
||
568 | |||
569 | for key, value in hookObj.replace do |
||
570 | if(type(value) == "function") then |
||
571 | toggle,ta1,ta2,ta3,ta4,ta5,ta6,ta7,ta8,ta9,ta10,ta11,ta12,ta13,ta14,ta15,ta16,ta17,ta18,ta19,ta20 = value(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); |
||
572 | if(not toggle) then |
||
573 | ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14,ra15,ra16,ra17,ra18,ra19,ra20 = ta1,ta2,ta3,ta4,ta5,ta6,ta7,ta8,ta9,ta10,ta11,ta12,ta13,ta14,ta15,ta16,ta17,ta18,ta19,ta20; |
||
574 | break; |
||
575 | end |
||
576 | end |
||
577 | end |
||
578 | if (toggle) and (hookObj.orig) then |
||
579 | ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14,ra15,ra16,ra17,ra18,ra19,ra20 = hookObj.orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); |
||
580 | end |
||
581 | for key,value in hookObj.after do |
||
582 | if(type(value) == "function") then |
||
583 | SeaHooks_assignReturnArgs(true,ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14,ra15,ra16,ra17,ra18,ra19,ra20); |
||
584 | toggle,ta1,ta2,ta3,ta4,ta5,ta6,ta7,ta8,ta9,ta10,ta11,ta12,ta13,ta14,ta15,ta16,ta17,ta18,ta19,ta20 = value(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); |
||
585 | SeaHooks_assignReturnArgs(); |
||
586 | if(toggle) then |
||
587 | ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14,ra15,ra16,ra17,ra18,ra19,ra20 = ta1,ta2,ta3,ta4,ta5,ta6,ta7,ta8,ta9,ta10,ta11,ta12,ta13,ta14,ta15,ta16,ta17,ta18,ta19,ta20; |
||
588 | end |
||
589 | end |
||
590 | end |
||
591 | if ( (type(ra1) == "table") and ( ( ra2 and ra3 and ra4 and ra5 and ra6 and ra7 and ra8 and ra9 and ra10 and ra11 and ra12 and ra13 and ra14 and ra15 and ra16 and ra17 and ra18 and ra19 and ra20 ) == nil ) ) then |
||
592 | return unpack(ra1); |
||
593 | end |
||
594 | return ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14,ra15,ra16,ra17,ra18,ra19,ra20; |
||
595 | end |
||
596 |
|
||
597 | --Debug Hook Handler. Called for each hook function to iterate over hook functions and original. |
||
598 | SeaHooks_hookHandlerDebug = function (hookObj,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
599 | --assumes SEA_HOOKS_DEBUG |
||
600 | local name, parent, hookFuncName; |
||
601 | if (type(hookObj) ~= "table") then |
||
602 | name = hookObj; |
||
603 | hookObj = Sea.util.Hooks[hookObj]; |
||
604 | -- Quick exit since there's nothing to do! |
||
605 | if (not hookObj) then |
||
606 | SeaHooks_debugErrorPrint(true, nil, RED_FONT_COLOR, "SeaHooks Error: SeaHooks_hookHandler called with no defined hook parameters for '", name, "'."); |
||
607 | return; |
||
608 | end; |
||
609 | else |
||
610 | name = hookObj.name or 'unknown'; |
||
611 | end |
||
612 | local debugVerbose = (SEA_HOOKS_DEBUG_VERBOSE) and (SEA_HOOKS_DEBUG_VERBOSE == name); |
||
613 | if (hookObj.count == 0) then |
||
614 | --Quickly Exit if no hooks exist |
||
615 | if (hookObj.orig) then |
||
616 | SeaHooks_debugErrorPrint(debugVerbose, nil, NORMAL_FONT_COLOR, "SeaHooks Progress: No known hooks for '", name, "'. Calling orig."); |
||
617 | return hookObj.orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); |
||
618 | end |
||
619 | SeaHooks_debugErrorPrint(debugVerbose, nil, NORMAL_FONT_COLOR, "SeaHooks Progress: No known hooks or orig for '", name, "'. Exiting."); |
||
620 | return; |
||
621 | end |
||
622 | local ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14,ra15,ra16,ra17,ra18,ra19,ra20; --return args |
||
623 | local toggle; -- used for first arg returns from hooks |
||
624 | -- Itterate over and call 'hide' hooks. If there are none the for loop is skipped. |
||
625 | for key, value in hookObj.hide do |
||
626 | if(type(value) == "function") then |
||
627 | if (type(hookObj.hide[key.."Info"]) == "function") then |
||
628 | parent = hookObj.hide[key.."Info"].parent; |
||
629 | hookFuncName = hookObj.hide[key.."Info"].name; |
||
630 | |||
631 | SeaHooks_debugErrorPrint(debugVerbose, nil, NORMAL_FONT_COLOR, "SeaHooks Progress: calling 'hide' hook #", key, ": '", hookFuncName,"' for '", name, "', registered by '", parent,"'."); |
||
632 | --toggle (true) used to call orig function |
||
633 | toggle,ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14,ra15,ra16,ra17,ra18,ra19,ra20 = value(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); |
||
634 | if(not toggle) then |
||
635 | if (SEA_HOOKS_DEBUG) then |
||
636 | SeaHooks_debugErrorPrint(debugVerbose, nil, NORMAL_FONT_COLOR, "SeaHooks Progress: 'hide' hook #", key, " for '", name, "' has hidden all subsequent hook and original function calls."); |
||
637 | local numHideHooks = table.getn(hookObj.hide); |
||
638 | SeaHooks_debugErrorPrint((numHideHooks > key), nil, RED_FONT_COLOR, "SeaHooks Error: detected ", numHideHooks, " 'hide' hooks for '", name, "', one of which has hidden another. This will most likely cause addon conflicts."); |
||
639 | end |
||
640 | --exit after first hide unless it says to call orig |
||
641 | return ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14,ra15,ra16,ra17,ra18,ra19,ra20; |
||
642 | end |
||
643 | end |
||
644 | end |
||
645 | local ta1,ta2,ta3,ta4,ta5,ta6,ta7,ta8,ta9,ta10,ta11,ta12,ta13,ta14,ta15,ta16,ta17,ta18,ta19,ta20; --temp args |
||
646 | -- Itterate over and call 'before' hooks. If there are none the for loop is skipped. |
||
647 | for key, value in hookObj.before do |
||
648 | if(type(value) == "function") then |
||
649 | SeaHooks_debugErrorPrint(debugVerbose, nil, NORMAL_FONT_COLOR, "SeaHooks Progress: calling a 'before' hook for '", name, "'."); |
||
650 | --toggle (true) used to override the input args |
||
651 | toggle,ta1,ta2,ta3,ta4,ta5,ta6,ta7,ta8,ta9,ta10,ta11,ta12,ta13,ta14,ta15,ta16,ta17,ta18,ta19,ta20 = value(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); |
||
652 | if(toggle) then |
||
653 | -- Last 'before' hook that modifies input overrides all previous 'before' hooks for input values. |
||
654 | -- Keep in mind any previous input modification will modify the input of subsequent 'before' hooks as well as all the subsequent hook and orig function calls |
||
655 | a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20 = ta1,ta2,ta3,ta4,ta5,ta6,ta7,ta8,ta9,ta10,ta11,ta12,ta13,ta14,ta15,ta16,ta17,ta18,ta19,ta20; |
||
656 | SeaHooks_debugErrorPrint(debugVerbose, nil, NORMAL_FONT_COLOR, "SeaHooks Progress: 'before' hook #", key, " for '", name, "' has returned argument(s) to be passed to subsequent hook and original function calls."); |
||
657 | end |
||
658 | end |
||
659 | end |
||
660 | toggle = true; -- if no 'replace' hooks are called, calls the orig |
||
661 | -- Itterate over and call 'replace' hooks. If there are none the for loop is skipped. |
||
662 | for key, value in hookObj.replace do |
||
663 | if(type(value) == "function") then |
||
664 | SeaHooks_debugErrorPrint(debugVerbose, nil, NORMAL_FONT_COLOR, "SeaHooks Progress: calling a 'replace' hook for '", name, "'."); |
||
665 | --toggle (true) used to call the orig |
||
666 | toggle,ta1,ta2,ta3,ta4,ta5,ta6,ta7,ta8,ta9,ta10,ta11,ta12,ta13,ta14,ta15,ta16,ta17,ta18,ta19,ta20 = value(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); |
||
667 | if(not toggle) then |
||
668 | -- Last 'replace' hook that modifies output (not toggle) overrides all previous 'replace' hooks for return values. |
||
669 | -- Theorhetically it would be nice if 'replace' hooks that fequently returned true to continue were called before ones that didn't. |
||
670 | -- That could be done by reordering the 'replace' list. Is it worth it? It might still conflict on first call. It might be better to just inform the debugger and let the programmer unhook and rehook in the order he wants. |
||
671 | ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14,ra15,ra16,ra17,ra18,ra19,ra20 = ta1,ta2,ta3,ta4,ta5,ta6,ta7,ta8,ta9,ta10,ta11,ta12,ta13,ta14,ta15,ta16,ta17,ta18,ta19,ta20; |
||
672 | --We should only call one replace hook that doesn't request the origional be called. Otherwise we will perform multiple versions of the main function, which would likely be worse, than not calling the extras at all. |
||
673 | break; |
||
674 | end |
||
675 | end |
||
676 | end |
||
677 | if (toggle) and (hookObj.orig) then --Frame Script Elements do not necissarily have an orig function |
||
678 | SeaHooks_debugErrorPrint(debugVerbose, nil, NORMAL_FONT_COLOR, "SeaHooks Progress: calling the 'orig' function for '", name, "'."); |
||
679 | -- If the 'orig' is called use its return values, overrides any 'replace' return values defined before a final continuing one. |
||
680 | ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14,ra15,ra16,ra17,ra18,ra19,ra20 = hookObj.orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); |
||
681 | end |
||
682 | -- Itterate over and call 'after' hooks. If there are none the for loop is skipped. |
||
683 | for key,value in hookObj.after do |
||
684 | if(type(value) == "function") then |
||
685 | SeaHooks_debugErrorPrint(debugVerbose, nil, NORMAL_FONT_COLOR, "SeaHooks Progress: calling an 'after' hook for '", name, "'."); |
||
686 | --toggle (true) used to override the return args |
||
687 | --Current function return args availible via global pass vars |
||
688 | SeaHooks_assignReturnArgs(true,ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14,ra15,ra16,ra17,ra18,ra19,ra20); |
||
689 | toggle,ta1,ta2,ta3,ta4,ta5,ta6,ta7,ta8,ta9,ta10,ta11,ta12,ta13,ta14,ta15,ta16,ta17,ta18,ta19,ta20 = value(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); |
||
690 | SeaHooks_assignReturnArgs(); --nil pass vars |
||
691 | if(toggle) then |
||
692 | -- Last 'after' hook that modifies output overrides all other hooks for return values. |
||
693 | ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14,ra15,ra16,ra17,ra18,ra19,ra20 = ta1,ta2,ta3,ta4,ta5,ta6,ta7,ta8,ta9,ta10,ta11,ta12,ta13,ta14,ta15,ta16,ta17,ta18,ta19,ta20; |
||
694 | SeaHooks_debugErrorPrint(debugVerbose, nil, NORMAL_FONT_COLOR, "SeaHooks Progress: 'after' hook for '", name, "' has returned argument(s) to be passed to subsequent hook and original function calls."); |
||
695 | end |
||
696 | end |
||
697 | end |
||
698 | --Only unpack ra1 if it is the only return argument passed. |
||
699 | if ( (type(ra1) == "table") and ( ( ra2 and ra3 and ra4 and ra5 and ra6 and ra7 and ra8 and ra9 and ra10 and ra11 and ra12 and ra13 and ra14 and ra15 and ra16 and ra17 and ra18 and ra19 and ra20 ) == nil ) ) then |
||
700 | SeaHooks_debugErrorPrint(SEA_HOOKS_DEBUG, nil, RED_FONT_COLOR, "SeaHooks Error: Return argument #1 is a table for '", name, "'. This can be used to pass return arguments from a replace/after hook. If that is not the intention of your hook then pass an additional non-nil argument to avoid unpacking."); |
||
701 | return unpack(ra1); |
||
702 | end |
||
703 | return ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14,ra15,ra16,ra17,ra18,ra19,ra20; |
||
704 | end |
||
705 |
|
||
706 | -- Assigns up to 20 arguments to a global table so as to save on table creation and still allow return argument passing to 'after' hooks |
||
707 | -- Written by AnduinLothar (karlkfi@cosmosui.org) |
||
708 | SeaHooks_assignReturnArgs = function( toggle,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20 ) |
||
709 | local temp = Sea.util.returnArgs; |
||
710 | if (toggle) then |
||
711 | temp[1]=a1;temp[2]=a2;temp[3]=a3;temp[4]=a4;temp[5]=a5;temp[6]=a6;temp[7]=a7;temp[8]=a8;temp[9]=a9;temp[10]=a10; |
||
712 | temp[11]=a11;temp[12]=a12;temp[13]=a13;temp[14]=a14;temp[15]=a15;temp[16]=a16;temp[17]=a17;temp[18]=a18;temp[19]=a19;temp[20]=a20; |
||
713 | local n=0; |
||
714 | for i=1, 20 do |
||
715 | if temp[i] then |
||
716 | n=i; |
||
717 | end |
||
718 | end |
||
719 | table.setn(temp,n); |
||
720 | else |
||
721 | for i=1, 20 do |
||
722 | temp[i]=nil; |
||
723 | end |
||
724 | table.setn(temp,0); |
||
725 | end |
||
726 | Sea.util.returnArgs = temp; |
||
727 | end |
||
728 |
|
||
729 | -- Quick Sea print bypass for speed. (only makes 1 table) Won't cause as much slow down on debug. But don't try to vebose debug any OnUpdate functions. |
||
730 | -- Written by AnduinLothar (karlkfi@cosmosui.org) |
||
731 | SeaHooks_debugErrorPrint = function( toggle, frameUnused, color, ... ) |
||
732 | --frameUnused is a placeholder to match Sea.io.dprintfc syntax |
||
733 | if (toggle) then |
||
734 | local msg = ""; |
||
735 | for key, value in arg do |
||
736 | if (type(key) == "number") then |
||
737 | if ( value == nil ) then |
||
738 | msg = msg .. "(nil)"; |
||
739 | |||
740 | local currType = type(value); |
||
741 | if (currType == "boolean" ) then |
||
742 | msg = msg .. "("; |
||
743 | if (value) then |
||
744 | msg = msg .. "true"; |
||
745 | else |
||
746 | msg = msg .. "false"; |
||
747 | end |
||
748 | msg = msg .. ")"; |
||
749 | elseif (currType ~= "string" and currType ~= "number") then |
||
750 | msg = msg .. "(" .. currType .. ")"; |
||
751 | else |
||
752 | msg = msg .. value; |
||
753 | end |
||
754 | end |
||
755 | end |
||
756 | end |
||
757 | DEFAULT_CHAT_FRAME:AddMessage(msg, color.r, color.g, color.b); |
||
758 | end |
||
759 | end |
||
760 |
|
||
761 |
|
||
762 | |||
763 | --Update old style hook database (Immediate Execution) |
||
764 | for origName, info in Sea.util.Hooks do |
||
765 | if (type(info) == "table") then |
||
766 | Sea.util.Hooks[origName].count = 0; |
||
767 | for hookType, hookTable in info do |
||
768 | if (type(hookTable) == "table") then |
||
769 | if (type(hookTable.n) == "number") then |
||
770 | table.setn(Sea.util.Hooks[origName][hookType], hookTable.n); |
||
771 | SeaHooks_debugErrorPrint((SEA_HOOKS_DEBUG and SEA_HOOKS_DEBUG_VERBOSE), nil, NORMAL_FONT_COLOR, "SeaHooks Progress: Updating Hook Registry for '", origName, "' - '", hookType, "' hooks, ", hookTable.n, " found. If possible, these hooks might benifit if their addons optionally required SeaHooks."); |
||
772 | Sea.util.Hooks[origName][hookType].n = nil; |
||
773 | end |
||
774 | local i=1; |
||
775 | while (type(hookTable[i]) == "function") do |
||
776 | Sea.util.Hooks[origName].count = Sea.util.Hooks[origName].count + 1; |
||
777 | i=i+1; |
||
778 | end |
||
779 | end |
||
780 | end |
||
781 | end |
||
782 | end |
||
783 |
|
||
784 | end |
||
785 |
|
||
786 |
|
||
787 |
|