diff --git a/EllesmereUIBags/EUI_Bags_Options.lua b/EllesmereUIBags/EUI_Bags_Options.lua index 1a660d59..ff464abf 100644 --- a/EllesmereUIBags/EUI_Bags_Options.lua +++ b/EllesmereUIBags/EUI_Bags_Options.lua @@ -472,20 +472,28 @@ initFrame:SetScript("OnEvent", function(self) local cbDD, cbDDRefresh = EllesmereUI.BuildVisOptsCBDropdown( rightRgn, 210, rightRgn:GetFrameLevel() + 2, currencyItems, + -- Tracked currencies are per character (the module owns + -- the accessor and its first-use seeding; see + -- CurrencyOrder in EllesmereUIBags.lua). Reading + -- db.profile.currencyOrder here would edit the legacy + -- shared table that nothing renders any more. function(cID) - local co = db.profile.currencyOrder + local co = EllesmereUI._BagsCurrencyOrder + and EllesmereUI._BagsCurrencyOrder() return co and co[cID] and true or false end, function(cID, v) - if not db.profile.currencyOrder then db.profile.currencyOrder = {} end + local co = EllesmereUI._BagsCurrencyOrder + and EllesmereUI._BagsCurrencyOrder() + if not co then return end if v then local maxOrder = 0 - for _, ord in pairs(db.profile.currencyOrder) do + for _, ord in pairs(co) do if type(ord) == "number" and ord > maxOrder then maxOrder = ord end end - db.profile.currencyOrder[cID] = maxOrder + 1 + co[cID] = maxOrder + 1 else - db.profile.currencyOrder[cID] = nil + co[cID] = nil end if _G.EUI_Bags and _G.EUI_Bags.RefreshInventory then C_Timer.After(0.1, function() @@ -827,6 +835,7 @@ initFrame:SetScript("OnEvent", function(self) EllesmereUIDB.bagItemAssignments = nil EllesmereUIDB.characterGold = nil EllesmereUIDB.warbandGold = nil + EllesmereUIDB.bagCurrencyByChar = nil end EllesmereUI:InvalidatePageCache() end, diff --git a/EllesmereUIBags/EllesmereUIBags.lua b/EllesmereUIBags/EllesmereUIBags.lua index 4555be7c..8d3e8308 100644 --- a/EllesmereUIBags/EllesmereUIBags.lua +++ b/EllesmereUIBags/EllesmereUIBags.lua @@ -83,6 +83,64 @@ local EUI = EllesmereUI local _emptyP = {} local function BP() return (EUI._bagsDB and EUI._bagsDB.profile) or _emptyP end +-- Tracked currencies are PER CHARACTER, unlike every other bag setting. +-- +-- They used to live in one profile-level `currencyOrder` table, which meant +-- ticking a currency on one character put it in every character's bag. Worse, +-- the input feeding that table is Blizzard's own currency tab, which IS +-- per-character (see the TokenFrame.OnTokenWatchChanged sync below): a +-- per-character source writing a shared store can only ever bleed. Reported by +-- a user wanting one currency on their main and another on the alt that farms +-- it, which the shared table made impossible. +-- +-- Stored at the EllesmereUIDB ROOT, not in the bag profile, which is where the +-- module already keeps its other per-character data (characterGold, +-- bagPinnedItems, bagItemAssignments). Profile data is the wrong home for it in +-- two ways: ApplyProfileData wipes db.profile wholesale before copying an +-- imported snapshot, so importing any shared profile would erase every +-- character's currencies, and profile exports would ship a roster of the +-- author's character names, realms and per-alt currency lists to whoever +-- imported it -- the leak PRIVATE_ADDON_KEYS exists to plug. +local _bagsCharKey -- session-constant; UpdateCurrencyDisplays is a render path +local function BagsCharKey() + if not _bagsCharKey then + local n, r = UnitName("player"), GetRealmName() + if not n or not r then return nil end -- too early; do not cache a stub + _bagsCharKey = n .. " - " .. r + end + return _bagsCharKey +end + +-- The per-character order table, seeded on this character's first use. +-- Returns nil only when the DB or the player identity is not up yet (callers +-- already handle that). +local function CurrencyOrder() + if not EllesmereUIDB then return nil end + local key = BagsCharKey() + if not key then return nil end + local byChar = EllesmereUIDB.bagCurrencyByChar + if type(byChar) ~= "table" then byChar = {}; EllesmereUIDB.bagCurrencyByChar = byChar end + local t = byChar[key] + if type(t) ~= "table" then + t = {} + -- Seed from the legacy shared table so an upgrading user keeps exactly + -- what they had. The legacy table is deliberately NOT deleted: every + -- character seeds from it once, at ITS first login after the upgrade, + -- so a character that has not logged in yet still inherits the old + -- setup instead of an empty footer. Nothing writes to it any more, so + -- the seed stays stable. A per-character migration is never a one-shot. + local legacy = BP().currencyOrder + if type(legacy) == "table" then + for cID, order in pairs(legacy) do + if type(order) == "number" then t[cID] = order end + end + end + byChar[key] = t + end + return t +end +EUI._BagsCurrencyOrder = CurrencyOrder + -- Resolve the default bag-type view ("all" | "onebag" | "multibag"). Reads the -- new bagDefaultBagType key, falling back to the legacy bagDefaultOneBag boolean -- so existing users keep their OneBag default. (Cross-version profile imports are @@ -1667,7 +1725,7 @@ local function UpdateCurrencyDisplays(footerWidth) -- Build tracked list from internal order table (decoupled from Blizzard) local tracked = {} - local orderDB = BP().currencyOrder + local orderDB = CurrencyOrder() if orderDB and C_CurrencyInfo and C_CurrencyInfo.GetCurrencyInfo then for cID, order in pairs(orderDB) do if type(order) == "number" then @@ -6656,14 +6714,16 @@ local function StartAddon() end end - -- Seed currencyOrder from Blizzard's tracked currencies on first load + -- Seed this character's tracked currencies from Blizzard's on first load if EllesmereUIDB and C_CurrencyInfo and C_CurrencyInfo.GetBackpackCurrencyInfo then - if not BP().currencyOrder then BP().currencyOrder = {} end - local co = BP().currencyOrder - -- Only seed if our table is empty (first install or fresh profile) + -- Only seed when this character's table is empty: first install, a + -- fresh profile, or a character whose legacy seed was empty too. + local co = CurrencyOrder() local hasAny = false - for _ in pairs(co) do hasAny = true; break end - if not hasAny then + if co then + for _ in pairs(co) do hasAny = true; break end + end + if co and not hasAny then local order = 0 for i = 1, 20 do local info = C_CurrencyInfo.GetBackpackCurrencyInfo(i) @@ -6695,8 +6755,8 @@ local function StartAddon() if EventRegistry and EventRegistry.RegisterCallback then EventRegistry:RegisterCallback("TokenFrame.OnTokenWatchChanged", function() if not EllesmereUIDB then return end - if not BP().currencyOrder then BP().currencyOrder = {} end - local co = BP().currencyOrder + local co = CurrencyOrder() + if not co then return end local blizzSet = ReadBlizzSet() -- Add newly checked currencies for cID in pairs(blizzSet) do