Add a locale-keyed cache for no-argument translation lookups so repeated
literal keys resolve without redoing the lookup chain. Reset on locale change
and on locale override application.
Ported from phase3-measured-perf (cherry-pick -x 970dd88), adapted to current
main (hoisted the per-locale cache-table creation; excludes the branch's audit
doc and gitignored test).
The 1.6.4 changelog described an earlier SyncBlizzardObjectivePOIs helper that
was superseded by the per-quest duplicate-POI suppression in QuestieCompat
(commit 70a9934). Update both CHANGELOG.md and the HTML changelog to describe
the actual shipped behavior.
Update the 1.6.4 entry to reflect the consolidated main: add the Lua 5.0
compatibility items (modulo->math.mod, Options {...} typo) and the native
objective POI sync, prestige cache reset, and quest completion cache fixes.
Fix the stale perf-refactor note that referenced the now-removed
phase2-lua50-sweep branch; remaining measured perf work is on
phase3-measured-perf and being cherry-picked one at a time. Mirror into the
HTML changelog and bump its version badge to v1.6.4.
QuestieOptions.tabs.{auto,dbm,icons,nameplate} were initialized with {...}
instead of {}. At file scope in Lua 5.1 this silently captures the addon
varargs into the table; in Lua 5.0 it is a parse error. All sibling tabs use
{}. No behavioral change (Initialize repopulates the table).
Lua 5.0 (Vanilla 1.12) has no % operator outside string formatting; it is a
parse error. Route the 9 arithmetic modulo sites through the existing math.mod
shim (Compat/Compat.lua) so the addon parses on 5.0 through Retail.
Sites: QuestieDB daily/weekly flag tests, QuestieEvent DMF cycle math,
QuestieLearner GUID/flag math, QuestiePlayer race/class flag tests.
Brings the still-needed changes from questie-phase1perf that main lacked.
Main already had the Lua 5.0 shims (QuestieLoader bit/strsplit, QuestieStream
and QuestieSerializer math.mod sweep), so those are omitted.
- QuestieNameplate: skip missing entries instead of return-aborting the whole
activeGUIDs loop (one bad unit no longer stalls every nameplate update)
- QuestieQuest.ClearAllNotes: skip DB-missing quests instead of aborting, so
remaining quests' notes still get cleared
- QuestieOptionsTracker: fix fadeTickerValue:Cancel -> fadeTicker:Cancel (3x);
fadeTickerValue is a number, the ticker handle is fadeTicker
- QuestieCommsData: nil-guard GetNPC/GetObject before reading .name
- QuestieAnnounce: bound the alreadySentBandaid dedup cache (reset at 1000)
- QuestieDB.IsComplete: hoist GetQuest into expectedQuest (one call, not two)
- QuestieFramePool/QuestieFrame: drop the dead BaseOnUpdate ticker branch
(BaseOnUpdate was never defined; behavior was always OnUpdate=nil)
- QuestieLib: document unused questId arg on Ascension_IsScalingEnabled
- Database/Corrections x3: strip stray UTF-8 BOM
- Questie-X.toc: remove duplicate QuestieSlash.lua load line
Uncredited kills (mobs other players killed that you never engaged)
passed px,py=nil to LearnNPC, whose GetPlayerCoords fallback stored YOUR
position as the mob's spawn and incremented the kill count. Gate spawn
recording (LearnNPC + _StoreGuidSpawnEvidence) on a captured position, so
only credited kills with a real position store a spawn. Bystander kills
no longer pollute coordinates or inflate counts.
ShowQuestIcons/HideQuestIcons indexed icon (=_G[frameName]) when it can
be nil for a registry entry whose frame was already reset, crashing the
fade pass (attempt to index local 'icon'). Guard icon/icon.data/
icon.data.QuestData and skip stale frames; ShowQuestIcons no longer
error()s on the desync.
The dedupe helper was a local function defined after
AddUnitDataToTooltip, so that function resolved it as a nil global and
every unit tooltip errored (attempt to call global '_TooltipHasLeftLine').
Moved it above all Add*DataToTooltip functions.
Expose QuestieLearner:GetIdAndTypeFromGUID / GetObjectIdFromGUID /
GetNpcIdFromGUID (they handle modern dash GUIDs AND legacy 0x hex /
GameObject GUIDs). Tooltips now fall back to these when strsplit('-',guid)
can't parse the GUID, so NPC IDs no longer silently fail to write on
hex-GUID units; the Object ID line resolves from the object's GUID when
its name isn't in the lookup. IDs deduped per tooltip.
The ID lines were gated by lastItemId/lastGuid (only added when the
hovered item/unit changed). WoW clears and re-fires OnTooltipSetItem/
OnTooltipSetUnit for the same item/unit and rebuilds the tooltip, so the
gate skipped re-adding the line on the rebuilt tooltip and the ID
disappeared. Add the ID line on every render instead, deduped per
tooltip via _TooltipHasLeftLine so it shows exactly once.
- Critters are never quest-relevant. Added a static CRITTER_NPC_SET (common
classic critters) plus runtime detection via UnitCreatureType on
mouseover/target (covers Ascension custom critters). LearnNPC and the kill
handler skip critters; InjectLearnedData purges already-recorded ones; and
critters are purged on sight when a unit token is available.
- Object/NPC spawns mis-stored under Eversong parent areaId 3430 (e.g. object
180516 'Shrine of Dath'Remar' on Sunstrider) now migrate to uiMapId 1241,
along with the [9]/[5] home-zone field. Legit Eversong data is keyed 1941,
so any 3430 key is mis-stored Sunstrider data.
Verified in Tests/QuestieLearnerCritterPurge_spec.lua.
Two bugs made saved learner spawns collapse to one pin on every login:
1. The spawn zone-key migration was inverted: it ran
GetAreaIdByUiMapId(1241) -> Eversong parent areaId 3430 and moved
Sunstrider coords there (wrong map / NE corner), deduping distinct
coords via InsertIfNewBucket along the way. Now it converts only
legacy areaId keys FORWARD to the canonical uiMapId and leaves uiMapId
keys untouched. Same for the [9]/[5] home-zone fields.
2. Sanitize de-duplicated coords with the flat COORD_GRID (2.0) instead
of the per-zone grid, collapsing Sunstrider's tightly-packed spawns
(grid 0.5). Now uses GetCoordGridForZone(zoneId).
Both rewrote learned.npcs in place, persisting the damage to
SavedVariables. Regression test in QuestieLearnerMultiSpawn_spec.lua.
A prior change (dd630fd) kept clustering enabled on Sunstrider Isle in
learner mode to avoid pin fan-out, but that collapsed several distinct
learned coordinates (e.g. 7 Arcane Wraith spots) into a single pin --
breaking the DB-building workflow where every learned spawn must be
visible. The SavedVariables data was correct the whole time; this was a
display regression. Sunstrider (1241) now shows every distinct pin by
default in all data-source modes; consolidation only happens when the
player explicitly raises the Dense Pin Clustering Aggressiveness knob.
The Ascension server appends a new progress line on every objective
update instead of replacing it, so tooltips stacked 0/8 1/8 2/8 3/8 for
one objective. New always-on DedupeAscensionProgressLines collapses each
stack to its most-progressed line. It only hides a line when the same
tooltip holds another progress line with the same objective text AND
denominator, so other addons' lines and Questie's own single-line
objectives are never touched. Separate from the opt-in full-strip option
(#16). Unit-tested in Tests/QuestieTooltipDedupe_spec.lua.
Draw-queue race: ProcessQueue processes the world-map and minimap queues
independently. When a frame was unloaded while still queued, its
minimap-queue entry could trigger the deferred Unload first (removing
both icons and clearing _needsUnload), then a later map-queue entry
re-added the world-map icon -- orphaned, since Unload had nil'd the
questIdFrames/_G reference, so it lingered until /reload while the
minimap cleared. Unload now drops the frame's pending draw-queue entries
(new QuestieMap:DequeueFrameDrawCalls) so an unloaded frame can never be
re-added to a map.
- Key the kill spawn under the same map space the coords were captured in
(GetCurrentPlayerPosition mapId), not a separately-derived GetZoneId()
that can disagree on subzones and place pins on the wrong map.
- Throttled debug warning when a credited kill yields no usable position,
so a systematic capture failure is diagnosable.
- Add Tests/QuestieLearnerKillCapture_spec.lua: drives the real kill
handler end-to-end and asserts capture, the 0,0 guard, and the per-mode
display contract (learner shows learned spawn, static never leaks it).