Navigation menu

WoW:Hooking functions: Difference between revisions

Jump to navigation Jump to search
→‎How to Hook a Function: Better example, imo.
No edit summary
(→‎How to Hook a Function: Better example, imo.)
Line 14: Line 14:
Let's say we wanted to show the target's level instead of the skull for players and monsters much higher level than us.  The function responsible for hiding the level is TargetFrame_CheckLevel(), so we need to hook that function to make it un-hide the level.
Let's say we wanted to show the target's level instead of the skull for players and monsters much higher level than us.  The function responsible for hiding the level is TargetFrame_CheckLevel(), so we need to hook that function to make it un-hide the level.


We create a new AddOn named ShowLevel and add an OnLoad handler in the XML. In the LUA file we have:
Let's assume our AddOn is named "MyAddOn", and that is has an OnLoad handler that gets called from its XML <OnLoad> event. In the Lua file we would have:


  local Pre_ShowLevel_TargetFrame_CheckLevel;
  local MyAddOn_Orig_TargetFrame_CheckLevel;
  function ShowLevel_OnLoad()
 
    Pre_ShowLevel_TargetFrame_CheckLevel = TargetFrame_CheckLevel;
  function MyAddOn_OnLoad()
    TargetFrame_CheckLevel = ShowLevel_TargetFrame_CheckLevel;
  MyAddOn_Orig_TargetFrame_CheckLevel = TargetFrame_CheckLevel; -- Remember old function
  TargetFrame_CheckLevel = MyAddOn_TargetFrame_CheckLevel;       -- Hook in ours
  end
  end


So what the above does is that it creates the Pre_ShowLevel_TargetFrame_CheckLevel function to hold the old function. Then it puts our function in place of the old one, so that anyone calling TargetFrame_CheckLevel() is now actually invoking ShowLevel_TargetFrame_CheckLevel() instead.
So what the above does is that it remembers the reference to the original "TargetFrame_CheckLevel" in "MyAddOn_Orig_TargetFrame_CheckLevel". Then it puts our function in place of the old one, so that anyone calling TargetFrame_CheckLevel() is now actually invoking MyAddOn_TargetFrame_CheckLevel() instead.


The next step is to create our ShowLevels_TargetFrame_CheckLevel()
The next step is to create our MyAddOn_TargetFrame_CheckLevel(). Let's assume we want it to show target levels.


  function ShowLevels_TargetFrame_CheckLevel()
  function MyAddOn_TargetFrame_CheckLevel()
    Pre_ShowLevels_TargetFrame_CheckLevel();
  local retval = MyAddOn_Orig_TargetFrame_CheckLevel(); -- Call original function!
    TargetLevelText:Show();
  TargetLevelText:Show();
    TargetHighLevelTexture:Hide();
  TargetHighLevelTexture:Hide();
  return retval;
  end
  end


So in this function, we first invoke the old function to let it do what it needs to do.  Next, un-hide the level and hide the skull.  Pretty simple right?
So in this function, we first invoke the old function to let it do what it needs to do.  Next, un-hide the level and hide the skull.  Pretty simple right?


== An Easier Way to Hook a Function? ==
== An Easier Way to Hook a Function? ==
Line 71: Line 72:


This can be tricky, and really depends on what you are writing.  By default you should probably call the old function first, and then do whatever you need.  However, in some instances, you will want to call the old function last, call it conditionally, or not even call it at all.
This can be tricky, and really depends on what you are writing.  By default you should probably call the old function first, and then do whatever you need.  However, in some instances, you will want to call the old function last, call it conditionally, or not even call it at all.
* Note: Not calling the old function at all can have ''very'' interesting effects if another addon hooked it before you did. What you will be doing then, is not letting that addon see the function call. This is where hook libraries do help.


== Functions that Take Arguments ==
== Functions that Take Arguments ==
Line 138: Line 141:
== Notes ==
== Notes ==


* I'm not totally sure about scoping, but it's probably a good idea to uniquely name the variable where you store the old functionality. I tend to use a Pre_''addon''_''function name'' syntax.  Just don't use something like Old_''function name''
* If you use a ''local'' variable to store the old function, its name matters less. But often in bigger addons, you may need to call it from several of your addon's files, and local variables won't work. Use a syntax that uniquely identifies your previous function reference, like:
::<tt>Pre_''addon''_''functionname''</tt> &nbsp; or
::<tt>''addon''_Orig_''functionname''</tt>.
 
* An alternative is to store the old function as a member of a global variable, a la MyAddOn.FunctionToBeHooked = FunctionToBeHooked; FunctionToBeHooked = function() ...
* An alternative is to store the old function as a member of a global variable, a la MyAddOn.FunctionToBeHooked = FunctionToBeHooked; FunctionToBeHooked = function() ...
* Warning! Blizzard has moved some pieces of the UI to be loaded on demand. The functions in those pieces cannot be hooked until they are loaded.
* Warning! Blizzard has moved some pieces of the UI to be loaded on demand. The functions in those pieces cannot be hooked until they are loaded.
* Warning! Blizzard '''does''' add new arguments and return values to their functions. See [[HOWTO: Hook functions in a safer way]] for a solution!
[[Category: HOWTOs|Hook a Function]]
[[Category: HOWTOs|Hook a Function]]
Anonymous user