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. - **[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) ## v1.5.4 (2026-03-29)
### Ascension Custom Zone Support ### Ascension Custom Zone Support
+6 -1
View File
@@ -139,7 +139,9 @@ function ZoneDB:GetAreaIdByUiMapId(uiMapId)
-- Fast path: O(1) pre-built reverse cache -- Fast path: O(1) pre-built reverse cache
local cached = uiMapIdToAreaIdCache[uiMapId] 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) -- Slow fallback: name-based lookup (only for unmapped IDs, result is cached for next time)
local mapInfo = C_Map.GetMapInfo(uiMapId) local mapInfo = C_Map.GetMapInfo(uiMapId)
@@ -158,6 +160,9 @@ function ZoneDB:GetAreaIdByUiMapId(uiMapId)
if Questie.db.profile.debugEnabled then if Questie.db.profile.debugEnabled then
Questie:Debug(Questie.DEBUG_DEVELOP, "No AreaId found for UiMapId: " .. uiMapId .. ":" .. (mapInfo and mapInfo.name or "nil")) Questie:Debug(Questie.DEBUG_DEVELOP, "No AreaId found for UiMapId: " .. uiMapId .. ":" .. (mapInfo and mapInfo.name or "nil"))
end end
-- We must cache that we found nothing so we don't run the slow lookup again
uiMapIdToAreaIdCache[uiMapId] = false
return nil return nil
end end
+4 -2
View File
@@ -585,7 +585,7 @@ function QuestieMap:DrawWorldIcon(data, areaID, x, y, showFlag)
function iconMinimap:FadeLogic() function iconMinimap:FadeLogic()
local profile = Questie.db.profile 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 if (QuestieMap.playerX and QuestieMap.playerY) then
local x, y local x, y
if not self.worldX then if not self.worldX then
@@ -597,7 +597,9 @@ function QuestieMap:DrawWorldIcon(data, areaID, x, y, showFlag)
y = self.worldY y = self.worldY
end end
if (x and y) then 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 if (distance > profile.fadeLevel) then
local fade = 1 - (math.min(10, (distance - profile.fadeLevel)) * normalizedValue); local fade = 1 - (math.min(10, (distance - profile.fadeLevel)) * normalizedValue);
+1 -7
View File
@@ -1090,17 +1090,11 @@ function QuestieQuest:CheckQuestSourceItem(questId, makeObjective)
local sourceItemId = (quest and tonumber(quest.sourceItemId)) or 0 local sourceItemId = (quest and tonumber(quest.sourceItemId)) or 0
if quest and sourceItemId > 0 then if quest and sourceItemId > 0 then
for bag = -2, 4 do if GetItemCount(sourceItemId) > 0 then
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 return true
end end
end
sourceItem = false sourceItem = false
end
-- If we are missing the sourceItem for zero objective quests then make an objective for it so the -- 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. -- player has a visual indication as to what item is missing and so the quest has a "tag" of some kind.
+26 -48
View File
@@ -493,30 +493,29 @@ function TrackerLinePool.Initialize(questFrame)
btn.SetItem = function(self, quest, buttonType, size) btn.SetItem = function(self, quest, buttonType, size)
local validTexture local validTexture
local foundItemId
for bag = -2, 4 do -- Check primary source item
for slot = 1, QuestieCompat.GetContainerNumSlots(bag) do if quest.sourceItemId and quest.sourceItemId ~= 0 and buttonType == "primary" then
local texture, _, _, _, _, _, _, _, _, itemId = QuestieCompat.GetContainerItemInfo(bag, slot) if QuestieDB.QueryItemSingle(quest.sourceItemId, "class") == 12 and GetItemCount(quest.sourceItemId, false, false) > 0 then
-- These type of quest items can never be secondary buttons foundItemId = quest.sourceItemId
if quest.sourceItemId == itemId and QuestieDB.QueryItemSingle(itemId, "class") == 12 and buttonType == "primary" then
validTexture = texture
self.itemId = quest.sourceItemId
break
end end
-- These type of quest items are technically secondary buttons but are assigned primary button slots end
if (not quest.sourceItemId or quest.sourceItemId == 0) and type(quest.requiredSourceItems) == "table" and #quest.requiredSourceItems == 1 then
-- Check secondary source items
if not foundItemId and type(quest.requiredSourceItems) == "table" then
if #quest.requiredSourceItems == 1 then
local questItemId = quest.requiredSourceItems[1] local questItemId = quest.requiredSourceItems[1]
if questItemId and questItemId ~= quest.sourceItemId and QuestieDB.QueryItemSingle(questItemId, "class") == 12 and questItemId == itemId then if questItemId and questItemId ~= quest.sourceItemId and QuestieDB.QueryItemSingle(questItemId, "class") == 12 then
validTexture = texture if GetItemCount(questItemId, false, false) > 0 then
self.itemId = questItemId foundItemId = questItemId
break
end end
-- These type of quest items can never be primary buttons end
elseif type(quest.requiredSourceItems) == "table" and #quest.requiredSourceItems > 1 then elseif #quest.requiredSourceItems > 1 and buttonType == "secondary" then
for _, questItemId in pairs(quest.requiredSourceItems) do 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 if questItemId and questItemId ~= quest.sourceItemId and QuestieDB.QueryItemSingle(questItemId, "class") == 12 then
validTexture = texture if GetItemCount(questItemId, false, false) > 0 then
self.itemId = questItemId foundItemId = questItemId
break break
end end
end end
@@ -524,35 +523,9 @@ function TrackerLinePool.Initialize(questFrame)
end end
end end
-- Edge case to find "equipped" quest items since they will no longer be in the players bag if foundItemId then
if (not validTexture) then self.itemId = foundItemId
for inventorySlot = 1, 19 do validTexture = select(10, GetItemInfo(foundItemId)) or GetItemIcon(foundItemId)
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
end end
if validTexture and self.itemId then if validTexture and self.itemId then
@@ -617,6 +590,8 @@ function TrackerLinePool.Initialize(questFrame)
return return
end end
self.updateTimer = (self.updateTimer or 0) + elapsed
if self.updateTimer >= 0.2 then
local start, duration, enabled = QuestieCompat.GetItemCooldown(self.itemId) local start, duration, enabled = QuestieCompat.GetItemCooldown(self.itemId)
if enabled == 1 and duration > 0 then if enabled == 1 and duration > 0 then
@@ -644,6 +619,9 @@ function TrackerLinePool.Initialize(questFrame)
end end
end end
self.updateTimer = 0
end
if UnitExists("target") then if UnitExists("target") then
if not self.itemName then if not self.itemName then
self.itemName = GetItemInfo(self.itemId) self.itemName = GetItemInfo(self.itemId)
+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; 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>[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>[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> </ul>
<hr> <hr>