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).
The kill handler's position capture ran inside 'if credited then', but
credited was read before its 'local credited = ...' assignment a few
lines below, so it was always nil and px,py were never captured -- every
killed NPC stayed spawnSource='fallback' with no [7] and drew no learner
pins regardless of kill count. Move the credited computation above the
capture and nil-guard a 0,0 position. GetPlayerCoords now uses the robust
GetCurrentPlayerPosition (Sunstrider-corrected), returning nil when
invalid so no 0,0 pins are recorded. Reverts the earlier HBD GetPlayerCoords
approach which treated the wrong symptom and caused spurious pins.
FadeLogic only re-checked ShouldBeHidden when deciding whether to
re-show an already-hidden icon, so a filtered quest (e.g. a dungeon
quest) that was already visible -- or that HBD's pin renderer showed on
coming into range -- was never hidden on the minimap while the world map
hid it. FadeLogic now proactively FakeHides any in-range icon whose
ShouldBeHidden is true, in both minimap fade paths; the second path also
gains the #17 minimap-radius cutoff gating it was missing.
GetPlayerCoords used raw GetPlayerMapPosition('player'), which returns
0,0 when the world map isn't on the player's zone (the usual case) and
mis-reports on Ascension subzones like Sunstrider. Learn events captured
no position, so NPCs were saved spawnSource='fallback' with no [7]
spawns and their learner-only pins never persisted -- showing briefly
after a live kill then vanishing. Read from HBD:GetPlayerZonePosition()
(robust SetMapToCurrentZone/Sunstrider-corrected, cached), falling back
to the old API only if HBD is unavailable.
HideAscensionQuestLines ran on every tooltip and removed any line
matching a quest-objective pattern (N/M, [N] ...), clobbering other
tooltip addons' lines (durability, stack counts, etc.). Gate it behind a
new General-tab option 'Hide Ascension quest progress lines' (default
off) so Questie no longer modifies tooltip lines it does not own by
default. Existing installs read the unset option as off automatically.
At fractional UI scales (e.g. 0.71 game scale + Windows display scaling)
the raw fractional pin offset landed icons between physical pixels,
rendering blurry and offset from the engine-drawn native quest blips.
Snap the offset to a whole physical pixel via the minimap's effective
scale so Questie's icons sit on the same grid as native markers.
Ascension board bounties (e.g. NPC 24 'Outlaw's Contract Board') aren't
reliably flagged repeatable, so IsRepeatable missed them and their ! kept
showing below 60. Add QuestieDB.IsBoardQuest (detects starter NPC/object
names containing 'board', cached per quest); the hide-below-60 option now
hides repeatable OR board quests in both the draw path and ShouldBeHidden.
The ElvUI tooltip style shipped on by default, so Questie restyled every
default WoW tooltip (stripping the border) for users who never asked for
it and don't run ElvUI. Default is now false, plus migration [8] resets
it off once for existing profiles.
Some Ascension turn-ins (crafting/auto-complete) fire QUEST_REMOVED with
no preceding QUEST_TURNED_IN, so the 1s abandon timer runs after
QuestLogCache.RemoveQuest has cleared the quest, making IsComplete return
0 and the turned-in quest get marked abandoned -- its objective pins and
turn-in ? then linger. Capture IsComplete at QUEST_REMOVED time and use
that snapshot in MarkQuestAsAbandoned.
The cutoff hid icons beyond its yard value before checking the minimap's
visible radius, so the default 100 hid icons that were clearly on the
minimap (view radius is 133-466 yd by zoom). Now it only clips icons
outside the visible circle: HBD's pin renderer gates the cutoff on
dist > 1, and QuestieMap FadeLogic raises the effective cutoff to at
least the current minimap view radius via new HBDPins:GetMinimapRadius().
HideAscensionQuestLines kept a questBlockActive flag and hid every
following non-indented line after an objective line until an indented
one. Questie's own Item/NPC/Object ID lines and other addons' additions
(e.g. an item-count overlay) are appended at the bottom of the tooltip,
so they were wiped too. Now only lines matching an Ascension objective
pattern are hidden; trailing lines are left intact.
Changelog entries for the import/export work landed in 2c695c4: Export
Current Zone, live map+stats refresh after import (no reload), and the
200k-entry import guard.
QuestieLearnerExport:
- Extract _Encode helper to consolidate serialize+deflate+encode
- Add ExportZone(serverKey, zoneId) to export only the learned data
for a specific zone (NPCs/objects with spawns in that zone, plus
their dropped items and related quests) for smaller, faster exports
- Cap ValidateImport at 200k entries to guard against pathological
payloads that could stall the client during merge
- Call SmoothReset after MergeImport so newly imported spawns appear
on the map without requiring /reload
QuestieOptionsDatabase:
- Refresh AceConfigRegistry after import so Database tab stats update
immediately (previously required /reload or opening Options)
- Add Export Current Zone button tied to ExportZone()
Hardens the learner data-ingestion paths against malformed/partial data
across NPC/object/item/quest types:
- _ValidateLearnedSpawnData now validates object spawn coordinates (key 4)
in addition to NPC spawns (key 7); object coords were previously
unvalidated. Extracted a shared _ValidateCoordTable helper.
- _ApplyIncomingNetworkMerge coordinate merge skips malformed zone keys and
coordinates (non-number / out-of-range) per entry instead of erroring,
and guards the item drop-list merge against non-number NPC ids.
- The live comms-merge flush isolates each broadcast in a pcall so one
malformed entry can't abort the batch or break the live-update loop;
the post-merge InjectLearnedData is also guarded.
Live Learn* entry points already validate id/type. selene 0 errors;
busted 145 successes / same 7 pre-existing failures.
Importing learned data merged from several players must not corrupt the
store. Fixes:
- ValidateImport prefix check was a no-op: parsed
as (always false), so non-Questie strings were
never rejected. Now a proper inequality check.
- MergeImport now ensures the learner stores exist (fresh profile can
import), merges each entry synchronously via _ApplyIncomingNetworkMerge
(validates structure, only adopts missing fields, never overwrites good
local data), wraps each entry in pcall so one malformed entry is
skipped/counted rather than aborting the whole import, and returns
accurate merged/skipped/rejected counts.
- Synchronous merge also fixes InjectLearnedData previously running before
the async-queued merges landed.
selene 0 errors; busted 145 successes / same 7 pre-existing failures.