fix(map): harden quest completion pin cleanup
This commit is contained in:
@@ -618,6 +618,36 @@ end
|
|||||||
local allianceChampionMarkerQuests = { [13699] = true, [13713] = true, [13723] = true, [13724] = true, [13725] = true }
|
local allianceChampionMarkerQuests = { [13699] = true, [13713] = true, [13723] = true, [13724] = true, [13725] = true }
|
||||||
local hordeChampionMarkerQuests = { [13726] = true, [13727] = true, [13728] = true, [13729] = true, [13731] = true }
|
local hordeChampionMarkerQuests = { [13726] = true, [13727] = true, [13728] = true, [13729] = true, [13731] = true }
|
||||||
|
|
||||||
|
local function _CleanupCompletedQuestObjectivePins(quest)
|
||||||
|
if (not quest) or (not quest.Id) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Full quest completion has to drain objective-owned frame refs before the
|
||||||
|
-- cached objective table is cleared. Some kill pins can be absent from the
|
||||||
|
-- map registry after data-source refreshes, but still live in AlreadySpawned.
|
||||||
|
if type(quest.Objectives) == "table" then
|
||||||
|
for objectiveIndex, objective in pairs(quest.Objectives) do
|
||||||
|
if type(objective) == "table" then
|
||||||
|
_UnloadAlreadySpawnedIcons(objective)
|
||||||
|
if type(objectiveIndex) == "number" then
|
||||||
|
QuestieMap:UnloadQuestFramesForObjective(quest.Id, objectiveIndex)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if type(quest.SpecialObjectives) == "table" then
|
||||||
|
for _, objective in pairs(quest.SpecialObjectives) do
|
||||||
|
if type(objective) == "table" then
|
||||||
|
_UnloadAlreadySpawnedIcons(objective)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
QuestieMap:UnloadQuestFrames(quest.Id)
|
||||||
|
end
|
||||||
|
|
||||||
---@param questId number
|
---@param questId number
|
||||||
function QuestieQuest:CompleteQuest(questId)
|
function QuestieQuest:CompleteQuest(questId)
|
||||||
-- Skip quests which are turn in only and are not added to the quest log in the first place
|
-- Skip quests which are turn in only and are not added to the quest log in the first place
|
||||||
@@ -651,11 +681,15 @@ function QuestieQuest:CompleteQuest(questId)
|
|||||||
-- Cached Completed=true / isUpdated=true flags that would cause
|
-- Cached Completed=true / isUpdated=true flags that would cause
|
||||||
-- PopulateObjectiveNotes to skip drawing map pins (bug: complete-abandon-reaccept).
|
-- PopulateObjectiveNotes to skip drawing map pins (bug: complete-abandon-reaccept).
|
||||||
local quest = QuestieDB.GetQuest(questId)
|
local quest = QuestieDB.GetQuest(questId)
|
||||||
if quest and type(quest.Objectives) == "table" then
|
if quest then
|
||||||
|
_CleanupCompletedQuestObjectivePins(quest)
|
||||||
|
|
||||||
|
if type(quest.Objectives) == "table" then
|
||||||
quest.Objectives = {}
|
quest.Objectives = {}
|
||||||
end
|
end
|
||||||
|
else
|
||||||
QuestieMap:UnloadQuestFrames(questId)
|
QuestieMap:UnloadQuestFrames(questId)
|
||||||
|
end
|
||||||
|
|
||||||
-- Clear the pending-complete guard now that frames are unloaded
|
-- Clear the pending-complete guard now that frames are unloaded
|
||||||
if QuestiePlayer.pendingCompleteQuestIds then
|
if QuestiePlayer.pendingCompleteQuestIds then
|
||||||
@@ -669,6 +703,13 @@ function QuestieQuest:CompleteQuest(questId)
|
|||||||
-- Delayed verification to ensure all objective icons are removed
|
-- Delayed verification to ensure all objective icons are removed
|
||||||
-- This handles race conditions where AvailableQuests might redraw icons or UnloadQuestFrames misses some
|
-- This handles race conditions where AvailableQuests might redraw icons or UnloadQuestFrames misses some
|
||||||
C_Timer.After(0.5, function()
|
C_Timer.After(0.5, function()
|
||||||
|
local delayedQuest = QuestieDB.GetQuest(questId)
|
||||||
|
if delayedQuest then
|
||||||
|
_CleanupCompletedQuestObjectivePins(delayedQuest)
|
||||||
|
elseif QuestieMap.questIdFrames[questId] then
|
||||||
|
QuestieMap:UnloadQuestFrames(questId)
|
||||||
|
end
|
||||||
|
|
||||||
if QuestieMap.questIdFrames[questId] then
|
if QuestieMap.questIdFrames[questId] then
|
||||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest:CompleteQuest] Lingering frames detected for quest:",
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest:CompleteQuest] Lingering frames detected for quest:",
|
||||||
questId, "- forcing cleanup")
|
questId, "- forcing cleanup")
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
local function read(path)
|
||||||
|
local f = assert(io.open(path, "r"), "cannot open " .. path)
|
||||||
|
local content = f:read("*a")
|
||||||
|
f:close()
|
||||||
|
return content
|
||||||
|
end
|
||||||
|
|
||||||
|
local function has(content, needle)
|
||||||
|
return content:find(needle, 1, true) ~= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
describe("QuestieQuest completion objective pin cleanup", function()
|
||||||
|
local questieQuest = read("Modules/Quest/QuestieQuest.lua")
|
||||||
|
|
||||||
|
it("unloads objective-owned spawned pins before clearing cached objectives", function()
|
||||||
|
local completeStart = assert(questieQuest:find("function QuestieQuest:CompleteQuest(questId)", 1, true))
|
||||||
|
local completeEnd = assert(questieQuest:find("---@param questId number\nfunction QuestieQuest:AbandonedQuest", completeStart, true))
|
||||||
|
local completeQuest = questieQuest:sub(completeStart, completeEnd)
|
||||||
|
local cleanupCall = assert(completeQuest:find("_CleanupCompletedQuestObjectivePins(quest)", 1, true))
|
||||||
|
local clearObjectives = assert(completeQuest:find("quest.Objectives = {}", 1, true))
|
||||||
|
|
||||||
|
assert.is_true(cleanupCall < clearObjectives)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("cleans standard objectives, special objectives, and registry frames", function()
|
||||||
|
local helperStart = assert(questieQuest:find("local function _CleanupCompletedQuestObjectivePins(quest)", 1, true))
|
||||||
|
local helperEnd = assert(questieQuest:find("---@param questId number\nfunction QuestieQuest:CompleteQuest", helperStart, true))
|
||||||
|
local helper = questieQuest:sub(helperStart, helperEnd)
|
||||||
|
|
||||||
|
assert.is_true(has(helper, "for objectiveIndex, objective in pairs(quest.Objectives) do"))
|
||||||
|
assert.is_true(has(helper, "_UnloadAlreadySpawnedIcons(objective)"))
|
||||||
|
assert.is_true(has(helper, "QuestieMap:UnloadQuestFramesForObjective(quest.Id, objectiveIndex)"))
|
||||||
|
assert.is_true(has(helper, "for _, objective in pairs(quest.SpecialObjectives) do"))
|
||||||
|
assert.is_true(has(helper, "QuestieMap:UnloadQuestFrames(quest.Id)"))
|
||||||
|
end)
|
||||||
|
end)
|
||||||
Reference in New Issue
Block a user