Mercurial > wow > buffalo2
diff ObjectiveCore.lua @ 19:605e8f0e46db
ObjectiveCore / Style / Events / Frame
- polishing the execution path for better performance
- make use of the Blizzard_ObjectiveTracker bitfield values to ensure compatibility in possible secure hooks
- avoid full updates when possible (using said bitfield values to indicate targeted sections)
- extreme streamlining of event handling layout: specific reason updates are invoked from API hooks; broader updates are invoked by when the event listener catches something vague like 'QUEST_LOG_UPDATE'
author | Nenue |
---|---|
date | Wed, 06 Apr 2016 07:38:35 -0400 |
parents | 880828018bf4 |
children | 6bd2102d340b |
line wrap: on
line diff
--- a/ObjectiveCore.lua Tue Apr 05 02:38:01 2016 -0400 +++ b/ObjectiveCore.lua Wed Apr 06 07:38:35 2016 -0400 @@ -3,29 +3,16 @@ -- @project-revision@ @project-hash@ -- @file-revision@ @file-hash@ -- Created: 3/26/2016 1:51 AM -local B = select(2,...).frame -local pairs, setmetatable, type, tostring = pairs, setmetatable, type, tostring -local format = string.format +local B, _G = select(2,...).frame, _G +local pairs, setmetatable, type, tostring = _G.pairs, _G.setmetatable, _G.type, _G.tostring +local format = _G.format local mod = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame') local print = B.print('Objectives') -local ObjectiveTrackerFrame, VeneerObjectiveScroll, CreateFrame = ObjectiveTrackerFrame, VeneerObjectiveScroll, CreateFrame - ---[[ - Full quest info is available if: - - It's in the player quest log, or is available from the Gossip interface - - It's being shared from another player and is acceptible - - It's an auto-quest that is available in the current location - Partial quest info is availabe if: - - It's already completed (i.e. it appears in CompletedQuestInfo()). - - It's an scheduled interval quest (daily, weekly, etc.) - - It's contained in a quest link received from chat - Under any other circumstances, only minimal info can be pulled: - - Its availability to the player - - Its relation with the currently engaged NPC - - Its binary completion status - -]] - +local ObjectiveTrackerFrame, VeneerObjectiveScroll, CreateFrame = _G.ObjectiveTrackerFrame, _G.VeneerObjectiveScroll, _G.CreateFrame +local Wrapper = _G.VeneerObjectiveWrapper +local ipairs, tinsert, hooksecurefunc = _G.ipairs, _G.tinsert, _G.hooksecurefunc +local Scroller = VeneerObjectiveWrapper.scrollArea +local Scroll = _G.VeneerObjectiveScroll --- Performance values --[[ @@ -45,155 +32,324 @@ self:RegisterEvent("QUEST_TURNED_IN"); self:RegisterEvent("PLAYER_MONEY"); ]] -mod.Reason ={ - UPDATE_MASK_AUTOQUEST = 0x00000001, - UPDATE_MASK_QUEST = 0x00000002, - UPDATE_MASK_BONUS = 0x00000004, - UPDATE_MASK_CHEEVS = 0x00000008, - UPDATE_MASK_ALL = 0x00000017, - QUEST_LOG_UPDATE = 0x00000003, - TRACKED_ACHIEVEMENT_LIST_CHANGED = 0x00000008, - QUEST_WATCH_LIST_CHANGED = 0x00000003, - QUEST_AUTOCOMPLETE = 0x00000003, - QUEST_ACCEPTED = 0x00000003, - SUPER_TRACKED_QUEST_CHANGED = 0x00000002, - SCENARIO_UPDATE = 0x00000004, - SCENARIO_CRITERIA_UPDATE = 0x00000004, - TRACKED_ACHIEVEMENT_UPDATE = 0x00000008, - ZONE_CHANGED_NEW_AREA = 0x00000017, - ZONE_CHANGED = 0x00000017, - QUEST_POI_UPDATE = 0x00000003, - QUEST_TURNED_IN = 0x00000003, -} + +--- These are the bitfields used by Blizzard_ObjectiveTracker to determine which segments get parsed. +--- They are replicated here so that plugins can make use of any securehook args involving this info. +local OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST = OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST -- 0x0100 +local OBJECTIVE_TRACKER_UPDATE_MODULE_AUTO_QUEST_POPUP = OBJECTIVE_TRACKER_UPDATE_MODULE_AUTO_QUEST_POPUP -- 0x0200 +local OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE = OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE -- 0x0400 +local OBJECTIVE_TRACKER_UPDATE_MODULE_SCENARIO = OBJECTIVE_TRACKER_UPDATE_MODULE_SCENARIO -- 0x0800 +local OBJECTIVE_TRACKER_UPDATE_MODULE_ACHIEVEMENT = OBJECTIVE_TRACKER_UPDATE_MODULE_ACHIEVEMENT -- 0x1000 + + +local OBJECTIVE_TRACKER_UPDATE_STATIC = OBJECTIVE_TRACKER_UPDATE_STATIC -- 0x0000 +local OBJECTIVE_TRACKER_UPDATE_ALL = OBJECTIVE_TRACKER_UPDATE_ALL -- 0xFFFF +local OBJECTIVE_TRACKER_UPDATE_ID = OBJECTIVE_TRACKER_UPDATE_ID -- 0 + +local OBJECTIVE_TRACKER_UPDATE_QUEST = OBJECTIVE_TRACKER_UPDATE_QUEST -- 0x0001 +local OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED = OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED -- 0x0002 +local OBJECTIVE_TRACKER_UPDATE_TASK_ADDED = OBJECTIVE_TRACKER_UPDATE_TASK_ADDED -- 0x0004 +local OBJECTIVE_TRACKER_UPDATE_SCENARIO = OBJECTIVE_TRACKER_UPDATE_SCENARIO -- 0x0008 +local OBJECTIVE_TRACKER_UPDATE_SCENARIO_NEW_STAGE = OBJECTIVE_TRACKER_UPDATE_SCENARIO_NEW_STAGE -- 0x0010 +local OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT = OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT -- 0x0020 +local OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT_ADDED = OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT_ADDED -- 0x0040 +local OBJECTIVE_TRACKER_UPDATE_SCENARIO_BONUS_DELAYED = OBJECTIVE_TRACKER_UPDATE_SCENARIO_BONUS_DELAYED -- 0x0080 + +local OBJECTIVE_TRACKER_UPDATE_REASON = OBJECTIVE_TRACKER_UPDATE_ALL -- default +--- Used to determine which trackers are listening for money events mod.MoneyReasons = 0 ---- Baseline defaults +--- Baseline defaults table; values defined in the files that they pertain to mod.defaults = {} ---- list used to make things happen +--- Tracker display order mod.orderedNames = {'Bonus', 'AutoQuest', 'Quest', 'Cheevs'} ---- ipairs() list of handlers for wrapper update -mod.orderedHandlers = {} -mod.orderedTrackers = {} -mod.indexedTrackers = {} ---- pairs() list of handler frames for tracker updates -mod.namedTrackers = {} +--- ipairs() argument tables +mod.orderedHandlers = setmetatable({}, {__mode = "k"}) +mod.orderedTrackers = setmetatable({}, {__mode = "k"}) +mod.indexedTrackers = setmetatable({}, {__mode = "k"}) ---- Handler stubs +--- pairs() argument tables +mod.namedTrackers = setmetatable({}, {__mode = "k"}) + +local WRAPPER_ANCHOR_POINT = 'TOPRIGHT' +local WRAPPER_OFFSET_X = 0 +local WRAPPER_OFFSET_Y = -200 +local WRAPPER_MAX_HEIGHT = 670 +local WRAPPER_WIDTH = 280 +local WRAPPER_HEADER_HEIGHT = 24 + +mod.defaults.Wrapper = { + AnchorPoint = WRAPPER_ANCHOR_POINT, + OffsetX = WRAPPER_OFFSET_X, + OffsetY = WRAPPER_OFFSET_Y, + Height = WRAPPER_MAX_HEIGHT, + Width = WRAPPER_WIDTH, + HeaderHeight = WRAPPER_HEADER_HEIGHT +} +--- Tracker module definitions begin here; innards dealing with data retreival and output are defined further in +mod.DefaultTracker = { + previousHeight = 0, + + name = "temp", + displayName = "temp", + updateReasonModule = 0xFF00, + updateReasonEvent = 0x00FF, + + numWatched = 0, --- number of entries being handled + numBlocks = 0, --- number of blocks created + actualBlocks = 0, --- number of blocks in use + + freeBlocks = {}, --- block heap + usedBlocks = {}, + + Info = {}, -- find data by ID + BlockInfo = {}, -- find data by block ID + Watched = {}, -- find watchIndex by data ID + WatchInfo = {}, -- find data by watch index + WatchBlock = {}, -- find block by watch index +} + mod.AutoQuest = { name = "AutoQuest", displayName = "Notice", + updateReasonModule = OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST, + updateReasonEvents = OBJECTIVE_TRACKER_UPDATE_QUEST + + OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED, } mod.Quest = { name = "Quest", displayName = "Quests", + updateReasonModule = OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST, + updateReasonEvents = OBJECTIVE_TRACKER_UPDATE_QUEST + + OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED, } mod.Cheevs = { name = "Cheevs", displayName = "Achievements", + updateReasonModule = OBJECTIVE_TRACKER_UPDATE_MODULE_ACHIEVEMENT, + updateReasonEvents = OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT + + OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT_ADDED, } mod.Bonus = { name = "Bonus", displayName = "Bonus Objectives", + updateReasonModule = OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE, + updateReasonEvents = OBJECTIVE_TRACKER_UPDATE_QUEST + + OBJECTIVE_TRACKER_UPDATE_TASK_ADDED + + OBJECTIVE_TRACKER_UPDATE_SCENARIO + + OBJECTIVE_TRACKER_UPDATE_SCENARIO_NEW_STAGE + + OBJECTIVE_TRACKER_UPDATE_SCENARIO_BONUS_DELAYED } ---- Handler template -local CreateHandler = function (self, name, index) - print(self, name) +local Tracker_string = function (self) + return self.name +end +local Tracker_call = function (self, reason) + self:Update(reason) +end + +local Tracker_Initialize = function (self, name, index) + print('Initializing |cFF00FFFF'..name..'|r module...') local handler = setmetatable(mod[name] or {}, { - __tostring = function() return name end, - __call = function (self) mod.UpdateTracker(self) end + __tostring = Tracker_string, + __call = Tracker_call }) if type(mod.orderedHandlers[index]) == 'table' then return mod.orderedHandlers[index] end - print('take up locals first') + print('|cFFFFFF00Acquiring locals') local preset = {} - for k,v in pairs(mod[name]) do + for k, _ in pairs(handler) do preset[k] = true - if type(v) == 'table' then - handler[k] = {} - else - handler[k] = v - end end - print('resulting handler contents') + print('|cFFFF8800Inheriting') for k, v in pairs(self) do if not handler[k] then if type(v) == 'table' then -- assume all tables to be local data; don't inherit or ref handler[k] = {} else - handler[k] = mod.Tracker[k] + handler[k] = self[k] end - else - print(name, 'has its own', k) + print('copying', k) end end print('|cFFFF4400'..tostring(name)..'|r:') for k, v in pairs(handler) do - print(format("%24s %8s %s", (preset[k] and '|cFFFFFFFF' or '|cFFFFFF00') .. k .. '|r', type(v), tostring(v))) + print(format("%32s %8s %s", (preset[k] and '|cFFFFFFFF' or '|cFFFFFF00') .. k .. '|r', type(v), tostring(v))) end mod[name] = handler + local trackerName = 'Veneer'..name..'Tracker' + local handler = mod[name] + local frame = CreateFrame('Frame', trackerName, _G.VeneerObjectiveScroll, 'VeneerTrackerTemplate') + frame.title:SetText(handler.displayName) + mod.SetBlockStyle(frame, 'Tracker', 'Normal') + handler.frame = frame + handler.trackerName = trackerName + mod.orderedTrackers[index] = frame + mod.namedTrackers[name] = frame + mod.indexedTrackers[handler] = frame + print('|cFFFF0088' .. trackerName .. '|r created for |cFF00FFFF' .. handler.displayName .. '|r module') + mod.orderedHandlers[index] = handler return true end -mod.Tracker = setmetatable({}, { - __call = CreateHandler, - __tostring = function() return 'DEFAULT_TRACKING_HANDLER' end -}) -local Tracker = mod.Tracker -Tracker.numWatched = 0 --- number of entries being handled -Tracker.numBlocks = 0 --- number of blocks created -Tracker.actualBlocks = 0 --- number of blocks in use - -Tracker.freeBlocks = {} --- block heap -Tracker.usedBlocks = {} - -Tracker.Watched = {} -- find by watchIndex -Tracker.Info = {} -- find by data ID -Tracker.BlockInfo = {} -- find by block ID -Tracker.WatchInfo = {} -- find data by watch index -Tracker.WatchBlock = {} -- find block by watch index - - - -Tracker.GetBlock = function(handler, blockIndex) - local block = handler.usedBlocks[blockIndex] - if not handler.usedBlocks[blockIndex] then - if #handler.freeBlocks >= 1 then - block = handler.freeBlocks[#handler.freeBlocks] - handler.freeBlocks[#handler.freeBlocks] = nil +function mod:OnEvent (event, ...) + local isHandled + print('|cFF00FF00'.. event ..'|r', ...) + if ( event == "QUEST_LOG_UPDATE" ) then + mod:Update(OBJECTIVE_TRACKER_UPDATE_QUEST); + elseif ( event == "TRACKED_ACHIEVEMENT_UPDATE" ) then + --AchievementObjectiveTracker_OnAchievementUpdate(...); + mod.Cheevs:Update(OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT) + elseif ( event == "QUEST_ACCEPTED" ) then + local questLogIndex, questID = ...; + if ( IsQuestTask(questID) ) then + mod:Update(OBJECTIVE_TRACKER_UPDATE_TASK_ADDED, questID); else - block = CreateFrame('Frame', 'Veneer'..tostring(handler)..'Block'..blockIndex, VeneerObjectiveScroll, 'VeneerTrackerBlock') - block.SetStyle = mod.SetBlockStyle - block.Select = handler.Select - block.Open = handler.Open - block.Remove = handler.Remove - block.Link = handler.Link - block:SetScript('OnMouseUp', handler.OnMouseUp) - block:SetScript('OnMouseDown', handler.OnMouseDown) - block:ClearAllPoints() + if ( AUTO_QUEST_WATCH == "1" and GetNumQuestWatches() < MAX_WATCHABLE_QUESTS ) then + AddQuestWatch(questLogIndex); + SetSuperTrackedQuestID(questID); + end + end + elseif ( event == "TRACKED_ACHIEVEMENT_LIST_CHANGED" ) then + local achievementID, added = ...; + if ( added ) then + mod:Update(OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT_ADDED, achievementID); + else + mod:Update(OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT); + end + elseif ( event == "QUEST_WATCH_LIST_CHANGED" ) then + local questID, added = ...; + if ( added ) then + if ( not IsQuestTask(questID) ) then + mod:Update(OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED, questID); + end + else + mod:Update(OBJECTIVE_TRACKER_UPDATE_QUEST); + end + elseif ( event == "QUEST_POI_UPDATE" ) then + QuestPOIUpdateIcons(); + if ( GetCVar("trackQuestSorting") == "proximity" ) then + SortQuestWatches(); end - handler.usedBlocks[blockIndex] = block + mod:Update(OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST); + + elseif ( event == "SCENARIO_CRITERIA_UPDATE" ) then + mod:Update(OBJECTIVE_TRACKER_UPDATE_SCENARIO); + elseif ( event == "SUPER_TRACKED_QUEST_CHANGED" ) then + mod:Update(OBJECTIVE_TRACKER_UPDATE_QUEST) + elseif ( event == "ZONE_CHANGED" ) then + local inMicroDungeon = IsPlayerInMicroDungeon(); + if ( inMicroDungeon ~= self.inMicroDungeon ) then + if ( not WorldMapFrame:IsShown() and GetCVarBool("questPOI") ) then + SetMapToCurrentZone(); -- update the zone to get the right POI numbers for the tracker + end + --SortQuestWatches(); + self.inMicroDungeon = inMicroDungeon; + end + elseif ( event == "QUEST_AUTOCOMPLETE" ) then + local questId = ...; + AddAutoQuestPopUp(questId, "COMPLETE"); + elseif ( event == "SCENARIO_UPDATE" ) then + local newStage = ...; + if ( newStage ) then + mod:Update(OBJECTIVE_TRACKER_UPDATE_SCENARIO_NEW_STAGE); + else + mod:Update(OBJECTIVE_TRACKER_UPDATE_SCENARIO); + end + elseif ( event == "ZONE_CHANGED_NEW_AREA" ) then + if ( not WorldMapFrame:IsShown() and GetCVarBool("questPOI") ) then + SetMapToCurrentZone(); -- update the zone to get the right POI numbers for the tracker + end + SortQuestWatches(); + elseif ( event == "QUEST_TURNED_IN" ) then + local questID, xp, money = ...; + if ( IsQuestTask(questID) ) then + mod.Bonus:Update() + end + elseif ( event == "PLAYER_MONEY" and self.watchMoneyReasons > 0 ) then + mod:Update(self.watchMoneyReasons); end - return handler.usedBlocks[blockIndex] end +--- Done once per ui load +local BlizzHooks = { + ['AddQuestWatch'] = 'AddQuestWatch', + ['RemoveQuestWatch'] = 'RemoveQuestWatch', + ['AbandonQuest'] = 'AbandonQuest', + ['AcknowledgeAutoAcceptQuest'] = 'AcknowledgeAutoAcceptQuest', + ['AddAutoQuestPopUp'] = 'AddAutoQuestPopUp', + ['RemoveAutoQuestPopUp'] = 'RemoveAutoQuestPopUp', + ['AddTrackedAchievement'] = 'AddTrackedAchievement', + ['RemoveTrackedAchievement'] = 'RemoveTrackedAchievement', + ['SetSuperTrackedQuestID'] = 'SetSuperTrackedQuestID' +} +local VeneerData function mod:OnInitialize() - self.InitializeWrapper() - self.InitializeXPTracker() - mod.SetEvents() + local c = mod.Conf.Wrapper + VeneerData = _G.VeneerData + VeneerData.CallLog = VeneerData.CallLog or {} + if not mod.isHooked then + mod.isHooked = true + for blizzFunc, veneerFunc in pairs(BlizzHooks) do + if mod[veneerFunc] then + hooksecurefunc(blizzFunc, mod[veneerFunc]) + else + hooksecurefunc(blizzFunc, function(...) + print('|cFFFF0088securehook('..tostring(blizzFunc)..')|r args:', ...) + tinsert(VeneerData.CallLog, {blizzFunc, ...}) + end) + end + end + end + Scroller:SetScrollChild(Scroll) + Scroller:SetWidth(c.Width) + Scroll:SetPoint('TOPLEFT', Scroller, 'TOPLEFT') + Scroll:SetWidth(c.Width) ObjectiveTrackerFrame:UnregisterAllEvents() ObjectiveTrackerFrame:Hide() end + +--- Done any time the the minimize button is toggled up + +function mod:OnEnable() + for id, name in ipairs(mod.orderedNames) do + if not mod.orderedHandlers[id] then + Tracker_Initialize(mod.DefaultTracker, name, id) + end + end + + for event, func in pairs(mod) do + if type(func) == 'function' and event:match('^[A-Z_]+$') then + print('|cFFFF44FFlistening to', event) + Wrapper:RegisterEvent(event) + end + end + + local c = mod.Conf.Wrapper + Wrapper:SetPoint(c.AnchorPoint, UIParent, c.AnchorPoint, c.OffsetX, c.OffsetY) + B.Conf.FramePosition[Wrapper:GetName()] = {c.AnchorPoint, c.AnchorPoint, c.OffsetX, c.OffsetY} + Wrapper:SetWidth(c.Width) + + + mod.InitializeWidgets() + mod:Update() +end + +function mod:OnDisable() + +end + +