mirror of
https://github.com/brues-code/pfUI.git
synced 2026-11-01 08:26:57 +00:00
Follow target-of-target frames with UNIT_TARGET
A frame whose unit is another unit's target (targettarget, targettargettarget, pettarget, focustarget, partyNtarget) has no token that unit events name, so it polled: bars every 0.2s, a full aura and portrait rescan every second, and a GUID compare to notice swaps. Such a frame now registers its unit events by the unit's GUID, which every unit event also fires with, and UNIT_TARGET by the GUID of every link of its chain. A link retargeting re-points the frame at once and queues one full refresh; the ticks are gone. The 0.2s visibility timer stays for them, since nothing reports a unit going out of sight. Nameplates register UNIT_TARGET on their own token, so a mob turning to someone else recolours its combat state immediately instead of after the colour cache and data tick run out. Drop pfScanActive and the namebuf delay: both guarded against the old target-swapping range scan, which no longer exists. focus.lua's instantRefresh was never read.
This commit is contained in:
+94
-59
@@ -216,13 +216,14 @@ local function DebuffOnClick()
|
||||
end
|
||||
|
||||
-- Every enabled unit frame. Group, target and pet events re-check a frame's
|
||||
-- visibility in OnEvent. A frame with a tick shows another unit's target or a
|
||||
-- pet that can go out of sight, and no event reports either, so a timer
|
||||
-- re-checks those frames, hidden ones included.
|
||||
-- visibility in OnEvent, and UNIT_TARGET does for a chained unit (another
|
||||
-- unit's target). No event reports a unit going out of sight, though, and a
|
||||
-- pet (the frames with a tick) or a chained unit can, so a timer re-checks
|
||||
-- those frames, hidden ones included.
|
||||
local visibilityframes = {}
|
||||
C_Timer.NewTicker(.2, function()
|
||||
for frame in pairs(visibilityframes) do
|
||||
if frame.tick then frame:UpdateVisibility() end
|
||||
if frame.tick or frame.chain then frame:UpdateVisibility() end
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -239,6 +240,7 @@ local VISIBILITY_EVENTS = {
|
||||
RAID_ROSTER_UPDATE = true,
|
||||
PLAYER_TARGET_CHANGED = true,
|
||||
UNIT_PET = true,
|
||||
UNIT_TARGET = true, -- a link of a chained frame's unit retargeted
|
||||
}
|
||||
|
||||
-- ============================================================================
|
||||
@@ -443,7 +445,24 @@ function pfUI.uf:UpdateVisibility()
|
||||
-- rebuilding label..id -- and calling UnitGUID -- for every unit event fired
|
||||
-- by anything, anywhere. A frame that is not in use drops them entirely; the
|
||||
-- VISIBILITY_EVENTS that bring it back are registered plainly.
|
||||
self:RegisterUnitEvents(visibility ~= "hide" and self.unitstr or nil)
|
||||
--
|
||||
-- A chained unit -- another unit's target, "targettarget" or "party1target"
|
||||
-- -- has no token that unit events name, so the frame follows it by GUID,
|
||||
-- which every unit event also fires with. It follows the unit only while
|
||||
-- the client has it: a link's target can be out of sight, and its coming
|
||||
-- back is then a new unit too. The unit changes with no event of its own
|
||||
-- whenever a link of the chain retargets; UNIT_TARGET on every link reports
|
||||
-- that (RegisterChainEvents), and the GUID compare turns it into the full
|
||||
-- refresh a new unit needs.
|
||||
self.chain = visibility ~= "hide" and unitstr:match("^(.+)target$") or nil
|
||||
if self.chain then
|
||||
local guid = UnitName(unitstr) and UnitGUID(unitstr)
|
||||
if guid ~= self.eventunit then self.update_full = true end
|
||||
self:RegisterUnitEvents(guid)
|
||||
else
|
||||
self:RegisterUnitEvents(visibility ~= "hide" and unitstr or nil)
|
||||
end
|
||||
self:RegisterChainEvents(self.chain)
|
||||
|
||||
-- vanilla visibility
|
||||
if visibility == "hide" then
|
||||
@@ -970,9 +989,10 @@ function pfUI.uf:UpdateConfig()
|
||||
f:UpdateFrameSize()
|
||||
else
|
||||
f:UnregisterAllEvents()
|
||||
-- that dropped the unit filters along with the registrations, so the cache
|
||||
-- has to go too or the next UpdateVisibility believes they are still set
|
||||
f.eventunit = nil
|
||||
-- that dropped the unit filters along with the registrations, so the
|
||||
-- caches have to go too or the next UpdateVisibility believes they are
|
||||
-- still set
|
||||
f.eventunit, f.chainkey = nil, nil
|
||||
f:Hide()
|
||||
end
|
||||
end
|
||||
@@ -1011,7 +1031,7 @@ function pfUI.uf.OnEvent()
|
||||
|
||||
-- a hidden frame runs no OnUpdate, so its unit coming into existence has to
|
||||
-- show it from here
|
||||
if VISIBILITY_EVENTS[event] and not (event == "PLAYER_TARGET_CHANGED" and pfScanActive) then
|
||||
if VISIBILITY_EVENTS[event] then
|
||||
this:UpdateVisibility()
|
||||
end
|
||||
|
||||
@@ -1020,7 +1040,7 @@ function pfUI.uf.OnEvent()
|
||||
this.update_full = true
|
||||
-- Clear GUID tracking on zone change for full rebuild
|
||||
if pfUI.uf.ClearGuidTracking then pfUI.uf.ClearGuidTracking() end
|
||||
elseif this.label == "target" and event == "PLAYER_TARGET_CHANGED" and not pfScanActive == true then
|
||||
elseif this.label == "target" and event == "PLAYER_TARGET_CHANGED" then
|
||||
this.update_full = true
|
||||
-- immediately update raid icon to avoid delay on target swap
|
||||
if this.raidIcon and this.config and this.config.raidicon == "1" then
|
||||
@@ -1064,12 +1084,12 @@ function pfUI.uf.OnEvent()
|
||||
this.update_aura = true
|
||||
elseif this.label == "pet" and event == "UNIT_HAPPINESS" then
|
||||
this.update_full = true
|
||||
-- UNIT_XXX Events. RegisterUnitEvents means arg1 can only be this frame's own
|
||||
-- unit; the compare is kept for the case the filter sits out, which is when
|
||||
-- arg1 is not a string. The old GUID alternative is gone: these events fire
|
||||
-- once per token that resolves to the unit AND once with the raw GUID, so the
|
||||
-- token form always arrives and the GUID form was only ever a duplicate wake.
|
||||
elseif arg1 and arg1 == this.unitstr then
|
||||
-- UNIT_XXX Events. RegisterUnitEvents means arg1 can only be the unit this
|
||||
-- frame follows -- its token, or a chained unit's GUID; the compare is kept
|
||||
-- for the case the filter sits out, which is when arg1 is not a string. These
|
||||
-- events fire once per token that resolves to the unit AND once with the raw
|
||||
-- GUID, so filtering on one of the two never wakes the frame twice.
|
||||
elseif arg1 and arg1 == this.eventunit then
|
||||
if event == "UNIT_PORTRAIT_UPDATE" or event == "UNIT_MODEL_CHANGED" then
|
||||
this.update_portrait = true
|
||||
elseif event == "UNIT_AURA" then
|
||||
@@ -1148,31 +1168,18 @@ function pfUI.uf.OnUpdate()
|
||||
local unitstr = this.label .. this.id
|
||||
this.lastTick = now + (tickInterval or .5)
|
||||
|
||||
-- target target has a huge delay, make sure to not tick during range checks
|
||||
if this.label == "targettarget" or this.label == "targettargettarget" then
|
||||
local name = UnitName(this.label)
|
||||
if name ~= this.namebuf1 then
|
||||
this.namebuf1 = name
|
||||
elseif name ~= this.namebuf2 then
|
||||
this.namebuf2 = name
|
||||
else
|
||||
pfUI.uf:RefreshUnitState(this)
|
||||
pfUI.uf:RefreshUnitState(this)
|
||||
-- group frames get their leader/loot/raid mark icons refreshed by
|
||||
-- events through update_indicators, so polling them is only a safety
|
||||
-- net; the other frames keep polling per tick
|
||||
local label = this.label
|
||||
if label == "raid" or label == "party" or label == "raidpet" or label == "partypet" then
|
||||
if (this.lastIndicatorPoll or 0) < now then
|
||||
this.lastIndicatorPoll = now + 3
|
||||
pfUI.uf:RefreshIndicators(this)
|
||||
end
|
||||
else
|
||||
pfUI.uf:RefreshUnitState(this)
|
||||
-- group frames get their leader/loot/raid mark icons refreshed by
|
||||
-- events through update_indicators, so polling them is only a safety
|
||||
-- net; frames whose unit changes without events keep polling per tick
|
||||
local label = this.label
|
||||
if label == "raid" or label == "party" or label == "raidpet" or label == "partypet" then
|
||||
if (this.lastIndicatorPoll or 0) < now then
|
||||
this.lastIndicatorPoll = now + 3
|
||||
pfUI.uf:RefreshIndicators(this)
|
||||
end
|
||||
else
|
||||
pfUI.uf:RefreshIndicators(this)
|
||||
end
|
||||
pfUI.uf:RefreshIndicators(this)
|
||||
end
|
||||
|
||||
if this.config and this.config.glowaggro == "1" and pfUI.api.UnitHasAggro(unitstr) > 0 then
|
||||
@@ -1185,9 +1192,10 @@ function pfUI.uf.OnUpdate()
|
||||
this.glow:Hide()
|
||||
end
|
||||
|
||||
-- update eventless frames (targettarget, etc). A full refresh rescans
|
||||
-- every aura and the portrait, so only do it when the unit behind the
|
||||
-- frame changes or once a second; other ticks refresh the bars only.
|
||||
-- update polled frames (the pets, created with a tick). A full refresh
|
||||
-- rescans every aura and the portrait, so only do it when the unit
|
||||
-- behind the frame changes or once a second; other ticks refresh the
|
||||
-- bars only.
|
||||
if this.tick then
|
||||
local guid = UnitGUID(unitstr)
|
||||
if guid ~= this.tickGuid or (this.tickFull or 0) < now then
|
||||
@@ -1330,16 +1338,17 @@ local UNIT_EVENTS = {
|
||||
"INCOMING_RESURRECT_CHANGED", -- frame=ressIcon
|
||||
}
|
||||
|
||||
-- Point this frame's unit-event subscriptions at `unitstr`, or drop them when
|
||||
-- the frame has no unit. Cheap to call repeatedly: it no-ops unless the unit
|
||||
-- actually changed, which matters because every refresh runs UpdateVisibility.
|
||||
function pfUI.uf:RegisterUnitEvents(unitstr)
|
||||
if self.eventunit == unitstr then return end
|
||||
self.eventunit = unitstr
|
||||
-- Point this frame's unit-event subscriptions at `unit` (a token, or a chained
|
||||
-- unit's GUID), or drop them when the frame has no unit. Cheap to call
|
||||
-- repeatedly: it no-ops unless the unit actually changed, which matters
|
||||
-- because every refresh runs UpdateVisibility.
|
||||
function pfUI.uf:RegisterUnitEvents(unit)
|
||||
if self.eventunit == unit then return end
|
||||
self.eventunit = unit
|
||||
|
||||
for i = 1, table.getn(UNIT_EVENTS) do
|
||||
if unitstr then
|
||||
self:RegisterUnitEvent(UNIT_EVENTS[i], unitstr)
|
||||
if unit then
|
||||
self:RegisterUnitEvent(UNIT_EVENTS[i], unit)
|
||||
else
|
||||
self:UnregisterEvent(UNIT_EVENTS[i])
|
||||
end
|
||||
@@ -1348,13 +1357,42 @@ function pfUI.uf:RegisterUnitEvents(unitstr)
|
||||
-- UNIT_COMBAT rides along only while the frame draws combat feedback text.
|
||||
-- UpdateConfig clears eventunit when it toggles that, so the next
|
||||
-- UpdateVisibility re-runs this.
|
||||
if unitstr and self.combatfeedback then
|
||||
self:RegisterUnitEvent("UNIT_COMBAT", unitstr)
|
||||
if unit and self.combatfeedback then
|
||||
self:RegisterUnitEvent("UNIT_COMBAT", unit)
|
||||
else
|
||||
self:UnregisterEvent("UNIT_COMBAT")
|
||||
end
|
||||
end
|
||||
|
||||
-- Point this frame's UNIT_TARGET subscription at every link of its chained
|
||||
-- unit, whose `owner` is the unit it is the target of -- for
|
||||
-- "targettargettarget" the links are "targettarget" and "target" -- or drop it
|
||||
-- when `owner` is nil. By GUID, since the inner links are no token that events
|
||||
-- name. Cheap to call repeatedly: it re-registers only when a link changed.
|
||||
local chainlinks = {}
|
||||
function pfUI.uf:RegisterChainEvents(owner)
|
||||
local n, key = 0, nil
|
||||
while owner do
|
||||
local guid = UnitGUID(owner)
|
||||
if guid then
|
||||
n = n + 1
|
||||
chainlinks[n] = guid
|
||||
key = key and key .. guid or guid
|
||||
end
|
||||
owner = owner:match("^(.+)target$")
|
||||
end
|
||||
|
||||
if key == self.chainkey then return end
|
||||
self.chainkey = key
|
||||
|
||||
if key then
|
||||
for i = table.getn(chainlinks), n + 1, -1 do chainlinks[i] = nil end
|
||||
self:RegisterUnitEvent("UNIT_TARGET", unpack(chainlinks))
|
||||
else
|
||||
self:UnregisterEvent("UNIT_TARGET")
|
||||
end
|
||||
end
|
||||
|
||||
function pfUI.uf:EnableEvents()
|
||||
local f = self
|
||||
|
||||
@@ -1473,6 +1511,7 @@ function pfUI.uf:CreateUnitFrame(unit, id, config, tick)
|
||||
f.EnableScripts = pfUI.uf.EnableScripts
|
||||
f.EnableEvents = pfUI.uf.EnableEvents
|
||||
f.RegisterUnitEvents = pfUI.uf.RegisterUnitEvents
|
||||
f.RegisterChainEvents = pfUI.uf.RegisterChainEvents
|
||||
f.EnableClickCast = pfUI.uf.EnableClickCast
|
||||
f.GetColor = pfUI.uf.GetColor
|
||||
|
||||
@@ -1593,9 +1632,10 @@ function pfUI.uf:CreateUnitFrame(unit, id, config, tick)
|
||||
f:UpdateFrameSize()
|
||||
else
|
||||
f:UnregisterAllEvents()
|
||||
-- that dropped the unit filters along with the registrations, so the cache
|
||||
-- has to go too or the next UpdateVisibility believes they are still set
|
||||
f.eventunit = nil
|
||||
-- that dropped the unit filters along with the registrations, so the
|
||||
-- caches have to go too or the next UpdateVisibility believes they are
|
||||
-- still set
|
||||
f.eventunit, f.chainkey = nil, nil
|
||||
f:Hide()
|
||||
end
|
||||
|
||||
@@ -1750,11 +1790,6 @@ function pfUI.uf:RefreshUnit(unit, component)
|
||||
if not unit.id then unit.id = "" end
|
||||
component = component or ""
|
||||
|
||||
-- don't update scanner activity
|
||||
if unit.label == "target" or unit.label == "targettarget" or unit.label == "targettargettarget" then
|
||||
if pfScanActive == true then return end
|
||||
end
|
||||
|
||||
-- hide unused and invalid frames
|
||||
unit:UpdateVisibility()
|
||||
|
||||
|
||||
+6
-7
@@ -8,7 +8,7 @@ pfUI:RegisterModule("focus", function ()
|
||||
UpdateMovable(pfUI.uf.focus)
|
||||
pfUI.uf.focus:Hide()
|
||||
|
||||
pfUI.uf.focustarget = pfUI.uf:CreateUnitFrame("FocusTarget", nil, C.unitframes.focustarget, .2)
|
||||
pfUI.uf.focustarget = pfUI.uf:CreateUnitFrame("FocusTarget", nil, C.unitframes.focustarget)
|
||||
pfUI.uf.focustarget:UpdateFrameSize()
|
||||
pfUI.uf.focustarget:SetPoint("BOTTOMLEFT", pfUI.uf.focus, "TOP", 0, 10)
|
||||
UpdateMovable(pfUI.uf.focustarget)
|
||||
@@ -16,14 +16,13 @@ pfUI:RegisterModule("focus", function ()
|
||||
|
||||
-- PLAYER_FOCUS_CHANGED drives immediate refresh on focus assign / clear.
|
||||
-- Between events, ClassicAPI fires UNIT_* (health/mana/aura/...) with
|
||||
-- arg1 == "focus" and arg1 == "focustarget", so the bars update
|
||||
-- event-driven like target. No event reports the focus changing its
|
||||
-- target, so focustarget ticks like targettarget.
|
||||
-- arg1 == "focus", so the bars update event-driven like target.
|
||||
-- focustarget is a chained unit like targettarget: UNIT_TARGET follows the
|
||||
-- focus retargeting, and a new focus only needs its visibility re-checked,
|
||||
-- which queues the full refresh when its target is a different unit.
|
||||
pfUI.events:RegisterFrameEventAndCallback("PLAYER_FOCUS_CHANGED", function()
|
||||
pfUI.uf.focus.instantRefresh = true
|
||||
pfUI.uf:RefreshUnit(pfUI.uf.focus, "all")
|
||||
pfUI.uf.focustarget.instantRefresh = true
|
||||
pfUI.uf:RefreshUnit(pfUI.uf.focustarget, "all")
|
||||
pfUI.uf.focustarget:UpdateVisibility()
|
||||
end)
|
||||
end)
|
||||
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ pfUI:RegisterModule("group", function ()
|
||||
end
|
||||
|
||||
if C.unitframes.grouptarget.visible == "1" and active then
|
||||
pfUI.uf.group[i].target = pfUI.uf.group[i].target or pfUI.uf:CreateUnitFrame("Party" .. i .. "Target", nil, C.unitframes.grouptarget, 0.2)
|
||||
pfUI.uf.group[i].target = pfUI.uf.group[i].target or pfUI.uf:CreateUnitFrame("Party" .. i .. "Target", nil, C.unitframes.grouptarget)
|
||||
pfUI.uf.group[i].target:UpdateFrameSize()
|
||||
pfUI.uf.group[i].target:SetPoint("TOPLEFT", pfUI.uf.group[i], "TOPRIGHT", 3*default_border, 0)
|
||||
pfUI.uf.group[i].target:UpdateConfig()
|
||||
|
||||
@@ -608,6 +608,7 @@ nameplates:RegisterUnitEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE", "target", "focu
|
||||
-- RegisterUnitEvent on an already-filtered registration swaps the units.
|
||||
plate.nameplate:RegisterUnitEvent("UNIT_AURA", arg1)
|
||||
plate.nameplate:RegisterUnitEvent("UNIT_FLAGS", arg1)
|
||||
plate.nameplate:RegisterUnitEvent("UNIT_TARGET", arg1)
|
||||
plate.nameplate:RegisterUnitEvent("UNIT_SPELLCAST_START", arg1)
|
||||
plate.nameplate:RegisterUnitEvent("UNIT_SPELLCAST_CHANNEL_START", arg1)
|
||||
plate.nameplate:RegisterUnitEvent("UNIT_SPELLCAST_STOP", arg1)
|
||||
@@ -765,6 +766,14 @@ nameplates:RegisterUnitEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE", "target", "focu
|
||||
this.auraUpdate = true
|
||||
elseif event == "UNIT_FLAGS" then
|
||||
this.eventcache = true
|
||||
elseif event == "UNIT_TARGET" then
|
||||
-- the unit turned to someone else: recolour its combat state now
|
||||
-- rather than once the colour cache and the data tick run out
|
||||
if cfg.outcombatstate or cfg.barcombatstate then
|
||||
local cached = this.cachedGuid and combatColorCache[this.cachedGuid]
|
||||
if cached then cached.expires = 0 end
|
||||
this.eventcache = true
|
||||
end
|
||||
elseif event == "UNIT_SPELLCAST_START" or event == "UNIT_SPELLCAST_CHANNEL_START" then
|
||||
-- the payload carries no timing, so poll it (PollCastInfo picks cast
|
||||
-- vs channel)
|
||||
|
||||
@@ -3,7 +3,7 @@ pfUI:RegisterModule("pettarget", function ()
|
||||
if C.unitframes.disable == "1" then return end
|
||||
local rawborder, default_border = GetBorderSize("unitframes")
|
||||
|
||||
pfUI.uf.pettarget = pfUI.uf:CreateUnitFrame("PetTarget", nil, C.unitframes.ptarget, .2)
|
||||
pfUI.uf.pettarget = pfUI.uf:CreateUnitFrame("PetTarget", nil, C.unitframes.ptarget)
|
||||
pfUI.uf.pettarget:UpdateFrameSize()
|
||||
pfUI.uf.pettarget:SetPoint("TOP", pfUI.uf.pet or pfUI.uf.target or UIParent, "BOTTOM", 0, -default_border)
|
||||
UpdateMovable(pfUI.uf.pettarget)
|
||||
|
||||
@@ -2,7 +2,7 @@ pfUI:RegisterModule("targettarget", function ()
|
||||
-- do not go further on disabled UFs
|
||||
if C.unitframes.disable == "1" then return end
|
||||
|
||||
pfUI.uf.targettarget = pfUI.uf:CreateUnitFrame("TargetTarget", nil, C.unitframes.ttarget, .2)
|
||||
pfUI.uf.targettarget = pfUI.uf:CreateUnitFrame("TargetTarget", nil, C.unitframes.ttarget)
|
||||
pfUI.uf.targettarget:UpdateFrameSize()
|
||||
pfUI.uf.targettarget:SetPoint("BOTTOM", UIParent , "BOTTOM", 0, 125)
|
||||
UpdateMovable(pfUI.uf.targettarget)
|
||||
|
||||
@@ -2,7 +2,7 @@ pfUI:RegisterModule("targettargettarget", function ()
|
||||
-- do not go further on disabled UFs
|
||||
if C.unitframes.disable == "1" then return end
|
||||
|
||||
pfUI.uf.targettargettarget = pfUI.uf:CreateUnitFrame("TargetTargetTarget", nil, C.unitframes.tttarget, .2)
|
||||
pfUI.uf.targettargettarget = pfUI.uf:CreateUnitFrame("TargetTargetTarget", nil, C.unitframes.tttarget)
|
||||
pfUI.uf.targettargettarget:UpdateFrameSize()
|
||||
pfUI.uf.targettargettarget:SetPoint("BOTTOM", UIParent , "BOTTOM", 0, 200)
|
||||
UpdateMovable(pfUI.uf.targettargettarget)
|
||||
|
||||
Reference in New Issue
Block a user