diff --git a/CHANGELOG.md b/CHANGELOG.md index babe837..d67ccd6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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`. diff --git a/Modules/Map/QuestieMap.lua b/Modules/Map/QuestieMap.lua index 58ad43c..ebff74e 100644 --- a/Modules/Map/QuestieMap.lua +++ b/Modules/Map/QuestieMap.lua @@ -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 diff --git a/Modules/QuestieLearner.lua b/Modules/QuestieLearner.lua index 5e177d6..8bb00e2 100644 --- a/Modules/QuestieLearner.lua +++ b/Modules/QuestieLearner.lua @@ -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