fix: real-time minimap pins + defensive GetAchievementNumCriteria shim

1. _InvalidateSpawnListsForNPC was setting objective.AlreadySpawned = nil,
   causing _DetermineIconsToDraw to crash on nil-index when trying to draw
   updated pins. The xpcall wrapper in UpdateObjectiveNotes swallowed the
   error silently, so no icons appeared.

   Fix: unload existing map/minimap icons explicitly, then set
   AlreadySpawned = {} (empty table) instead of nil. Also clear
   hasRegisteredTooltips so tooltips refresh.

2. Added GetAchievementNumCriteria defensive shim for Ascension servers
   with incomplete achievement databases. Returns 0 for invalid IDs
   instead of hard-erroring in Blizzard's WorldMapFrame.
This commit is contained in:
Xurkon
2026-05-16 08:54:52 -05:00
parent d3bcb6da49
commit 810ea7f802
2 changed files with 52 additions and 5 deletions
+18
View File
@@ -604,6 +604,24 @@ QuestieCompat.IsAchievementCompleted = QuestieCompat.IsAchievementCompleted or f
return completed or false
end
--- GetAchievementNumCriteria Shim
-- Ascension and some custom servers have incomplete achievement databases.
-- Blizzard's WorldMapFrame calls this with invalid IDs, causing a hard error.
-- Wrap the global to return 0 for invalid inputs so the UI doesn't break.
do
local _original = GetAchievementNumCriteria
GetAchievementNumCriteria = function(achievementID)
if type(achievementID) ~= "number" or achievementID <= 0 then
return 0
end
local ok, numCriteria = pcall(_original, achievementID)
if ok then
return numCriteria or 0
end
return 0
end
end
--- LibUIDropDownMenu Shim
QuestieCompat.LibUIDropDownMenu = QuestieCompat.LibUIDropDownMenu or {}
QuestieCompat.LibUIDropDownMenu.UIDropDownMenu_Menu_NewSize = function()
+35 -6
View File
@@ -309,8 +309,9 @@ local function _RefreshActiveQuestPins(questIdSet)
end
-- Invalidates cached objective.spawnList for any active quest whose objectives
-- reference the given npcId. This forces the map system to rebuild spawn lists
-- from QuestieDB on the next update, picking up newly learned coordinates.
-- reference the given npcId. Unloads existing world/minimap icons, resets
-- tooltip registration, and forces the map system to rebuild spawn lists from
-- QuestieDB on the next update — picking up newly learned coordinates in real time.
local function _InvalidateSpawnListsForNPC(npcId)
if not QuestieQuest or not QuestiePlayer or not QuestiePlayer.currentQuestlog then return end
local timer = (C_Timer) or (QuestieCompat and QuestieCompat.C_Timer)
@@ -318,6 +319,7 @@ local function _InvalidateSpawnListsForNPC(npcId)
for questId, _ in pairs(QuestiePlayer.currentQuestlog) do
local quest = QuestieDB.GetQuest and QuestieDB.GetQuest(questId)
if quest and quest.Objectives then
local needsUnload = false
for _, objective in pairs(quest.Objectives) do
local shouldInvalidate = false
-- Monster objectives reference NPCs directly in spawnList keys
@@ -337,12 +339,39 @@ local function _InvalidateSpawnListsForNPC(npcId)
shouldInvalidate = true
end
if shouldInvalidate then
objective.spawnList = nil
objective.AlreadySpawned = nil
questsToRefresh[questId] = true
break -- one invalidation per quest is enough
-- Unload existing icons manually so frames are removed from map/minimap.
-- We can't call QuestieQuest's local _UnloadAlreadySpawnedIcons from here,
-- so we iterate the refs directly.
if objective.AlreadySpawned then
for _, spawn in pairs(objective.AlreadySpawned) do
if spawn then
if spawn.mapRefs then
for _, mapIcon in ipairs(spawn.mapRefs) do
if mapIcon and mapIcon.Unload then mapIcon:Unload() end
end
end
if spawn.minimapRefs then
for _, minimapIcon in ipairs(spawn.minimapRefs) do
if minimapIcon and minimapIcon.Unload then minimapIcon:Unload() end
end
end
end
end
end
objective.spawnList = nil
objective.AlreadySpawned = {} -- empty table, NOT nil (_DetermineIconsToDraw indexes this)
objective.hasRegisteredTooltips = false
objective.registeredItemTooltips = false
needsUnload = true
end
end
if needsUnload then
-- Also purge QuestieMap's quest frame registry so no stale refs remain.
if QuestieMap and QuestieMap.UnloadQuestFrames then
QuestieMap:UnloadQuestFrames(questId)
end
questsToRefresh[questId] = true
end
end
end
_RefreshActiveQuestPins(questsToRefresh)