fix: merge learner overrides in learner mode

This commit is contained in:
Xurkon
2026-06-06 11:56:46 -05:00
parent 287751a071
commit c76650b70c
4 changed files with 55 additions and 10 deletions
+1 -1
View File
@@ -17,7 +17,7 @@
### Bug Fixes ### Bug Fixes
- **[QuestieLearner - Turn-In Arrow Spawn Promotion]** Allowed quest-related NPC and object spawns to keep their live learner coordinates even when the static database marks those spawn fields as protected. Quest giver and turn-in locations now have a path to reach the live override tables, so the arrow can point at learner-discovered hand-in targets without relaxing protection for unrelated world spawns. - **[QuestieLearner - Turn-In Arrow Spawn Promotion]** Allowed quest-related NPC and object spawns to keep their live learner coordinates even when the static database marks those spawn fields as protected. Learner mode now merges the learner's live override tables back into the getter path too, so quest giver and turn-in locations can point from learner-discovered hand-in targets without relaxing protection for unrelated world spawns.
- **[QuestieLearner - Quest-Only Item Learning]** Hardened item learning so plain junk loot no longer gets recorded as learner state. Only quest-relevant items are accepted now, including items that already have quest references in learned quest data. Quest-item drops still learn and still build source pins, but non-quest loot like generic trade goods and junk no longer pollutes the item learner or source cache. - **[QuestieLearner - Quest-Only Item Learning]** Hardened item learning so plain junk loot no longer gets recorded as learner state. Only quest-relevant items are accepted now, including items that already have quest references in learned quest data. Quest-item drops still learn and still build source pins, but non-quest loot like generic trade goods and junk no longer pollutes the item learner or source cache.
- **[QuestieLearner - Quest-Only Object Learning]** Hardened object learning so non-quest world objects are ignored unless they are explicitly tied to a quest flow. Quest giver, turn-in, objective, and `GAMEOBJECT_USED` promotions now mark the object as quest-relevant before it is stored, and learned object coordinates are only promoted into live object overrides when the object has quest references. This keeps source pins for real quest objects while preventing unrelated world objects from being recorded. - **[QuestieLearner - Quest-Only Object Learning]** Hardened object learning so non-quest world objects are ignored unless they are explicitly tied to a quest flow. Quest giver, turn-in, objective, and `GAMEOBJECT_USED` promotions now mark the object as quest-relevant before it is stored, and learned object coordinates are only promoted into live object overrides when the object has quest references. This keeps source pins for real quest objects while preventing unrelated world objects from being recorded.
- **[QuestieLearner - Quest Object Coordinate Promotion]** When a quest-related object is learned, the learner now preserves the actual interaction coordinates when available instead of relying only on fallback player position. Object objective mapping now reuses the recent object evidence cache so the stored spawn point matches the real interaction location and can render immediately as a map pin. - **[QuestieLearner - Quest Object Coordinate Promotion]** When a quest-related object is learned, the learner now preserves the actual interaction coordinates when available instead of relying only on fallback player position. Object objective mapping now reuses the recent object evidence cache so the stored spawn point matches the real interaction location and can render immediately as a map pin.
+16 -8
View File
@@ -664,9 +664,12 @@ function QuestieDB:GetObject(objectId)
local rawdata local rawdata
local override local override
override = QuestieDB.objectDataOverrides and (QuestieDB.objectDataOverrides[objectId] or QuestieDB.objectDataOverrides[tostring(objectId)])
if mode == "learner" or QuestieDB:IsStoreMissing("objectData") then if mode == "learner" or QuestieDB:IsStoreMissing("objectData") then
rawdata = learnerRecord rawdata = learnerRecord
override = nil if not rawdata then
rawdata = override
end
else else
rawdata = QuestieDB.QueryObject(objectId, QuestieDB._objectAdapterQueryOrder) rawdata = QuestieDB.QueryObject(objectId, QuestieDB._objectAdapterQueryOrder)
if not rawdata and learnerRecord and mode == "auto" then if not rawdata and learnerRecord and mode == "auto" then
@@ -674,7 +677,6 @@ function QuestieDB:GetObject(objectId)
-- and "none" must never silently fall back to learner records. -- and "none" must never silently fall back to learner records.
rawdata = learnerRecord rawdata = learnerRecord
end end
override = QuestieDB.objectDataOverrides and (QuestieDB.objectDataOverrides[objectId] or QuestieDB.objectDataOverrides[tostring(objectId)])
end end
if not rawdata and not override then if not rawdata and not override then
@@ -722,9 +724,12 @@ function QuestieDB:GetItem(itemId)
local learnerRecord = _GetLearnerRecord("items", itemId) local learnerRecord = _GetLearnerRecord("items", itemId)
local rawdata local rawdata
local override local override
override = QuestieDB.itemDataOverrides and (QuestieDB.itemDataOverrides[itemId] or QuestieDB.itemDataOverrides[tostring(itemId)])
if mode == "learner" or QuestieDB:IsStoreMissing("itemData") then if mode == "learner" or QuestieDB:IsStoreMissing("itemData") then
rawdata = learnerRecord rawdata = learnerRecord
override = nil if not rawdata then
rawdata = override
end
else else
rawdata = QuestieDB.QueryItem(itemId, QuestieDB._itemAdapterQueryOrder) rawdata = QuestieDB.QueryItem(itemId, QuestieDB._itemAdapterQueryOrder)
if not rawdata and learnerRecord and mode == "auto" then if not rawdata and learnerRecord and mode == "auto" then
@@ -732,7 +737,6 @@ function QuestieDB:GetItem(itemId)
-- and "none" must never silently fall back to learner records. -- and "none" must never silently fall back to learner records.
rawdata = learnerRecord rawdata = learnerRecord
end end
override = QuestieDB.itemDataOverrides and (QuestieDB.itemDataOverrides[itemId] or QuestieDB.itemDataOverrides[tostring(itemId)])
end end
if not rawdata and not override then if not rawdata and not override then
@@ -1606,9 +1610,12 @@ function QuestieDB.GetQuest(questId, ...) -- /dump QuestieDB.GetQuest(867)
local learnerRecord = _GetLearnerRecord("quests", questId) local learnerRecord = _GetLearnerRecord("quests", questId)
local rawdata local rawdata
local overrideData local overrideData
overrideData = QuestieDB.questDataOverrides and (QuestieDB.questDataOverrides[questId] or QuestieDB.questDataOverrides[tostring(questId)])
if mode == "learner" or QuestieDB:IsStoreMissing("questData") then if mode == "learner" or QuestieDB:IsStoreMissing("questData") then
rawdata = learnerRecord rawdata = learnerRecord
overrideData = nil if not rawdata then
rawdata = overrideData
end
else else
rawdata = QuestieDB.QueryQuest(questId, QuestieDB._questAdapterQueryOrder) rawdata = QuestieDB.QueryQuest(questId, QuestieDB._questAdapterQueryOrder)
if not rawdata and learnerRecord and mode == "auto" then if not rawdata and learnerRecord and mode == "auto" then
@@ -1616,7 +1623,6 @@ function QuestieDB.GetQuest(questId, ...) -- /dump QuestieDB.GetQuest(867)
-- and "none" must never silently fall back to learner records. -- and "none" must never silently fall back to learner records.
rawdata = learnerRecord rawdata = learnerRecord
end end
overrideData = QuestieDB.questDataOverrides and (QuestieDB.questDataOverrides[questId] or QuestieDB.questDataOverrides[tostring(questId)])
end end
if (not rawdata) then if (not rawdata) then
@@ -2221,9 +2227,12 @@ function QuestieDB:GetNPC(npcId)
local learnerRecord = _GetLearnerRecord("npcs", npcId) local learnerRecord = _GetLearnerRecord("npcs", npcId)
local rawdata local rawdata
local override local override
override = QuestieDB.npcDataOverrides and (QuestieDB.npcDataOverrides[npcId] or QuestieDB.npcDataOverrides[tostring(npcId)])
if mode == "learner" or QuestieDB:IsStoreMissing("npcData") then if mode == "learner" or QuestieDB:IsStoreMissing("npcData") then
rawdata = learnerRecord rawdata = learnerRecord
override = nil if not rawdata then
rawdata = override
end
else else
rawdata = QuestieDB.QueryNPC(npcId, QuestieDB._npcAdapterQueryOrder) rawdata = QuestieDB.QueryNPC(npcId, QuestieDB._npcAdapterQueryOrder)
if not rawdata and learnerRecord and mode == "auto" then if not rawdata and learnerRecord and mode == "auto" then
@@ -2231,7 +2240,6 @@ function QuestieDB:GetNPC(npcId)
-- and "none" must never silently fall back to learner records. -- and "none" must never silently fall back to learner records.
rawdata = learnerRecord rawdata = learnerRecord
end end
override = QuestieDB.npcDataOverrides and (QuestieDB.npcDataOverrides[npcId] or QuestieDB.npcDataOverrides[tostring(npcId)])
end end
if not rawdata and not override then if not rawdata and not override then
@@ -109,6 +109,43 @@ describe("QuestieLearner learner mode activation", function()
end) end)
end) end)
describe("QuestieDB learner mode merges learner overrides", function()
before_each(function()
dofile("Tests/wow_api_mock.lua")
dofile("Database/QuestieDB.lua")
dofile("Database/npcDB.lua")
Questie.dbLearner.global.settings.enabled = true
Questie.dbLearner.global.settings.dataSourceMode = "learner"
Questie.dbLearner.global.npcs = {
[7001] = {
[1] = "Learner NPC",
},
}
QuestieDB.npcDataOverrides = {
[7001] = {
[1] = "Learner NPC",
[7] = {
[44] = {
{ 12.5, 34.5 },
},
},
},
}
QuestieDB.private = QuestieDB.private or {}
QuestieDB.private.npcCache = {}
end)
it("prefers the learner override spawn table when raw learner data is incomplete", function()
local npc = QuestieDB:GetNPC(7001)
assert.is_table(npc)
assert.is_table(npc.spawns)
assert.is_table(npc.spawns[44])
assert.equals(1, table.getn(npc.spawns[44]))
assert.equals(12.5, npc.spawns[44][1][1])
assert.equals(34.5, npc.spawns[44][1][2])
end)
end)
describe("QuestieLearner quest accept resolution", function() describe("QuestieLearner quest accept resolution", function()
local QuestieLearner local QuestieLearner
local originalGetNumQuestLogEntries local originalGetNumQuestLogEntries
+1 -1
View File
@@ -178,7 +178,7 @@
<div class="container"> <div class="container">
<h2 id="unreleased-performance-refactor">[Unreleased] &mdash; Performance Refactor Branches</h2> <h2 id="unreleased-performance-refactor">[Unreleased] &mdash; Performance Refactor Branches</h2>
<ul> <ul>
<li><strong>[QuestieLearner &mdash; Turn-In Arrow Spawn Promotion]</strong> Allowed quest-related NPC and object spawns to keep their live learner coordinates even when the static database marks those spawn fields as protected. Quest giver and turn-in locations now have a path to reach the live override tables, so the arrow can point at learner-discovered hand-in targets without relaxing protection for unrelated world spawns.</li> <li><strong>[QuestieLearner &mdash; Turn-In Arrow Spawn Promotion]</strong> Allowed quest-related NPC and object spawns to keep their live learner coordinates even when the static database marks those spawn fields as protected. Learner mode now merges the learner's live override tables back into the getter path too, so quest giver and turn-in locations can point from learner-discovered hand-in targets without relaxing protection for unrelated world spawns.</li>
<li><strong>[QuestieLearner &mdash; Quest-Only Item Learning]</strong> Hardened item learning so plain junk loot no longer gets recorded as learner state. Only quest-relevant items are accepted now, including items that already have quest references in learned quest data. Quest-item drops still learn and still build source pins, but non-quest loot like generic trade goods and junk no longer pollutes the item learner or source cache.</li> <li><strong>[QuestieLearner &mdash; Quest-Only Item Learning]</strong> Hardened item learning so plain junk loot no longer gets recorded as learner state. Only quest-relevant items are accepted now, including items that already have quest references in learned quest data. Quest-item drops still learn and still build source pins, but non-quest loot like generic trade goods and junk no longer pollutes the item learner or source cache.</li>
<li><strong>[QuestieLearner &mdash; Quest-Only Object Learning]</strong> Hardened object learning so non-quest world objects are ignored unless they are explicitly tied to a quest flow. Quest giver, turn-in, objective, and <code>GAMEOBJECT_USED</code> promotions now mark the object as quest-relevant before it is stored, and learned object coordinates are only promoted into live object overrides when the object has quest references. This keeps source pins for real quest objects while preventing unrelated world objects from being recorded.</li> <li><strong>[QuestieLearner &mdash; Quest-Only Object Learning]</strong> Hardened object learning so non-quest world objects are ignored unless they are explicitly tied to a quest flow. Quest giver, turn-in, objective, and <code>GAMEOBJECT_USED</code> promotions now mark the object as quest-relevant before it is stored, and learned object coordinates are only promoted into live object overrides when the object has quest references. This keeps source pins for real quest objects while preventing unrelated world objects from being recorded.</li>
<li><strong>[QuestieLearner &mdash; Quest Object Coordinate Promotion]</strong> When a quest-related object is learned, the learner now preserves the actual interaction coordinates when available instead of relying only on fallback player position. Object objective mapping now reuses the recent object evidence cache so the stored spawn point matches the real interaction location and can render immediately as a map pin.</li> <li><strong>[QuestieLearner &mdash; Quest Object Coordinate Promotion]</strong> When a quest-related object is learned, the learner now preserves the actual interaction coordinates when available instead of relying only on fallback player position. Object objective mapping now reuses the recent object evidence cache so the stored spawn point matches the real interaction location and can render immediately as a map pin.</li>