Fix(unitframes): pab pixel drift - #2068
Open
JuJuFX-dev wants to merge 4 commits into
Open
Conversation
PAB snapped icon size, padding and row gap with PP.Scale, which truncates to whole physical pixels. The per-icon loss added up along a row, so a bar measured a different number of UI units at 1080p and at 1440p, and the CENTER anchor spread that difference over both edges. A bar placed flush against another element at one resolution opened a gap or overlapped it at the other. Round every PAB grid number to the nearest pixel through a local PabSnap, the same rounding Action Bars and Cooldown Manager use. ComputeGrid now also returns the unrounded design size. Stored positions refer to that design frame, and OriginShift offsets the SetPoint so the growth origin (the parent corner the aura container is pinned to, or the center for centered growth) no longer depends on the resolution. The unlock-mode movers of the default and custom bars convert between the visual and the stored position in both directions, so a save and load round trip is exact. The in-session resize compensation in ApplyLiveConfig now moves a stored center toward the actual growth origin. It always pinned the top-right corner before, which was only right for leftward growth with rows wrapping down.
Rounding to the nearest pixel changes the snapped bar size. With the design-frame positions of the previous commit, every existing bar would have moved once after the update, by up to half the accumulated rounding. A stored position now refers to the design frame only after an unlock-mode move has saved it, which marks it with design = true. Every other position, the defaults included, keeps its pre-fix placement: ComputeGrid also returns the extent the old PP.Scale truncation produced, and BarAnchorOffset puts the growth origin exactly where that truncated frame, snapped as before, had it at the current resolution. Such a position stays resolution-dependent, as before, until the bar is moved. The movers' savePos goes through MoverStorePos, which keeps the stored table untouched when the incoming position equals what loadPos returned, so a discard or an untouched commit does not convert it. The in-session resize compensation moves each position by the delta of its own reference frame.
Review follow-ups to the two commits before this one. ApplyLiveConfig only re-placed a bar when its grid size changed. A grow or wrap direction change moves the growth origin without changing that size, so the bar kept the previous rounding shift until the next reload, and loadPos disagreed with where the frame actually was. lastSize now carries the direction pair and the re-place runs on a change of it too, in combat through the regen queue. The re-place is skipped for a bar anchored in unlock mode: the anchor owns its placement and re-applies itself on a size change, so re-seating such a bar to its stored position pulled it off the anchor. RebaseBarPositionToCenter marks its result as a design position. Centered growth has no rounding shift at CENTER, so the measured center already is the design center; without the flag the next apply snapped it twice and could jump a pixel. PabSnap rounds ties up with the same 0.001 guard PP.SnapForES uses, so float dust at an exact half pixel cannot flip a size between sessions.
The layers harvest element geometry through loadPosition and write it back through savePosition. For Player Aura Bars those are the VISUAL positions: they depend on the resolution and carry no design flag, so a layer harvested at one resolution and flushed at another moved the bar and converted its stored position along the way. Add an opt-in pair, loadRawPosition and saveRawPosition. When an element exposes both, the harvest banks its stored table verbatim (marked with rawPos for the flush) and the flush hands that table straight back, guarded by an exact equality that counts the element's own position flags rather than coordinates alone. Elements without the pair keep the existing loadPosition/savePosition path unchanged, including the anchor-owned skip and the settle. PlayerAuraBars' default and custom bar elements expose the pair, so their stored positions survive a layer round trip at any resolution.
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.
What does this PR do?
Player Aura Bars laid out its icons in a way that depended on the screen resolution. Icon size, padding and row spacing went through
PP.Scale, which truncates to whole physical pixels, so at a UI scale that is not pixel-perfect for the current resolution every icon and every gap lost up to a pixel. The loss adds up along a row, and because the bars are anchored by their center, the missing width was spread over both edges. The result: a bar carefully placed against another element at one resolution no longer sat there at another. In the reported case the buff bar sat flush to the left of the minimap at 1440p and, after switching to 1080p at the same UI scale and aspect ratio, the gap was gone and the bar sat a pixel above the map.Every PAB grid number is now rounded to the nearest pixel instead, the same rounding Action Bars and Cooldown Manager already use (their comments call the
PP.Scaletruncation a bug outright). On top of that, a bar's growth origin, meaning the parent corner its aura container is pinned to and the center for the centered growth modes, is now derived from a resolution-independent design size, so it stays put instead of drifting with the rounding. Bars whose position was saved after this change line up within a pixel between 1080p and 1440p, and profiles shared between players on different resolutions land in the same place.Existing bars do not move. A stored position only switches to the new resolution-independent meaning once the bar is actually moved in unlock mode; until then it keeps the exact placement it had before, with its growth origin pixel-identical to what the old truncating layout produced at the current resolution. The trade-off is that a bar that is never moved stays resolution-dependent, as it is today, so the reported setup needs the bar re-placed once to benefit. Icons can also come out a pixel larger than before, since rounding up is now possible where the old code always rounded down.
Three smaller defects in the same area are fixed along the way. Changing a bar's grow or wrap direction now re-places it immediately, where it previously kept the old placement until the next reload. The in-session compensation that keeps a bar's edge fixed while its grid grows or shrinks now holds the bar's actual growth origin; it always pinned the top-right corner before, which is only the right corner for leftward growth with rows wrapping down. And a bar switching to a centered growth mode no longer risks a one-pixel jump on the next login.
One shared file is touched: spec-override unlock layers harvested element positions through
loadPositionand wrote them back throughsavePosition, which for these bars are the on-screen positions and therefore resolution-dependent. Layers can now bank an element's stored position table verbatim through an opt-inloadRawPosition/saveRawPositionpair, so a layer harvested at one resolution stays correct when it is applied at another. Elements that do not expose the pair keep the existing path, including the anchor-owned skip and the settle, and behave exactly as before.How was it tested?
Tested in game on the live client.
Checklist
HookScript/hooksecurefunconly, neverSetScripton Blizzard frames