Mercurial > wow > buffalo2
diff Modules/BuffFrame.lua @ 59:07ef62fe201f
Re-write of BuffFrame module:
- uses secure hooks on blizzard BuffFrame.lua functions to determine needed action
- make use of built-in table behavior to reduce unnecessary frame updates
author | Nenue |
---|---|
date | Thu, 28 Jul 2016 18:27:56 -0400 |
parents | |
children | 2a636b00c31e |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Modules/BuffFrame.lua Thu Jul 28 18:27:56 2016 -0400 @@ -0,0 +1,315 @@ +-- Veneer +-- BuffFrame.lua +-- Created: 7/27/2016 8:08 PM +-- %file-revision% +-- +local PLUGIN_NAME = 'BuffFrame' +local plugin = {} +local vn, print = LibStub("LibKraken").register(VeneerController, plugin) + + + +local buttons = {} +local buffTypes = { + { + name = 'buff', + pattern = 'BuffButton(%d)', + filters = 'HELPFUL', + }, + { + name = 'debuff', + pattern = 'DebuffButton(%d)', + filters = 'HARMFUL', + }, + { + name = 'tempenchant', + pattern = 'TempEnchant(%d)', + filters = 'TEMPENCHANT' + } +} + +local textureMapping = { + [1] = 16, --Main hand + [2] = 17, --Off-hand + [3] = 18, --Ranged +} + +local tickCounter = {} +local aurasCache = {} +local skinnedFrames = {} +local pendingFrames = {} +local anchors = {} +local expirationCache = {} + +local VeneerButton_OnHide = function(self) + self:SetScript('OnDragStart', self.StartMoving) + self:SetScript('OnDragStop', self.StopMovingOrSizing) + self:SetMovable(true) + self:EnableMouse(true) + self:RegisterForDrag('LeftButton') +end +local VeneerButton_OnShow = function(self) + self:SetScript('OnDragStart', self.StartMoving) + self:SetScript('OnDragStop', self.StopMovingOrSizing) + self:SetMovable(true) + self:EnableMouse(true) + self:RegisterForDrag('LeftButton') +end + + +local GetVeneer = function(frame) + local name = frame:GetName() + if not _G[name..'Veneer'] then + + local veneer = CreateFrame('Frame', name..'Veneer', UIParent) + veneer:SetAllPoints(frame) + veneer.bg = veneer:CreateTexture() + veneer.bg:SetColorTexture(0,1,0,0.5) + veneer.bg:SetAllPoints(veneer) + veneer.bg:Hide() + veneer:Hide() + + veneer:SetScript('OnShow', VeneerButton_OnShow) + veneer:SetScript('OnHide', VeneerButton_OnHide) + + local position = tonumber(name:match("%d")) + if position == 1 then + veneer:Show() + end + + veneer.progress = CreateFrame('Frame', name .. 'VeneerProgress', veneer) + veneer.progress:Hide() + veneer.progress:SetPoint('BOTTOMLEFT', veneer, 'BOTTOMLEFT', 3, -6) + veneer.progress:SetPoint('TOPRIGHT', veneer, 'BOTTOMRIGHT', -3, -1) + + veneer.progress.bg = veneer.progress:CreateTexture(nil, 'BACKGROUND') + veneer.progress.bg:SetColorTexture(0,0,0,0.5) + veneer.progress.bg:SetAllPoints(veneer.progress) + + veneer.progress.fg = veneer.progress:CreateTexture(nil, 'ARTWORK') + veneer.progress.fg:SetColorTexture(0,1,0,1) + veneer.progress.fg:SetPoint('BOTTOMLEFT', 1,1) + veneer.progress.fg:SetPoint('TOP', 0, -1) + + veneer.progress.status = veneer.progress:CreateFontString() + veneer.progress.status:SetFontObject(VeneerNumberFont) + veneer.progress.status:SetPoint('TOP') + + end + + + return _G[name..'Veneer'] +end + +local UpdateVeneer = function (frame, duration, expires) + local veneer = GetVeneer(frame) + + if expires and duration then + veneer.progress:Show() + + local startTime = (expires - duration) + local endTime = expires or 0 + print('|cFF0088FF'..frame:GetName()..'|r', 'has expiration', startTime, 'to', endTime, 'over', duration, 'frame', veneer.progress:GetWidth()) + veneer.progress:SetScript('OnUpdate', function(self) + local w = floor(veneer.progress:GetWidth()+.5) + local t = GetTime() + local progress = (t - startTime) / duration + if t >= endTime or not frame:IsVisible() then + veneer.startTime = nil + self:SetScript('OnUpdate', nil) + self:Hide() + else + self.fg:SetWidth(w - ceil(w * progress) - 2) + end + end) + end + + + + veneer:Show() +end + + +-- Associates skinning elements with said button +local SkinFrame = function(name) + local frame = _G[name ] + if skinnedFrames[frame] then + print('|cFFFF4400Attempting to skin a frame that already went through.|r') + return + end + + local icon = _G[name .. 'Icon'] + local border = _G[name .. 'Border'] + local duration = _G[name .. 'Duration'] + local slot = frame:GetID() or 0 + + tickCounter[frame] = (tickCounter[frame] or 0) + 1 + + + print(tickCounter[frame], frame:GetName(), '|cFFFFFF00'..slot..'|r') + skinnedFrames[frame] = frame + frame:SetSize(48,48) + icon:SetTexCoord(0,1,0,1) + if border then + border:SetSize(50,50) + end + if duration then + duration:ClearAllPoints() + duration:SetPoint('BOTTOM') + duration:SetFontObject(VeneerNumberFont) + duration:SetDrawLayer('OVERLAY') + + end + + GetVeneer(frame) + + anchors[frame] = veneer + print('Initializing', name) +end + + +--- Provides the number of changed indices for use in deciding between partial and full veneer updates +local CacheCheck = function(frame, ...) + aurasCache[frame] = aurasCache[frame] or {} + local hasChange = 0 + local numVals = select('#',...) + for i = 1, numVals do + local arg = select(i, ...) + if aurasCache[frame][i] ~= arg then + hasChange = hasChange + 1 + end + aurasCache[frame][i] = arg + end + return hasChange +end + +local AuraButton_Update = function(name, index, filter) + local bName = name..index + local frame = _G[bName] + if frame and frame:IsVisible() then + tickCounter[frame] = (tickCounter[frame] or 0) + 1 + local cacheDiff = CacheCheck(frame, UnitAura(frame.unit, frame:GetID(), frame.filter)) + -- did something change? + if (cacheDiff >= 1) or not skinnedFrames[frame] then + print(frame:GetName(), 'diff:', cacheDiff) + tinsert(pendingFrames, frame) + end + + + if frame.expirationTime ~= expirationCache[name] then + print('|cFFBBFF00expirationTime|r', name, frame.expirationTime) + expirationCache[name] = frame.expirationTime + print(unpack(aurasCache[frame])) + UpdateVeneer(frame, aurasCache[frame][6], aurasCache[frame][7]) + end + + -- is it a new button? + if not skinnedFrames[frame] then + SkinFrame(bName) + end + end +end + +local BuffFrame_UpdateAllBuffAnchors = function() + local todo = {} + if #pendingFrames >= 1 then + + print('|cFFBBFF00AllBuffAnchors|r', #pendingFrames) + while pendingFrames[1] do + local frame = tremove(pendingFrames) + tinsert(todo, frame:GetName()) + + UpdateVeneer(frame) + + + end + print(table.concat(todo, ', ')) + end + --BuffButton1 + --DebuffButton1 + TempEnchant1:SetPoint('TOPRIGHT', BuffButton1, 'TOPRIGHT', BuffButton1:GetWidth()+4, 0) +end + +local AuraButton_UpdateDuration = function(frame, timeLeft) + local ts = '' + if timeLeft > 3600 then + ts = ts .. floor(timeLeft/3600) .. ':' + timeLeft = mod(timeLeft, 3600) + end + if timeLeft > 60 then + ts = ts .. floor(timeLeft/60) .. '\'' + timeLeft = mod(timeLeft, 60) + end + ts = ts .. floor(timeLeft)..'"' + + frame.duration:SetText(ts) + frame.duration:SetVertexColor(1,1,1) + +end + +local visibility = {} +local TempEnchantButton_OnHide = function(self) + local isVisible = self:IsVisible() + if isVisible ~= visibility[self] then + print('|cFFFFFF00HIDE|r', self:GetName()) + visibility[self] = isVisible + end +end + +-- Obtains the first instance of Tenchant use + +local TemporaryEnchantFrame_Update = function(...) + local numVals = select('#', ...) + local numItems = numVals / 4 + if numItems >= 1 then + for itemIndex = numItems, 1, -1 do + local frame = _G['TempEnchant'..itemIndex] + local hasEnchant, timeRemaining, enchantCharges = select((4 * (itemIndex -1)) + 1, ...) + + + if hasEnchant then + local endTime = floor(GetTime()*1000) + timeRemaining + + + --print(endTime) + if endTime ~= expirationCache[frame] then + if expirationCache[frame] then + print(endTime, expirationCache[frame], endTime - expirationCache[frame]) + end + expirationCache[frame] = endTime + print('push tempenchant timer update', timeRemaining / 1000, GetTime()+(timeRemaining/1000)) + UpdateVeneer(frame, timeRemaining/1000, GetTime()+(timeRemaining/1000)) + end + else + GetVeneer(frame):Hide() + end + + end + + end + +end + +local BuffFrame_Update = function(...) + --print('Time for udpate!', ...) +end + + +hooksecurefunc("BuffFrame_Update", BuffFrame_Update) +hooksecurefunc("AuraButton_UpdateDuration", AuraButton_UpdateDuration) +hooksecurefunc("AuraButton_Update", AuraButton_Update) +hooksecurefunc("BuffFrame_UpdateAllBuffAnchors", BuffFrame_UpdateAllBuffAnchors) +hooksecurefunc("TemporaryEnchantFrame_Update", TemporaryEnchantFrame_Update) + +-- The TempEnchant frames are hardcoded in the base FrameXML, so get them now +for i = 1, 3 do + + SkinFrame('TempEnchant'..i) + hooksecurefunc(_G['TempEnchant'..i], "Hide", TempEnchantButton_OnHide) + + +end + +plugin.init = function () + plugin.db = vn.db[PLUGIN_NAME] +end \ No newline at end of file