Fix(Unit Frames): keep the frame built when Visibility is set to Never - #1888
Merged
EllesmereGaming merged 6 commits intoSep 2, 2026
Conversation
Visibility "Never" wrote enabledFrames[unit] = false alongside barVisibility, and that key is a build-time decision: ns.GetUnitFrameSource reports the unit "hidden" and InitializeFrames skips the spawn entirely. A Spec Override carrying "Never" therefore left the frame uncreated for the whole session -- switching back to a spec without the override wrote enabledFrames true again and ran the reload pass, but there was no frame to show and only a /reload brought it back. Visibility is a runtime axis now and leaves enabledFrames alone, so the frame is always built and "never" is hidden the same way "in_combat" and "mouseover" are: ToggleFrame's group trio and UpdateFrameVisibility's secure bucket both already handle it, and both reverse when the override lifts. enabledFrames goes back to meaning what the Enable Pet / Target of Target / Focus Target / Boss toggles say, which is why SetUnitFrameSource no longer rewrites barVisibility to keep the two in sync -- picking a frame source would otherwise clear a user's "Never". Two things ride on the old pairing and are kept: a unit on Blizzard's frame set to "Never" still resolves "hidden", since suppressing Blizzard's frame is the only way to honour it when we spawn nothing of our own; and Blizzard's player cast bar is still left alone under "Never", because ours is built but hides with the frame. A profile migration clears the enabledFrames flag the old pairing wrote for player/target/focus -- those three have no Enable toggle of their own, so a stored false there can only have come from it.
The migration cleared the base enabledFrames flag but left the same fkey banked in the spec and conditional override stores, where auto-capture put it while the two keys were written together. Nothing blacklists it, so the next spec apply wrote false back and the frame went missing again at the following login -- and with Visibility no longer writing the key there was no way back from the UI. Strip it for player/target/focus, the same way the Dragon Riding migration does; the other units keep theirs, since their Enable toggles own that key. Under a leftover Match Any selection the engine evaluates the scalar and answers false rather than nil for "never", so the secure bucket read it as engine-owned and kept the frame shown at alpha 0 -- invisible but still eating clicks. Never is exclusive, so it now settles the verdict ahead of the engine. A frame Visibility hides outright is built but never on screen, so its unlock mover had nothing to drag. Gate the unit and cast bar elements on isHidden, which is re-read on every unlock-mode open, so lifting the hide needs no reload.
Four places treated Visibility "Never" as "no frame exists", which was true only because it used to clear enabledFrames: ResolveVisResting had no alpha case for it, so the mode rested on the Show/Hide bucket alone -- and that bucket is lockdown-gated, leaving a Never picked (or applied by an override) in combat at full alpha until PLAYER_REGEN_ENABLED. The companion mini frame inherited only the parent's alpha, so a "never" parent left an invisible click blocker; pin its driver the way the disabled-parent branch already does. A class resource bar unlocked from the frame is parented to UIParent and outlived its owner. Only Never takes it along -- the other hiding modes have always kept their own bar visible. GetMiniDonorSettings picked the mini frames' border/texture/font donor off enabledFrames, so a focus set to Never used to fall out for free and now has to be checked directly.
The Show/Hide bucket that hid a "never" frame is lockdown-gated, so acquiring a target in combat let the unit watch show an alpha-0 click blocker until regen. Never is terminal, so it pins state-visibility to a constant hide instead -- the same lever the companion mini already uses -- and the watch cannot out-vote it. The unlock movers gated on the element's own barVisibility, which the minis and an unlocked class resource bar do not have; map each to the frame whose Visibility governs it, with Always Show Pet opting out as it does everywhere. The options file carried two more copies of the mini-frame donor rule, so a focus set to Never fell out of the live frames' inheritance but not the preview's. Both now route through the runtime resolver.
…write GetMiniDonorSettings runs from the mini frames' OnEnter/OnLeave, so the local helper it grew allocated a closure on every hover for no reason; back to plain branches. The class resource bar alpha is written from the visibility pass, which runs on every target change, and for the "blizzard" style the bar is Blizzard's own frame. Write it only when it actually moves.
An applied Visibility override replaces the whole shared setting, "never" included, so the new never handling cannot read the stored scalar: a shared Never under an override of Always would pin the secure driver to a constant hide and the frame would stay missing, and an override of Never would leave the unlocked class resource bar on screen. The visibility pass now derives one override-aware verdict and both driver pins, the class resource bar and the Show/Hide bucket read it. The other "never" reads this branch added -- Blizzard frame source, the mini donor, player cast bar suppression, the unlock movers -- go through ns.VisEffective for the same reason. VisUnitDisabled drops its override carve-out with it. That carve-out existed because Visibility wrote enabledFrames; now that it does not, the flag means only the "Enable X Frame" toggles, and honouring an override there would resurrect a frame the user deliberately disabled.
dfrisone
force-pushed
the
fix/uf-visibility-override-stale-driver
branch
from
September 2, 2026 04:26
e06b7d6 to
3f290e5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bug: https://discord.com/channels/585577383847788554/1484909708392530121
Issue: with a spec override setting the player frame's Visibility to Never for healer or tank, switching back to a spec without the override left the frame hidden until /reload. It looks intermittent because it depends on which spec the session started on.
Root cause: the Visibility dropdown wrote enabledFrames[unit] alongside barVisibility, and that key is build-time. ns.GetUnitFrameSource reports the unit hidden and InitializeFrames skips the spawn, once, at login. A spec override applies a couple of frames later, so a spec carrying Never left the frame uncreated, and switching back wrote the key true again with no frame to show.
Fix: Visibility no longer touches enabledFrames, so the frame is always built and Never hides it the way in_combat and mouseover do, pinned on a state-visibility driver so it holds in combat too. A migration clears the flag the old pairing wrote and strips it from existing override stores. Verified in game by the reporter.