local MAJOR_VERSION = "LibGetFrame-1.0" local MINOR_VERSION = 24 if not LibStub then error(MAJOR_VERSION .. " requires LibStub.") end local lib = LibStub:NewLibrary(MAJOR_VERSION, MINOR_VERSION) if not lib then return end lib.callbacks = lib.callbacks or LibStub("CallbackHandler-1.0"):New(lib) local callbacks = lib.callbacks local GetPlayerInfoByGUID, UnitExists, IsAddOnLoaded, UnitIsUnit, SecureButton_GetUnit = GetPlayerInfoByGUID, UnitExists, IsAddOnLoaded, UnitIsUnit, SecureButton_GetUnit local tinsert, CopyTable, wipe = tinsert, CopyTable, wipe local maxDepth = 50 local defaultFramePriorities = { -- raid frames [1] = "^Vd1", -- vuhdo [2] = "^Vd2", -- vuhdo [3] = "^Vd3", -- vuhdo [4] = "^Vd4", -- vuhdo [5] = "^Vd5", -- vuhdo [6] = "^Vd", -- vuhdo [7] = "^HealBot", -- healbot [8] = "^GridLayout", -- grid [9] = "^Grid2Layout", -- grid2 [10] = "^PlexusLayout", -- plexus [11] = "^ElvUF_RaidGroup", -- elv [12] = "^oUF_bdGrid", -- bdgrid [13] = "^oUF_.-Raid", -- generic oUF [14] = "^LimeGroup", -- lime [15] = "^SUFHeaderraid", -- suf -- party frames [16] = "^AleaUI_GroupHeader", -- Alea [17] = "^SUFHeaderparty", --suf [18] = "^ElvUF_PartyGroup", -- elv [19] = "^oUF_.-Party", -- generic oUF [20] = "^PitBull4_Groups_Party", -- pitbull4 [21] = "^CompactRaid", -- blizz [22] = "^PartyMemberFrame", -- blizz -- player frame [23] = "^SUFUnitplayer", [24] = "^PitBull4_Frames_Player", [25] = "^ElvUF_Player", [26] = "^oUF_.-Player", [27] = "^PlayerFrame", } local defaultPlayerFrames = { "SUFUnitplayer", "PitBull4_Frames_Player", "ElvUF_Player", "oUF_.-Player", "oUF_PlayerPlate", "PlayerFrame", } local defaultTargetFrames = { "SUFUnittarget", "PitBull4_Frames_Target", "ElvUF_Target", "oUF_.-Target", "TargetFrame", } local defaultTargettargetFrames = { "SUFUnittargetarget", "PitBull4_Frames_Target's target", "ElvUF_TargetTarget", "oUF_.-TargetTarget", "oUF_ToT", "TargetTargetFrame", } local defaultPartyTargetFrames = { "SUFChildpartytarget%d", } local GetFramesCache = {} local FrameToUnitFresh = {} local FrameToUnit = {} local UpdatedFrames = {} local function ScanFrames(depth, frame, ...) if not frame then return end if depth < maxDepth then local frameType = frame:GetObjectType() if frameType == "Frame" or frameType == "Button" then ScanFrames(depth + 1, frame:GetChildren()) end if frameType == "Button" then local unit = SecureButton_GetUnit(frame) local name = frame:GetName() if unit and frame:IsVisible() and name then GetFramesCache[frame] = name if unit ~= FrameToUnit[frame] then FrameToUnit[frame] = unit UpdatedFrames[frame] = unit end FrameToUnitFresh[frame] = unit end end end ScanFrames(depth, ...) end local wait = false local function doScanForUnitFrames() wait = false wipe(UpdatedFrames) wipe(GetFramesCache) wipe(FrameToUnitFresh) ScanFrames(0, UIParent) callbacks:Fire("GETFRAME_REFRESH") for frame, unit in pairs(UpdatedFrames) do callbacks:Fire("FRAME_UNIT_UPDATE", frame, unit) end for frame, unit in pairs(FrameToUnit) do if FrameToUnitFresh[frame] ~= unit then callbacks:Fire("FRAME_UNIT_REMOVED", frame, unit) FrameToUnit[frame] = nil end end end local waitFrame = CreateFrame("Frame") local function waitFrame_OnUpdate(self, elapsed) self.delay = (self.delay or 1) - elapsed if self.delay < elapsed then doScanForUnitFrames() self:SetScript("OnUpdate", nil) self.delay = nil end end local function ScanForUnitFrames(noDelay) if noDelay then doScanForUnitFrames() elseif not wait then wait = true waitFrame:SetScript("OnUpdate", waitFrame_OnUpdate) end end local function isFrameFiltered(name, ignoredFrames) for _, filter in pairs(ignoredFrames) do if name:find(filter) then return true end end return false end local function GetUnitFrames(target, ignoredFrames) if not UnitExists(target) then if type(target) == "string" and target:find("Player") then target = select(6, GetPlayerInfoByGUID(target)) else target = target:gsub(" .*", "") if not UnitExists(target) then return end end end local frames for frame, frameName in pairs(GetFramesCache) do local unit = SecureButton_GetUnit(frame) if unit and UnitIsUnit(unit, target) and not isFrameFiltered(frameName, ignoredFrames) then frames = frames or {} frames[frame] = frameName end end return frames end local function ElvuiWorkaround(frame) if IsAddOnLoaded("ElvUI") and frame and frame:GetName():find("^ElvUF_") and frame.Health then return frame.Health else return frame end end local defaultOptions = { framePriorities = defaultFramePriorities, ignorePlayerFrame = true, ignoreTargetFrame = true, ignoreTargettargetFrame = true, ignorePartyTargetFrame = true, playerFrames = defaultPlayerFrames, targetFrames = defaultTargetFrames, targettargetFrames = defaultTargettargetFrames, partyTargetFrames = defaultPartyTargetFrames, ignoreFrames = { "PitBull4_Frames_Target's target's target", "ElvUF_PartyGroup%dUnitButton%dTarget", "ElvUF_FocusTarget", "RavenButton" }, returnAll = false, } local GetFramesCacheListener local function Init(noDelay) GetFramesCacheListener = CreateFrame("Frame") GetFramesCacheListener:RegisterEvent("PLAYER_REGEN_DISABLED") GetFramesCacheListener:RegisterEvent("PLAYER_REGEN_ENABLED") GetFramesCacheListener:RegisterEvent("PLAYER_ENTERING_WORLD") GetFramesCacheListener:RegisterEvent("PARTY_MEMBERS_CHANGED") GetFramesCacheListener:RegisterEvent("RAID_ROSTER_UPDATE") GetFramesCacheListener:SetScript("OnEvent", function() ScanForUnitFrames(false) end) ScanForUnitFrames(noDelay) end function lib.GetUnitFrame(target, opt) if type(GetFramesCacheListener) ~= "table" then Init(true) end opt = opt or {} setmetatable(opt, { __index = defaultOptions }) if not target then return end local ignoredFrames = CopyTable(opt.ignoreFrames) if opt.ignorePlayerFrame then for _,v in pairs(opt.playerFrames) do tinsert(ignoredFrames, v) end end if opt.ignoreTargetFrame then for _,v in pairs(opt.targetFrames) do tinsert(ignoredFrames, v) end end if opt.ignoreTargettargetFrame then for _,v in pairs(opt.targettargetFrames) do tinsert(ignoredFrames, v) end end if opt.ignorePartyTargetFrame then for _,v in pairs(opt.partyTargetFrames) do tinsert(ignoredFrames, v) end end local frames = GetUnitFrames(target, ignoredFrames) if not frames then return end if not opt.returnAll then for i = 1, #opt.framePriorities do for frame, frameName in pairs(frames) do if frameName:find(opt.framePriorities[i]) then return ElvuiWorkaround(frame) end end end local next = next return ElvuiWorkaround(next(frames)) else for frame in pairs(frames) do frames[frame] = ElvuiWorkaround(frame) end return frames end end lib.GetFrame = lib.GetUnitFrame -- compatibility