fix(tracker): group quests under their quest log header for server categories

Ascension files its main quest chain under a header of its own,
"Ascension Main Quest", which exists in no zone table. The tracker fell
back to the quest's zoneOrSort, and for anything the Learner recorded
that is the zone the quest was picked up in -- so the whole chain showed
up under "Red Cloud Mesa".

A header that resolves to no area is a category the server invented, and
the client's own grouping is the only thing that knows about it, so use
it. Headers are now mapped in a single pass per draw instead of a walk of
the quest log per quest.
This commit is contained in:
2026-07-30 18:15:10 +02:00
parent c2b1b82b2f
commit 706fc0b8ad
+45 -19
View File
@@ -676,27 +676,37 @@ local function GetAreaIdByZoneName(zoneName)
return l10n:GetAreaIdByLocalName(zoneName)
end
-- Walk the quest log to find the zone header for a given questId.
-- In 3.3.5, zone names appear as isHeader=true entries above their quests.
-- Returns the header title string, or nil if not found.
-- questId -> the header the client filed it under in the quest log. In 3.3.5 those headers are
-- isHeader=true entries sitting above the quests they cover. Built in one pass and kept, because
-- the tracker asks per quest and redraws often -- walking the log once per quest is quadratic.
local questLogHeaders = {}
local function BuildQuestLogHeaders()
local headers = {}
local header
for i = 1, (GetNumQuestLogEntries and GetNumQuestLogEntries() or 0) do
local title, _, _, isHeader, _, _, _, logId = GetQuestLogTitle(i)
if isHeader then
if title and title ~= "" then
header = title
end
elseif logId and header then
headers[logId] = header
end
end
questLogHeaders = headers
end
-- Returns the header title string, or nil if the quest is not in the log under one.
local function GetQuestLogZoneName(questId)
local targetIndex = nil
local total = GetNumQuestLogEntries and GetNumQuestLogEntries() or 0
for i = 1, total do
local _, _, _, isHeader, _, _, _, logId = GetQuestLogTitle(i)
if not isHeader and logId == questId then
targetIndex = i
break
end
if not questLogHeaders[questId] then
-- Asked about a quest the last pass did not see, so the log has moved on since.
BuildQuestLogHeaders()
end
if not targetIndex then return nil end
for i = targetIndex, 1, -1 do
local title, _, _, isHeader = GetQuestLogTitle(i)
if isHeader and title and title ~= "" then
return title
end
end
return nil
return questLogHeaders[questId]
end
local function _GetZoneName(zoneOrSort, questId, zoneNameOverride)
@@ -707,6 +717,19 @@ local function _GetZoneName(zoneOrSort, questId, zoneNameOverride)
local zoneName
local sortObj = Questie.db.profile.trackerSortObjectives
if sortObj == "byZone" or sortObj == "byZoneComplete" or sortObj == "byZoneCompleteReversed" or sortObj == "byZonePlayerProximity" or sortObj == "byZonePlayerProximityReversed" then
-- A server can file quests under categories of its own -- Ascension's "Ascension Main
-- Quest" -- and those exist nowhere in the zone tables, so the quest data points at a zone
-- instead: for anything the Learner recorded, whichever zone it was picked up in. A header
-- that does not resolve to an area is one of those categories, and the client's own
-- grouping is the only thing that knows about it.
local logHeader = GetQuestLogZoneName(questId)
if logHeader and logHeader ~= "" then
local headerAreaId = GetAreaIdByZoneName(logHeader)
if (not headerAreaId) or headerAreaId == 0 then
return logHeader
end
end
if (zoneOrSort) > 0 then
zoneName = TrackerUtils:GetZoneNameByID(zoneOrSort)
if not zoneName or zoneName == "Unknown Zone" then
@@ -813,6 +836,9 @@ function TrackerUtils:GetSortedQuestIds()
local sortedQuestIds = {}
local questDetails = {}
local sortObj = Questie.db.profile.trackerSortObjectives
-- One walk of the quest log for the whole draw, so the per-quest zone lookups below are reads.
BuildQuestLogHeaders()
-- Update quest objectives
for questId, quest in pairs(QuestiePlayer.currentQuestlog) do