fix: reduce questie fps stutter hot paths

This commit is contained in:
Xurkon
2026-06-12 17:30:48 -05:00
parent 90f1f31474
commit e706fa1130
3 changed files with 20 additions and 8 deletions
+1
View File
@@ -41,6 +41,7 @@
### Bug Fixes
- **[Performance - Minimap Filter And Learner Kill Hot Paths]** (#20) Reduced two likely stutter sources introduced after 1.6.2: minimap fade passes now cache expensive quest-filter visibility checks for already-visible icons instead of re-running them every 0.1s per icon, while still forcing a fresh check before hidden icons reappear; and the learner kill path no longer runs the spawn-evidence merge scan before the merger's three-evidence minimum can succeed.
- **[Map Tooltip - Objective Progress Refresh]** (#18) Minimap and world-map objective pin tooltips now refresh the underlying objective before rendering progress text, so kill counters update on hover instead of staying at the count captured when the pin was drawn.
- **[Learner - Stop Recording Bystander Kills As Your Own]** Kills of mobs you never engaged (other players killing nearby mobs) were being recorded as spawns at *your* position and inflating the kill count. The combat-log handler passed `px,py=nil` to `LearnNPC` for uncredited kills, whose `GetPlayerCoords` fallback then stored your location as the mob's spawn. Spawn recording (`LearnNPC` + GUID evidence) is now gated on a captured position, so only credited kills (your own / party kills you engaged, where a real position was captured) store a spawn. Bystander kills no longer pollute the learner with your coordinates or inflate the count; the NPC's name/quest data is still learned via mouseover/target.
- **[Fix - Fade Pass Crash On Stale Frame]** Hardened `ShowQuestIcons`/`HideQuestIcons` against a stale-frame desync (`attempt to index local 'icon'`): a frame name lingering in the registry after its frame was reset is now skipped gracefully instead of erroring out of the whole fade pass (and `ShowQuestIcons` no longer `error()`s on the desync), with nil-guards on `icon`/`icon.data`/`icon.data.QuestData`.
+15 -4
View File
@@ -56,6 +56,7 @@ local tunpack = unpack;
local drawTimer
local fadeLogicTimerShown
local fadeLogicCoroutine
local MINIMAP_VISIBILITY_CHECK_INTERVAL = 1
local function _ResolveMapUiMapId(uiMapId, x, y)
-- Ghost map 946 has no real coordinate data; redirect to Eversong (1941).
@@ -69,6 +70,15 @@ local function _ResolveMapUiMapId(uiMapId, x, y)
return uiMapId
end
local function _ShouldMinimapIconBeHidden(icon, forceRefresh)
local now = GetTime()
if forceRefresh or (not icon._lastShouldBeHiddenCheck) or (now - icon._lastShouldBeHiddenCheck) >= MINIMAP_VISIBILITY_CHECK_INTERVAL then
icon._lastShouldBeHiddenCheck = now
icon._lastShouldBeHiddenResult = icon:ShouldBeHidden()
end
return icon._lastShouldBeHiddenResult
end
local isDrawQueueDisabled = false
--* TODO: How the frames are handled needs to be reworked, why are we getting them from _G
@@ -362,6 +372,7 @@ function QuestieMap:RefreshMinimapIconVisibility()
for minimapFrame, data in pairs(HBDPins.activeMinimapPins) do
if minimapFrame and minimapFrame.miniMapIcon and minimapFrame.FadeLogic then
minimapFrame.minimapVisibilityCutoff = minimapVisibilityCutoff
minimapFrame._lastShouldBeHiddenCheck = nil
minimapFrame:FadeLogic()
if minimapFrame.GlowUpdate then
minimapFrame:GlowUpdate()
@@ -686,7 +697,7 @@ function QuestieMap:DrawManualIcon(data, areaID, x, y, typ)
-- when deciding whether to RE-SHOW an already-hidden icon, so a filtered icon
-- that was already visible (e.g. a dungeon quest) lingered on the minimap
-- while the world map correctly hid it. Hiding here keeps both maps in sync. (#11)
if self:ShouldBeHidden() then
if _ShouldMinimapIconBeHidden(self) then
if not self.hidden then
self:FakeHide()
end
@@ -718,7 +729,7 @@ function QuestieMap:DrawManualIcon(data, areaID, x, y, typ)
-- Previously FadeLogic re-showed ANY FakeHidden minimap icon once in
-- range, so the world-map quest-type filters never applied to the
-- minimap. ShouldBeHidden mirrors the world-map draw-time check.
if not self:ShouldBeHidden() then
if not _ShouldMinimapIconBeHidden(self, true) then
self:FakeShow()
end
elseif (distance > profile.fadeLevel) then
@@ -866,7 +877,7 @@ function QuestieMap:DrawWorldIcon(data, areaID, x, y, showFlag)
if (x and y) then
-- Proactively hide any filtered minimap icon even if currently shown,
-- keeping the minimap in sync with the world-map filters. (#11)
if self:ShouldBeHidden() then
if _ShouldMinimapIconBeHidden(self) then
if not self.hidden then
self:FakeHide()
end
@@ -896,7 +907,7 @@ function QuestieMap:DrawWorldIcon(data, areaID, x, y, showFlag)
-- Previously FadeLogic re-showed ANY FakeHidden minimap icon once in
-- range, so the world-map quest-type filters never applied to the
-- minimap. ShouldBeHidden mirrors the world-map draw-time check.
if not self:ShouldBeHidden() then
if not _ShouldMinimapIconBeHidden(self, true) then
self:FakeShow()
end
elseif (distance > profile.fadeLevel) then
+4 -4
View File
@@ -4439,15 +4439,15 @@ function QuestieLearner:OnCombatLogEvent(timestamp, eventType, srcGUID, srcName,
-- "y", tostring(py))
end
-- Phase 3: weighted merge when evidence count is sufficient.
-- Temporarily lowered to 1 for Sunstrider/Mana Wyrm diagnostics so we can
-- verify the promotion path immediately.
-- Phase 3: weighted merge when evidence count is sufficient. The merger
-- itself requires at least three evidence points, so avoid doing its scan
-- on every early kill while the candidate still cannot be promoted.
local guidSpawns = Questie.dbLearner.global.npcs[npcId]
and Questie.dbLearner.global.npcs[npcId][8]
if guidSpawns then
local count = 0
for _ in pairs(guidSpawns) do count = count + 1 end
if self:IsLearnerLiveEnabled() and count >= 1 then
if self:IsLearnerLiveEnabled() and count >= 3 then
_MergeSpawnEvidence(npcId)
end
end