feat: QuestieLearner comprehensive overhaul v1.2.6

- Full quest field capture (title, level, objectives, description, money, zone)
- Mouseover filter: only record NPCs with QUESTGIVER npcFlag (0x02) or known DB entries
- OnTargetChanged: cache GUID for kill tracking only, no more spurious LearnNPC calls
- Grid-bucket coordinate clustering (COORD_GRID=2.0) replaces naive radius dedup
- Object recording: detect GameObject loot, gossip, and quest giver/finisher
- Item loot: async GetItemInfo retry via GET_ITEM_INFO_RECEIVED event
- LearnQuestGiver: entityType parameter (1=NPC,2=obj,3=item) for correct wiki layout
- InjectLearnedData: uses grid clustering in all merge paths
- MergeImport: calls InjectLearnedData immediately after merge (live override injection)
- README: corrected import reload requirement description
- CHANGELOG + docs/changelog.html updated with developer detail
This commit is contained in:
Xurkon
2026-03-16 20:49:02 -05:00
parent 46a3476884
commit 8bc74a488b
5 changed files with 502 additions and 278 deletions
+27
View File
@@ -1,5 +1,32 @@
# Changelog
## v1.2.6 — QuestieLearner Comprehensive Overhaul
> 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.
### QuestieLearner.lua — Full Rewrite
- **[Quest capture completeness]** `LearnQuest` now accepts a generic `data` table keyed by Questie wiki array indices rather than individual positional arguments. `OnQuestDetail` captures title, objectives text block, quest description body, and current zone as `zoneOrSort[8]`. `OnQuestAccepted` fills quest level from `GetQuestLogTitle`, per-objective text from `GetQuestLogLeaderBoard`, and required money from `GetQuestLogRequiredMoney`. `OnQuestComplete` captures finish/reward text via `GetRewardText`.
- **[Mouseover filter]** `OnMouseoverUnit` now only learns an NPC if its `UnitNPCFlags` bitmask includes the `QUESTGIVER` bit (`0x02`), OR if the NPC already exists in `QuestieDB` as a known quest starter/finisher. All other NPCs are silently ignored — this eliminates the flood of irrelevant NPC entries the learner previously accumulated.
- **[Target changed]** `OnTargetChanged` no longer calls `LearnNPC` on every target switch. It now only populates the `guidNpcCache` for kill-tracking purposes, avoiding recording non-quest NPCs.
- **[Coordinate clustering — grid bucketing]** Replaced the naive "within 1 unit radius" deduplication with a 2×2 grid bucket scheme (`COORD_GRID = 2.0`). A new point is inserted only when no existing point shares the same grid cell. This prevents coordinate scatter across a kill area while still preserving distinct spawn clusters. The `InsertIfNewBucket` helper is shared across NPC, Object, and all merge paths (including `InjectLearnedData` and `HandleNetworkData`).
- **[Object recording]** `OnLootOpened` now checks whether the loot source GUID is a `GameObject` (not just a creature). If so, `LearnObject` is called with the object's ID and name. `OnGossipShow` records both objects and NPCs via `GetIdAndTypeFromGUID`. `OnQuestDetail` and `OnQuestComplete` also record the interacting object when the quest giver/finisher is a `GameObject`.
- **[Item loot — async GetItemInfo retry]** `OnLootOpened` queues unresolved item links (where `GetItemInfo` returns nil because the item is not yet in the client cache) into `_Learner.pendingItemLinks`. A new `OnGetItemInfoReceived(itemId)` handler fires on the `GET_ITEM_INFO_RECEIVED` event, resolves queued links for that item ID, and calls `LearnItem`/`LearnItemDrop` once the data is available. This fixes silent data loss on first-encounter loots.
- **[Quest giver entity type]** `LearnQuestGiver` now accepts an `entityType` argument (1=NPC, 2=GameObject, 3=item) and stores starters/finishers in the correct sub-array slot matching the Questie wiki spec `{ [1]={npcIds}, [2]={objIds}, [3]={itemIds} }`.
- **[Kill tracking fallback]** `OnCombatLogEvent` retains all three GUID-resolution paths (dash-split, GUID cache, hex-prefix) with a 10-minute TTL cache cleanup. Uses `CombatLogGetCurrentEventInfo()` with fallback to varargs for cross-client compatibility.
- **[GET_ITEM_INFO_RECEIVED event]** Registered in `RegisterEvents` so the async item retry path fires correctly.
- **[InjectLearnedData — grid clustering]** All coordinate merge loops in `InjectLearnedData` now use `InsertIfNewBucket` instead of the old radius check.
### QuestieLearnerExport.lua — Import Live-Inject Fix
- **[MergeImport → InjectLearnedData]** After `MergeType` completes for all four categories, `MergeImport` now immediately calls `QuestieLearner:InjectLearnedData()`. Imported data is pushed into `QuestieDB.*DataOverrides` in the same frame — override-driven map pins update without a `/reload`. A full reload is still needed to pick up newly imported quest starters/finishers for quests already tracked in the player's quest log.
### README — Import Clarification
- Corrected the "no reload required" claim. The import flow now accurately describes when an immediate effect is visible versus when a `/reload` is beneficial.
---
## v1.2.5 — Ebonhold DB Plugin Load Fix
> Fixed a fatal load-time crash in all four Ebonhold DB files caused by calling `GetRealmName()` and `QuestieLoader:CreateModule()` at file scope (before WoW's API is fully available). Switched to plain global table population; realm-gating and injection remain safely deferred to `EbonholdLoader.lua`'s `PLAYER_LOGIN` handler.
+440 -277
View File
File diff suppressed because it is too large Load Diff
+6
View File
@@ -288,6 +288,12 @@ function QuestieLearnerExport:MergeImport()
self.lastImportData = nil
self.lastImportStats = nil
-- Push merged data into QuestieDB overrides immediately (no reload required for override data)
local QuestieLearner = QuestieLoader:ImportModule("QuestieLearner")
if QuestieLearner and QuestieLearner.InjectLearnedData then
QuestieLearner:InjectLearnedData()
end
local msg = "Import complete: merged " .. merged .. " entries, skipped " .. skipped .. " (already known)."
Questie:Debug(Questie.DEBUG_DEVELOP, "[LearnerExport]", msg)
return true, msg
+1 -1
View File
@@ -245,7 +245,7 @@ To load data exported by another player or provided by the community:
1. Open Questie-X options → **Database** tab.
2. Paste the export string into the import text box.
3. Click **Import**. Questie-X decodes and merges the data into your local database immediately — no reload required.
3. Click **Import**. Questie-X decodes and merges the data into your local database and immediately injects it into the active override tables — map pins and tracker entries update without a full reload. A `/reload` is only required if you want newly imported quest starters/finishers to appear on the world map for quests already in your log.
Imported entries follow the same validation rules as received broadcast entries. Conflicts (same NPC ID with different coordinates) are resolved by keeping the entry with the most data fields populated.
+28
View File
@@ -175,6 +175,34 @@
</div>
</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>
<h3>QuestieLearner.lua — Full Rewrite</h3>
<ul>
<li><strong>[Quest capture completeness]</strong> <code>LearnQuest</code> now accepts a generic <code>data</code> table keyed by Questie wiki array indices rather than individual positional arguments. <code>OnQuestDetail</code> captures title, objectives text block, quest description body, and current zone as <code>zoneOrSort[8]</code>. <code>OnQuestAccepted</code> fills quest level from <code>GetQuestLogTitle</code>, per-objective text from <code>GetQuestLogLeaderBoard</code>, and required money from <code>GetQuestLogRequiredMoney</code>. <code>OnQuestComplete</code> captures finish/reward text via <code>GetRewardText</code>.</li>
<li><strong>[Mouseover filter]</strong> <code>OnMouseoverUnit</code> now only learns an NPC if its <code>UnitNPCFlags</code> bitmask includes the <code>QUESTGIVER</code> bit (<code>0x02</code>), OR if the NPC already exists in <code>QuestieDB</code> as a known quest starter/finisher. All other NPCs are silently ignored — this eliminates the flood of irrelevant NPC entries the learner previously accumulated.</li>
<li><strong>[Target changed]</strong> <code>OnTargetChanged</code> no longer calls <code>LearnNPC</code> on every target switch. It now only populates the <code>guidNpcCache</code> for kill-tracking purposes, avoiding recording non-quest NPCs.</li>
<li><strong>[Coordinate clustering — grid bucketing]</strong> Replaced the naive "within 1 unit radius" deduplication with a 2×2 grid bucket scheme (<code>COORD_GRID = 2.0</code>). A new point is inserted only when no existing point shares the same grid cell. This prevents coordinate scatter across a kill area while still preserving distinct spawn clusters. The <code>InsertIfNewBucket</code> helper is shared across NPC, Object, and all merge paths (including <code>InjectLearnedData</code> and <code>HandleNetworkData</code>).</li>
<li><strong>[Object recording]</strong> <code>OnLootOpened</code> now checks whether the loot source GUID is a <code>GameObject</code>. If so, <code>LearnObject</code> is called with the object's ID and name. <code>OnGossipShow</code> records both objects and NPCs via <code>GetIdAndTypeFromGUID</code>. <code>OnQuestDetail</code> and <code>OnQuestComplete</code> also record the interacting object when the quest giver/finisher is a <code>GameObject</code>.</li>
<li><strong>[Item loot — async GetItemInfo retry]</strong> <code>OnLootOpened</code> queues unresolved item links (where <code>GetItemInfo</code> returns nil because the item is not yet in the client cache) into <code>_Learner.pendingItemLinks</code>. A new <code>OnGetItemInfoReceived(itemId)</code> handler fires on the <code>GET_ITEM_INFO_RECEIVED</code> event, resolves queued links for that item ID, and calls <code>LearnItem</code>/<code>LearnItemDrop</code> once the data is available. This fixes silent data loss on first-encounter loots.</li>
<li><strong>[Quest giver entity type]</strong> <code>LearnQuestGiver</code> now accepts an <code>entityType</code> argument (1=NPC, 2=GameObject, 3=item) and stores starters/finishers in the correct sub-array slot matching the Questie wiki spec <code>{ [1]={npcIds}, [2]={objIds}, [3]={itemIds} }</code>.</li>
<li><strong>[Kill tracking]</strong> <code>OnCombatLogEvent</code> retains all three GUID-resolution paths (dash-split, GUID cache, hex-prefix) with a 10-minute TTL cache cleanup. Uses <code>CombatLogGetCurrentEventInfo()</code> with fallback to varargs for cross-client compatibility.</li>
<li><strong>[InjectLearnedData — grid clustering]</strong> All coordinate merge loops now use <code>InsertIfNewBucket</code> instead of the old radius check.</li>
</ul>
<h3>QuestieLearnerExport.lua — Import Live-Inject Fix</h3>
<ul>
<li><strong>[MergeImport → InjectLearnedData]</strong> After merging all four data categories, <code>MergeImport</code> immediately calls <code>QuestieLearner:InjectLearnedData()</code>. Imported data is pushed into <code>QuestieDB.*DataOverrides</code> in the same frame — override-driven map pins update without a <code>/reload</code>. A full reload is still needed to pick up newly imported quest starters/finishers for quests already in the player's quest log.</li>
</ul>
<h3>README — Import Clarification</h3>
<ul>
<li>Corrected the "no reload required" claim. The import flow now accurately describes when an immediate effect is visible versus when a <code>/reload</code> is beneficial.</li>
</ul>
</div>
<div class="container">
<h2 id="v125">v1.2.5 — Ebonhold &amp; Ascension DB Plugin Load Fix</h2>
<p><em>Fixed a fatal load-time crash in all four Ebonhold DB files (and identically in the Ascension DB files) caused by calling <code>GetRealmName()</code> and <code>QuestieLoader:CreateModule()</code> at file scope — before WoW's API is fully available. Switched to plain global table population; realm-gating and injection remain safely deferred to the loader's <code>PLAYER_LOGIN</code> handler.</em></p>