From b2e3485531b21709583f37ae75f87d4403c18b6f Mon Sep 17 00:00:00 2001
From: KameleonUK
Date: Thu, 4 Jun 2026 06:45:29 +0100
Subject: [PATCH 1/6] Fix: Tooltip error in other addons that hook itemlink for
tooltip
---
Core/Tooltip.lua | 15 +++++++--------
UI/ItemButton.lua | 12 ++++++++++--
2 files changed, 17 insertions(+), 10 deletions(-)
diff --git a/Core/Tooltip.lua b/Core/Tooltip.lua
index add1d2c..a7db598 100644
--- a/Core/Tooltip.lua
+++ b/Core/Tooltip.lua
@@ -483,15 +483,14 @@ function Tooltip:Initialize()
local oldSetHyperlink = GameTooltip.SetHyperlink
function GameTooltip:SetHyperlink(link)
return WithDeferredMoney(self, function()
+ -- The native Blizzard SetHyperlink only accepts a bare "item:ID:e:e:e" string.
+ -- Any addon that captured the native before Guda loaded (e.g. AtlasLoot) will
+ -- call it directly with whatever we pass here, so we MUST strip the color codes
+ -- and |H...|h wrapper before forwarding. Passing the full colored link causes
+ -- "unknown link type" in those addons.
local _, _, inner = string.find(link or "", "|H(.+)|h")
- local forwarded = link
- local itemLinkForCounts = link
- if inner then
- forwarded = inner
- if strfind(inner, "^item:") then
- itemLinkForCounts = inner
- end
- end
+ local forwarded = inner or link
+ local itemLinkForCounts = inner or link
local ret = oldSetHyperlink(self, forwarded)
if itemLinkForCounts and strfind(itemLinkForCounts, "item:") then
Tooltip:AddInventoryInfo(self, itemLinkForCounts)
diff --git a/UI/ItemButton.lua b/UI/ItemButton.lua
index 5755b18..90f38a3 100644
--- a/UI/ItemButton.lua
+++ b/UI/ItemButton.lua
@@ -2524,10 +2524,18 @@ function Guda_ItemButton_OnEnter(self)
GameTooltip:SetHyperlink(self.itemData.link)
end
elseif self.bagID == -2 then
- -- Keyring: SetBagItem might be unreliable for -2 in some 1.12.1 environments, fallback to hyperlink if needed
+ -- Keyring (bag -2): in 1.12 the native SetBagItem builds the keyring tooltip
+ -- by internally calling SetHyperlink with the FULL colored link
+ -- (|cff..|Hitem:..|h[Name]|h|r). When other addons (AtlasLoot, WoWTranslate)
+ -- have re-hooked SetHyperlink in an order that bypasses Guda's stripping, that
+ -- full link reaches a hook whose captured original is the raw Blizzard
+ -- SetHyperlink — which only accepts the BARE "item:ID:0:0:0" form and otherwise
+ -- throws "unknown link type". We avoid that internal path entirely by calling
+ -- SetHyperlink ourselves with the bare form extracted from the container link.
local link = GetContainerItemLink(self.bagID, self.slotID)
if link then
- GameTooltip:SetHyperlink(link)
+ local _, _, bare = string.find(link, "|H(item:[^|]+)|h")
+ GameTooltip:SetHyperlink(bare or link)
else
GameTooltip:SetBagItem(self.bagID, self.slotID)
end
From b06c47e53cd76573d7f367032c3122d3c73a99a6 Mon Sep 17 00:00:00 2001
From: KameleonUK <42344512+KameleonUK@users.noreply.github.com>
Date: Mon, 22 Jun 2026 08:17:04 +0100
Subject: [PATCH 2/6] Fix Tooltip error in other addons
Refactor tooltip setting to use GudaSetTooltipHyperlink for better compatibility with item links.
---
UI/ItemButton.lua | 32 ++++++++++++++++++++++++++------
1 file changed, 26 insertions(+), 6 deletions(-)
diff --git a/UI/ItemButton.lua b/UI/ItemButton.lua
index 5755b18..c0c2058 100644
--- a/UI/ItemButton.lua
+++ b/UI/ItemButton.lua
@@ -263,6 +263,19 @@ local function IsInCategoryView(isBank)
return (addon.Modules.DB:GetSetting(key) or "single") == "category"
end
+-- Set a tooltip from an item link, passing the BARE "item:ID:e:e:e" form rather
+-- than the full colored link. The 1.12 native GameTooltip:SetHyperlink only
+-- accepts the bare form; passing a full |cff..|Hitem:..|h[Name]|h|r link can
+-- reach a bare-only native further down a re-hooked SetHyperlink chain (e.g. when
+-- AtlasLoot / WoWTranslate / SuperCleverRoidMacros have re-hooked in an order that
+-- bypasses Guda's own stripping hook) and throw "unknown link type" in that addon.
+-- Always route Guda-originated SetHyperlink calls through this helper.
+local function GudaSetTooltipHyperlink(tooltip, link)
+ if not link then return end
+ local _, _, bare = string.find(link, "|H(item:[^|]+)|h")
+ tooltip:SetHyperlink(bare or link)
+end
+
-- Auto-clear cursor tracking when cursor is truly empty, and notify BagFrame
-- of drag-state transitions. In 1.12 CURSOR_UPDATE is unreliable for item
-- pickups, so we also poll CursorHasItem() on a throttled OnUpdate —
@@ -2449,7 +2462,7 @@ function Guda_ItemButton_OnEnter(self)
-- Read-only / other character mailbox OR current character mailbox when closed
GameTooltip.GudaViewedCharacter = self.otherChar or currentPlayerName
if self.itemData.link then
- GameTooltip:SetHyperlink(self.itemData.link)
+ GudaSetTooltipHyperlink(GameTooltip, self.itemData.link)
else
GameTooltip:SetHyperlink("item:" .. self.itemData.itemID .. ":0:0:0")
end
@@ -2504,7 +2517,7 @@ function Guda_ItemButton_OnEnter(self)
elseif self.otherChar or self.isReadOnly then
GameTooltip.GudaViewedCharacter = self.otherChar
if self.itemData and self.itemData.link then
- local ok = pcall(GameTooltip.SetHyperlink, GameTooltip, self.itemData.link)
+ local ok = pcall(GudaSetTooltipHyperlink, GameTooltip, self.itemData.link)
if not ok then
GameTooltip:Hide()
return
@@ -2521,13 +2534,20 @@ function Guda_ItemButton_OnEnter(self)
GameTooltip:SetBagItem(self.bagID, self.slotID)
elseif self.itemData and self.itemData.link then
-- Bank is closed - use cached link
- GameTooltip:SetHyperlink(self.itemData.link)
+ GudaSetTooltipHyperlink(GameTooltip, self.itemData.link)
end
elseif self.bagID == -2 then
- -- Keyring: SetBagItem might be unreliable for -2 in some 1.12.1 environments, fallback to hyperlink if needed
+ -- Keyring (bag -2): in 1.12 the native SetBagItem builds the keyring tooltip
+ -- by internally calling SetHyperlink with the FULL colored link
+ -- (|cff..|Hitem:..|h[Name]|h|r). When other addons (AtlasLoot, WoWTranslate)
+ -- have re-hooked SetHyperlink in an order that bypasses Guda's stripping, that
+ -- full link reaches a hook whose captured original is the raw Blizzard
+ -- SetHyperlink — which only accepts the BARE "item:ID:0:0:0" form and otherwise
+ -- throws "unknown link type". We avoid that internal path entirely by calling
+ -- SetHyperlink ourselves with the bare form (GudaSetTooltipHyperlink extracts it).
local link = GetContainerItemLink(self.bagID, self.slotID)
if link then
- GameTooltip:SetHyperlink(link)
+ GudaSetTooltipHyperlink(GameTooltip, link)
else
GameTooltip:SetBagItem(self.bagID, self.slotID)
end
@@ -2636,4 +2656,4 @@ function Guda_ItemButton_OnLeave(self)
Guda_BagFrame_ClearBagButtonHighlight()
end
end
-end
\ No newline at end of file
+end
From 7d18d420889d7a13309ad0af920603b3e6972e30 Mon Sep 17 00:00:00 2001
From: KameleonUK <42344512+KameleonUK@users.noreply.github.com>
Date: Mon, 22 Jun 2026 08:17:41 +0100
Subject: [PATCH 3/6] Fix Tooltip error in other addons
Refactor hyperlink handling in GameTooltip to simplify link processing and ensure compatibility with other addons.
---
Core/Tooltip.lua | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/Core/Tooltip.lua b/Core/Tooltip.lua
index add1d2c..027b7e2 100644
--- a/Core/Tooltip.lua
+++ b/Core/Tooltip.lua
@@ -483,15 +483,14 @@ function Tooltip:Initialize()
local oldSetHyperlink = GameTooltip.SetHyperlink
function GameTooltip:SetHyperlink(link)
return WithDeferredMoney(self, function()
+ -- The native Blizzard SetHyperlink only accepts a bare "item:ID:e:e:e" string.
+ -- Any addon that captured the native before Guda loaded (e.g. AtlasLoot) will
+ -- call it directly with whatever we pass here, so we MUST strip the color codes
+ -- and |H...|h wrapper before forwarding. Passing the full colored link causes
+ -- "unknown link type" in those addons.
local _, _, inner = string.find(link or "", "|H(.+)|h")
- local forwarded = link
- local itemLinkForCounts = link
- if inner then
- forwarded = inner
- if strfind(inner, "^item:") then
- itemLinkForCounts = inner
- end
- end
+ local forwarded = inner or link
+ local itemLinkForCounts = inner or link
local ret = oldSetHyperlink(self, forwarded)
if itemLinkForCounts and strfind(itemLinkForCounts, "item:") then
Tooltip:AddInventoryInfo(self, itemLinkForCounts)
@@ -653,4 +652,4 @@ function Tooltip:Initialize()
end)
addon:Print("Tooltip integration enabled - Inventory displays above vendor price")
-end
\ No newline at end of file
+end
From 2280d8b48733f0536cd9dc7d6b8e5d75304c9651 Mon Sep 17 00:00:00 2001
From: KameleonUK
Date: Thu, 25 Jun 2026 11:45:06 +0100
Subject: [PATCH 4/6] Modification to Clam Opener to fix issue #75
---
Core/ClamOpener.lua | 28 ++++++++++++++++++++++------
1 file changed, 22 insertions(+), 6 deletions(-)
diff --git a/Core/ClamOpener.lua b/Core/ClamOpener.lua
index 9af5449..bc9335c 100644
--- a/Core/ClamOpener.lua
+++ b/Core/ClamOpener.lua
@@ -22,6 +22,8 @@ local QUIET_DELAY = 0.5 -- seconds of silence after a *_CLOSED event before aut
local running = false
local silentRun = false
local pendingToken = 0 -- bumped on every auto-trigger and on LOOT_OPENED to cancel stale timers
+local waitingForLoot = false
+local OpenNext -- forward declaration; defined after OnClamLootClosed
-- Returns true if any blocking window (loot/mail/trade/merchant/bank/auction)
-- is currently open. We don't want to UseContainerItem while these are active --
@@ -65,22 +67,33 @@ end
local function StopRun(reason)
if not running then return end
running = false
- -- Only drop the per-run UI_ERROR_MESSAGE listener; the persistent auto-
- -- trigger events stay registered.
addon.Modules.Events:UnregisterOwner("ClamOpener_Run")
+ addon.Modules.Events:UnregisterOwner("ClamOpener_LootWait")
+ waitingForLoot = false
if reason and not silentRun then
addon:Print(reason)
end
silentRun = false
end
-local function OpenNext()
+-- waitingForLoot: set between UseContainerItem and the LOOT_CLOSED that confirms
+-- the clam loot window has fully closed, preventing any concurrent UseContainerItem.
+local function OnClamLootClosed()
+ -- Unregister this one-shot listener immediately.
+ addon.Modules.Events:UnregisterOwner("ClamOpener_LootWait")
+ waitingForLoot = false
if not running then return end
+ -- Small delay to let the client fully settle before the next open.
+ Guda_ScheduleTimer(OPEN_DELAY, OpenNext)
+end
+
+OpenNext = function()
+ if not running then return end
+ if waitingForLoot then return end
-- Never use a clam while something else is in-flight: cursor busy,
-- a blocking window open, or a server-side loot still active. Any of
- -- these + UseContainerItem races the client loot state machine and
- -- can soft-lock the loot UI ("too far away" greyed-out items).
+ -- these + UseContainerItem races the open window or get queued and lost.
if CursorHasItem()
or IsBlockingWindowOpen()
or (GetNumLootItems and GetNumLootItems() > 0) then
@@ -94,8 +107,11 @@ local function OpenNext()
return
end
+ -- Arm the one-shot LOOT_CLOSED listener before calling UseContainerItem
+ -- so we cannot miss the event even if it fires in the same frame.
+ waitingForLoot = true
+ addon.Modules.Events:Register("LOOT_CLOSED", OnClamLootClosed, "ClamOpener_LootWait")
UseContainerItem(bagID, slotID)
- Guda_ScheduleTimer(OPEN_DELAY, OpenNext)
end
-- Stop on UI_ERROR_MESSAGE (e.g. inventory full). UseContainerItem fires this
From bd96db85c760adb37a1806d020418e473902e5dc Mon Sep 17 00:00:00 2001
From: KameleonUK
Date: Thu, 25 Jun 2026 11:47:21 +0100
Subject: [PATCH 5/6] Modifed Tooltip to prevent errors in other addons that
extend tooltip.
---
UI/ItemButton.lua | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/UI/ItemButton.lua b/UI/ItemButton.lua
index 90f38a3..5566581 100644
--- a/UI/ItemButton.lua
+++ b/UI/ItemButton.lua
@@ -263,6 +263,19 @@ local function IsInCategoryView(isBank)
return (addon.Modules.DB:GetSetting(key) or "single") == "category"
end
+-- Set a tooltip from an item link, passing the BARE "item:ID:e:e:e" form rather
+-- than the full colored link. The 1.12 native GameTooltip:SetHyperlink only
+-- accepts the bare form; passing a full |cff..|Hitem:..|h[Name]|h|r link can
+-- reach a bare-only native further down a re-hooked SetHyperlink chain (e.g. when
+-- AtlasLoot / WoWTranslate / SuperCleverRoidMacros have re-hooked in an order that
+-- bypasses Guda's own stripping hook) and throw "unknown link type" in that addon.
+-- Always route Guda-originated SetHyperlink calls through this helper.
+local function GudaSetTooltipHyperlink(tooltip, link)
+ if not link then return end
+ local _, _, bare = string.find(link, "|H(item:[^|]+)|h")
+ tooltip:SetHyperlink(bare or link)
+end
+
-- Auto-clear cursor tracking when cursor is truly empty, and notify BagFrame
-- of drag-state transitions. In 1.12 CURSOR_UPDATE is unreliable for item
-- pickups, so we also poll CursorHasItem() on a throttled OnUpdate —
@@ -2449,7 +2462,7 @@ function Guda_ItemButton_OnEnter(self)
-- Read-only / other character mailbox OR current character mailbox when closed
GameTooltip.GudaViewedCharacter = self.otherChar or currentPlayerName
if self.itemData.link then
- GameTooltip:SetHyperlink(self.itemData.link)
+ GudaSetTooltipHyperlink(GameTooltip, self.itemData.link)
else
GameTooltip:SetHyperlink("item:" .. self.itemData.itemID .. ":0:0:0")
end
@@ -2504,7 +2517,7 @@ function Guda_ItemButton_OnEnter(self)
elseif self.otherChar or self.isReadOnly then
GameTooltip.GudaViewedCharacter = self.otherChar
if self.itemData and self.itemData.link then
- local ok = pcall(GameTooltip.SetHyperlink, GameTooltip, self.itemData.link)
+ local ok = pcall(GudaSetTooltipHyperlink, GameTooltip, self.itemData.link)
if not ok then
GameTooltip:Hide()
return
@@ -2521,7 +2534,7 @@ function Guda_ItemButton_OnEnter(self)
GameTooltip:SetBagItem(self.bagID, self.slotID)
elseif self.itemData and self.itemData.link then
-- Bank is closed - use cached link
- GameTooltip:SetHyperlink(self.itemData.link)
+ GudaSetTooltipHyperlink(GameTooltip, self.itemData.link)
end
elseif self.bagID == -2 then
-- Keyring (bag -2): in 1.12 the native SetBagItem builds the keyring tooltip
@@ -2531,11 +2544,10 @@ function Guda_ItemButton_OnEnter(self)
-- full link reaches a hook whose captured original is the raw Blizzard
-- SetHyperlink — which only accepts the BARE "item:ID:0:0:0" form and otherwise
-- throws "unknown link type". We avoid that internal path entirely by calling
- -- SetHyperlink ourselves with the bare form extracted from the container link.
+ -- SetHyperlink ourselves with the bare form (GudaSetTooltipHyperlink extracts it).
local link = GetContainerItemLink(self.bagID, self.slotID)
if link then
- local _, _, bare = string.find(link, "|H(item:[^|]+)|h")
- GameTooltip:SetHyperlink(bare or link)
+ GudaSetTooltipHyperlink(GameTooltip, link)
else
GameTooltip:SetBagItem(self.bagID, self.slotID)
end
From 1dc13786a7843146145d39fa90a69c47e041a014 Mon Sep 17 00:00:00 2001
From: KameleonUK
Date: Thu, 25 Jun 2026 11:49:41 +0100
Subject: [PATCH 6/6] Ignore backup files in commits
---
.gitignore | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/.gitignore b/.gitignore
index 06727ec..3610e1c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,6 @@
.vscode
.idea
NUL
-temp
\ No newline at end of file
+temp
+Tooltip_OG.lua
+ItemButton_OG.lua
\ No newline at end of file