ACUtil bug!!! - meldavy/ipf-documentation GitHub Wiki
Today I was debugging a really dumb ACUtil bug for an hour. I'm pretty sure every other addon developer has already went through this and found their own workaround. But encountering it for the first time, I was really lost.
Preface
While working on a new addon, I implemented a hook using ACUtil, and it was working while testing. But after packaging it and testing it afterwards, the hook started to not run at all. But back in my testing environment, it would work - it just wouldn't work after packaging.
One difference is that in my testing environment, I name my addons "TEST", while in production, I do a quick ctrl+R to find and replace all instances of TEST with the actual name of my addon, in this case, NearbyPlayerInfo. So I thought this was either some kind of illegal naming, or I may have messed up the packaging or whatnot... But at the end, I was wrong.
acutil.setupHook()
The root cause of this issue was acutil's setupHook() function. Were you able to spot it as well? Basically, if setupHook() is called more than once for the same base function, the new hooked function will get overwritten! Meaning that by only using acutil, we cannot have more than 1 addon that overrides the same base function!!!
Solution
I've gone ahead and written my own version of setupHook, now provided by default within my addon template.
function Template.SetupHook(func, baseFuncName)
local addonUpper = string.upper(addonName)
local replacementName = addonUpper .. "_BASE_" .. baseFuncName
if (_G[replacementName] == nil) then
base[baseFuncName] = _G[baseFuncName];
_G[replacementName] = _G[baseFuncName];
_G[baseFuncName] = func
else
_G[baseFuncName] = func
end
end
Here I use a slightly different method. Firstly, this following line is redundant:
_G[replacementName] = _G[baseFuncName];
What I achieve here is I use the addon namer as a way to generate a unique string to reference the old function, rather than a basename + _OLD naming scheme which will cause conflicts as mentioned previously.
Next, I set add a key-val pair to the base variable, so that I can reference old functions using their old base names like below:
base["OLD_FUNCTION_NAME"](args)
Thus we won't need to worry about what we're actually renaming the base function to, we keep a local reference to it in a hashmap where the key is the actual base function name.
Thus, if we are overriding, let's say ITEM_SANDRA_ONELINE_REVERT_RANDOM_REG_TARGETITEM as an example:
function MYADDON_ON_INIT()
MyAddon.SetupHook(MY_NEW_FUNCTION, "ITEM_SANDRA_ONELINE_REVERT_RANDOM_REG_TARGETITEM")
end
function MY_NEW_FUNCTION(args)
... do stuff
base["ITEM_SANDRA_ONELINE_REVERT_RANDOM_REG_TARGETITEM"](args) -- invoke base function
end