fix(tracker): guard VoiceOver questPlayButtons and AceGUI tree tooltip (#15)

Two crashes reported in #15 on Elune (1.6.3):

- TrackerUtils:IsVoiceOverLoaded only verified the VoiceOver addons were
  loaded, not that VoiceOver.QuestOverlayUI.questPlayButtons exists. Some
  VoiceOver builds expose a QuestOverlayUI without that table, so
  UpdateVoiceOverPlayButtons and SetAllPlayButtonAlpha crashed with
  'attempt to index field questPlayButtons (a nil value)'. Now verified in
  IsVoiceOverLoaded, which all play-button call sites gate on.

- AceGUIContainer-TreeGroup crashed indexing a nil AceGUI.tooltip when a
  conflicting addon registered a broken AceGUI-3.0 core (version 1.#INF)
  that won LibStub but never created the shared tooltip frame. The tree
  button handlers now lazily recreate it; widget version bumped 47->48 so
  the fixed widget wins registration.
This commit is contained in:
Xurkon
2026-06-09 20:41:37 -05:00
parent 08b266d7ba
commit 69a9a4a7a3
3 changed files with 22 additions and 3 deletions
+2
View File
@@ -28,6 +28,8 @@
### Bug Fixes
- **[Tracker - VoiceOver questPlayButtons Nil Crash]** (#15) Fixed `attempt to index field 'questPlayButtons' (a nil value)` in `TrackerUtils:UpdateVoiceOverPlayButtons` and `TrackerLinePool.SetAllPlayButtonAlpha`. `TrackerUtils:IsVoiceOverLoaded` only checked that the VoiceOver addons were loaded, but some VoiceOver builds (seen on Elune) expose a `QuestOverlayUI` without a `questPlayButtons` table. It now also verifies `VoiceOver.QuestOverlayUI.questPlayButtons` exists; since every play-button call site gates on this function, the integration is now safely skipped instead of crashing on those builds.
- **[Libs/AceGUI - Tree Tooltip Nil Crash]** (#15) Hardened `AceGUIContainer-TreeGroup` against `attempt to index ... 'tooltip' (a nil value)` when a conflicting addon registers a broken `AceGUI-3.0` core (observed in the wild as version `1.#INF`) that wins LibStub but never creates the shared `AceGUI.tooltip` frame. The tree button enter/leave handlers now lazily (re)create the tooltip frame; the widget version was bumped 47→48 so the fixed widget wins registration over an unpatched same-version copy.
- **[Tooltip - Learner Spawn Data Never In Main Tooltip]** Learner spawn/kill data is no longer added inline to the main NPC tooltip under any setting. Previously, with the "Use secondary learner tooltip" option off, `_AddLearnedSpawnTooltipLine` appended the lines directly to `GameTooltip`. The toggle now gates the data entirely: on = shown in the separate secondary frame, off = not shown anywhere. Removed the now-unused `_AddTooltipSeparator` helper and updated the option description. (Complements the earlier System A suppression that kept the duplicate learner lines out of the main tooltip.)
- **[Tooltip - Stale Quest Objective Lookup On Turn-In]** Hovering an NPC right after turning in (or abandoning) one of its associated quests spammed a `debugstack` trace in DEVELOP mode: the learner objective-correlation block in `QuestieTooltips:GetTooltip` called `QuestLogCache.GetQuestObjectives` for a quest no longer in `QuestLogCache` (gracefully returns `{}`, but logs a stack). The NPC and object correlation loops now skip quests not in `QuestiePlayer.currentQuestlog`, so live objective progress is only looked up for quests the player is currently on. No functional change for active quests (a completed quest had no progress to show anyway).
- **[Tooltip - Secondary Learner Tooltip Leak]** With the "Use secondary learner tooltip" option enabled, learner spawn/kill lines still appeared in the main NPC tooltip instead of going solely to the secondary frame. Two parallel learner-tooltip systems were both rendering on unit hover: QuestieLearner's `OnTooltipSetUnit` hook (toggle-aware, secondary-capable) and `Tooltip.lua`'s `_GetLearnerTooltipLines` (always injected "Learned spawn / Total spawns learned / Total kills recorded" into the `m_<npcId>` tooltip data). `QuestieTooltips:GetTooltip` now takes a `suppressLearnerLines` flag, and the NPC unit-hover call in `TooltipHandler.lua` passes it so the inline learner lines are omitted there — the `OnTooltipSetUnit` hook owns that display and routes it to the main tooltip (secondary off) or the separate secondary frame (secondary on). Map-pin and object tooltips are unaffected and keep their learner lines. Also removes the latent duplicate learner lines that appeared in the main tooltip even with the secondary frame disabled.
@@ -2,7 +2,10 @@
TreeGroup Container
Container that uses a tree control to switch between groups.
-------------------------------------------------------------------------------]]
local Type, Version = "TreeGroup", 47
-- Version bumped 47 -> 48 (Questie-X): hardened Button_OnEnter/OnLeave against a nil
-- AceGUI.tooltip caused by a conflicting addon's broken AceGUI-3.0 core. The bump ensures
-- this fixed widget wins registration over an unpatched same-version copy.
local Type, Version = "TreeGroup", 48
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
@@ -202,6 +205,13 @@ local function Button_OnEnter(frame)
self:Fire("OnButtonEnter", frame.uniquevalue, frame)
if self.enabletooltips then
-- AceGUI.tooltip can be nil when a conflicting addon registered a broken
-- AceGUI-3.0 core (seen in the wild as version "1.#INF") that won LibStub
-- but never created the shared tooltip frame. Lazily (re)create it so tree
-- button tooltips work instead of erroring with "attempt to index ... tooltip".
if not AceGUI.tooltip then
AceGUI.tooltip = CreateFrame("GameTooltip", "AceGUITooltip", UIParent, "GameTooltipTemplate")
end
local tooltip = AceGUI.tooltip
tooltip:SetOwner(frame, "ANCHOR_NONE")
tooltip:ClearAllPoints()
@@ -216,7 +226,7 @@ local function Button_OnLeave(frame)
local self = frame.obj
self:Fire("OnButtonLeave", frame.uniquevalue, frame)
if self.enabletooltips then
if self.enabletooltips and AceGUI.tooltip then
AceGUI.tooltip:Hide()
end
end
+8 -1
View File
@@ -1232,7 +1232,14 @@ function TrackerUtils:GetSortedQuestIds()
end
function TrackerUtils:IsVoiceOverLoaded()
if (IsAddOnLoaded("AI_VoiceOver") and IsAddOnLoaded("AI_VoiceOverData_Vanilla")) then
-- Require not just that the VoiceOver addons are loaded, but that the runtime
-- structure we index actually exists. Some VoiceOver builds (e.g. on Elune) expose
-- a different QuestOverlayUI shape where questPlayButtons is absent, which previously
-- crashed UpdateVoiceOverPlayButtons / SetAllPlayButtonAlpha with "attempt to index
-- field 'questPlayButtons' (a nil value)". All play-button call sites gate on this
-- function, so verifying the table here makes them all safe.
if IsAddOnLoaded("AI_VoiceOver") and IsAddOnLoaded("AI_VoiceOverData_Vanilla")
and VoiceOver and VoiceOver.QuestOverlayUI and VoiceOver.QuestOverlayUI.questPlayButtons then
return true
end