diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c47d729..5d52e483 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/DandersFrames/Features/Auras.lua b/DandersFrames/Features/Auras.lua index a45ce454..773db352 100644 --- a/DandersFrames/Features/Auras.lua +++ b/DandersFrames/Features/Auras.lua @@ -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. @@ -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 @@ -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 @@ -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 diff --git a/DandersFrames/Features/ElementAppearance.lua b/DandersFrames/Features/ElementAppearance.lua index 98eb769f..08b3e390 100644 --- a/DandersFrames/Features/ElementAppearance.lua +++ b/DandersFrames/Features/ElementAppearance.lua @@ -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 diff --git a/DandersFrames/Frames/AuraContainer.lua b/DandersFrames/Frames/AuraContainer.lua index 15085fe7..0262cc2d 100644 --- a/DandersFrames/Frames/AuraContainer.lua +++ b/DandersFrames/Frames/AuraContainer.lua @@ -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