From 7956463927526634c7367fb6f9cc01972ecb4419 Mon Sep 17 00:00:00 2001 From: Brues <5278969+brues-code@users.noreply.github.com> Date: Thu, 4 Jun 2026 02:10:03 -0500 Subject: [PATCH] questitem: use C_QuestLog.GetQuestDetails Replaces the SelectQuestLogEntry-based scrape (1..50 quest indices, save/ restore log selection, per-quest GetQuestLogQuestText + GetNumQuestLeaderBoards + GetQuestLogLeaderBoard, string-blob with _obj_req_ markers, substring-by- name match in AddTooltip) with a single C_QuestLog.GetQuestIDForLogIndex + C_QuestLog.GetQuestDetails round-trip per quest. Build an itemID-keyed { index, count } map up front and look up directly in AddTooltip. Fixes false matches where an item name happens to substring- match unrelated quest text. --- modules/questitem.lua | 116 ++++++++++++------------------------------ 1 file changed, 33 insertions(+), 83 deletions(-) diff --git a/modules/questitem.lua b/modules/questitem.lua index e72a3613..874ce0a4 100644 --- a/modules/questitem.lua +++ b/modules/questitem.lua @@ -1,15 +1,13 @@ pfUI:RegisterModule("questitem", function () - local questlog = {} - local itemcache = {} + -- [itemID] = { index = questLogIndex, count = requiredCount }. Rebuilt + -- on QUEST_LOG_UPDATE from ClassicAPI's per-quest cached requirements. + local requiredItems = {} - local function AddTooltip(frame, item, itemID) - -- abort when no item was given - if not item then return end - - -- abort if questitem is disabled + local function AddTooltip(frame, itemID) + if not itemID then return end if C.tooltip.questitem.showquest ~= "1" then return end - -- check if we can replace the questitem string + -- Replace the existing "Quest Item" line if the tooltip already has one. local replace = nil if frame and _G[frame:GetName().."TextLeft2"] then if _G[frame:GetName().."TextLeft2"]:GetText() == ITEM_BIND_QUEST then @@ -17,49 +15,20 @@ pfUI:RegisterModule("questitem", function () end end - -- set fallbacks for unidentified quests + local entry = requiredItems[itemID] + if not entry and not replace then return end + local quest, level = UNKNOWN, 255 - - -- check cache for already existing values - if itemcache[item] and itemcache[item] == false then - -- not a quest item - return - elseif itemcache[item] then - -- read from caches - quest, level = GetQuestLogTitle(itemcache[item]) - elseif item then - -- scan for quests - for id, text in pairs(questlog) do - if string.find(string.lower((text or "")), string.lower(item), 1) then - quest, level = GetQuestLogTitle(id) - itemcache[item] = id - break - end - end - end - - -- mark non quest items - if not itemcache[item] and not replace then - itemcache[item] = false - return - end - - -- return on invalid/empty quest results + if entry then quest, level = GetQuestLogTitle(entry.index) end if not quest then return end - -- read difficulty color local color = GetDifficultyColor(level) - -- read item counts - if C.tooltip.questitem.showcount == "1" and itemcache[item] and itemcache[item] ~= false then - local _, _, required = strfind(string.lower(questlog[itemcache[item]]), "_"..string.lower(item).."_(.-)_") - if required then - local have = itemID and C_Item.GetItemCount(itemID) or 0 - quest = string.format("%s |cffaaaaaa[%s/%s]", quest, have, required) - end + if C.tooltip.questitem.showcount == "1" and entry and entry.count and entry.count > 0 then + local have = C_Item.GetItemCount(itemID) or 0 + quest = string.format("%s |cffaaaaaa[%s/%s]", quest, have, entry.count) end - -- add quest to quest item if replace then _G[frame:GetName().."TextLeft2"]:SetText("|cffffffff"..ITEM_BIND_QUEST..": |r" .. quest) _G[frame:GetName().."TextLeft2"]:SetTextColor(color.r, color.g, color.b) @@ -70,59 +39,40 @@ pfUI:RegisterModule("questitem", function () frame:Show() end - -- initialize questlog scanner pfUI.questitem = CreateFrame("Frame", "pfQuestItemScanner", UIParent) pfUI.questitem:RegisterEvent("PLAYER_ENTERING_WORLD") pfUI.questitem:RegisterEvent("QUEST_LOG_UPDATE") pfUI.questitem:SetScript("OnEvent", function() - -- queue update events to run in .5 seconds + -- debounce rebuilds — QUEST_LOG_UPDATE fires in bursts this.run = GetTime() + .5 end) pfUI.questitem:SetScript("OnUpdate", function() if C.tooltip.questitem.showquest ~= "1" then return end - - -- skip if nothing to do if not this.run or GetTime() < this.run then return end - -- clear item caches - for name, quest in pairs(itemcache) do - itemcache[name] = nil - end + for k in pairs(requiredItems) do requiredItems[k] = nil end - -- reload quests - local text, objective, objcount, objtext, header, _ - local logid = GetQuestLogSelection() - for quest=1, 50 do - SelectQuestLogEntry(quest) - - -- detect and ignore quest headers - _, _, _, header = GetQuestLogTitle(quest) - - if not header then - text, objective = GetQuestLogQuestText() - objcount = GetNumQuestLeaderBoards() - questlog[quest] = string.format("%s:%s", (text or ""), (objective or "")) - - -- scan objectives - if objcount > 0 then - for i=1, objcount do - objtext = GetQuestLogLeaderBoard(i) - local _, _, obj, cur, req = strfind((objtext or ""), "(.*):%s*([%d]+)%s*/%s*([%d]+)") - if obj and req then - questlog[quest] = string.format("%s:_%s_%s_", questlog[quest], obj, req) - else - questlog[quest] = string.format("%s:%s", questlog[quest], (objtext or "")) + -- GetQuestIDForLogIndex returns nil past the end, 0 for headers, else + -- the questID. GetQuestDetails reads the engine's static-info cache — + -- nil if not yet populated; we'll catch it on the next refresh. + local i = 1 + while true do + local questID = C_QuestLog.GetQuestIDForLogIndex(i) + if questID == nil then break end + if questID > 0 then + local details = C_QuestLog.GetQuestDetails(questID) + if details and details.requirements then + for _, req in ipairs(details.requirements) do + if req.kind == "item" and req.id and req.id > 0 then + requiredItems[req.id] = { index = i, count = req.count } end end end - else - questlog[quest] = nil end + i = i + 1 end - -- restore questlog selection - SelectQuestLogEntry(logid) this.run = nil end) @@ -137,8 +87,8 @@ pfUI:RegisterModule("questitem", function () pfUI.questitem.tooltip = CreateFrame("Frame", "pfQuestItems", GameTooltip) pfUI.questitem.tooltip:SetScript("OnShow", function() if GameTooltip:HasItem() then - local name, _, id = GameTooltip:GetItem() - if name and id then AddTooltip(GameTooltip, name, id) end + local _, _, id = GameTooltip:GetItem() + if id then AddTooltip(GameTooltip, id) end end end) @@ -148,8 +98,8 @@ pfUI:RegisterModule("questitem", function () hooksecurefunc("SetItemRef", function() if IsModifierKeyDown() then return end if ItemRefTooltip:HasItem() then - local name, _, id = ItemRefTooltip:GetItem() - if name and id then AddTooltip(ItemRefTooltip, name, id) end + local _, _, id = ItemRefTooltip:GetItem() + if id then AddTooltip(ItemRefTooltip, id) end end end) end)