diff ObjectiveTracker/Quests.lua @ 37:e84d645c8ab8

- revised the tracker update function to build its complete data list up front and use the values as points of comparison for determining possible out of place blocks, which will be iterated over afterward to remove what wasn't re-used - also entailed revising the exact role of global event handlers and function hooks, limiting their directions of communication so one doesn't end up calling the other multiple or inifinity times - schema handling polish
author Nenue
date Mon, 18 Apr 2016 07:56:23 -0400
parents 69d03f8e293e
children 1f8f9cc3d956
line wrap: on
line diff
--- a/ObjectiveTracker/Quests.lua	Sun Apr 17 13:00:31 2016 -0400
+++ b/ObjectiveTracker/Quests.lua	Mon Apr 18 07:56:23 2016 -0400
@@ -9,12 +9,10 @@
 local QUEST_TAG_ACCOUNT, LE_QUEST_FACTION_HORDE, LE_QUEST_FREQUENCY_DAILY, LE_QUEST_FREQUENCY_WEEKLY = QUEST_TAG_ACCOUNT, LE_QUEST_FACTION_HORDE, LE_QUEST_FREQUENCY_DAILY, LE_QUEST_FREQUENCY_WEEKLY
 local QUEST_TAG_TCOORDS, IsQuestSequenced = QUEST_TAG_TCOORDS, IsQuestSequenced
 local Default, Quest = T.DefaultHandler, T.Quest
-local format = format
-local print = B.print('Tracker')
-local lprint = B.print('Line')
-local iprint = B.print('Info')
-local colors = T.colors
-local tprint = B.print('Tracker')
+local format, wipe, select = format, table.wipe, select
+local wipeall = B.wipeall
+local lprint, iprint, tprint = B.print('Line'), B.print('Info'), B.print('Tracker')
+local print = tprint
 
 local superTrackQuestID, playerMoney, inScenario, showPOIs
 Quest.Update = function(self, reason, ...)
@@ -79,39 +77,166 @@
 
 -----------------------------
 --- QUEST
+local tremove, tinsert = tremove, tinsert
+local GetQuestLogIndexByID, IsQuestWatched = GetQuestLogIndexByID, IsQuestWatched
 Quest.QuestBlock = {}
 Quest.LogBlock = {}
 Quest.LogInfo = {}
+function Quest:FreeBlock (block)
+  local used = Quest.usedBlocks
+  local free = Quest.freeBlocks
+  local reason = ''
+  local doRelease = false
+  local info = block.info
+  local questID = info.questID
+  local logIndex = info.logIndex
 
-function Quest:GetNumWatched ()
+  if info.posIndex then
+    if used[info.posIndex] == block then
+      doRelease = true
+      reason = 'posIndex mismatch'
+    end
+  elseif logIndex then
+    if not IsQuestWatched(logIndex) then
+      reason = 'not being watched'
+    elseif not self.LogBlock[logIndex] then
+      doRelease = true
+      reason = 'missing logBlock entry'
+    elseif (self.LogBlock[logIndex] ~= block) then
+      doRelease = true
+      reason = 'different block using index'
+    end
+  elseif info.questID then
+    if not GetQuestLogIndexByID(info.questID) then
+      doRelease = true
+      reason = 'no identifiable quest log entry'
+    end
+  end
+
+
+  if doRelease then
+    print('  |cFF00FF00FreeBlock (' .. block:GetName() .. '):', reason)
+    block:Hide()
+    tremove(used, info.posIndex)
+    tinsert(free, block)
+  end
+
+
+end
+local watchesChecked = {}
+local infosChecked = {}
+local blocksChecked = {}
+local GetQuestWatchIndex = GetQuestWatchIndex
+--- Get a total of things to show, and straighten out the index while we're at it
+--- Return the number shown, total in log, and the info table to parse
+Quest.GetNumWatched = function (self, id, added)
   superTrackQuestID = GetSuperTrackedQuestID()
   playerMoney = GetMoney();
   inScenario = C_Scenario.IsInScenario();
   showPOIs = GetCVarBool("questPOI");
-  self.numAll = GetNumQuestLogEntries()
-  self.numWatched = GetNumQuestWatches()
-  return self.numWatched, self.numAll
+  local numAll = GetNumQuestLogEntries()
+  local numWatched = GetNumQuestWatches()
+  local bottomIndex = 1
+  print('    |cFF00FF88GetNumWatched:|r',self.name, numWatched, 'of', numAll)
+  local start, limit = 1, numAll
+
+  --- start a list of blocks affected by this function
+  wipe(blocksChecked)
+  if id and not added then
+    if self.InfoBlock[id] then
+      tinsert(blocksChecked, self.InfoBlock[id])
+    end
+  end
+
+  for logIndex = start, limit do
+    local reason1, reason2 = '', ''
+    local title, level, suggestedGroup, isHeader, isCollapsed, isComplete, frequency, questID, startEvent, displayQuestID, isOnMap, hasLocalPOI, isTask, isStory = GetQuestLogTitle(logIndex)
+    local watchIndex = GetQuestWatchIndex(logIndex)
+
+    if watchIndex and watchIndex >= bottomIndex then
+      local watchInfo = self.WatchInfo[watchIndex]
+      local watchBlock = self.WatchBlock[watchIndex]
+      if watchInfo and watchInfo.questID ~= questID then
+        print('    |cFFBBFF00GetNumWatched: trimming WatchInfo ['..watchIndex..'] =/=', questID)
+        self.WatchInfo[watchIndex] = nil
+      end
+      if watchBlock and watchBlock.info.questID ~= questID then
+        print('    |cFFBBFF00GetNumWatched: trimming WatchBlock ['..watchIndex..'] =/=', watchBlock:GetName())
+        self.WatchBlock[watchIndex] = nil
+        tinsert(blocksChecked, watchBlock)
+      end
+    end
+
+    local logBlock = self.LogBlock[logIndex]
+    if logBlock and logBlock.info.questID ~= questID then
+      --print('    |cFFBBFF00GetNumWatched: trimming LogBlock ['..logIndex..'] =/=', logBlock:GetName())
+      self.LogBlock[logIndex] = nil
+      tinsert(blocksChecked, logBlock)
+    end
+
+    if questID ~= 0 then
+      self.Info[questID] = self:GetInfo(logIndex, watchIndex)
+      --print('    |cFF44BBFFGetNumWatched:|r map', questID, 'to', logIndex, (watchIndex and ('('..watchIndex..')') or ''))
+    end
+  end
+
+  --- remove any orphaned blocks from view and, if possible, free it for re-use
+  for i, block in ipairs(blocksChecked) do
+    if not GetQuestLogIndexByID(block.info.questID, 'player') then
+      print('    |cFFBBFF00GetNumWatched:|r literating a block without an index |cFFBBFF00'.. block:GetName()..'|r')
+      block:Hide()
+      self:FreeBlock(block)
+    end
+    if not IsQuestWatched(block.info.logIndex) then
+      print('    |cFFBBFF00GetNumWatched:|r hiding untracked quest |cFFBBFF00'.. block:GetName()..'|r')
+      block:Hide()
+    end
+  end
+
+  self.numWatched = numWatched
+  self.numAll = numAll
+
+  return numWatched, numAll, self.WatchList
 end
 
+
 --- Returns an iterable table from which tracker blocks can be filled out. Data includes:
 -- All entry-layer GetXInfo return values
 -- Manifest of line data to be displayed in relation to the tracked object
-Quest.GetInfo = function (self, watchIndex)
+Quest.GetInfo = function (self, logIndex, watchIndex)
   local print = iprint
-
-  local questID, title, questLogIndex, numObjectives, requiredMoney, isComplete, startEvent, isAutoComplete,
-    failureTime, timeElapsed, questType, isTask, isStory, isOnMap, hasLocalPOI = GetQuestWatchInfo(watchIndex)
+  local title, level, suggestedGroup, isHeader, isCollapsed, isComplete, frequency, questID, startEvent, displayQuestID, isOnMap, hasLocalPOI, isTask, isStory = GetQuestLogTitle(logIndex)
   if ( not questID ) then
+    tprint('      |cFFFF0088GetInfo:|r', logIndex, watchIndex, '|cFFFF2299no data|r')
     return
   end
 
-  tprint('      |cFFFFBB00GetInfo:|r', watchIndex, '|cFFFF2299'..title..'|r')
-  local _, level, suggestedGroup, isHeader, isCollapsed, isComplete, frequency, _, startEvent, displayQuestID, isOnMap, hasLocalPOI, isTask, isStory = GetQuestLogTitle(questLogIndex)
+  Quest.Info[questID] = Quest.Info[questID] or {}
+  local q = Quest.Info[questID]
+  q.questID = questID
+  q.id = questID
+  q.logIndex = logIndex
+  q.watchIndex = watchIndex
 
-  Quest.Info[questID] = Quest.Info[questID] or {}
+  local numObjectives, requiredMoney, isAutoComplete, failureTime, timeElapsed, questType
+   = 0, 0, nil, false, false, 0
+  if watchIndex then
+    local _
+    _,_,_, numObjectives, requiredMoney, _, _, isAutoComplete,
+    failureTime, timeElapsed, questType = GetQuestWatchInfo(watchIndex)
+    self.WatchList[watchIndex] = q
+    --tprint('      |cFF88FF00GetInfo:|r set watch entry', watchIndex)
+    tprint('      |cFFFFBB00GetInfo:|r', logIndex, watchIndex, '|cFFFF2299'..title..'|r')
+  end
+  self.LogInfo[logIndex] = q
 
+  q.numObjectives = numObjectives
+  q.requiredMoney = requiredMoney
+  q.failureTime = failureTime
+  q.timeElapsed = timeElapsed
 
-  local q = Quest.Info[questID]
+
+
   q.type = 'Quest'
   q.title = title
   q.level = level
@@ -174,7 +299,7 @@
     -- Case 3: quest in progress
     -- * Multiple objective lines
     -- * Possible extra lines for money and timer data respectively
-    objectives = Quest.GetObjectives(questLogIndex, numObjectives, false, isSequenced, isStory)
+    objectives = Quest.GetObjectives(logIndex, numObjectives, false, isSequenced, isStory)
     q.objectives = objectives
 
     --- anything past here gets appended to existing objectives
@@ -208,13 +333,9 @@
       end
     end
   end
-  q.numObjectives = numObjectives
   q.objectives = objectives
-  q.requiredMoney = requiredMoney
   q.moneyInfo = moneyInfo
   q.timerInfo = timerInfo
-  q.failureTime = failureTime
-  q.timeElapsed = timeElapsed
   q.completionText = completionText
 
   -- POI data
@@ -222,7 +343,8 @@
   if ( showPOIs ) then
     POI = {
       questID = questID,
-      questLogIndex = questLogIndex,
+      logIndex = logIndex,
+      watchIndex = watchIndex
     }
     local poiButton;
     if ( hasLocalPOI ) then
@@ -236,7 +358,7 @@
       POI.type = 'remote'
     end
 
-    local distance, onContinent = GetDistanceSqToQuest(questLogIndex)
+    local distance, onContinent = GetDistanceSqToQuest(logIndex)
     if distance ~= nil and distance > 0 then
       POI.distance = distance
       POI.onContinent = onContinent
@@ -248,6 +370,7 @@
   -- completionTag  - in progres, complete, failed, autocomplete
   -- typeTag        - account, faction, pvp, dungeon, group
   -- frequencyTag   - daily/weekly
+  local schema = 'default'
   local questTagID, tagName = GetQuestTagInfo(questID)
   local tagInfo = {}
   local tagCoords = {}
@@ -255,8 +378,10 @@
   if( questTagID and questTagID == QUEST_TAG_ACCOUNT ) then
     if( factionGroup ) then
       tagID = "ALLIANCE"
+      schema = 'alliance'
       if ( factionGroup == LE_QUEST_FACTION_HORDE ) then
         tagID = "HORDE"
+        schema = 'horde'
       end
       isFaction = true
     else
@@ -280,11 +405,13 @@
     tagInfo['frequencyTag'] = tagID
     tagCoords['frequencyTag'] = QUEST_TAG_TCOORDS[tagID]
     isDaily = true
+    schema = 'daily'
   elseif( frequency == LE_QUEST_FREQUENCY_WEEKLY and (not isComplete or isComplete == 0) )then
     tagID = 'WEEKLY'
     tagInfo['frequencyTag'] = tagID
     tagCoords['frequencyTag'] = QUEST_TAG_TCOORDS[tagID]
     isWeekly = true
+    schema = 'weekly'
   elseif( questTagID ) then
     tagID = questTagID
   end
@@ -303,12 +430,12 @@
   q.tagName = tagName
 
   -- action button information
-  local link, icon, charges = GetQuestLogSpecialItemInfo(questLogIndex)
-  local start, duration, enable = GetQuestLogSpecialItemCooldown(questLogIndex)
+  local link, icon, charges = GetQuestLogSpecialItemInfo(logIndex)
+  local start, duration, enable = GetQuestLogSpecialItemCooldown(logIndex)
   if link or icon or charges then
     q.specialItem = {
       questID = questID,
-      questLogIndex = questLogIndex,
+      logIndex = questLogIndex,
       link = link,
       charges = charges,
       icon = icon,
@@ -341,14 +468,13 @@
   T.SetRewards(q, questID)
 
   q.questID = questID
-  q.logIndex = questLogIndex
+  q.logIndex = logIndex
   q.watchIndex = watchIndex
   q.id = questID
-  self.WatchInfo[watchIndex] = q
-  self.LogInfo[questLogIndex] = q
+  q.schema = schema
 
   if Devian and Devian.InWorkspace() then
-    print('|cFF00DDFFstatus:|r', temp_status, '|cFF00FF00questLogIndex|r:', questLogIndex, title)
+    print('|cFF00DDFFstatus:|r', temp_status, '|cFF00FF00questLogIndex|r:', logIndex, title)
     local temp  ={}
     local data_txt = '|cFFFF4400values:|r'
     for k,v in pairs(q) do
@@ -371,10 +497,10 @@
   return q
 end
 
-Quest.GetObjectives = function(questLogIndex, numObjectives, isComplete, isSequenced, isStory)
+Quest.GetObjectives = function(logIndex, numObjectives, isComplete, isSequenced, isStory)
   local objectives = {}
   for i = 1, numObjectives do
-    local text, type, finished = GetQuestLogLeaderBoard(i, questLogIndex)
+    local text, type, finished = GetQuestLogLeaderBoard(i, logIndex)
     print(format('      |cFFFF4400GetObjectives:|r #%d %s %s %s', i, tostring(type), tostring(text), tostring(finished)))
     objectives[i] = {
       index = i,