Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# DandersFrames Changelog

## [Unreleased]

### Bug Fixes

* (Aura Designer) Fix layout and filter group indicators staying at full brightness on out-of-range players when element-specific fading is on — placed indicators faded, groups next to them did not. (by Krathe)

## [5.3.1]

### New Features
Expand Down
30 changes: 30 additions & 0 deletions DandersFrames/Features/Auras.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2449,6 +2449,33 @@ local function rowTuningSig(cfg)
}, "|")
end

-- ☠ CONFIRM THE RETARGET ACTUALLY RE-PARSED, AND SAY SO WHEN IT DID NOT.
-- NativeBackend:setUnit already does a partition bounce out of combat, which is SUPPOSED to
-- make the container drop the previous occupant's parse. Field evidence says it does not
-- always land: a shaman's own Earth Shield stayed on a frame after "party3 -> party2", out
-- of combat, with the log showing the three retargets and then nothing at all
-- (2026-08-26 22:14). A buff nobody re-casts generates no UNIT_AURA on the new unit, so a
-- missed re-parse has nothing to correct it and the icon sits there until a reload.
--
-- Handle:Refresh is the addon-callable re-parse and it RETURNS whether a genuine one
-- happened, so this is a fix and an instrument at once: it forces the parse, and a "did NOT
-- happen" line is the bounce having failed rather than an unexplained icon.
-- ✅ Source-confirmed combat-safe (see the note on Handle:Refresh). No combat gate needed
-- anyway — in combat the retarget itself defers to regen, so this cannot be reached there.
-- ⚠ Cheap: the drives call this only on an ACTUAL unit change, never per pass.
local function confirmRetarget(h, label, unit)
if not (h and h.Refresh) then return end
local ok, reparsed = pcall(h.Refresh, h)
if not ok then
DF:DebugWarn("AURAROW", "%s: retarget re-parse THREW on %s", label, tostring(unit))
elseif not reparsed then
DF:DebugWarn("AURAROW", "%s: retarget re-parse did NOT happen on %s - the row may "
.. "still be showing the previous occupant", label, tostring(unit))
else
DF:Debug("AURAROW", "%s: retarget re-parsed on %s", label, tostring(unit))
end
end

-- Drive the factory buff row for one frame. Creates the container lazily, hides the legacy
-- icons (no double row), keeps it on the frame's unit, and applies setting changes. The
-- container self-updates from UNIT_AURA, so there is no per-tick render here.
Expand Down Expand Up @@ -2493,6 +2520,7 @@ function DF:DriveBuffFactory(frame, db)
InCombatLockdown() and " (in combat: row hidden until regen)" or "")
h:SetUnit(frame.unit)
frame.dfBuffFactoryHidden = InCombatLockdown() or nil
if not InCombatLockdown() then confirmRetarget(h, "buff", frame.unit) end
elseif frame.dfBuffFactoryHidden and not InCombatLockdown() then
DF:Debug("AURAROW", "buff: regen, unhiding row after deferred retarget")
frame.dfBuffFactoryHidden = nil
Expand Down Expand Up @@ -2695,6 +2723,7 @@ function DF:DriveDebuffFactory(frame, db)
InCombatLockdown() and " (in combat: row hidden until regen)" or "")
h:SetUnit(frame.unit)
frame.dfDebuffFactoryHidden = InCombatLockdown() or nil
if not InCombatLockdown() then confirmRetarget(h, "debuff", frame.unit) end
elseif frame.dfDebuffFactoryHidden and not InCombatLockdown() then
DF:Debug("AURAROW", "debuff: regen, unhiding row after deferred retarget")
frame.dfDebuffFactoryHidden = nil
Expand Down Expand Up @@ -3002,6 +3031,7 @@ function DF:DriveDefensiveFactory(frame, db)
InCombatLockdown() and " (in combat: row hidden until regen)" or "")
h:SetUnit(frame.unit)
frame.dfDefFactoryHidden = InCombatLockdown() or nil
if not InCombatLockdown() then confirmRetarget(h, "defensive", frame.unit) end
elseif frame.dfDefFactoryHidden and not InCombatLockdown() then
DF:Debug("AURAROW", "defensive: regen, unhiding row after deferred retarget")
frame.dfDefFactoryHidden = nil
Expand Down
18 changes: 17 additions & 1 deletion DandersFrames/Features/ElementAppearance.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1431,8 +1431,24 @@ end
-- regions hangs off — its own anchor frame for a container, dfLevelHost for a
-- collapsed slot — so fading it fades the indicator whole. Nil only if host creation
-- failed, hence the guard. See SlotHandle:GetAlphaHost.
-- ☠☠ "fgroups"/"dgroups" WERE MISSING FROM THIS LIST, AND THAT WAS THE WHOLE
-- "AD groups don't fade out of range" bug (element mode, 2026-08-26). The Factory's own
-- retarget list names all eight stores; this one named six. Group containers therefore
-- had NO alpha writer at all in element mode — the frame is pinned at base there, so the
-- cascade that covers them in whole-frame mode never runs, and nothing else touches them.
-- Placed indicators kept fading (slot-owner anchor), which made it look like the old
-- anchor fix had regressed. It had not: groups are a different pathway that never had the
-- fade wired.
-- ⚠ Krathe's differential located it — "my AD single PI is working, it's a group that
-- doesn't fade" — after four wrong theories from me about the anchor path.
-- ★ Group handles are ROW handles: entry.handle.button is nil, so the walk's existing
-- callback routes them onto the fade branch (base-only in whole-frame mode, where the
-- cascade already fades them — no squared fade, see [ad_oor_fade_two_layers]).
-- ☠ If the Factory ever grows a ninth store, IT GOES IN BOTH LISTS — this one and the
-- retarget walk at Factory.lua ~5464 — or its containers will silently skip either fades
-- or unit reassignment.
local AD_STORE_KEYS = { "healthbar", "background", "border", "placed",
"nametext", "healthtext" }
"nametext", "healthtext", "fgroups", "dgroups" }

-- ☠ THE WRITE IS PROTECTED, AND A DENIED HOST IS REMEMBERED.
-- GetAlphaHost is supposed to answer with a DF-owned frame, so in principle a tainted
Expand Down
19 changes: 19 additions & 0 deletions DandersFrames/Frames/AuraContainer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6698,6 +6698,25 @@ local function ensureOwner(frame, unit)
owner = { frame = frame, anchor = anchor, container = c, unit = unit, slots = {}, seq = 0 }
frame.dfSlotOwner = owner
AuraContainer.stats.slotOwners = (AuraContainer.stats.slotOwners or 0) + 1

-- ★ SEED THE APPEARANCE AT BIRTH — defensive, not a diagnosis.
-- In element-fade mode this anchor is the only thing that fades slot-backed Aura
-- Designer indicators, the pass that writes it runs on a range EDGE, and the owner is
-- stood up LAZILY on first slot acquisition. An anchor born while its unit is already
-- out of range would therefore start at full alpha with no further edge to correct it;
-- this call closes that ordering hole. Idempotent (the pass recomputes from db + the
-- frame's own range state) and effectively a no-op in whole-frame mode, where the
-- unit-frame cascade covers the anchor anyway.
--
-- ⚠ HONEST STATUS: this shipped mid-hunt as THE fix for "AD indicators don't fade out
-- of range" (2026-08-26) and it was NOT that bug — the field fault was group
-- containers being absent from ElementAppearance's AD_STORE_KEYS walk entirely, fixed
-- separately. The birth-order hole above is real but was never proven to be biting.
-- Kept because it is one cheap call at a rare event; if it is ever suspected of
-- misbehaving, deleting it outright is safe.
if DF.UpdateAuraDesignerAppearance then
pcall(DF.UpdateAuraDesignerAppearance, DF, frame)
end
return owner
end

Expand Down