diff WorldMap.lua @ 109:caa482329919

POI optimization
author Nenue
date Mon, 10 Jul 2017 18:34:11 -0400
parents WorldQuests.lua@b67ba1078824
children f6ef9a9f5476
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WorldMap.lua	Mon Jul 10 18:34:11 2017 -0400
@@ -0,0 +1,660 @@
+-- WorldPlan
+-- WorldMap.lua
+-- Created: 11/2/2016 3:40 PM
+-- %file-revision%
+
+local print = DEVIAN_WORKSPACE and function(...) _G.print('WorldQuests', ...) end or nop
+local rprint = DEVIAN_WORKSPACE and function(...) _G.print('WQRefresh', ...) end or nop
+local qprint = DEVIAN_WORKSPACE and function(...) _G.print('POI', ...) end or nop
+local wprint = DEVIAN_WORKSPACE and function(...) _G.print('WP', ...) end or nop
+local mprint = DEVIAN_WORKSPACE and function(...) _G.print('Canvas', ...) end or nop
+local _, db = ...
+local Module = {
+  UsedPositions = {},
+}
+WorldPlanMapMixin = Module
+
+local _G = _G
+local type, tostring, tonumber, pairs, ipairs = type, tostring, tonumber, pairs, ipairs
+local MC_GetNumZones, MC_GetZoneInfo = C_MapCanvas.GetNumZones, C_MapCanvas.GetZoneInfo
+local TQ_GetQuestsForPlayerByMapID = C_TaskQuest.GetQuestsForPlayerByMapID -- This function is not yet documented
+local TQ_GetQuestZoneID = C_TaskQuest.GetQuestZoneID
+local TQ_IsActive = C_TaskQuest.IsActive
+local TQ_RequestPreloadRewardData = C_TaskQuest.RequestPreloadRewardData
+local pairs, ipairs, tinsert, tremove, wipe = pairs, ipairs, tinsert, tremove, table.wipe
+local GetTaskInfo, GetTasksTable, HaveQuestData = GetTaskInfo, GetTasksTable, HaveQuestData
+local GetTime = GetTime
+local SpellCanTargetQuest, IsQuestIDValidSpellTarget = SpellCanTargetQuest, IsQuestIDValidSpellTarget
+local tonumber, abs = tonumber, math.abs
+local GetQuestLogRewardInfo = GetQuestLogRewardInfo
+local GetCurrentMapAreaID, GetMapInfo, GetMapNameByID = GetCurrentMapAreaID, GetMapInfo, GetMapNameByID
+local GetQuestBountyInfoForMapID, GetQuestLogTitle, GetQuestLogIndexByID, IsQuestComplete = GetQuestBountyInfoForMapID, GetQuestLogTitle, GetQuestLogIndexByID, IsQuestComplete
+local HaveQuestRewardData = HaveQuestRewardData
+local TQ_GetQuestLocation = C_TaskQuest.GetQuestLocation
+local InCombatLockdown, hooksecurefunc = InCombatLockdown, hooksecurefunc
+
+local ToggleButton = {}
+local BROKEN_ISLES_ID, DALARAN_ID, AZSUNA_ID, VALSHARAH_ID, HIGHMOUNTAIN_ID, STORMHEIM_ID, SURAMAR_ID, EOA_ID = 1007, 1014, 1015,1018, 1024, 1017, 1033, 1096
+local WORLD_QUEST_MAPS = { [DALARAN_ID] = 'Dalaran70',  [AZSUNA_ID] = 'Azsuna',  [VALSHARAH_ID] = "Val'sharah",
+  [HIGHMOUNTAIN_ID] = 'Highmountain', [STORMHEIM_ID] = 'Stormheim',  [SURAMAR_ID] = 'Suramar',  [EOA_ID] = 'EyeOfAszhara', }
+
+local REWARD_CASH = WORLD_QUEST_REWARD_TYPE_FLAG_GOLD
+local REWARD_ARTIFACT_POWER = WORLD_QUEST_REWARD_TYPE_FLAG_ARTIFACT_POWER
+local REWARD_GEAR = WORLD_QUEST_REWARD_TYPE_FLAG_EQUIPMENT
+local REWARD_CURRENCY = WORLD_QUEST_REWARD_TYPE_FLAG_ORDER_RESOURCES
+local REWARD_REAGENT = WORLD_QUEST_REWARD_TYPE_FLAG_MATERIALS
+local SCALE_FACTORS = { 0.25, 0.7, 1 }
+
+local BountyBoard = WorldMapFrame.UIElementsFrame.BountyBoard
+local ActionButton = WorldMapFrame.UIElementsFrame.ActionButton
+local defaults = {}
+local completedQuests = {}
+
+local continentScanned
+local layoutDirty = true
+local bountiesDirty = true
+local artifactPowerDirty = true
+local hooksDirty = true
+local currentScale = WorldMapDetailFrame:GetScale()
+local canTargetQuests
+local isDataLoaded = true
+local artifactKnowledgeLevel
+local superTrackedQuestID
+local lastRefresh
+local refreshReason
+
+local bountyQuests = {}
+local bountyInfo = {}
+local bountyDisplayLocation, bountyLockedQuestID, selectedBountyIndex, selectedBountyQuestID
+
+local totalPins = 0
+local numShown = 0
+local numLoaded = 0
+local numOverlays = 1
+local scaleConstant = 1
+local pinBaseIndex = 1550
+local overlayBaseIndex = 1600
+
+local artifactKnowldegeSpells = {
+  [207856] = true,
+  [209203] = true,
+  [209204] = true,
+  [209205] = true,
+  [209206] = true,
+  [209207] = true,
+  [209208] = true,
+  [209209] = true,
+  [209210] = true,
+  [209211] = true,
+  [209212] = true,
+  [219978] = true,
+  [227852] = true,
+  [236477] = true,
+  [236489] = true,
+  [236302] = true,
+  [236488] = true,
+  [236490] = true,
+  [240475] = true,
+  [243176] = true,
+  [243177] = true,
+  [243178] = true,
+  [243182] = true,
+  [243183] = true,
+  [243187] = true,
+  [245133] = true,
+}
+
+--%debug%
+local SetTimedCallbackForAllPins = function(seconds, callback)
+  C_Timer.After(seconds, function()
+    for id, pin in pairs(WorldPlanQuests.QuestsByID) do
+      callback(pin)
+    end
+  end)
+end
+
+function Module:OnLoad()
+  --print('|cFFFF4400'..self:GetName()..':OnLoad()')
+
+  self:SetParent(WorldMapFrame.UIElementsFrame)
+  WorldPlan:AddHandler(self, defaults)
+
+  for areaID, fileName in pairs(WORLD_QUEST_MAPS) do
+    db.QuestsByZone[areaID] = {}
+  end
+
+  -- WORLD_MAP_UPDATE and PLAYER_ENTERING_WORLD are passed down from a higher level
+  self:RegisterEvent('WORLD_QUEST_COMPLETED_BY_SPELL')
+  self:RegisterEvent('SUPER_TRACKED_QUEST_CHANGED')
+  self:RegisterEvent('SKILL_LINES_CHANGED')
+  self:RegisterEvent('ARTIFACT_UPDATE')
+  self:RegisterEvent('QUEST_LOG_UPDATE')
+  self:RegisterEvent('UNIT_SPELLCAST_STOP')
+end
+
+function Module:OnEvent (event, ...)
+  print('|cFFFFFF00OnEvent() '..event..'|r', GetTime(), ...)
+  if (event == 'QUEST_LOG_UPDATE') then
+    self:UpdateBounties(event)
+  elseif event == 'WORLD_QUEST_COMPLETED_BY_SPELL' then
+    local questID = ...
+    if questID and db.QuestsByID[questID] then
+      completedQuests[questID] = true
+      db.QuestsByID[questID]:Release()
+    end
+    self:Refresh(event)
+  elseif event == 'SKILL_LINES_CHANGED' or event == 'CURRENT_SPELL_CAST_CHANGED' then
+    self:Refresh(event)
+  elseif event == 'ARTIFACT_UPDATE' then
+    self:UpdateArtifactPower()
+  elseif event == 'MODIFIER_STATE_CHANGED' then
+    self:UpdateModifierState()
+  elseif event == 'SUPER_TRACKED_QUEST_CHANGED' then
+    if superTrackedQuestID and db.QuestsByID[superTrackedQuestID] then
+      db.QuestsByID[superTrackedQuestID].isStale = true
+    end
+    local newID = GetSuperTrackedQuestID()
+    if newID and db.QuestsByID[newID] then
+      db.QuestsByID[newID].isStale = true
+    end
+  elseif event == 'UNIT_SPELLCAST_STOP' then
+    local name, _, _, _, spellID = ...
+    if artifactKnowldegeSpells[spellID] then
+      db.log('AK spellcast ended ' .. tostring(name) .. ' ('.. tostring(spellID)..')')
+      self:UpdateArtifactPower()
+    end
+  end
+end
+
+function Module:OnUpdate(sinceLast)
+  if WorldPlanData.DebugEnabled then
+    if self.refreshBenchMarkTicker then
+      --print(self.refreshBenchMarkTicker)
+      self.refreshBenchMarkTicker =   self.refreshBenchMarkTicker - 1
+
+      if self.refreshBenchMarkTicker == 0 then
+
+        self.refreshTime = floor((GetTime() - self.refreshBenchMark) * 1000)
+        self.debugMessage:SetText(self.refreshTime)
+        self.refreshBenchMarkTicker = nil
+      end
+    else
+      self.refreshBenchMark = GetTime()
+    end
+  end
+
+  if self.filtersDirty or self.isStale then
+    self:Refresh()
+  end
+
+  if #db.UpdatedPins >= 1 then
+    --print('|cFF00FF88pending update', #db.UpdatedPins)
+    self:UpdateNext()
+  end
+end
+
+local callbacks = {}
+callbacks.ClickWorldMapActionButton = function(WorldQuests)
+  WorldQuests:Refresh('CLICK_MAP_ACTION_BUTTON')
+end
+callbacks.WorldMap_UpdateQuestBonusObjectives = function(WorldQuests)
+  WorldQuests:UpdateTaskPOIs()
+end
+callbacks.WorldMapFrame_UpdateMap = function(WorldQuests)
+  WorldQuests:RefreshIfChanged('WMF_UPDATE')
+end
+callbacks.WorldMapScrollFrame_ReanchorQuestPOIs = function (WorldQuests)
+  WorldQuests:RefreshIfChanged('WMF_REANCHOR')
+end
+
+callbacks[BountyBoard] = {}
+callbacks[BountyBoard].SetSelectedBountyIndex = function(WorldQuests)
+  WorldQuests:UpdateBounties('BOUNTY_SELECTED')
+  for questID, pin in pairs(db.QuestsByID) do
+    pin.checkCriteria = true
+    pin:Refresh()
+  end
+end
+
+callbacks[ActionButton] = {}
+callbacks[ActionButton].UpdateCastingState = function(WorldQuests)
+  for questID, pin in pairs(db.QuestsByID) do
+    pin.checkCursor = true
+    pin:Refresh()
+  end
+end
+
+callbacks.UseWorldMapActionButtonSpellOnQuest = function(questID)
+  local pin = db.QuestsByID[questID]
+  -- calling this implies that the pin is used in some way
+  if pin then
+    db.log(pin.title ..  ' completed by spell?', IsQuestComplete(pin.questID))
+    pin:OnFilters()
+    pin.isStale = true
+  end
+end
+
+function Module:SetupCallbacks()
+  if InCombatLockdown() then
+    return true
+  end
+  print('SetupCallbacks()')
+  for target, arg in pairs(callbacks) do
+    --print(type(target))
+    if type(target) == 'table' then
+      local callerName = target:GetName() or tostring(target)
+      for name, method  in pairs(arg) do
+        --print(callerName, arg)
+        hooksecurefunc(target, name, function(...)
+          self:OnSecureHook(callerName .. '.' .. name, method, ...)
+        end)
+      end
+    else
+      hooksecurefunc(target, function(...)
+        self:OnSecureHook(target, arg, ...)
+      end)
+    end
+  end
+end
+
+function Module:Setup()
+  --print('|cFFFF4400'..self:GetName()..':Setup()')
+  for mapID, mapName in pairs(WORLD_QUEST_MAPS) do
+    db.QuestsByZone[mapID] = {}
+  end
+
+  hooksDirty = self:SetupCallbacks()
+
+  self:SetAllPoints(WorldMapFrame.UIElementsFrame)
+  self:UpdateArtifactPower()
+  self:UpdateBounties('SETUP')
+  self:Show()
+end
+
+function Module:OnMapInfo(isBrokenIsle, isZoomedOut, mapAreaID, isNewMap, isMapOpen)
+  if isNewMap or self.isStale then
+    print('|cFF0088FFOnMapInfo()|r, mapAreaID =', mapAreaID,'visible =', isMapOpen, 'changed =', isNewMap)
+    layoutDirty = true
+    self:Refresh('WORLD_MAP_CHANGED')
+  end
+end
+
+function Module:OnConfigUpdate()
+  --print('|cFFFFFF00OnConfigUpdate()|r')
+  if db.Config.FadeWhileGrouped then
+    db.PinAlpha = 0.15
+  else
+    db.PinAlpha = 1
+  end
+
+  if not db.Config.EnablePins then
+    for _, pin in pairs(db.QuestsByID) do
+      pin:SetShown(false)
+    end
+  end
+end
+
+function Module:OnSecureHook(callbackName, func, ...)
+  print('|cFFFF4400'..callbackName..'|r', ...)
+  func(self, ...)
+end
+
+function Module:UpdateModifierState()
+
+end
+
+function Module:UpdateTaskPOIs()
+  canTargetQuests = SpellCanTargetQuest()
+  for i = 1, NUM_WORLDMAP_TASK_POIS do
+    local poiFrame = _G['WorldMapFrameTaskPOI'..i]
+    if poiFrame and poiFrame.worldQuest then
+      local pin = db.QuestsByID[poiFrame.questID]
+      if pin and pin.used and canTargetQuests and IsQuestIDValidSpellTarget(pin.questID) then
+        poiFrame:Show()
+      else
+        poiFrame:Hide()
+      end
+    end
+  end
+end
+-- re-anchors and scales pins that have had either of these changed due to data loading delays
+function Module:UpdateNext()
+  --print('|cFF00FF88UpdateNext()')
+  local pin = tremove(db.UpdatedPins)
+  pin:OnFilters()
+
+  local scaleFactor = SCALE_FACTORS[(pin.dataLoaded and not pin.filtered) and scaleConstant or 1]
+  --print(pin.title, pin.dataLoaded  and not pin.filtered, scaleFactor)
+  if pin.used then
+    pin:SetShown(true)
+    pin:SetAnchor(nil, pin.x, pin.y, self.hostWidth, self.hostHeight, scaleFactor)
+    pin:Refresh()
+  else
+    print('|cFFFF4400flagging queued pin that got hidden:', pin.title)
+    pin.isStale = true
+  end
+end
+
+function Module:UpdateBounties(...)
+  bountiesDirty = nil
+  print('|cFF00FF88BountyInfo()|r', ...)
+  wipe(db.BountiesByFactionID)
+  wipe(db.BountiesByQuestID)
+
+  db.selectedBounty = nil
+  selectedBountyIndex = BountyBoard:GetSelectedBountyIndex()
+  db.Bounties, bountyDisplayLocation, bountyLockedQuestID = GetQuestBountyInfoForMapID(db.currentMapID, db.Bounties)
+  local numBounties = 0
+  for index, info in ipairs(db.Bounties) do
+      numBounties = numBounties + 1
+      info.index = index
+      info.complete =  IsQuestComplete(info.questID)
+      if not info.complete then
+        db.BountiesByFactionID[info.factionID] = info
+        db.BountiesByQuestID[info.questID] = info
+        if index == selectedBountyIndex then
+          db.selectedBounty = info
+          selectedBountyQuestID = info.questID
+        end
+        print(' ', index, info.factionID, GetQuestLogTitle(GetQuestLogIndexByID(info.questID)), info.complete, (index == selectedBountyIndex) and 'SELECTED' or '')
+      end
+  end
+end
+
+-- check current artifact knowledge and update pins accordingly
+function Module:UpdateArtifactPower(overrideLevel)
+  if InCombatLockdown() then
+    artifactPowerDirty = true
+    return
+  end
+
+  print('|cFF00FF88UpdateArtifactPower()|r')
+  local _, akLevel = GetCurrencyInfo(1171)
+  if overrideLevel then
+    akLevel = overrideLevel
+  end
+
+  --db.print('current AK', akLevel)
+  if akLevel and (akLevel ~= artifactKnowledgeLevel) or (not artifactKnowledgeLevel) then
+    --print('new ak level', akLevel)
+    db.log('AK update ' .. tostring(artifactKnowledgeLevel) .. ' to '.. tostring(akLevel))
+    for _, pin in pairs(db.QuestsByID) do
+      if (pin.rewardType == REWARD_ARTIFACT_POWER) then
+        print(pin.title, pin.itemNumber)
+        local newAP = pin:UpdateArtifactPower()
+        if newAP then
+          pin.itemNumber = newAP
+          print(newAP)
+        else
+          pin.dataLoaded = nil
+        end
+        pin.isStale = true
+      end
+    end
+    artifactKnowledgeLevel = akLevel
+  end
+  artifactPowerDirty = nil
+end
+
+local msg = '|cFF00FF88WorldQuests:Refresh()|r|cFF00FFFF'
+function Module:Refresh(...)
+
+  if hooksDirty then
+    hooksDirty = self:SetupCallbacks()
+  end
+
+
+  if not self:IsVisible() then
+    print('|cFFFF4400Refresh()|r', ...)
+    return
+  else
+    if lastRefresh == GetTime() then
+      print('|cFFFF4400multiple refreshes tried')
+    end
+    lastRefresh = GetTime()
+    print(msg, lastRefresh, ...)
+  end
+
+
+  if bountiesDirty then
+    self:UpdateBounties()
+  end
+
+  if not db.Config.EnablePins then
+    numShown = 0
+    self.refreshBenchMark = GetTime()
+    self.refreshBenchMarkTicker = 2
+    print('starting bench', self.refreshBenchMark)
+    return
+  end
+
+  scaleConstant = db.isContinentMap and 2 or 3
+  canTargetQuests = SpellCanTargetQuest()
+
+  for index, pin in pairs(db.QuestsByID) do
+    pin.used = nil
+  end
+
+  self:UpdateAnchors(...)
+
+  if artifactPowerDirty and not InCombatLockdown() then
+    self:UpdateArtifactPower()
+  end
+  -- calculate quests shown
+  numShown = 0
+  numLoaded = 0
+  for questID, pin in pairs(db.QuestsByID) do
+    local oV = pin:IsShown()
+    if pin.used then
+      print('show', pin.title)
+      pin.throttle = 1
+      pin:SetShown(true)
+      numShown = numShown + 1
+      if pin.dataLoaded then
+        numLoaded = numLoaded + 1
+      end
+
+      pin.checkCriteria = true
+      pin.checkFilters = true
+      pin:Refresh('WORLDMAP_REFRESH ' .. GetTime())
+
+    else
+      if pin:IsShown() then
+        print('|cFFFF4400need to remove', pin.title)
+
+      end
+
+      pin.hideReason = "Not used in map area " .. (db.currentMapID)
+      pin:SetShown(false)
+    end
+
+  end
+
+
+--
+  self.refreshBenchMark = GetTime()
+  self.refreshBenchMarkTicker = 2
+  print('starting bench', self.refreshBenchMark)
+
+--
+
+  layoutDirty = nil
+  self.isStale = nil
+  self.sizesDirty = nil
+  self.isZoomDirty = nil
+
+  if WorldPlanSummary then
+    WorldPlanSummary.isStale = true
+  end
+
+end
+
+function Module:RefreshIfChanged(event)
+  local scaleCheck = WorldMapDetailFrame:GetScale()
+  refreshReason = nil
+  if scaleCheck ~= currentScale then
+    refreshReason = 'map scale updated'
+    currentScale = scaleCheck
+    layoutDirty = true
+  elseif self.isStale or layoutDirty then
+    refreshReason = 'layout is marked dirty'
+  end
+  if not refreshReason then
+    return
+  end
+
+  if self:IsVisible() then
+    print('|cFF00FFFFRefreshIfChanged()|r', refreshReason)
+    self:Refresh(event)
+  else
+    print('|cFF00FFFFRefreshIfChanged()|r', refreshReason)
+    self.isStale = true
+  end
+end
+
+-- Walks the current map tree and fires updates as needed
+function Module:UpdateAnchors (event)
+  wipe(self.UsedPositions)
+  local hostWidth, hostHeight = WorldMapPOIFrame:GetSize()
+
+  if (hostWidth ~= self.hostWidth) or (hostHeight ~= self.hostHeight) then
+    self.hostWidth, self.hostHeight = hostWidth, hostHeight
+    layoutDirty = true
+  end
+
+  print('|cFF00FF00UpdateAnchors()', event)
+  local mapFileName, textureHeight, textureWidth, isMicroDungeon, microDungeonMapName = GetMapInfo()
+  if isMicroDungeon then
+    return
+  end
+
+  isDataLoaded = true
+  local taskInfo = TQ_GetQuestsForPlayerByMapID(db.currentMapID)
+  if taskInfo then
+    self:UpdateQuestsForMap(taskInfo, db.currentMapID)
+  end
+  local numZones = MC_GetNumZones(db.currentMapID)
+  if numZones then
+    for i = 1, numZones do
+      local mapAreaID = MC_GetZoneInfo(db.currentMapID, i)
+      local taskInfo = TQ_GetQuestsForPlayerByMapID(mapAreaID, db.currentMapID)
+
+      db.QuestsByZone[mapAreaID] = db.QuestsByZone[mapAreaID] or {}
+
+      if taskInfo then
+        self:UpdateQuestsForMap(taskInfo, mapAreaID)
+      end
+    end
+  end
+end
+
+-- Attempt to display the pins for quests in taskInfo
+function Module:UpdateQuestsForMap(taskInfo, mapID)
+  print('|cFF00FF00UpdateQuestsForMap()|r', GetMapNameByID(mapID), GetMapNameByID(db.currentMapID), layoutDirty)
+  if db.QuestsByZone[mapID] then
+    wipe(db.QuestsByZone[mapID])
+  elseif db.isBrokenIsle then
+    continentScanned = true
+  end
+  db.PinStrata = WorldMapFrame_InWindowedMode() and 'HIGH' or 'FULLSCREEN'
+  print('layoutDirty =',layoutDirty)
+
+  for index, info in pairs(taskInfo) do
+    local questID, x, y = info.questId, info.x, info.y
+    local pin = self:AcquirePin(info)
+    if pin then
+      if pin.canShow then
+        pin.used = true
+        print('using', pin.title, (pin.owningFrame ~= WorldMapFrame))
+        if layoutDirty or (pin.owningFrame ~= WorldMapFrame) then
+          local scaleFactor = SCALE_FACTORS[(not pin.filtered and scaleConstant) or 1]
+          pin.owningFrame = WorldMapFrame
+          pin:SetAnchor(WorldMapPOIFrame, x, y, self.hostWidth, self.hostHeight, scaleFactor)
+
+        end
+        if db.QuestsByZone[mapID] then
+          db.QuestsByZone[mapID][questID] = pin
+        end
+      else
+        print('|cFFFF4400discarding|r', pin.title)
+      end
+    end
+  end
+end
+
+-- locates or creates a corresponding pin frame for the provided TaskInfo data
+function Module:AcquirePin (info)
+  local questID = info.questId
+  if not (questID and QuestUtils_IsQuestWorldQuest(questID)) then
+    return nil
+  end
+  local pin = db.QuestsByID[questID]
+  -- check to avoid creating unnecessary frames
+  if IsQuestComplete(questID) or completedQuests[questID] then
+    completedQuests[questID] = true
+    if pin then
+      pin:Release()
+    end
+    return nil
+  end
+
+  if not pin then
+    local numFree = #db.FreePins
+    if numFree >= 1 then
+      pin = tremove(db.FreePins, numFree)
+      print('|cFF00FF00Acquire()|r Re-using', pin:GetName())
+    else
+      totalPins = totalPins + 1
+      local name = 'WorldPlanQuestMarker' .. numOverlays
+      print('|cFF00FF00Acquire()|r Creating', name)
+      pin = CreateFrame('Frame', name, WorldMapPOIFrame, 'WorldPlanQuestPin')
+
+      pin:SetID(totalPins)
+      numOverlays = numOverlays + 1
+      --pin.iconBorder:SetVertexColor(0,0,0,1)
+    end
+    pin.questID = questID
+    pin.throttle = pin.updateRate
+    pin.currentWidth = nil
+
+    db.QuestsByID[questID] = pin
+    tinsert(db.UsedPins, pin)
+  end
+
+  if info then
+    pin.inProgress = info.inProgress
+    pin.floor = info.floor
+    pin.numObjectives = info.numObjectives or 0
+    if info.x and info.y then
+      if (info.x ~= pin.x) or (info.y ~= pin.y) then
+        pin.isStale = true
+        --rprint('|cFFFF4400SetCoords|r', info.x, info.y)
+      end
+    end
+  end
+
+  pin.x = info.x or pin.x
+  pin.y = info.y or pin.y
+
+  if not HaveQuestRewardData(questID) then
+    TQ_RequestPreloadRewardData(questID);
+  end
+
+  if (not pin.dataLoaded) then
+    local dataLoaded = pin:GetData()
+    if dataLoaded then
+      WorldPlan.dataFlush = true
+    else
+      isDataLoaded = false
+    end
+  end
+
+  pin:OnFilters()
+  pin.isActive = TQ_IsActive(questID)
+  --rprint(pin:GetID(), pin.filtered, pin.used)
+  return pin
+end
+
+function Module:Debug(...)
+  print(...)
+end
\ No newline at end of file