Bags: track currencies per character instead of per profile - #1251
Open
dfrisone wants to merge 2 commits into
Open
Bags: track currencies per character instead of per profile#1251dfrisone wants to merge 2 commits into
dfrisone wants to merge 2 commits into
Conversation
Reported by a user wanting one currency on their main and another on the alt that farms it: every character showed the same set, from either the EUI dropdown or Blizzard's currency tab. The bag footer renders from the module's own currencyOrder table rather than Blizzard's tracked set, and that table is profile-level, so it is shared by every character on the profile. The input feeding it is not: a TokenFrame.OnTokenWatchChanged callback syncs Blizzard's currency tab, which IS per-character, into that shared table. A per-character source writing a shared store can only bleed, which is why ticking a currency on one character put it in everyone's bag and made Blizzard's own per-character tab look broken. (EUI never writes that tab; there is no SetCurrencyBackpack-family call in the module. It only ever reads it.) Tracked currencies now live under currencyOrderByChar, keyed by name-realm, which is the same key the profile system already uses for lastSpecByChar. Storage stays inside the Bags profile so it keeps riding the existing plumbing: defaults merge, logout strip, export. A profile exported to someone else simply carries keys their characters do not match, and they seed fresh. Each character seeds once from the legacy shared table, so an upgrading user keeps exactly what they had and only diverges as they change things. The legacy table is deliberately left in place rather than deleted or migrated: characters that have not logged in since the upgrade still need it to seed from, and nothing writes to it any more, so the seed stays stable. Fresh installs are unchanged and still seed from Blizzard's tracked set. The options dropdown goes through the module's accessor rather than reaching for db.profile.currencyOrder, so there is one definition of where this data lives and one place that owns the seeding.
…profile Self-review catch on the previous commit, which put currencyOrderByChar inside the bag profile. Two ways that was the wrong home, both with existing precedent in this very module: ApplyProfileData wipes db.profile wholesale (for k in pairs(profile) do profile[k] = nil end) before copying an imported snapshot, so importing any shared profile would have erased EVERY character's currencies and replaced them with the exporter's keys. Profile exports would also have shipped a roster of the author's character names, realms and per-alt currency lists to anyone importing it. That is exactly the leak PRIVATE_ADDON_KEYS exists to plug for DataBars' gold ledger and QoL's upgrade calculator. The module already keeps its other per-character data at the EllesmereUIDB root (characterGold, bagPinnedItems, bagItemAssignments), so this joins them as bagCurrencyByChar and is cleared alongside them by the per-character reset in the options page. Root storage also removes a failure the profile version had: a spec-driven profile switch could hand a character a freshly created empty table mid-session, with nothing to seed it and a blank footer for the rest of the session. Root data does not move with profiles, so first use happens once per character, ever. The character key is now resolved once and cached. It is session-constant and was being rebuilt, two API calls plus a string, on a render path driven by CURRENCY_DISPLAY_UPDATE. It refuses to cache before UnitName and GetRealmName are both available, so an early call returns nil rather than pinning a stub key for the session.
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.
The bug
Reported by a user who wanted one currency tracked on their main and a different one on the alt that farms it: the bag's currency display was identical on every character. Unticking everything and re-picking, from either the EUI dropdown or Blizzard's own currency tab, always ended with every character showing the same set.
Root cause
The bag footer does not render Blizzard's tracked currencies. It renders the module's own
currencyOrdertable (the code comment says "decoupled from Blizzard"), and that table lives in the bag profile, so every character on the profile shares it.The input feeding it is not shared. A
TokenFrame.OnTokenWatchChangedcallback syncs Blizzard's currency tab, which is per-character, into that one profile-level table. A per-character source writing a shared store can only ever bleed: ticking a currency on one character wrote it into everyone's bag.That also explains the half of the report that sounded impossible, that Blizzard's own per-character tracking looked broken. EUI never writes that tab, and there is no
SetCurrencyBackpack-family call anywhere in the module, only reads. What the user saw was the bag ignoring their per-character selection and showing the shared list instead.The fix
Tracked currencies move to
EllesmereUIDB.bagCurrencyByChar, keyed by name and realm.Storage is at the DB root, not in the profile. The module already keeps its other per-character data there (
characterGold,bagPinnedItems,bagItemAssignments), and it is cleared alongside them by the options page's per-character reset. Profile storage would have been wrong twice over:ApplyProfileDatawipesdb.profilewholesale before copying an imported snapshot, so importing any shared profile would have erased every character's currencies and substituted the exporter's.PRIVATE_ADDON_KEYSexists to plug for the DataBars gold ledger and the QoL upgrade calculator.Root storage also removes a failure mode the profile version had: a spec-driven profile switch (
RepointAllDBs, no reload) could hand a character a freshly created empty table mid-session with nothing to seed it, blanking the footer for the rest of the session. Root data does not move with profiles, so first use happens once per character, ever.Each character seeds once from the legacy shared table, so an upgrading user keeps exactly what they had and only diverges as they change things. The legacy table is deliberately left in place rather than deleted or migrated away: a per-character migration is not a one-shot, it runs once per character at that character's first login, so the seed source has to survive indefinitely. A character that has not logged in since the update still needs it, or it would open with an empty footer. Nothing writes to it any more, so the seed stays stable. Fresh installs are unchanged and still seed from Blizzard's tracked set.
One accessor owns the location and the seeding. The options dropdown goes through
EllesmereUI._BagsCurrencyOrderrather than reaching fordb.profile.currencyOrder, so there is a single definition of where this data lives. Because the TOC loads the options file before the module, that call is a runtime namespace lookup rather than a local captured at load time.The character key is resolved once and cached. It is session-constant and was being rebuilt, two API calls plus a string allocation, on a render path driven by
CURRENCY_DISPLAY_UPDATE. It refuses to cache beforeUnitNameandGetRealmNameboth answer, so an early call returns nil rather than pinning a stub key for the session.Scope
Two files, +70/−14. No new events, no timers, no API calls added.
bagCurrencyByCharis deliberately absent fromBAGS_DEFAULTS:StripDefaultsandDeepMergeDefaultsonly walk keys present in the defaults table, so the per-character data is never stripped or masked.Testing
Confirmed in game: currencies ticked on one character no longer follow to another, existing setups carry over untouched on upgrade, and Blizzard's currency tab now drives only the character it belongs to.