Because your hooking the functions instead of the Script, why not just hook the metatable instead so then you don't need to maintain that list?
That also fixes this problem.
Please, no. Do not do that.
Addons that do tooltip scanning expects the tooltip to have a very specific (and "clean") structure. They create tooltips that are not meant to be hooked by other addons.
for recipes (anything that crafts an item) it gets called twice (which sort of makes sense) so my text is duplicated.
theres no way to differentiate between the item itself and whats crafted, nor any method to get the crafted item link? GetItem() always returns the recipe.
my text is added after the craftable item description but before the "requires:" line for that item. (and then added again at the bottom)
In my OnTooltipSetItem script, I simply set a flag, such as tooltip.myaddon = true, and check if this flag is present so that the script doesn't add the line twice on recipes.
You then do an additional hook for OnTooltipCleared(I think that's the handler's name) to nil out tooltip.myaddon.
As for LinkWrangler, the author has provided a callback system which you can register with for LinkWrangler to inform your addon when it has created new tooltips (on demand) for you to apply your hooks or add your addon's lines.
In my OnTooltipSetItem script, I simply set a flag, such as tooltip.myaddon = true, and check if this flag is present so that the script doesn't add the line twice on recipes.
You then do an additional hook for OnTooltipCleared(I think that's the handler's name) to nil out tooltip.myaddon.
Unless I'm mistaken, if you add the line on the first call, it adds the line directly below the "item" made by the recipe, which ends up in the middle of the tooltip instead of the end, most likely not what you want.
As shown in this image, if you blocked the second call, only the first "ItemLevel: 85" line would be shown.
Secondly, using the OnTooltipSetItem method means extra checking on every item tooltip you show, not that you will show a lot of tooltips very often, but the overhead is there. While the hooking-all-methods method is a one time thing on load.
As for LinkWrangler, the author has provided a callback system which you can register with for LinkWrangler to inform your addon when it has created new tooltips (on demand) for you to apply your hooks or add your addon's lines.
Yes, thats just one addon, what about those that don't have one and you/your users would want support for it.
As shown in this image, if you blocked the second call, only the first "ItemLevel: 85" line would be shown.
While not pretty, this works:
do
local tt_OnTooltipSetItemOrSpell = function (self)
local is_a_recipe = self:NumLines() > 4 and select(5, _G[self:GetName().."TextLeft4"]:GetPoint(1)) < -2
local count = (self[ArkInventory] or 0) + 1
self[ArkInventory] = count
if (not is_a_recipe and count == 1) or (is_a_recipe and count == 2) then
ArkInventory.TooltipShowCustom(self)
end
end
local tt_OnTooltipCleared = function (self)
self[ArkInventory] = nil
end
local function HookTooltip(tt)
tt:HookScript("OnTooltipSetItem", tt_OnTooltipSetItemOrSpell)
tt:HookScript("OnTooltipSetSpell", tt_OnTooltipSetItemOrSpell)
tt:HookScript("OnTooltipCleared", tt_OnTooltipCleared)
end
for _, tt in ipairs(tooltip_frames) do HookTooltip(tt) end
end
do
local tt_OnTooltipSetItemOrSpell = function (self)
local is_a_recipe = self:NumLines() > 4 and select(5, _G[self:GetName().."TextLeft4"]:GetPoint(1)) < -2
local count = (self[ArkInventory] or 0) + 1
self[ArkInventory] = count
if (not is_a_recipe and count == 1) or (is_a_recipe and count == 2) then
ArkInventory.TooltipShowCustom(self)
end
end
local tt_OnTooltipCleared = function (self)
self[ArkInventory] = nil
end
local function HookTooltip(tt)
tt:HookScript("OnTooltipSetItem", tt_OnTooltipSetItemOrSpell)
tt:HookScript("OnTooltipSetSpell", tt_OnTooltipSetItemOrSpell)
tt:HookScript("OnTooltipCleared", tt_OnTooltipCleared)
end
for _, tt in ipairs(tooltip_frames) do HookTooltip(tt) end
end
This is assuming TextLeft4 is always an empty line for recipes, which is not the case.
The question is why not avoid the overhead when you can?
Unless I'm mistaken, if you add the line on the first call, it adds the line directly below the "item" made by the recipe, which ends up in the middle of the tooltip instead of the end, most likely not what you want.
As shown in this image, if you blocked the second call, only the first "ItemLevel: 85" line would be shown.
You are mistaken. Mendeleev does post hooks of OnTooltipSetItem and OnTooltipCleared and it works perfectly when both the recipe and the item the recipe creates are in the local cache. I don't remember what happens when one isn't in the cache though, but if it does misbehave it will be correct the next time the tooltip is shown.
The top line in your screenshot is from the second call not the first.
Secondly, using the OnTooltipSetItem method means extra checking on every item tooltip you show, not that you will show a lot of tooltips very often, but the overhead is there. While the hooking-all-methods method is a one time thing on load.
Yes, thats just one addon, what about those that don't have one and you/your users would want support for it.
What are you smoking? The hooks are still called on every tooltip even if you use the hook-all-methods method.
As for the custom tooltip issue, how about some kind of standard when creating a custom tooltip that you want to be shown, and be modified i.e.
local handledscripts = {OnTooltipSetItem = true, OnTooltipSetUnit = true, OnTooltipSetSpell = true}
for script, _ in pairs(handledscripts) do
mytip:SetScript(script, GameTooltip:GetScript(script))
end
hooksecurefunc(GameTooltip, "SetScript",
function(gt, script, handle)
if handledscripts[script] then
mytip:SetScript(script, handle)
end
end
)
You are mistaken. Mendeleev does post hooks of OnTooltipSetItem and OnTooltipCleared and it works perfectly when both the recipe and the item the recipe creates are in the local cache. I don't remember what happens when one isn't in the cache though, but if it does misbehave it will be correct the next time the tooltip is shown.
The top line in your screenshot is from the second call not the first.
What are you smoking? The hooks are still called on every tooltip even if you use the hook-all-methods method.
What are you smoking? The hooks are still called on every tooltip but without the extra lines of code to check if its the first call or second. And with out the OnTooltipCleared hook call. And with out the extra code if you want to check for recipes. ...
PS: I don't normally respond to rude posts. I know its kinda your style of talking, but please learn to not speak like you understand something when obviously you don't got a clue.
This is assuming TextLeft4 is always an empty line for recipes, which is not the case.
You're right that it's not always the same fontstring, but it's not an empty line, it's a vertical offset. You could probably find a (very expensive) way to check this in a safe way.
The question is why not avoid the overhead when you can?
The sole purpose of "OnTooltipSetItem" is to allow hooking, whatever the setting function is, whatever the parameters order and type that are called on all methods that creates tooltip, if it IS an item, then the "OnTooltipSetItem" callback is called. The fact that it's called twice is a implementation bug.
You can try to tweak around this bug and you should ask for the bug to be fixed. The issue with pre-hooking is that you need to know all functions that set a tooltip and hook them all. It needs to be maintained. You also have to care about not tainting.
The fact that it's called twice is a implementation bug.
Actually I think the behavior is intended, and correct. The bug is that self:GetItem() doesn't return the crafted item, or both items. We bitched at the blues to fix that a few times, but I've kinda stopped caring. Double info on recipe tips doesn't really bother me.
*edit* and taint should *never* be an issue with tooltips... but still the script handler is better than direct hookerage.
You're right that it's not always the same fontstring, but it's not an empty line, it's a vertical offset. You could probably find a (very expensive) way to check this in a safe way.
The sole purpose of "OnTooltipSetItem" is to allow hooking, whatever the setting function is, whatever the parameters order and type that are called on all methods that creates tooltip, if it IS an item, then the "OnTooltipSetItem" callback is called. The fact that it's called twice is a implementation bug.
You can try to tweak around this bug and you should ask for the bug to be fixed. The issue with pre-hooking is that you need to know all functions that set a tooltip and hook them all. It needs to be maintained. You also have to care about not tainting.
I remember reporting this on the official forums way back when this feature was first introduced in a TBC patch, but they don't seem to care and its still broken on 3.2 PTR.
Also with the new GetItemStats(itemlink, table) API in 3.2, its also nearly useless in its current state. I wonder why it would only accept itemlink as input if it doesn't consider gems or enchants, it should just accept itemId which doesn't work in the current build, you have to feed it a proper itemlink.
Actually I think the behavior is intended, and correct. The bug is that self:GetItem() doesn't return the crafted item, or both items. We bitched at the blues to fix that a few times, but I've kinda stopped caring. Double info on recipe tips doesn't really bother me.
*edit* and taint should *never* be an issue with tooltips... but still the script handler is better than direct hookerage.
It's not better if you need to workaround the recipe glitch. Like I said, depends on what you are trying to do.
Actually I think the behavior is intended, and correct.
Well, I don't :-) I think that if it was intended, then we would have a way to know when a tooltip is completely filled, because that really useful to know, as the whole issue here shows. This is unintended, but Blizzard has more pressing matters than fixing bugs that does not concern the client's default behaviour. Like fixing bugs that does concern their own UI.
*edit* and taint should *never* be an issue with tooltips... but still the script handler is better than direct hookerage.
When unsecurely hooking GameTooltip:SetHyperlink(), you taint all the code path that may follow such a call in blizzard's UI. It doesn't matter only if that code path is short, and do not spread this taint. You don't have the same problem when hooking the "OnTooltipSetItem" handler, mainly because there is no such handler in the default UI. How many calls to GameTooltip:Set*** exists in the default UI ? How many of these calls are not at the end of a event handler ? Did you check them all to make sure that tainting the code path that follow this call is safe ?
So, I've been looking at the tooltip code in both Bagon_Tooltips and Engravings, and have gotten the following rough code from them (It's just a stripped down version of the stuff in Bagon_Tooltips, really.)
local function AddText(frame, link)
frame:AddDoubleLine("This is", "some text")
frame:Show()
end
local function HookTip(tooltip)
tooltip:HookScript('OnTooltipSetItem', function(self, ...)
local itemLink = select(2, self:GetItem())
if itemLink and GetItemInfo(itemLink) then --fix for blizzard doing craziness when doing getiteminfo
AddText(self, itemLink)
end
end)
end
HookTip(GameTooltip)
HookTip(ItemRefTooltip)
So, I really just need to then add in some code to get the relevant information to add in the AddText function, right? (AddDoubleLine was used as that's what I'm using in my addon anyway.)
So, I've been looking at the tooltip code in both Bagon_Tooltips and Engravings, and have gotten the following rough code from them (It's just a stripped down version of the stuff in Bagon_Tooltips, really.)
So, I really just need to then add in some code to get the relevant information to add in the AddText function, right? (AddDoubleLine was used as that's what I'm using in my addon anyway.)
jup, but I don't think you need the frame:Show() bit, as the tooltip is shown after "OnTooltipSetItem", anyway.
Also it might be an idea to stick the
function(self, ...)
local itemLink = select(2, self:GetItem())
if itemLink and GetItemInfo(itemLink) then --fix for blizzard doing craziness when doing getiteminfo
AddText(self, itemLink)
end
end
bit outside the HookTip function so your don't end up creating 2 of the same function.
Just tested it, and you don't need to call :Show() when hooking "OnTooltipSetUnit" or "OnTooltipSetItem", as it will get called after using your hook.
But it is required for stuff like hooking the recipe shown when mouse is over the recipe icon in the tradeskill panel:
[php]
local button = _G.TradeSkillSkillIcon
local TS_OnEnter = button:GetScript"OnEnter"
local TS_OnLeave = button:GetScript"OnLeave"
local orgSetTradeSkillItem = GameTooltip.SetTradeSkillItem
local function newSetTradeSkillItem(...)
orgSetTradeSkillItem(...)
GameTooltip:AddLine("\n"..L"|cffff8040Click|r to create a shortcut.", .2, 1, .2)
GameTooltip:Show()
end
As for LinkWrangler, the author has provided a callback system which you can register with for LinkWrangler to inform your addon when it has created new tooltips (on demand) for you to apply your hooks or add your addon's lines.
Yes, thats just one addon, what about those that don't have one and you/your users would want support for it.
Well, your method of hooking CreateFrame() and then checking if the frame returned is of type GameTooltip, and then checking the name of the frame against a list of known addon (and their used gametooltip names) isn't any better. If you already have a list of addons you are comparing the name of the tooltip frames against, you should already know if you need to securehook CreateFrame or not (answer: you don't - because LinkWranger is the only one you support which create tooltips dynamically).
Well, your method of hooking CreateFrame() and then checking if the frame returned is of type GameTooltip, and then checking the name of the frame against a list of known addon (and their used gametooltip names) isn't any better.
You say you have a better solution of correctly hooking dynamically created tooltips that don't have an API? I'm all ears.
If you already have a list of addons you are comparing the name of the tooltip frames against, you should already know if you need to securehook CreateFrame or not (answer: you don't - because LinkWranger is the only one you support which create tooltips dynamically).
Wrong, LinkWranger far from the only addon that creates tooltips dynamically, LibTipHooker supports quite a few more of them if you care to check yourself.
Please, no. Do not do that.
Addons that do tooltip scanning expects the tooltip to have a very specific (and "clean") structure. They create tooltips that are not meant to be hooked by other addons.
In my OnTooltipSetItem script, I simply set a flag, such as tooltip.myaddon = true, and check if this flag is present so that the script doesn't add the line twice on recipes.
You then do an additional hook for OnTooltipCleared(I think that's the handler's name) to nil out tooltip.myaddon.
As for LinkWrangler, the author has provided a callback system which you can register with for LinkWrangler to inform your addon when it has created new tooltips (on demand) for you to apply your hooks or add your addon's lines.
Unless I'm mistaken, if you add the line on the first call, it adds the line directly below the "item" made by the recipe, which ends up in the middle of the tooltip instead of the end, most likely not what you want.
As shown in this image, if you blocked the second call, only the first "ItemLevel: 85" line would be shown.
Secondly, using the OnTooltipSetItem method means extra checking on every item tooltip you show, not that you will show a lot of tooltips very often, but the overhead is there. While the hooking-all-methods method is a one time thing on load.
Yes, thats just one addon, what about those that don't have one and you/your users would want support for it.
While not pretty, this works:
This is assuming TextLeft4 is always an empty line for recipes, which is not the case.
The question is why not avoid the overhead when you can?
You are mistaken. Mendeleev does post hooks of OnTooltipSetItem and OnTooltipCleared and it works perfectly when both the recipe and the item the recipe creates are in the local cache. I don't remember what happens when one isn't in the cache though, but if it does misbehave it will be correct the next time the tooltip is shown.
The top line in your screenshot is from the second call not the first.
What are you smoking? The hooks are still called on every tooltip even if you use the hook-all-methods method.
Awful idea, or zomg fantastic idea?
No you are.
"Recipe source" from Mendeleev
What are you smoking? The hooks are still called on every tooltip but without the extra lines of code to check if its the first call or second. And with out the OnTooltipCleared hook call. And with out the extra code if you want to check for recipes. ...
PS: I don't normally respond to rude posts. I know its kinda your style of talking, but please learn to not speak like you understand something when obviously you don't got a clue.
You're right that it's not always the same fontstring, but it's not an empty line, it's a vertical offset. You could probably find a (very expensive) way to check this in a safe way.
The sole purpose of "OnTooltipSetItem" is to allow hooking, whatever the setting function is, whatever the parameters order and type that are called on all methods that creates tooltip, if it IS an item, then the "OnTooltipSetItem" callback is called. The fact that it's called twice is a implementation bug.
You can try to tweak around this bug and you should ask for the bug to be fixed. The issue with pre-hooking is that you need to know all functions that set a tooltip and hook them all. It needs to be maintained. You also have to care about not tainting.
Actually I think the behavior is intended, and correct. The bug is that self:GetItem() doesn't return the crafted item, or both items. We bitched at the blues to fix that a few times, but I've kinda stopped caring. Double info on recipe tips doesn't really bother me.
*edit* and taint should *never* be an issue with tooltips... but still the script handler is better than direct hookerage.
I remember reporting this on the official forums way back when this feature was first introduced in a TBC patch, but they don't seem to care and its still broken on 3.2 PTR.
Also with the new GetItemStats(itemlink, table) API in 3.2, its also nearly useless in its current state. I wonder why it would only accept itemlink as input if it doesn't consider gems or enchants, it should just accept itemId which doesn't work in the current build, you have to feed it a proper itemlink.
It's not better if you need to workaround the recipe glitch. Like I said, depends on what you are trying to do.
Well, I don't :-) I think that if it was intended, then we would have a way to know when a tooltip is completely filled, because that really useful to know, as the whole issue here shows. This is unintended, but Blizzard has more pressing matters than fixing bugs that does not concern the client's default behaviour. Like fixing bugs that does concern their own UI.
When unsecurely hooking GameTooltip:SetHyperlink(), you taint all the code path that may follow such a call in blizzard's UI. It doesn't matter only if that code path is short, and do not spread this taint. You don't have the same problem when hooking the "OnTooltipSetItem" handler, mainly because there is no such handler in the default UI. How many calls to GameTooltip:Set*** exists in the default UI ? How many of these calls are not at the end of a event handler ? Did you check them all to make sure that tainting the code path that follow this call is safe ?
So, I really just need to then add in some code to get the relevant information to add in the AddText function, right? (AddDoubleLine was used as that's what I'm using in my addon anyway.)
jup, but I don't think you need the frame:Show() bit, as the tooltip is shown after "OnTooltipSetItem", anyway.
Also it might be an idea to stick the
bit outside the HookTip function so your don't end up creating 2 of the same function.
It is required to have the tooltip layout refreshed.
Just tested it, and you don't need to call :Show() when hooking "OnTooltipSetUnit" or "OnTooltipSetItem", as it will get called after using your hook.
But it is required for stuff like hooking the recipe shown when mouse is over the recipe icon in the tradeskill panel:
[php]
local button = _G.TradeSkillSkillIcon
local TS_OnEnter = button:GetScript"OnEnter"
local TS_OnLeave = button:GetScript"OnLeave"
local orgSetTradeSkillItem = GameTooltip.SetTradeSkillItem
local function newSetTradeSkillItem(...)
orgSetTradeSkillItem(...)
GameTooltip:AddLine("\n"..L"|cffff8040Click|r to create a shortcut.", .2, 1, .2)
GameTooltip:Show()
end
button:SetScript("OnEnter", function(...)
GameTooltip.SetTradeSkillItem = newSetTradeSkillItem
TS_OnEnter(...)
end)
button:SetScript("OnLeave", function(...)
TS_OnLeave(...)
GameTooltip.SetTradeSkillItem = orgSetTradeSkillItem
end)
[/php]
Well, your method of hooking CreateFrame() and then checking if the frame returned is of type GameTooltip, and then checking the name of the frame against a list of known addon (and their used gametooltip names) isn't any better. If you already have a list of addons you are comparing the name of the tooltip frames against, you should already know if you need to securehook CreateFrame or not (answer: you don't - because LinkWranger is the only one you support which create tooltips dynamically).
You say you have a better solution of correctly hooking dynamically created tooltips that don't have an API? I'm all ears.
Wrong, LinkWranger far from the only addon that creates tooltips dynamically, LibTipHooker supports quite a few more of them if you care to check yourself.