|Go to Page...|
|Updated:||12-17-06 10:52 PM|
Always wanted to use standard hooking and unhooking methods that are safe, felxible, compatible with other hooks and easy to debug but didn't want to require your users to down load all of the Sea Library? Well now you can embed that functionality into your addon as easily as modifying your TOC! Not only that but if multiple Sea/SeaHook libraries are loaded a simple versioning system with keep the live copy up to date without extranious loading and having multiple copies in memory.
This is the most flexible hooking system you've ever seen; plus it's optimized to create the least gc possible!
The calls you'll use the most:
Sea.util.hook( "origFunctionName", "hookFunctionName", "hide/before/replace/after")
Sea.util.unhook( "origFunctionName", "hookFunctionName", "hide/before/replace/after")
Hook types :
"hide" - called instead of the orig function. If you return true, subsequent hooks will be called afterwards, otherwise no further non-hide hooks nor the orig function will be called.
"before" - called before the orig 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 the same orig function.
"replace" - called instead of the orig function. If you return true, the orig function will be called afterwards. Subsequent args will be returned by the hooked function call.
"after" - called after the orig function. If you return true, the subsequent args will be returned by the hooked function call.
Sea.util.getReturnArgs() - Get the current return values of a hooked function from within an 'after' hook. (So that you don't have to duplicate logic and/or can simply modify the return arguments.)
==Frame Script Element Hooking==
Sea.util.hook( "frameName", "hookFunctionName", "before/after/replace/hide", "scriptElementName")
Sea.util.unhook( "frameName", "hookFunctionName", "before/after/replace/hide", "scriptElementName")
The variables for origFunctionName/frameName/hookFunctionName may all be tabled index strings. Thus "myTable.key" works as a valid function definition if you would normally call it by doing myTable.key() or myTable["key"]()
This is made possible by the following functions (which can by themselves as well):
Sea.util.split( "text", "separator"[, oldTable[, noPurge]] )
- Drop the SeaHooks folder into your Interface\AddOns\YourAddon\ folder
- Add Sea and SeaHooks as optional dependancies
- Add the following line to the end of your TOC file, before your addon files:
- Drop the SeaHooks folder into your Interface\AddOns\ directory
- Add SeaHooks a required dependancy
Another nice thing about Sea hooks is that you can look in one place to find all your hooking conflicts. If there's a problem just look in the Sea.util.Hooks table. Hooks are listed by the name of the orig function, or by "frameName.scriptElementName". If all your addons are usign this method it makes them infinitely easier to debug conflicts. Plus it's simple to replace a manual hook with a Sea hook, usually just a couple of lines. In the rare case that a manual hook calls the orig function in the middle you can usually split it into a "before" and "after" hook and make life easier for everyone. This standardized hooking is cleaner to code with, simpler to read and understand, flexible enough to handle any hook type and now doesn't require your users to download a dependancy! If you can think of ANY reason why it would be better to use another hooking method please let us know. We'd love to make SeaHooks the primere method preferred by addon developers.
Sea.util.debugHooks( enable , "verboseFunctionName" ) - Enable standard or verbose error logging.
(Prints to the default chat frame)
--Verbose: Sea.util.debugHooks(1, "ChatFrame_OnLoad");
Change Log :
- Rewrote hook handler to use a more table intensive method. This may use more memory, but executes much less code and should use overall less processor time. This allows for the removal of all of the table recycling code: SeaHooks_assignArgs, SeaHooks_inverseAssignArgs, SeaHooks_getTables, SeaHooks_releaseTables and Sea.util.argStack. This also fixes two serious issues that were cropping up:
- Args and return args no longer stop after the first nil
- The number of arguments and return arguments allowable to hook is now unlimited
- Fixed bug with hooked functions only returning a single value
- Added SeaHooks_inverseAssignArgs for replace hooks, so that it now correctly passes return arguments when fully replacing the function
- Removed Sea.util.returnArgs completely. Use the new passReturnArgs, 4th arg to Sea.util.hook
- Added a check to make sure GetScript returned a function (since there's an issue with it returning a number)
- Added another argument to hook: needsRetArgs. This boolean will allow 'after' hooks to be passed a table of args and a table of return args. All other hooks will pass unpacked args like v0.7 and earlier
- Removed Sea.util.topReturnArgs
- Fixed a bug with local functions being out of scope
- Prepared for Lua 5.1
- Removed Sea.string.split and Sea.string.explode aliases. use Sea.util.split
- Added Sea.util.join (removed from Sea.io)
- Completely revamped the hook handler.
-- Hooks now use recycled tables to store passed arguments and return arguments (now that Lua 5.1 handles table garbage better)
-- Now hook function are passed a single table of arguments passed to the parent function.
-- 'after' hooks are also passed a second table containing the current return values
-- DO NOT MODIFY PASSED TABLES. Assign them to local variables and use the 'return true, ...' construct to pass new arguments as specified for each typ of hook.
-- 'return true, ...' from all hooks (other than 'after' hooks) uses the passed arguments as the return arguments from the parent function.
-- 'return true, ...' from 'before' hooks passes those arguments (instead of the orig ones) to all subsequent hook functions and the orig function
-- Debug mode is temporarily dissabled, awaiting rewrite for new procedures
- Added an inclusive argument to split to catch empty strings
- Changed lua file name
(Included in v1.20)
- Fixed bug preventing propper unhooking
- Synced with Sea v1.11
- Only one replace hook is now called for each hook call, unless it returns true as arg1
- 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)
- 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
- 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
- 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.
- SeaHooks Forked into Mini-Library from the main Sea. Still backwards compatible.