docs: add v1.2.9 changelog — cross-link engine, zone fix, untrack fix
This commit is contained in:
@@ -175,6 +175,39 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<h2 id="v129">v1.2.9 — QuestieLearner Cross-Link Engine + Tracker Zone Fix + Untrack Fix</h2>
|
||||
<p><em>Introduces a universal bidirectional cross-link engine in QuestieLearner that automatically stitches relationships between all four entity types (NPCs, Quests, Objects, Items) as data is learned — no manual wiring needed. Fixes the tracker's persistent "Unknown Zone" header for custom/unknown quests by replacing unreliable map API calls with the canonical 3.3.5a quest log header walk. Fixes a logic inversion in UntrackQuestId that prevented shift-click untacking from working.</em></p>
|
||||
|
||||
<h3>QuestieLearner.lua — Universal Cross-Link Engine</h3>
|
||||
<ul>
|
||||
<li><strong>[Cross-link engine — full rewrite]</strong> Replaced the narrow NPC↔Quest cross-link stubs with a comprehensive bidirectional relationship engine covering all four entity types. Three shared primitives underpin the whole system: <code>_AddToArray(tbl, key, value, ovrTable, ovrId)</code> adds a value to an array field and mirrors it to the live <code>*DataOverrides</code> table in the same call; <code>_AddToNestedArray</code> does the same for two-level nested arrays (used for quest starters/finishers sub-slots <code>quest[2][1]</code>, <code>quest[2][2]</code>, etc.); <code>_AddToQuestObjective</code> inserts <code>{entityId, text}</code> pairs into <code>quest[10][slot]</code> with the same dual-write pattern. Every write is idempotent — a no-op if the value is already present. All three primitives write to both <code>learnedData</code> (SavedVariables, persistent) and the live <code>*DataOverrides</code> tables (in-memory, immediate effect on map pins and tooltips).</li>
|
||||
<li><strong>[CrossLinkAfterNPC]</strong> Called whenever a new NPC ID is first committed to <code>learnedData.npcs</code>. Performs three scans across all learned quests: (a) if <code>quest[2][1]</code> contains this npcId → adds questId to <code>npc[10]</code> (questStarts); (b) if <code>quest[3][1]</code> contains this npcId → adds questId to <code>npc[11]</code> (questEnds); (c) walks <code>quest[10][3]</code> (item objectives) — for each item whose <code>item[2]</code> (npcDrops) already references this NPC, the NPC is injected into <code>quest[10][1]</code> as a creature objective so it receives map pins and tooltip kill-count text.</li>
|
||||
<li><strong>[CrossLinkAfterQuest]</strong> Called when a new quest is first committed to <code>learnedData.quests</code>. Links all referenced entities in one pass: starter NPCs (<code>quest[2][1]</code>) → each known NPC's <code>npc[10]</code>; starter objects (<code>quest[2][2]</code>) → each known object's <code>obj[2]</code>; finisher NPCs (<code>quest[3][1]</code>) → <code>npc[11]</code>; finisher objects (<code>quest[3][2]</code>) → <code>obj[3]</code>; source item (<code>quest[11]</code>) → <code>item[5]</code> (startQuest key per itemDB schema); item drop chain: for each item in <code>quest[10][3]</code> whose <code>item[2]</code> lists known NPCs, those NPCs are injected into <code>quest[10][1]</code> as creature objectives.</li>
|
||||
<li><strong>[CrossLinkAfterObject]</strong> Called when a new object is first committed to <code>learnedData.objects</code>. Scans all learned quests: if <code>quest[2][2]</code> references this objectId → adds questId to <code>obj[2]</code> (questStarts); if <code>quest[3][2]</code> references it → adds questId to <code>obj[3]</code> (questEnds).</li>
|
||||
<li><strong>[CrossLinkAfterItem]</strong> Called when a new item is first committed to <code>learnedData.items</code> AND whenever a new drop-NPC relationship is added via <code>LearnItemDrop</code>. Two passes: (1) scan all learned quests for <code>quest[11] == itemId</code> → set <code>item[5] = questId</code> (this item starts that quest); (2) scan all learned quests for <code>quest[10][3]</code> entries matching itemId — for each such quest, every NPC in <code>item[2]</code> (drop sources) is injected into <code>quest[10][1]</code> as a creature objective. Practical example: accept a quest needing "Wolf Pelt" → wolf is killed and the pelt drops → <code>LearnItemDrop</code> fires → <code>CrossLinkAfterItem</code> runs → the wolf NPC is immediately added as a creature objective for the pelt quest with active map pins, no reload.</li>
|
||||
<li><strong>[CrossLinkAfterQuestGiver]</strong> Now handles all three entity type slots (1=NPC, 2=Object, 3=Item) instead of only NPCs. For typeSlot=1: stitches <code>npc[10/11]</code> ↔ <code>quest[2/3][1]</code> bidirectionally. For typeSlot=2: stitches <code>obj[2/3]</code> ↔ <code>quest[2/3][2]</code>. For typeSlot=3: adds itemId to <code>quest[2][3]</code> (item starters sub-slot). Called by <code>LearnQuestGiver</code> for all typeSlots, replacing the previous NPC-only check.</li>
|
||||
<li><strong>[LearnItemDrop hook]</strong> Now calls <code>CrossLinkAfterItem(itemId)</code> every time a new NPC is added to an item's drop list, not only on initial item creation. This retroactively propagates the drop→quest objective chain for previously learned items.</li>
|
||||
<li><strong>[LearnQuest / LearnObject / LearnItem hooks]</strong> Each now calls its respective <code>CrossLinkAfterX</code> function on first creation of the entity record. Subsequent updates to an existing record skip the cross-link scan (already linked on creation).</li>
|
||||
<li><strong>[Item schema correction]</strong> Fixed an incorrect use of key <code>[9]</code> (which maps to <code>itemLevel</code> in <code>QuestieDB.itemKeys</code>) for quest-source storage. The correct key is <code>[5]</code> (<code>startQuest</code>). Affects <code>CrossLinkAfterQuest</code> and <code>CrossLinkAfterItem</code>.</li>
|
||||
<li><strong>[Mouseover — all NPCs now learned]</strong> Removed the <code>UnitReaction < 4</code> early-return guard that blocked learning hostile or neutral NPCs via mouseover. The existing <code>QUESTGIVER</code> NPC-flag bitmask check (<code>0x02</code>) remains as the primary filter, ensuring only NPCs with a quest-giver relationship are stored. Hostile quest objective NPCs are now captured on any hover, target, or kill and are correctly cross-linked to their quests.</li>
|
||||
</ul>
|
||||
|
||||
<h3>TrackerUtils.lua — Zone Resolution Rewrite</h3>
|
||||
<ul>
|
||||
<li><strong>[GetQuestLogZoneName — canonical 3.3.5a zone lookup]</strong> Added new local function <code>GetQuestLogZoneName(questId)</code>. Implements the only fully reliable zone resolution method in 3.3.5a: iterates the quest log from index 1 to <code>GetNumQuestLogEntries()</code> to locate the target quest's log index, then walks backwards from that index until an entry where <code>isHeader=true</code> is found. That header's <code>title</code> string is the zone name (e.g. <code>"Shadowmoon Valley"</code>). <code>GetRealZoneText()</code> and <code>GetCurrentMapAreaID()</code> were previously used but are unreliable because they reflect the currently viewed map, not the quest's zone. The 3.3.5a client places zone header entries directly above their child quests in the flat quest log list — this is guaranteed by the client and is the same method Blizzard's own UI uses to render the zone groups.</li>
|
||||
<li><strong>[BuildFallbackQuest — zone via log walk]</strong> Replaced the <code>GetRealZoneText()</code> call with the inline header walk. The loop that already iterates the quest log to find the fallback quest's entry now continues backwards from that same index to find the header. <code>GetAreaIdByZoneName()</code> converts the string to an area ID for <code>zoneOrSort</code>; the raw string is stored as <code>quest.zoneName</code> for display. If no header is found (e.g. "Special" category with no zone header), <code>zoneName</code> remains nil and the tracker falls back to the <code>_GetZoneName(zoneOrSort)</code> path.</li>
|
||||
<li><strong>[_isLogFallback patch block — zone fix]</strong> The block that patches <code>QuestLogCache</code> fallback objects (identified by <code>_isLogFallback=true</code> and absence of an <code>IsComplete</code> method) now calls <code>GetQuestLogZoneName(capturedId)</code> immediately after patching <code>Objectives</code>, <code>SpecialObjectives</code>, and <code>ExtraObjectives</code>. If a zone name is returned, both <code>quest.zoneName</code> and <code>quest.zoneOrSort</code> are set on the object in-place. Previously this block left both values at their <code>QuestLogCache</code> defaults (<code>zoneOrSort=0</code>, <code>zoneName=nil</code>), which caused every fallback quest to group under "Unknown Zone" in the tracker regardless of where the quest was accepted.</li>
|
||||
<li><strong>[Fallback cache invalidation]</strong> <code>_fallbackQuests[qid]</code> is now evicted and unconditionally rebuilt if the cached entry has no <code>zoneName</code>. This handles the race condition where <code>BuildFallbackQuest</code> was called during addon initialization before the quest log entries were populated, caching a zoneless entry that would persist for the entire session.</li>
|
||||
</ul>
|
||||
|
||||
<h3>QuestieTracker.lua — Untrack Fix</h3>
|
||||
<ul>
|
||||
<li><strong>[UntrackQuestId — inverted logic fixed]</strong> <code>UntrackQuestId</code> previously set <code>AutoUntrackedQuests[questId] = nil</code> when the player untracks a quest. The tracker filter expression is <code>not Questie.db.char.AutoUntrackedQuests[questId]</code> — when the value is <code>nil</code>, <code>not nil</code> is <code>true</code>, meaning "show this quest". Clearing the entry on untrack therefore immediately re-showed the quest on the very next tracker update tick, making untacking appear completely broken. Fix: in <code>autoTrackQuests</code> mode, <code>UntrackQuestId</code> now sets <code>AutoUntrackedQuests[questId] = true</code> (evaluated as "hide"). In manual-track mode, it clears <code>TrackedQuests[questId]</code> as before, and <code>AutoUntrackedQuests</code> is cleared instead of being incorrectly toggled. The two tracking modes are now cleanly separated within the function.</li>
|
||||
<li><strong>[AQW_Insert — QuestLogFrame gate removed]</strong> The condition <code>IsShiftKeyDown() and QuestLogFrame:IsShown()</code> inside <code>AQW_Insert</code> was blocking the re-tracking path (clearing <code>AutoUntrackedQuests[questId]</code>) whenever the quest log frame was not open. Since untacking fires <code>RemoveQuestWatch</code> → <code>UntrackQuestId</code> directly, this <code>AQW_Insert</code> branch was only ever reached for re-tracking — yet the gate required the quest log to be open. The gate has been removed; re-tracking now works from any UI context.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<h2 id="v126">v1.2.6 — QuestieLearner Comprehensive Overhaul</h2>
|
||||
<p><em>Rewrote QuestieLearner from scratch to fix all known data-capture deficiencies. Adds full quest field coverage, grid-based coordinate clustering, quest-giver-only mouseover filtering, async item-info retry, object loot detection, and live inject-on-import so imported data takes effect without a reload.</em></p>
|
||||
|
||||
Reference in New Issue
Block a user