feat: add learner tooltip controls

This commit is contained in:
Xurkon
2026-06-06 13:59:31 -05:00
parent 2cb129ae4b
commit 1f3de0e02e
8 changed files with 147 additions and 4 deletions
+1
View File
@@ -5,6 +5,7 @@
### Performance
- **[Questie Debug - Message Throttle]** Added a live debug-message throttle so non-fatal debug output cannot spam chat faster than it can be read. The throttle is configurable in the Advanced tab and keeps fatal output separate.
- **[Questie Learner - Tooltip Controls]** Added learner-specific tooltip controls so players can toggle the learned spawn line, learner confidence lines, and automatic tooltip resizing from the Tooltip options. The learner tooltip paths now respect those toggles before adding extra lines.
- **[QuestieLearner - Kill/Pin Refresh Throttling]** Debounced learner-triggered map-pin refreshes so heavy kill streaks do not redraw pins on every event. Added a maximum wait cap so batched updates still flush predictably instead of being pushed out forever by constant activity.
- **[QuestieLearner - Bystander Kill Suppression]** Changed visible nearby `UNIT_DIED` handling so kills from other players can update short-lived correlation evidence without immediately running full learner injection or pin refresh work.
- **[QuestieLearner - PARTY_KILL Event-Order Fix]** Fixed an edge case where a `UNIT_DIED` debounce entry could suppress a later authoritative `PARTY_KILL` for the same GUID. The debounce now tracks event type and allows the player's/group's kill event through while still suppressing true duplicates.
@@ -481,6 +481,59 @@ function QuestieOptions.tabs.general:Initialize()
Questie.db.profile.enableTooltipsNextInChain = value
end
},
learnerTooltipHeader = {
type = "header",
order = 8.55,
name = function() return l10n('Learner Tooltips'); end,
},
learnerTooltips = {
type = "toggle",
order = 8.56,
name = function() return l10n('Enable learner tooltips'); end,
desc = function() return l10n('Show the learned spawn line and other learner-specific tooltip additions.'); end,
width = 1.5,
disabled = function() return not Questie.db.profile.enableTooltips; end,
get = function() return Questie.db.profile.learnerTooltips ~= false end,
set = function(_, value)
Questie.db.profile.learnerTooltips = value
end
},
learnerTooltipShowSpawn = {
type = "toggle",
order = 8.57,
name = function() return l10n('Show learned spawn line'); end,
desc = function() return l10n('Show the learned spawn coordinates and kill count on unit tooltips.'); end,
width = 1.5,
disabled = function() return not (Questie.db.profile.enableTooltips and (Questie.db.profile.learnerTooltips ~= false)); end,
get = function() return Questie.db.profile.learnerTooltipShowSpawn ~= false end,
set = function(_, value)
Questie.db.profile.learnerTooltipShowSpawn = value
end
},
learnerTooltipShowConfidence = {
type = "toggle",
order = 8.58,
name = function() return l10n('Show learner confidence lines'); end,
desc = function() return l10n('Show the learner confidence line attached to learned NPC and object tooltips.'); end,
width = 1.5,
disabled = function() return not (Questie.db.profile.enableTooltips and (Questie.db.profile.learnerTooltips ~= false)); end,
get = function() return Questie.db.profile.learnerTooltipShowConfidence ~= false end,
set = function(_, value)
Questie.db.profile.learnerTooltipShowConfidence = value
end
},
learnerTooltipAutoResize = {
type = "toggle",
order = 8.59,
name = function() return l10n('Auto-resize learner tooltips'); end,
desc = function() return l10n('Grow tooltip width to fit learner-added lines cleanly.'); end,
width = 1.5,
disabled = function() return not (Questie.db.profile.enableTooltips and (Questie.db.profile.learnerTooltips ~= false)); end,
get = function() return Questie.db.profile.learnerTooltipAutoResize ~= false end,
set = function(_, value)
Questie.db.profile.learnerTooltipAutoResize = value
end
},
partyOnlyToggle = {
type = "toggle",
order = 8.6,
@@ -89,6 +89,10 @@ function QuestieOptionsDefaults:Load()
enableTooltipsQuestLevel = true,
showQuestXpAtMaxLevel = true,
enableTooltipsNextInChain = true,
learnerTooltips = true,
learnerTooltipShowSpawn = true,
learnerTooltipShowConfidence = true,
learnerTooltipAutoResize = true,
learnerBroadcast = true,
enableMapIcons = true,
enableMiniMapIcons = true,
+12 -2
View File
@@ -4434,6 +4434,9 @@ local _tooltipHookRegistered = false
---@param unitToken string WoW unit token (e.g. "mouseover")
local function _AddLearnedSpawnTooltipLine(unitToken)
if not Questie or not Questie.dbLearner then return end
if not Questie.db.profile or Questie.db.profile.learnerTooltips == false or Questie.db.profile.learnerTooltipShowSpawn == false then
return
end
local guid = UnitGUID(unitToken)
if not guid then return end
@@ -4459,8 +4462,15 @@ local function _AddLearnedSpawnTooltipLine(unitToken)
local formattedX = ("%.1f"):format(x)
local formattedY = ("%.1f"):format(y)
GameTooltip:AddDoubleLine("Learned spawn", ("(%s, %s) from %d kill%s"):format(
formattedX, formattedY, kills, kills == 1 and "" or "s"))
local text = ("(%s, %s)"):format(formattedX, formattedY)
if Questie.db.profile.learnerTooltipShowConfidence ~= false then
text = text .. (" from %d kill%s"):format(kills, kills == 1 and "" or "s")
end
GameTooltip:AddDoubleLine("Learned spawn", text)
local QuestieTooltips = QuestieLoader:ImportModule("QuestieTooltips")
if QuestieTooltips and QuestieTooltips.ResizeTooltip then
QuestieTooltips:ResizeTooltip(GameTooltip)
end
end
--- Registers the GameTooltip OnTooltipSetUnit hook once.
+49 -2
View File
@@ -43,6 +43,53 @@ local _tooltipLastText = ""
local _InitObjectiveTexts
local function _LearnerTooltipsEnabled()
return not (Questie.db and Questie.db.profile) or Questie.db.profile.learnerTooltips ~= false
end
local function _ResizeTooltipToFit(tooltip)
if not tooltip or not tooltip.GetName then
return
end
local tooltipName = tooltip:GetName()
if not tooltipName then
return
end
local maxWidth = 0
for i = 1, tooltip:NumLines() do
local left = _G[tooltipName .. "TextLeft" .. i]
local right = _G[tooltipName .. "TextRight" .. i]
if left and left:GetText() then
maxWidth = math.max(maxWidth, left:GetStringWidth() or 0)
end
if right and right:GetText() then
maxWidth = math.max(maxWidth, right:GetStringWidth() or 0)
end
end
if maxWidth <= 0 then
return
end
maxWidth = maxWidth + 24
local currentWidth = tooltip.GetWidth and tooltip:GetWidth() or 0
if currentWidth < maxWidth then
if tooltip.SetMinimumWidth then
tooltip:SetMinimumWidth(maxWidth)
end
tooltip:SetWidth(maxWidth)
end
end
function QuestieTooltips:ResizeTooltip(tooltip)
if Questie.db.profile.learnerTooltipAutoResize == false then
return
end
_ResizeTooltipToFit(tooltip)
end
local function _GetQuestObjectiveSummary(questId)
if not QuestieDB or not QuestieDB.GetQuest then
return nil
@@ -307,7 +354,7 @@ if key:sub(1,2) == "m_" then
end
end
end
if learnedNpc.mc then
if learnedNpc.mc and _LearnerTooltipsEnabled() and Questie.db.profile.learnerTooltipShowConfidence ~= false then
tinsert(tooltipLines, "|cFF5EBAF3(Learned - Confidence: " .. tostring(learnedNpc.mc) .. ")|r")
end
end
@@ -360,7 +407,7 @@ elseif key:sub(1,2) == "o_" then
end
end
end
if learnedObj.mc then
if learnedObj.mc and _LearnerTooltipsEnabled() and Questie.db.profile.learnerTooltipShowConfidence ~= false then
tinsert(tooltipLines, "|cFF5EBAF3(Learned - Confidence: " .. tostring(learnedObj.mc) .. ")|r")
end
end
+9
View File
@@ -329,6 +329,9 @@ function _QuestieTooltips:AddUnitDataToTooltip()
_AddQuestStarterDropsToTooltip(npcNum)
end
if QuestieTooltips.ResizeTooltip then
QuestieTooltips:ResizeTooltip(GameTooltip)
end
QuestieTooltips.lastGametooltipCount = _QuestieTooltips:CountTooltip()
end
lastGuid = guid;
@@ -371,6 +374,9 @@ function _QuestieTooltips:AddItemDataToTooltip()
for _, v in next, tooltipData do
self:AddLine(v)
end
if QuestieTooltips.ResizeTooltip then
QuestieTooltips:ResizeTooltip(self)
end
end
QuestieTooltips.lastGametooltipCount = _QuestieTooltips:CountTooltip()
end
@@ -426,6 +432,9 @@ function _QuestieTooltips:AddObjectDataToTooltip(name)
end
end
end
if QuestieTooltips.ResizeTooltip then
QuestieTooltips:ResizeTooltip(GameTooltip)
end
GameTooltip:Show()
end
QuestieTooltips.lastGametooltipType = "object";
@@ -44,6 +44,24 @@ describe("QuestieLearner data source mode", function()
assert.is_true(has(tip, "mode ~= \"static\" and mode ~= \"none\""))
end)
it("exposes learner tooltip controls and tooltip resize support", function()
local general = read("Modules/Options/GeneralTab/QuestieOptionsGeneral.lua")
local defaults = read("Modules/Options/QuestieOptionsDefaults.lua")
local tip = read("Modules/Tooltips/Tooltip.lua")
local handler = read("Modules/Tooltips/TooltipHandler.lua")
local learner = read("Modules/QuestieLearner.lua")
assert.is_true(has(defaults, "learnerTooltips = true"))
assert.is_true(has(defaults, "learnerTooltipShowSpawn = true"))
assert.is_true(has(defaults, "learnerTooltipShowConfidence = true"))
assert.is_true(has(defaults, "learnerTooltipAutoResize = true"))
assert.is_true(has(general, "Learner Tooltips"))
assert.is_true(has(general, "Enable learner tooltips"))
assert.is_true(has(tip, "function QuestieTooltips:ResizeTooltip(tooltip)"))
assert.is_true(has(handler, "QuestieTooltips:ResizeTooltip(GameTooltip)"))
assert.is_true(has(handler, "QuestieTooltips:ResizeTooltip(self)"))
assert.is_true(has(learner, "learnerTooltipShowSpawn"))
end)
it("allows learner mode to draw pins from a single learned spawn when needed", function()
local priv = read("Modules/Quest/QuestieQuestPrivates.lua")
assert.is_true(has(priv, "local staticHasSpawns = spawns and next(spawns) ~= nil"))
+1
View File
@@ -180,6 +180,7 @@
<ul>
<li><strong>[QuestieDB &mdash; Required Source Item Guard]</strong> Fixed a fresh-load crash in <code>QuestieDB.GetQuest()</code> where quests that had <code>requiredSourceItems</code> but no <code>objectives</code> table would dereference <code>objectives[3]</code> while building <code>SpecialObjectives</code>. This was a code-side nil guard bug on our end, not a saved-variable problem, and it is now covered by a regression test.</li>
<li><strong>[Questie Debug &mdash; Message Throttle]</strong> Added a live debug-message throttle so non-fatal debug output cannot spam chat faster than it can be read. The throttle is configurable in the Advanced tab and keeps fatal output separate.</li>
<li><strong>[Questie Learner &mdash; Tooltip Controls]</strong> Added learner-specific tooltip controls so players can toggle the learned spawn line, learner confidence lines, and automatic tooltip resizing from the Tooltip options. The learner tooltip paths now respect those toggles before adding extra lines.</li>
<li><strong>[QuestieLearner &mdash; Learner Sunstrider Clustering]</strong> Relaxed the Sunstrider Isle clustering override in learner mode so the clustering/deduplication knobs can still consolidate newly learned pins there. Static/auto keeps the original Sunstrider visibility behavior, but learner mode now preserves clustering so nearby learner spawns do not render as an unbounded fan-out of separate icons.</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>