From fc4dbc4fb39a5703a10edf42e9285ec1627ccc77 Mon Sep 17 00:00:00 2001 From: Relationship <571+relationship@noreply.octowow.st> Date: Thu, 23 Jul 2026 12:29:47 +0000 Subject: [PATCH] Upload files to "/" --- Core.lua | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 91 insertions(+), 5 deletions(-) diff --git a/Core.lua b/Core.lua index ea0794f..cf32bea 100644 --- a/Core.lua +++ b/Core.lua @@ -6,7 +6,7 @@ RelationshipsAttune = RelationshipsAttune or {} local RA = RelationshipsAttune local L = RelationshipsAttune_L -RA.VERSION = "1.4.3" +RA.VERSION = "1.4.4" RA.COMM_PREFIX = "RATTUNE" RA.playerName = nil @@ -183,6 +183,75 @@ function RA:ScanQuestLog() end end +-- --------------------------------------------------------------- +-- Completed-quest scan (server-side completed quest cache). +-- +-- Turtle WoW / OctoWoW backport QueryQuestsCompleted() + +-- GetQuestsCompleted(t), which return every quest the character has +-- ever turned in -- including quests completed BEFORE the addon was +-- installed. Without this, the addon can only see quests that are +-- currently in the log (or that were "complete" in a previous scan +-- and then vanished), so a player who is already half-way through a +-- chain shows no progress until they accept the next quest. +-- +-- We pcall everything so stock 1.12 clients that don't expose these +-- APIs simply skip the scan and keep the existing behaviour. +-- --------------------------------------------------------------- +function RA:ScanCompletedQuests() + -- Build the set of quest ids we actually care about so we don't + -- pollute the DB with thousands of unrelated turn-ins. + if not RelationshipsAttune_Data then return end + local wanted = {} + for i = 1, table.getn(RelationshipsAttune_Data) do + local att = RelationshipsAttune_Data[i] + if att and att.steps then + for j = 1, table.getn(att.steps) do + local s = att.steps[j] + if s and s.type == "quest" and s.id then + wanted[s.id] = true + end + end + end + end + + local completed = {} + local haveAny = false + + -- Preferred: bulk table fill. + if type(GetQuestsCompleted) == "function" then + local ok = pcall(GetQuestsCompleted, completed) + if ok then + for _ in pairs(completed) do haveAny = true break end + end + end + + -- Fallback: per-id check (Turtle exposes IsQuestCompleted on some builds). + if not haveAny and type(IsQuestCompleted) == "function" then + for qid in pairs(wanted) do + local ok, res = pcall(IsQuestCompleted, qid) + if ok and res then + completed[qid] = true + haveAny = true + end + end + end + + if not haveAny then + -- Kick the server to populate the cache; the QUEST_QUERY_COMPLETE + -- event handler will re-run this scan when the reply arrives. + if type(QueryQuestsCompleted) == "function" then + pcall(QueryQuestsCompleted) + end + return + end + + for qid in pairs(wanted) do + if completed[qid] and RelationshipsAttuneCharDB.quests[qid] ~= "turnedin" then + RelationshipsAttuneCharDB.quests[qid] = "turnedin" + end + end +end + function RA:MarkQuestTurnedIn(questId) if not questId then return end @@ -610,6 +679,7 @@ function RA:MarkDirty() RA._dirty = true end -- Full periodic rescan (quest log + bags + recompute + UI refresh). function RA:AutoScan() RA:ScanQuestLog() + RA:ScanCompletedQuests() RA:ScanBags() RA:RecomputeAll() if RA.UI and RA.UI.Refresh then RA.UI:Refresh() end @@ -651,6 +721,7 @@ function RA:_OnUpdate(elapsed) end if fired then RA:WarmItemCache() + RA:ScanCompletedQuests() RA:ScanBags() RA:RecomputeAll() if RA.UI and RA.UI.Refresh then RA.UI:Refresh() end @@ -740,13 +811,13 @@ local function slashHandler(msg) if RA.Comm then RA.Comm:RequestSync() end print(L.MSG_SYNC_SENT) elseif msg == "scan" then - RA:ScanQuestLog(); RA:ScanBags(); RA:RecomputeAll() + RA:ScanQuestLog(); RA:ScanCompletedQuests(); RA:ScanBags(); RA:RecomputeAll() if RA.UI and RA.UI.Refresh then RA.UI:Refresh() end print(L.MSG_SCANNED) elseif msg == "reset" then RelationshipsAttuneCharDB = nil RA:InitDB() - RA:ScanQuestLog(); RA:ScanBags(); RA:RecomputeAll() + RA:ScanQuestLog(); RA:ScanCompletedQuests(); RA:ScanBags(); RA:RecomputeAll() if RA.UI and RA.UI.Refresh then RA.UI:Refresh() end print(L.MSG_RESET) elseif msg == "debug" or string.find(msg, "^find") then @@ -822,6 +893,7 @@ pcall(function() ef:RegisterEvent("ITEM_PUSH") end) pcall(function() ef:RegisterEvent("PLAYER_XP_UPDATE") end) pcall(function() ef:RegisterEvent("ZONE_CHANGED_NEW_AREA") end) pcall(function() ef:RegisterEvent("SKILL_LINES_CHANGED") end) +pcall(function() ef:RegisterEvent("QUEST_QUERY_COMPLETE") end) ef:SetScript("OnEvent", function() local e = event @@ -833,8 +905,15 @@ ef:SetScript("OnEvent", function() RA.playerFaction = UnitFactionGroup("player") or "Neutral" RA:BuildNameIndex() RA:WarmItemCache() - RA:ScanQuestLog(); RA:ScanBags(); RA:RecomputeAll() - RA._retryAt = { GetTime() + 3, GetTime() + 10 } + -- ScanCompletedQuests seeds the "already turned-in" state from the + -- server's completed-quest cache so mid-chain attunements show the + -- player's actual current step immediately at load, instead of + -- waiting until the next quest in the chain is accepted. + RA:ScanQuestLog(); RA:ScanCompletedQuests(); RA:ScanBags(); RA:RecomputeAll() + -- The completed-quest cache is often empty on first login until + -- QueryQuestsCompleted() round-trips to the server. Schedule extra + -- rescans so the UI catches up as soon as the cache is populated. + RA._retryAt = { GetTime() + 2, GetTime() + 5, GetTime() + 10 } if RA.Comm and RA.Comm.Init then RA.Comm:Init() end if RA.UI and RA.UI.Init then RA.UI:Init() end if RA.Minimap and RA.Minimap.Init then RA.Minimap:Init() end @@ -863,6 +942,13 @@ ef:SetScript("OnEvent", function() elseif e == "QUEST_TURNED_IN" then if arg1 then RA:MarkQuestTurnedIn(arg1) end + elseif e == "QUEST_QUERY_COMPLETE" then + if RA.initialized then + RA:ScanCompletedQuests() + RA:RecomputeAll() + if RA.UI and RA.UI.Refresh then RA.UI:Refresh() end + end + elseif e == "CHAT_MSG_ADDON" then if arg1 == RA.COMM_PREFIX and RA.Comm and RA.Comm.OnMessage then RA.Comm:OnMessage(arg2, arg3, arg4)