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:
Brues
2026-10-31 06:27:21 -05:00
parent 45bc65b3c0
commit a9542bd467
7 changed files with 113 additions and 70 deletions
+6 -7
View File
@@ -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
View File
@@ -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()
+9
View File
@@ -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)
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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)