diff --git a/CHANGELOG.md b/CHANGELOG.md index b5d73ff..d75bee2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ ### Bug Fixes +- **[Map - Completed Objective Pins Linger]** Added `QuestieMap:UnloadQuestFramesForObjective(questId, objectiveIndex)` and call it from every completion path in `QuestieQuest:PopulateObjective` (objective completed, hidden by `ShouldHideObjective`, and static no-`Update` objectives). Previously, removing a completed objective's map/minimap pins relied solely on `_UnloadAlreadySpawnedIcons`, which walks `objective.AlreadySpawned`. That table desyncs from the frames actually on screen after learner spawn-list invalidation or complete→abandon→reaccept cycles, so when it was reset to `{}` the live frames leaked and pins for fully-completed objectives (e.g. 6/6 kills, a collected item objective) stayed on the map even though tooltips updated correctly. The new function unloads frames deterministically off the map's own `questIdFrames` registry by matching `frame.data.ObjectiveIndex`, so completed-objective pins are removed regardless of `AlreadySpawned` state. Restricted to positive standard-objective indices; SpecialObjectives (sentinel index 0) keep using `AlreadySpawned` to avoid cross-unloading siblings. - **[QuestieLib - GetColoredQuestName Nil Guard]** Added a nil guard in `QuestieLib:GetColoredQuestName` so a synthetic `questId` (e.g. one used in a chat link on servers that do not have a real quest entry) no longer crashes with `attempt to index a nil value`. The function now checks `QuestieDB.GetQuest(questId)` before reading its `isComplete` flag. - **[Tooltip - Item Flicker on ElvUI Refresh]** Simplified the `AddItemDataToTooltip` redraw check to key purely on `itemId`. The previous condition also re-keyed on tooltip name, line count, and frame name — all of which ElvUI's tooltip-frame recycling transiently resets, so every refresh cycle looked like a new item and caused Questie's lines to flicker repeatedly. The new condition only re-adds when the actual itemId changes, so the tooltip stays stable across ElvUI's refresh ticks. - **[Tooltip - First-Hover Resize Pop]** Removed the unconditional `QuestieTooltips:ResizeTooltip(self)` call from `AddItemDataToTooltip`. With the flicker fix in place, the resize pass still fired once per item hover and triggered ElvUI's smooth-resize animation, causing a visible frame pop on first hover. ElvUI already manages tooltip sizing correctly, so the Questie resize call is no longer needed for item tooltips. diff --git a/Modules/Map/QuestieMap.lua b/Modules/Map/QuestieMap.lua index 74f0b2d..66c0e12 100644 --- a/Modules/Map/QuestieMap.lua +++ b/Modules/Map/QuestieMap.lua @@ -85,6 +85,28 @@ function QuestieMap:GetFramesForQuest(questId) return frames end +-- Unload only the frames belonging to a single objective of a quest. +-- Frames carry data.ObjectiveIndex (set in _DetermineIconsToDraw), so we can remove a +-- completed objective's pins deterministically off the map's own frame registry instead +-- of relying on objective.AlreadySpawned, which desyncs from on-screen frames after +-- learner spawn-list invalidation or complete->abandon->reaccept cycles. +function QuestieMap:UnloadQuestFramesForObjective(questId, objectiveIndex) + -- objectiveIndex 0 is the SpecialObjectives sentinel (shared by all special objectives), + -- so unloading by it would cross-remove sibling specials mid-pass. Only act on real + -- positive standard-objective indices; specials keep using AlreadySpawned. + if (not objectiveIndex) or objectiveIndex <= 0 or (not QuestieMap.questIdFrames[questId]) then + return + end + for name, frame in pairs(QuestieMap:GetFramesForQuest(questId)) do + if frame and frame.data and frame.data.ObjectiveIndex == objectiveIndex then + frame:Unload() + QuestieMap.questIdFrames[questId][name] = nil + _G[name] = nil + end + end + Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieMap] Unloading objective frames for questid:", questId, "objIdx:", objectiveIndex) +end + function QuestieMap:UnloadQuestFrames(questId, iconType) if QuestieMap.questIdFrames[questId] then if not iconType then diff --git a/Modules/Quest/QuestieQuest.lua b/Modules/Quest/QuestieQuest.lua index 8e3c507..3ccda99 100644 --- a/Modules/Quest/QuestieQuest.lua +++ b/Modules/Quest/QuestieQuest.lua @@ -1491,6 +1491,7 @@ function QuestieQuest:PopulateObjective(quest, objectiveIndex, objective, blockI Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieQuest:PopulateObjective] - No Update fn but objective is complete, unloading icons.") _UnloadAlreadySpawnedIcons(objective) + QuestieMap:UnloadQuestFramesForObjective(quest.Id, objectiveIndex) end return end @@ -1516,6 +1517,7 @@ function QuestieQuest:PopulateObjective(quest, objectiveIndex, objective, blockI if QuestieQuest.ShouldHideObjective(objective) then Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieQuest:PopulateObjective] HIDDEN by ShouldHideObjective, unloading icons for objIdx:", objectiveIndex) _UnloadAlreadySpawnedIcons(objective) + QuestieMap:UnloadQuestFramesForObjective(quest.Id, objectiveIndex) return end @@ -1536,6 +1538,7 @@ function QuestieQuest:PopulateObjective(quest, objectiveIndex, objective, blockI Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieQuest:PopulateObjective] SKIPPING objective (completed):", objective.Description, "completed:", tostring(completed), "quest.isComplete:", tostring(quest.isComplete)) _UnloadAlreadySpawnedIcons(objective) + QuestieMap:UnloadQuestFramesForObjective(quest.Id, objectiveIndex) return end