docs: add GUID reference, object vs NPC distinction, and settings backfill prereq to verification guide
This commit is contained in:
@@ -17,6 +17,15 @@ Or enable **Develop** in Questie Options → Advanced → Debug Level.
|
|||||||
|
|
||||||
> You do NOT need Critical enabled separately — Develop includes Critical-tier output.
|
> You do NOT need Critical enabled separately — Develop includes Critical-tier output.
|
||||||
|
|
||||||
|
### Verify Settings Are Enabled
|
||||||
|
|
||||||
|
If you upgraded from an older version, `learnedData` in your SavedVariables may be missing the newer settings keys (fixed in v1.2.7). Confirm all are `true` before testing:
|
||||||
|
```
|
||||||
|
/script local s=Questie.db.global.learnedData.settings; print("enabled:", tostring(s.enabled), "npcs:", tostring(s.learnNpcs), "quests:", tostring(s.learnQuests), "items:", tostring(s.learnItems), "objects:", tostring(s.learnObjects))
|
||||||
|
```
|
||||||
|
|
||||||
|
All five should print `true`. If any print `nil`, do a `/reload` — v1.2.7's `EnsureLearnedData` backfill will fix it on next load.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Test 1 — Initialization
|
## Test 1 — Initialization
|
||||||
@@ -47,6 +56,8 @@ Target the quest giver NPC and run:
|
|||||||
/script local guid = UnitGUID("target"); local id = tonumber(select(6, strsplit("-", guid))); print("NPC ID:", id)
|
/script local guid = UnitGUID("target"); local id = tonumber(select(6, strsplit("-", guid))); print("NPC ID:", id)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **Note:** This only works for dash-format GUIDs (e.g. `Creature-0-...`). If the GUID is in hex format (`0xF110...`), use the hex decode method in the GUID Reference section below.
|
||||||
|
|
||||||
### 2b — Clear it from learned data, then hover
|
### 2b — Clear it from learned data, then hover
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -86,10 +97,12 @@ Mouseover any wolf, enemy soldier, or non-quest creature.
|
|||||||
|
|
||||||
Pick up any quest from an NPC. Look for:
|
Pick up any quest from an NPC. Look for:
|
||||||
```
|
```
|
||||||
[QuestieLearner] Learned Quest: <id> <QuestName>
|
[QuestieLearner] New quest learned: <id> <QuestName>
|
||||||
[QuestieLearner] Learned NPC: <id> <GiverName> ← or "Learned Object" if quest giver is a chest/object
|
[QuestieLearner] New NPC learned: <id> <GiverName>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> Only prints on the **first time** each quest/NPC is learned. Subsequent accepts of the same quest are silent (data is updated internally).
|
||||||
|
|
||||||
Verify data was stored:
|
Verify data was stored:
|
||||||
```
|
```
|
||||||
/script local q=Questie.db.global.learnedData.quests; local n=0; for _ in pairs(q) do n=n+1 end; print("Learned quests:", n)
|
/script local q=Questie.db.global.learnedData.quests; local n=0; for _ in pairs(q) do n=n+1 end; print("Learned quests:", n)
|
||||||
@@ -97,10 +110,15 @@ Verify data was stored:
|
|||||||
|
|
||||||
Inspect a specific quest (replace `<questId>` with the ID you just accepted):
|
Inspect a specific quest (replace `<questId>` with the ID you just accepted):
|
||||||
```
|
```
|
||||||
/script local q=Questie.db.global.learnedData.quests[<questId>]; if q then print("name:", q[1], "level:", q[5], "reqLvl:", q[4], "zone:", q[8]) end
|
/script local q=Questie.db.global.learnedData.quests[<questId>]; if q then print("name:", q[1], "level:", q[5], "reqLvl:", q[4], "zone:", q[8]) else print("NOT captured") end
|
||||||
```
|
```
|
||||||
|
|
||||||
Expected: `name: <quest name> level: <number> zone: <mapId>`
|
If it says `NOT captured`, check your settings (Prerequisites section) — `learnQuests` being `nil` silently blocks all quest recording.
|
||||||
|
|
||||||
|
Check if the quest is already in a DB plugin (if so, learner skips it):
|
||||||
|
```
|
||||||
|
/script local q = QuestieDB:GetQuest(<questId>); if q then print("In DB:", q[1]) else print("NOT in DB - learner should capture it") end
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -108,8 +126,7 @@ Expected: `name: <quest name> level: <number> zone: <mapId>`
|
|||||||
|
|
||||||
Complete and turn in a quest. Look for:
|
Complete and turn in a quest. Look for:
|
||||||
```
|
```
|
||||||
[QuestieLearner] Learned Quest: <id> <QuestName>
|
[QuestieLearner] New NPC learned: <id> <FinisherName>
|
||||||
[QuestieLearner] Learned NPC: <id> <FinisherName>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Verify both starter and finisher are recorded:
|
Verify both starter and finisher are recorded:
|
||||||
@@ -131,40 +148,39 @@ Have an active kill quest in your quest log (e.g., "Kill 10 Wolves"). Kill one o
|
|||||||
|
|
||||||
**Expected output:**
|
**Expected output:**
|
||||||
```
|
```
|
||||||
[QuestieLearner] UNIT_DIED: recording kill NPC <id> <MobName>
|
[QuestieLearner] Kill recorded: NPC <id> <MobName>
|
||||||
[QuestieLearner] Learned NPC: <id> <MobName>
|
[QuestieLearner] New NPC learned: <id> <MobName>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> "New NPC learned" only appears the first time. Subsequent kills of the same NPC type are silent but still update coordinates.
|
||||||
|
|
||||||
Verify coordinates were stored:
|
Verify coordinates were stored:
|
||||||
```
|
```
|
||||||
/script local n=Questie.db.global.learnedData.npcs[<npcId>]; if n and n[7] then for z,c in pairs(n[7]) do print("zone "..z.." has "..#c.." coord clusters") end end
|
/script local n=Questie.db.global.learnedData.npcs[<npcId>]; if n and n[7] then for z,c in pairs(n[7]) do print("zone "..z.." has "..#c.." coord cluster(s)") end else print("no coords") end
|
||||||
```
|
```
|
||||||
|
|
||||||
Kill the same mob type multiple times in the same area. The cluster count should NOT increase for every single kill — only when you move to a meaningfully different location (>2% of zone width away).
|
Kill the same mob type multiple times in the same area. The cluster count should NOT increase for every kill — only when you move to a meaningfully different location (>2% of zone width apart).
|
||||||
|
|
||||||
### 5b — Non-Quest Mob (Should Be Ignored)
|
### 5b — Non-Quest Mob (Should Be Ignored)
|
||||||
|
|
||||||
Kill a mob that is NOT a quest objective and is NOT in QuestieDB.
|
Kill a mob that is NOT a quest objective and is NOT in QuestieDB.
|
||||||
|
|
||||||
**Expected output:** Nothing. `[QuestieLearner] UNIT_DIED` should NOT appear.
|
**Expected output:** Nothing. `[QuestieLearner] Kill recorded` should NOT appear.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Test 6 — Item Loot Recording
|
## Test 6 — Item Loot Recording
|
||||||
|
|
||||||
Loot a mob or chest that drops a **quest item** (purple/green bag icon in loot window, or any item that appears in the loot frame).
|
Loot a mob or chest that drops a quest item.
|
||||||
|
|
||||||
**Expected output (immediate, if item was already cached):**
|
**Expected output (immediate):**
|
||||||
```
|
```
|
||||||
[QuestieLearner] Learned Item: <id> <ItemName>
|
[QuestieLearner] New item learned: <id> <ItemName>
|
||||||
```
|
```
|
||||||
|
|
||||||
**Expected output (delayed by ~1 second if item was never seen before):**
|
**Expected output (delayed ~1 second if item never seen before):**
|
||||||
```
|
|
||||||
[QuestieLearner] Learned Item: <id> <ItemName>
|
|
||||||
```
|
|
||||||
|
|
||||||
This fires when `GET_ITEM_INFO_RECEIVED` resolves the async `GetItemInfo` call.
|
Same line, but fires when `GET_ITEM_INFO_RECEIVED` resolves the async `GetItemInfo` call.
|
||||||
|
|
||||||
Verify:
|
Verify:
|
||||||
```
|
```
|
||||||
@@ -175,27 +191,54 @@ Verify:
|
|||||||
|
|
||||||
## Test 7 — Object Recording
|
## Test 7 — Object Recording
|
||||||
|
|
||||||
Interact with a **clickable quest object** (a chest, a crate, a brazier, a scroll — any game object that starts or is part of a quest).
|
Interact with a clickable game object (chest, crate, brazier, scroll, etc.).
|
||||||
|
|
||||||
**Expected output:**
|
> **Important:** Some objects that look like interactable objects (e.g. Objectives Board) are actually implemented as **Creature NPCs** by the server. These will be recorded as NPCs, not objects — this is correct behavior.
|
||||||
|
|
||||||
|
### 7a — Identify what type an object/NPC is
|
||||||
|
|
||||||
|
With the gossip/interaction window open, run:
|
||||||
```
|
```
|
||||||
[QuestieLearner] Learned Object: <id> <ObjectName>
|
/script local g=UnitGUID("npc"); if g then local p=string.upper(string.sub(g,3,6)); print("GUID:", g, "Prefix:", p, "IsGameObject:", tostring(p=="F140")) end
|
||||||
```
|
```
|
||||||
|
|
||||||
Verify:
|
| Prefix | Type | Recorded as |
|
||||||
|
|---|---|---|
|
||||||
|
| `F140` | GameObject | Object (`learnedData.objects`) |
|
||||||
|
| `F130` | Creature | NPC (`learnedData.npcs`) |
|
||||||
|
| `F110` | Creature/Pet | NPC (`learnedData.npcs`) |
|
||||||
|
| `F131` | Vehicle | NPC (`learnedData.npcs`) |
|
||||||
|
|
||||||
|
### 7b — Decode a hex GUID to get the ID
|
||||||
|
|
||||||
```
|
```
|
||||||
/script local o=Questie.db.global.learnedData.objects; local n=0; for _ in pairs(o) do n=n+1 end; print("Learned objects:", n)
|
/script local g=UnitGUID("npc"); if g then local p=string.upper(string.sub(g,3,6)); local id=math.mod(tonumber(string.sub(g,11,18),16),8388608); print("Prefix:", p, "ID:", tostring(id)) end
|
||||||
|
```
|
||||||
|
|
||||||
|
> `strsplit("-", guid)` does **not** work on hex-format GUIDs — it returns the full string as the first value and nil for everything else. Always use the hex decode method above for `0x...` GUIDs.
|
||||||
|
|
||||||
|
### 7c — Print all learned objects
|
||||||
|
|
||||||
|
```
|
||||||
|
/script for id, data in pairs(Questie.db.global.learnedData.objects) do print("Object ID:", id, "Name:", tostring(data[1]), "Zone:", tostring(data[5])) end
|
||||||
|
```
|
||||||
|
|
||||||
|
With coordinates:
|
||||||
|
```
|
||||||
|
/script for id, data in pairs(Questie.db.global.learnedData.objects) do print("Object:", id, data[1]); if data[4] then for z, coords in pairs(data[4]) do print(" zone "..z.." - "..#coords.." coord(s)") end end end
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Test 8 — Overall Stats Check
|
## Test 8 — Overall Stats Check
|
||||||
|
|
||||||
Run this anytime to see a full summary of what has been learned this session:
|
Run this anytime to see a full summary:
|
||||||
```
|
```
|
||||||
/script local QL=QuestieLoader:ImportModule("QuestieLearner"); local n,q,i,o=QL:GetStats(); print("NPCs:"..n.." Quests:"..q.." Items:"..i.." Objects:"..o)
|
/script local QL=QuestieLoader:ImportModule("QuestieLearner"); local n,q,i,o=QL:GetStats(); print("NPCs:"..n.." Quests:"..q.." Items:"..i.." Objects:"..o)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Expected counts increase as you play. `Quests:0` after accepting quests = settings backfill issue (see Prerequisites).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Test 9 — Export
|
## Test 9 — Export
|
||||||
@@ -213,8 +256,8 @@ The export string starts with `QxLD:1!`. Copy it from the Database tab → Expor
|
|||||||
## Test 10 — Import (Round-Trip)
|
## Test 10 — Import (Round-Trip)
|
||||||
|
|
||||||
1. Export your data (Test 9).
|
1. Export your data (Test 9).
|
||||||
2. Run `/script QuestieLoader:ImportModule("QuestieLearner"):ClearAllData()` to wipe learned data.
|
2. Wipe learned data: `/script QuestieLoader:ImportModule("QuestieLearner"):ClearAllData()`
|
||||||
3. Open Questie Options → Database → paste the export string into the Import box → click Import.
|
3. Open Questie Options → Database → paste the export string → click Import.
|
||||||
|
|
||||||
Expected in chat:
|
Expected in chat:
|
||||||
```
|
```
|
||||||
@@ -222,20 +265,20 @@ Import complete: merged N entries, skipped 0 (already known).
|
|||||||
[QuestieLearner] Injected learned data: N NPCs, N quests, N items, N objects
|
[QuestieLearner] Injected learned data: N NPCs, N quests, N items, N objects
|
||||||
```
|
```
|
||||||
|
|
||||||
Verify stats match original count (Test 8).
|
Verify stats match original count (Test 8). Data takes effect immediately — no `/reload` required for override-based map pins.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Test 11 — Plugin Panel Stats (WotLKDB)
|
## Test 11 — Plugin Panel Stats (WotLKDB)
|
||||||
|
|
||||||
Open **Questie Options → Advanced** and scroll to **Loaded Questie-X Plugins**.
|
Open **Questie Options → Database** tab → scroll to **Loaded Questie-X Plugins**.
|
||||||
|
|
||||||
Expected for WotLKDB:
|
Expected for WotLKDB:
|
||||||
```
|
```
|
||||||
[Questie-WotLKDB] Quests: 9086 NPCs: XXXX Objects: XXXX Items: XXXX
|
[Questie-WotLKDB] Quests: 9086 NPCs: XXXX Objects: XXXX Items: XXXX
|
||||||
```
|
```
|
||||||
|
|
||||||
If you see all zeros, the `QuestieX_WotLKDB_Counts` global was not set before the Loader.lua read it. Check that `QuestieInit:LoadBaseDB()` is running before `PLAYER_LOGIN` completes.
|
If you see all zeros: `QuestieX_WotLKDB_Counts` is not set yet. This global is written by `LoadBaseDB()` inside an async coroutine — open the options panel a few seconds after login rather than immediately.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -248,17 +291,43 @@ On Client 2, run:
|
|||||||
/script print(type(Questie.db.global.learnedData.npcs[<npcId>]))
|
/script print(type(Questie.db.global.learnedData.npcs[<npcId>]))
|
||||||
```
|
```
|
||||||
|
|
||||||
Expected: `table` (the NPC data arrived via the hidden `questiecomm` channel or AceComm guild broadcast).
|
Expected: `table` (arrived via hidden `questiecomm` channel or AceComm guild broadcast).
|
||||||
|
|
||||||
> **Note:** Both clients must be in the same guild OR on the same server (for the hidden channel). Allow up to 10 seconds for the token-bucket throttle to release the message.
|
> Both clients must be in the same guild OR on the same server. Allow up to 10 seconds for the token-bucket throttle.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## GUID Reference
|
||||||
|
|
||||||
|
WoW uses two GUID formats. The learner handles both automatically.
|
||||||
|
|
||||||
|
### Dash-format (modern)
|
||||||
|
```
|
||||||
|
Creature-0-3726-0-189-5638296-000001ABCD
|
||||||
|
```
|
||||||
|
Parse with: `strsplit("-", guid)` → 6th element = ID, 1st = unit type string
|
||||||
|
|
||||||
|
### Hex-format (legacy, common on private servers)
|
||||||
|
```
|
||||||
|
0xF110092A18000718
|
||||||
|
```
|
||||||
|
Parse with position extraction:
|
||||||
|
- Characters 3–6 = unit type prefix (`F110`, `F130`, `F140`, etc.)
|
||||||
|
- Characters 11–18 = low 32 bits → `math.mod(tonumber(low32hex, 16), 8388608)` = entity ID
|
||||||
|
|
||||||
|
**Do NOT use `strsplit("-", ...)` on hex GUIDs** — it will return nil for all fields after the first.
|
||||||
|
|
||||||
|
Quick decode command for any hex GUID:
|
||||||
|
```
|
||||||
|
/script local g="0xF110092A18000718"; local p=string.upper(string.sub(g,3,6)); local id=math.mod(tonumber(string.sub(g,11,18),16),8388608); print("Prefix:",p,"ID:",id)
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Quick Diagnostic — All At Once
|
## Quick Diagnostic — All At Once
|
||||||
|
|
||||||
Paste this block into chat for a full snapshot:
|
|
||||||
```
|
```
|
||||||
/script local QL=QuestieLoader:ImportModule("QuestieLearner"); local n,q,i,o=QL:GetStats(); print("=== QuestieLearner Stats ==="); print("NPCs:"..n.." Quests:"..q.." Items:"..i.." Objects:"..o); local ld=Questie.db.global.learnedData; print("Enabled:", tostring(ld.settings.enabled)); print("Learn NPCs:", tostring(ld.settings.learnNpcs)); print("Learn Quests:", tostring(ld.settings.learnQuests)); print("Learn Items:", tostring(ld.settings.learnItems)); print("Learn Objects:", tostring(ld.settings.learnObjects))
|
/script local QL=QuestieLoader:ImportModule("QuestieLearner"); local n,q,i,o=QL:GetStats(); print("=== QuestieLearner Stats ==="); print("NPCs:"..n.." Quests:"..q.." Items:"..i.." Objects:"..o); local s=Questie.db.global.learnedData.settings; print("enabled:", tostring(s.enabled), "| npcs:", tostring(s.learnNpcs), "| quests:", tostring(s.learnQuests), "| items:", tostring(s.learnItems), "| objects:", tostring(s.learnObjects))
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -268,8 +337,12 @@ Paste this block into chat for a full snapshot:
|
|||||||
| Symptom | Cause | Fix |
|
| Symptom | Cause | Fix |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Nothing prints at all | Debug level not set to DEVELOP | `/script Questie.db.profile.debugLevel = Questie.DEBUG_DEVELOP` |
|
| Nothing prints at all | Debug level not set to DEVELOP | `/script Questie.db.profile.debugLevel = Questie.DEBUG_DEVELOP` |
|
||||||
| Random mobs being recorded | Old QuestieLearner.lua still loaded | Confirm v1.2.6+ is deployed, `/reload` |
|
| `Quests:0` despite accepting quests | `learnQuests = nil` in old SavedVariables | `/reload` — v1.2.7 backfill sets it to `true` |
|
||||||
| Kill coords not recording | NPC not in QuestieDB and not explicitly targeted/hovered before kill | Target the mob before killing it, or ensure your DB plugin is loaded |
|
| Random mobs being recorded | Old QuestieLearner.lua still loaded | Confirm v1.2.6+ deployed, `/reload` |
|
||||||
|
| Kill coords not recording | NPC not in QuestieDB and not targeted/hovered | Target the mob before killing it |
|
||||||
|
| Object recorded as NPC | Server implements it as a Creature (`F110`/`F130`) | Correct behavior — check prefix to confirm |
|
||||||
|
| `strsplit` returns nil | GUID is hex format, not dash-separated | Use hex decode method (see GUID Reference) |
|
||||||
|
| `UnitGUID("target")` returns nil | GameObjects can't be traditionally targeted | Use `UnitGUID("npc")` during gossip interaction instead |
|
||||||
| Export returns nil | `learnedData` is empty | Run Tests 2–7 first to accumulate data |
|
| Export returns nil | `learnedData` is empty | Run Tests 2–7 first to accumulate data |
|
||||||
| WotLKDB shows 0s in plugin panel | `QuestieX_WotLKDB_Counts` not set | Verify `QuestieInit:LoadBaseDB()` has the count-before-pull logic |
|
| WotLKDB shows 0s in plugin panel | Options opened before async init completed | Wait a few seconds after login then reopen options |
|
||||||
| Item not recorded after loot | `GetItemInfo` async — item never seen before | Wait 1–2 seconds; if still missing, the item may not be a quest item |
|
| Item not recorded after loot | `GetItemInfo` async on first encounter | Wait 1–2 seconds for `GET_ITEM_INFO_RECEIVED` |
|
||||||
|
|||||||
Reference in New Issue
Block a user