docs: append performance patches to v1.5.5 changelogs

This commit is contained in:
Xurkon
2026-03-29 17:54:19 -05:00
parent 1b5c8ef685
commit 4d48925145
6 changed files with 72 additions and 85 deletions
+5
View File
@@ -22,6 +22,11 @@ Addressed micro-stutters and FPS drops (190 → sub-100) reported during high-fr
- **[Fix — Profiler UI]** Resolved an issue where the `QuestieProfiler` UI text was overlapping horizontally when function names were too long, rendering the time and call counts illegible. Lines are now appropriately spaced and function names are clamped and left-aligned.
- **[Perf — Math Inlining]** Removed `QuestieLib:Euclid` function call overhead from the minimap icon `FadeLogic` hot loop in favor of an inline Pythagorean distance check, reducing micro-stutters during movement.
- **[Perf — Quest Tracker Bag Scans]** Removed O(N) nested loops iterating over the entire character inventory in `TrackerLinePool:SetItem` and `QuestieQuest:CheckQuestSourceItem`, replacing them with native O(1) `GetItemCount(itemId)` queries. Completely eliminated thousands of `GetContainerItemInfo` calls.
- **[Perf — Tracker Cooldown Throttling]** Added a 5Hz (0.2s) execution throttle to the tracker quest item button `btn.OnUpdate` frame handler, dropping baseline `GetItemCooldown` API polls from ~6000+ checks every few minutes down to a fraction of that load.
## v1.5.4 (2026-03-29)
### Ascension Custom Zone Support
+6 -1
View File
@@ -139,7 +139,9 @@ function ZoneDB:GetAreaIdByUiMapId(uiMapId)
-- Fast path: O(1) pre-built reverse cache
local cached = uiMapIdToAreaIdCache[uiMapId]
if cached then return cached end
if cached ~= nil then
return cached ~= false and cached or nil
end
-- Slow fallback: name-based lookup (only for unmapped IDs, result is cached for next time)
local mapInfo = C_Map.GetMapInfo(uiMapId)
@@ -158,6 +160,9 @@ function ZoneDB:GetAreaIdByUiMapId(uiMapId)
if Questie.db.profile.debugEnabled then
Questie:Debug(Questie.DEBUG_DEVELOP, "No AreaId found for UiMapId: " .. uiMapId .. ":" .. (mapInfo and mapInfo.name or "nil"))
end
-- We must cache that we found nothing so we don't run the slow lookup again
uiMapIdToAreaIdCache[uiMapId] = false
return nil
end
+4 -2
View File
@@ -585,7 +585,7 @@ function QuestieMap:DrawWorldIcon(data, areaID, x, y, showFlag)
function iconMinimap:FadeLogic()
local profile = Questie.db.profile
if self.miniMapIcon and self.x and self.y and self.texture and self.UiMapID and self.texture.SetVertexColor and HBD and HBD.GetPlayerZonePosition and QuestieLib and QuestieLib.Euclid then
if self.miniMapIcon and self.x and self.y and self.texture and self.UiMapID and self.texture.SetVertexColor and HBD and HBD.GetPlayerZonePosition then
if (QuestieMap.playerX and QuestieMap.playerY) then
local x, y
if not self.worldX then
@@ -597,7 +597,9 @@ function QuestieMap:DrawWorldIcon(data, areaID, x, y, showFlag)
y = self.worldY
end
if (x and y) then
local distance = QuestieLib:Euclid(QuestieMap.playerX, QuestieMap.playerY, x, y) / 10;
local xd = QuestieMap.playerX - x
local yd = QuestieMap.playerY - y
local distance = math.sqrt(xd * xd + yd * yd) / 10;
if (distance > profile.fadeLevel) then
local fade = 1 - (math.min(10, (distance - profile.fadeLevel)) * normalizedValue);
+4 -10
View File
@@ -1090,18 +1090,12 @@ function QuestieQuest:CheckQuestSourceItem(questId, makeObjective)
local sourceItemId = (quest and tonumber(quest.sourceItemId)) or 0
if quest and sourceItemId > 0 then
for bag = -2, 4 do
local numSlots = QuestieCompat.GetContainerNumSlots(bag) or 0
for slot = 1, numSlots do
local itemId = select(10, QuestieCompat.GetContainerItemInfo(bag, slot))
if itemId == sourceItemId then
return true
end
end
sourceItem = false
if GetItemCount(sourceItemId) > 0 then
return true
end
sourceItem = false
-- If we are missing the sourceItem for zero objective quests then make an objective for it so the
-- player has a visual indication as to what item is missing and so the quest has a "tag" of some kind.
-- Also double check the quests leaderboard and make sure an objective doesn't already exist.
+50 -72
View File
@@ -493,30 +493,29 @@ function TrackerLinePool.Initialize(questFrame)
btn.SetItem = function(self, quest, buttonType, size)
local validTexture
local foundItemId
for bag = -2, 4 do
for slot = 1, QuestieCompat.GetContainerNumSlots(bag) do
local texture, _, _, _, _, _, _, _, _, itemId = QuestieCompat.GetContainerItemInfo(bag, slot)
-- These type of quest items can never be secondary buttons
if quest.sourceItemId == itemId and QuestieDB.QueryItemSingle(itemId, "class") == 12 and buttonType == "primary" then
validTexture = texture
self.itemId = quest.sourceItemId
break
end
-- These type of quest items are technically secondary buttons but are assigned primary button slots
if (not quest.sourceItemId or quest.sourceItemId == 0) and type(quest.requiredSourceItems) == "table" and #quest.requiredSourceItems == 1 then
local questItemId = quest.requiredSourceItems[1]
if questItemId and questItemId ~= quest.sourceItemId and QuestieDB.QueryItemSingle(questItemId, "class") == 12 and questItemId == itemId then
validTexture = texture
self.itemId = questItemId
break
-- Check primary source item
if quest.sourceItemId and quest.sourceItemId ~= 0 and buttonType == "primary" then
if QuestieDB.QueryItemSingle(quest.sourceItemId, "class") == 12 and GetItemCount(quest.sourceItemId, false, false) > 0 then
foundItemId = quest.sourceItemId
end
end
-- Check secondary source items
if not foundItemId and type(quest.requiredSourceItems) == "table" then
if #quest.requiredSourceItems == 1 then
local questItemId = quest.requiredSourceItems[1]
if questItemId and questItemId ~= quest.sourceItemId and QuestieDB.QueryItemSingle(questItemId, "class") == 12 then
if GetItemCount(questItemId, false, false) > 0 then
foundItemId = questItemId
end
-- These type of quest items can never be primary buttons
elseif type(quest.requiredSourceItems) == "table" and #quest.requiredSourceItems > 1 then
for _, questItemId in pairs(quest.requiredSourceItems) do
if questItemId and questItemId ~= quest.sourceItemId and QuestieDB.QueryItemSingle(questItemId, "class") == 12 and questItemId == itemId and buttonType == "secondary" then
validTexture = texture
self.itemId = questItemId
end
elseif #quest.requiredSourceItems > 1 and buttonType == "secondary" then
for _, questItemId in pairs(quest.requiredSourceItems) do
if questItemId and questItemId ~= quest.sourceItemId and QuestieDB.QueryItemSingle(questItemId, "class") == 12 then
if GetItemCount(questItemId, false, false) > 0 then
foundItemId = questItemId
break
end
end
@@ -524,35 +523,9 @@ function TrackerLinePool.Initialize(questFrame)
end
end
-- Edge case to find "equipped" quest items since they will no longer be in the players bag
if (not validTexture) then
for inventorySlot = 1, 19 do
local itemId = GetInventoryItemID("player", inventorySlot)
-- These type of quest items can never be secondary buttons
if quest.sourceItemId == itemId and QuestieDB.QueryItemSingle(itemId, "class") == 12 and buttonType == "primary" then
validTexture = GetInventoryItemTexture("player", inventorySlot)
self.itemId = quest.sourceItemId
break
end
-- These type of quest items are technically secondary buttons but are assigned primary button slots
if type(quest.requiredSourceItems) == "table" and #quest.requiredSourceItems == 1 then
local questItemId = quest.requiredSourceItems[1]
if questItemId and questItemId ~= quest.sourceItemId and QuestieDB.QueryItemSingle(questItemId, "class") == 12 and questItemId == itemId then
validTexture = GetInventoryItemTexture("player", inventorySlot)
self.itemId = questItemId
break
end
-- These type of quest items can never be primary buttons
elseif type(quest.requiredSourceItems) == "table" and #quest.requiredSourceItems > 1 then
for _, questItemId in pairs(quest.requiredSourceItems) do
if questItemId and questItemId ~= quest.sourceItemId and QuestieDB.QueryItemSingle(questItemId, "class") == 12 and questItemId == itemId and buttonType == "secondary" then
validTexture = GetInventoryItemTexture("player", inventorySlot)
self.itemId = questItemId
break
end
end
end
end
if foundItemId then
self.itemId = foundItemId
validTexture = select(10, GetItemInfo(foundItemId)) or GetItemIcon(foundItemId)
end
if validTexture and self.itemId then
@@ -617,31 +590,36 @@ function TrackerLinePool.Initialize(questFrame)
return
end
local start, duration, enabled = QuestieCompat.GetItemCooldown(self.itemId)
self.updateTimer = (self.updateTimer or 0) + elapsed
if self.updateTimer >= 0.2 then
local start, duration, enabled = QuestieCompat.GetItemCooldown(self.itemId)
if enabled == 1 and duration > 0 then
cooldown:SetCooldown(start, duration, enabled)
cooldown:Show()
else
cooldown:Hide()
end
local charges = GetItemCount(self.itemId, nil, true)
if (not charges or charges ~= self.charges) then
self.count:Hide()
self.charges = GetItemCount(self.itemId, nil, true)
if self.charges > 1 then
self.count:SetText(self.charges)
self.count:Show()
if enabled == 1 and duration > 0 then
cooldown:SetCooldown(start, duration, enabled)
cooldown:Show()
else
cooldown:Hide()
end
if self.charges == 0 then
Questie:Debug(Questie.DEBUG_DEVELOP, "[TrackerLinePool: Button.OnUpdate]")
QuestieCombatQueue:Queue(function()
C_Timer.After(0.2, function()
QuestieTracker:Update()
local charges = GetItemCount(self.itemId, nil, true)
if (not charges or charges ~= self.charges) then
self.count:Hide()
self.charges = GetItemCount(self.itemId, nil, true)
if self.charges > 1 then
self.count:SetText(self.charges)
self.count:Show()
end
if self.charges == 0 then
Questie:Debug(Questie.DEBUG_DEVELOP, "[TrackerLinePool: Button.OnUpdate]")
QuestieCombatQueue:Queue(function()
C_Timer.After(0.2, function()
QuestieTracker:Update()
end)
end)
end)
end
end
self.updateTimer = 0
end
if UnitExists("target") then
+3
View File
@@ -184,6 +184,9 @@
<li><strong>[Performance &mdash; Network Refactor]</strong> Refactored <code>QuestieLearnerComms</code>: reduced compression overhead (negligible size difference but massive CPU savings), slowed processing ticker to match output rate limits, and optimized duplicate detection to O(1).</li>
<li><strong>[Performance &mdash; Arrow Closures]</strong> Hoisted heavy inner closures out of the hot <code>QuestieArrow:UpdateNearestTargets</code> loop to module-level functions, eliminating persistent memory allocation spikes and Garbage Collection (GC) pressure.</li>
<li><strong>[Fix &mdash; Profiler Display]</strong> Fixed textual overlap and vertical spacing issues in the <code>QuestieProfiler</code> UI. Function names are now properly left-aligned, and horizontal spacing ensures metrics remain legible regardless of function name length.</li>
<li><strong>[Performance &mdash; Math Inlining]</strong> Removed <code>QuestieLib:Euclid</code> function call overhead from the minimap icon <code>FadeLogic</code> hot loop in favor of an inline Pythagorean distance check, reducing micro-stutters during movement.</li>
<li><strong>[Performance &mdash; Quest Tracker Bag Scans]</strong> Removed O(N) nested loops iterating over the entire character inventory in <code>TrackerLinePool:SetItem</code> and <code>QuestieQuest:CheckQuestSourceItem</code>, replacing them with native O(1) <code>GetItemCount(itemId)</code> queries. Completely eliminated thousands of <code>GetContainerItemInfo</code> calls.</li>
<li><strong>[Performance &mdash; Tracker Cooldown Throttling]</strong> Added a 5Hz (0.2s) execution throttle to the tracker quest item button <code>btn.OnUpdate</code> frame handler, dropping baseline <code>GetItemCooldown</code> API polls from over 6000 checks every few minutes down to a fraction of that load.</li>
</ul>
<hr>