fix(quest): skip stale frames in Show/HideQuestIcons instead of crashing
ShowQuestIcons/HideQuestIcons indexed icon (=_G[frameName]) when it can be nil for a registry entry whose frame was already reset, crashing the fade pass (attempt to index local 'icon'). Guard icon/icon.data/ icon.data.QuestData and skip stale frames; ShowQuestIcons no longer error()s on the desync.
This commit is contained in:
@@ -41,6 +41,7 @@
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **[Fix - Fade Pass Crash On Stale Frame]** Hardened `ShowQuestIcons`/`HideQuestIcons` against a stale-frame desync (`attempt to index local 'icon'`): a frame name lingering in the registry after its frame was reset is now skipped gracefully instead of erroring out of the whole fade pass (and `ShowQuestIcons` no longer `error()`s on the desync), with nil-guards on `icon`/`icon.data`/`icon.data.QuestData`.
|
||||
- **[Fix - Tooltip Crash On Unit Hover]** Fixed a crash on every unit tooltip (`attempt to call global '_TooltipHasLeftLine'`): the dedupe helper was defined *after* `AddUnitDataToTooltip`, so that function couldn't see the local. It's now defined before all `Add*DataToTooltip` functions.
|
||||
- **[Tooltip - Robust ID Resolution For Hex/Object GUIDs]** Tooltip NPC IDs are now resolved with the learner's robust GUID parser (`QuestieLearner:GetIdAndTypeFromGUID`, now public) as a fallback when the naive `strsplit("-", guid)` can't parse the GUID — e.g. legacy `0x` hex GUIDs — which previously left the NPC ID line silently unwritten. The Object ID line gained a matching fallback: when a hovered object's name isn't in the lookup, it resolves the ID from the object's GUID via the new `QuestieLearner:GetObjectIdFromGUID`. Both ID lines are also deduped per tooltip.
|
||||
- **[Tooltip - ID Lines No Longer Vanish On Re-Hover]** The "Item ID" / "NPC ID" lines were only added when the hovered item/unit *changed* (`lastItemId`/`lastGuid` gate). But WoW clears and re-fires `OnTooltipSetItem`/`OnTooltipSetUnit` for the *same* item/unit, rebuilding the tooltip — and the gate skipped re-adding the line on the rebuilt tooltip, so the ID disappeared (e.g. hovering the same quest item twice). The ID lines are now (re)added on every render and deduplicated per tooltip (via `_TooltipHasLeftLine`), so they're always present exactly once.
|
||||
|
||||
@@ -120,13 +120,15 @@ function _QuestieQuest:ShowQuestIcons()
|
||||
while _ do -- this may seem a bit expensive, but its actually really fast due to the order things are checked
|
||||
---@type IconFrame
|
||||
local icon = _G[frameName];
|
||||
if not icon.data then
|
||||
error("Desync! Icon has not been removed correctly, but has already been reset. Skipping frame \"" ..
|
||||
frameName .. "\" for quest " .. questId)
|
||||
if (icon == nil) or (not icon.data) then
|
||||
-- Desync: the frame was reset/removed but its name lingered in the registry.
|
||||
-- Skip it gracefully (previously this errored out of the whole show pass).
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP,
|
||||
"[QuestieQuest:ShowQuestIcons] Skipping stale frame", tostring(frameName), "for quest", questId)
|
||||
else
|
||||
local objectiveString = tostring(questId) .. " " .. tostring(icon.data.ObjectiveIndex)
|
||||
if (not Questie.db.char.TrackerHiddenObjectives) or (not Questie.db.char.TrackerHiddenObjectives[objectiveString]) then
|
||||
if icon ~= nil and icon.hidden and (not icon:ShouldBeHidden()) then
|
||||
if icon.hidden and (not icon:ShouldBeHidden()) then
|
||||
icon:FakeShow()
|
||||
|
||||
if icon.data.lineFrames then
|
||||
@@ -137,7 +139,7 @@ function _QuestieQuest:ShowQuestIcons()
|
||||
end
|
||||
end
|
||||
end
|
||||
if (icon.data.QuestData.FadeIcons or (icon.data.ObjectiveData and icon.data.ObjectiveData.FadeIcons)) and icon.data.Type ~= "complete" then
|
||||
if ((icon.data.QuestData and icon.data.QuestData.FadeIcons) or (icon.data.ObjectiveData and icon.data.ObjectiveData.FadeIcons)) and icon.data.Type ~= "complete" then
|
||||
icon:FadeOut()
|
||||
else
|
||||
icon:FadeIn()
|
||||
@@ -172,25 +174,30 @@ function _QuestieQuest:HideQuestIcons()
|
||||
local __, frameName = next(frameList)
|
||||
while __ do -- this may seem a bit expensive, but its actually really fast due to the order things are checked
|
||||
local icon = _G[frameName];
|
||||
if icon ~= nil and (not icon.hidden) and icon:ShouldBeHidden() then -- check for function to make sure its a frame
|
||||
-- Hides Objective Icons
|
||||
icon:FakeHide()
|
||||
-- icon can be nil here if the frame was reset/removed while its name lingered in
|
||||
-- the registry (a stale entry). Guard every access so a desync just skips the
|
||||
-- frame instead of erroring out of the whole fade pass.
|
||||
if icon ~= nil and icon.data then
|
||||
if (not icon.hidden) and icon:ShouldBeHidden() then -- check for function to make sure its a frame
|
||||
-- Hides Objective Icons
|
||||
icon:FakeHide()
|
||||
|
||||
-- Hides Objective Tooltips
|
||||
QuestieTooltips:RemoveQuest(icon.data.Id)
|
||||
-- Hides Objective Tooltips
|
||||
QuestieTooltips:RemoveQuest(icon.data.Id)
|
||||
|
||||
if icon.data.lineFrames then
|
||||
local ___, lineIcon = next(icon.data.lineFrames)
|
||||
while ___ do
|
||||
lineIcon:FakeHide()
|
||||
___, lineIcon = next(icon.data.lineFrames, ___)
|
||||
if icon.data.lineFrames then
|
||||
local ___, lineIcon = next(icon.data.lineFrames)
|
||||
while ___ do
|
||||
lineIcon:FakeHide()
|
||||
___, lineIcon = next(icon.data.lineFrames, ___)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if (icon.data.QuestData.FadeIcons or (icon.data.ObjectiveData and icon.data.ObjectiveData.FadeIcons)) and icon.data.Type ~= "complete" then
|
||||
icon:FadeOut()
|
||||
else
|
||||
icon:FadeIn()
|
||||
if ((icon.data.QuestData and icon.data.QuestData.FadeIcons) or (icon.data.ObjectiveData and icon.data.ObjectiveData.FadeIcons)) and icon.data.Type ~= "complete" then
|
||||
icon:FadeOut()
|
||||
else
|
||||
icon:FadeIn()
|
||||
end
|
||||
end
|
||||
__, frameName = next(frameList, __)
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user