coa.9: revert scale default + crash fixes + personal/realm bank + woodworking
release / release (push) Successful in 5s
release / release (push) Successful in 5s
- Revert UIScale default 1.4->1.0 (scaling only zoomed, no extra content; real larger layout tracked separately). Apply saved scale on open, default 1.0. - Fix Options:Get/Set nil 'options' crash (TabOptions.lua:442). - Guild Members: guard Level_OnClick against cleared/stale row IDs. - Personal + Realm bank tracking ported from coa-bagnon (BANK_PERMISSIONS_PAYLOAD detection; personal per-char, realm per-realm; Search + BagUsage surfacing). - Woodcutting/Woodworking columns on Skills tab (CoA custom professions).
This commit is contained in:
@@ -35,6 +35,24 @@ local MSG_BANKTAB_TRANSFER = 6 -- .. or send the data
|
||||
|
||||
local AddonDB_Defaults = {
|
||||
global = {
|
||||
-- CoA (Ascension) Realm Bank: shared per-realm storage, keyed by "Account.Realm"
|
||||
-- (NOT per-character). Mirrors the guild bank's Tabs layout so the same
|
||||
-- scan/read helpers can be reused.
|
||||
RealmBanks = {
|
||||
['*'] = { -- ["Account.Realm"]
|
||||
lastUpdate = nil,
|
||||
Tabs = {
|
||||
['*'] = { -- tabID = table index [1] to [6]
|
||||
name = nil,
|
||||
icon = nil,
|
||||
size = 0,
|
||||
ids = {},
|
||||
links = {},
|
||||
counts = {}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
Guilds = {
|
||||
['*'] = { -- ["Account.Realm.Name"]
|
||||
money = nil,
|
||||
@@ -204,6 +222,16 @@ end
|
||||
local BAGS = 1 -- All bags, 0 to 11, and keyring ( id -2 )
|
||||
local BANK = 2 -- 28 main slots
|
||||
local GUILDBANK = 3 -- 98 main slots
|
||||
local PERSONALBANK = 4 -- CoA personal bank (per-character), read via guild bank API
|
||||
local REALMBANK = 5 -- CoA realm bank (per-realm), read via guild bank API
|
||||
|
||||
-- CoA reuses the Guild Bank UI for the Personal Bank and the Realm Bank.
|
||||
-- These container key prefixes keep their scanned tabs out of the regular
|
||||
-- "Bag0".."Bag11" / "Bag100" / "Bag-2" namespace so item-count loops can tell
|
||||
-- them apart. Personal bank tabs live under the character; realm bank tabs live
|
||||
-- in the realm-keyed global table.
|
||||
local PERSONALBANK_PREFIX = "PBank" -- char.Containers["PBank1".."PBank6"]
|
||||
local MAX_BANK_TABS = 6
|
||||
|
||||
local ContainerTypes = {
|
||||
[BAGS] = {
|
||||
@@ -262,9 +290,81 @@ local ContainerTypes = {
|
||||
GetCooldown = function(self, slotID)
|
||||
return nil
|
||||
end,
|
||||
},
|
||||
-- Personal & Realm banks are read through the guild bank API (CoA reuses that UI).
|
||||
[PERSONALBANK] = {
|
||||
GetSize = function(self)
|
||||
return MAX_GUILDBANK_SLOTS_PER_TAB or 98
|
||||
end,
|
||||
GetFreeSlots = function(self)
|
||||
return nil, nil
|
||||
end,
|
||||
GetLink = function(self, slotID, tabID)
|
||||
return GetGuildBankItemLink(tabID, slotID)
|
||||
end,
|
||||
GetCount = function(self, slotID, tabID)
|
||||
local _, count = GetGuildBankItemInfo(tabID, slotID)
|
||||
return count
|
||||
end,
|
||||
GetCooldown = function(self, slotID)
|
||||
return nil
|
||||
end,
|
||||
},
|
||||
[REALMBANK] = {
|
||||
GetSize = function(self)
|
||||
return MAX_GUILDBANK_SLOTS_PER_TAB or 98
|
||||
end,
|
||||
GetFreeSlots = function(self)
|
||||
return nil, nil
|
||||
end,
|
||||
GetLink = function(self, slotID, tabID)
|
||||
return GetGuildBankItemLink(tabID, slotID)
|
||||
end,
|
||||
GetCount = function(self, slotID, tabID)
|
||||
local _, count = GetGuildBankItemInfo(tabID, slotID)
|
||||
return count
|
||||
end,
|
||||
GetCooldown = function(self, slotID)
|
||||
return nil
|
||||
end,
|
||||
}
|
||||
}
|
||||
|
||||
-- *** CoA bank-type detection ***
|
||||
-- CoA exposes BANK_PERMISSIONS_PAYLOAD via the client-only HasJsonCacheData /
|
||||
-- GetJsonCacheData / C_Serialize APIs. Guard every call so this is harmless on
|
||||
-- non-CoA clients (where the personal/realm bank simply never triggers).
|
||||
local function GetCoABankType()
|
||||
if not (HasJsonCacheData and GetJsonCacheData and C_Serialize and C_Serialize.FromJSON) then
|
||||
return "guild"
|
||||
end
|
||||
if not HasJsonCacheData("BANK_PERMISSIONS_PAYLOAD", 0) then
|
||||
return "guild"
|
||||
end
|
||||
local json = GetJsonCacheData("BANK_PERMISSIONS_PAYLOAD", 0)
|
||||
if not json then
|
||||
return "guild"
|
||||
end
|
||||
local jsonObject = C_Serialize:FromJSON(json)
|
||||
if not jsonObject then
|
||||
return "guild"
|
||||
end
|
||||
if jsonObject.IsPersonalBank then
|
||||
return "personal"
|
||||
elseif jsonObject.IsRealmBank then
|
||||
return "realm"
|
||||
end
|
||||
return "guild"
|
||||
end
|
||||
|
||||
local function GetRealmBankKey()
|
||||
return format("%s.%s", THIS_ACCOUNT, GetRealmName())
|
||||
end
|
||||
|
||||
local function GetThisRealmBank()
|
||||
return addon.db.global.RealmBanks[GetRealmBankKey()]
|
||||
end
|
||||
|
||||
-- *** Scanning functions ***
|
||||
local function ScanContainer(bagID, containerType)
|
||||
local Container = ContainerTypes[containerType]
|
||||
@@ -273,8 +373,15 @@ local function ScanContainer(bagID, containerType)
|
||||
if containerType == GUILDBANK then
|
||||
local thisGuild = GetThisGuild()
|
||||
if not thisGuild then return end
|
||||
|
||||
|
||||
bag = thisGuild.Tabs[bagID] -- bag is actually the current tab
|
||||
elseif containerType == PERSONALBANK then
|
||||
-- per-character storage, keyed by a tab-specific prefix so it never
|
||||
-- collides with the normal bag/bank containers
|
||||
bag = addon.ThisCharacter.Containers[PERSONALBANK_PREFIX .. bagID]
|
||||
elseif containerType == REALMBANK then
|
||||
local realmBank = GetThisRealmBank()
|
||||
bag = realmBank.Tabs[bagID] -- bag is the current tab in the realm-keyed table
|
||||
else
|
||||
bag = addon.ThisCharacter.Containers["Bag" .. bagID]
|
||||
wipe(bag.cooldowns) -- does not exist for a guild bank
|
||||
@@ -315,8 +422,14 @@ local function ScanContainer(bagID, containerType)
|
||||
bag.cooldowns[index] = startTime .."|".. duration .. "|" .. 1
|
||||
end
|
||||
end
|
||||
|
||||
addon.ThisCharacter.lastUpdate = time()
|
||||
|
||||
if containerType == REALMBANK then
|
||||
GetThisRealmBank().lastUpdate = time()
|
||||
else
|
||||
-- personal bank, bags, bank and guild bank all stamp the character;
|
||||
-- this is what gates DataStore's "no value" guard for char-based getters
|
||||
addon.ThisCharacter.lastUpdate = time()
|
||||
end
|
||||
end
|
||||
|
||||
local function ScanBagSlotsInfo()
|
||||
@@ -463,25 +576,76 @@ local function OnBankFrameOpened()
|
||||
addon:RegisterEvent("PLAYERBANKSLOTS_CHANGED", OnPlayerBankSlotsChanged)
|
||||
end
|
||||
|
||||
-- Records the name/icon of a personal-bank tab. Reuses the per-character
|
||||
-- container created by ScanContainer (PERSONALBANK_PREFIX .. tabID).
|
||||
local function ScanPersonalBankInfo(tabID)
|
||||
local bag = addon.ThisCharacter.Containers[PERSONALBANK_PREFIX .. tabID]
|
||||
bag.name, bag.icon = GetGuildBankTabInfo(tabID)
|
||||
end
|
||||
|
||||
local function ScanRealmBankInfo(tabID)
|
||||
local t = GetThisRealmBank().Tabs[tabID]
|
||||
t.name, t.icon = GetGuildBankTabInfo(tabID)
|
||||
end
|
||||
|
||||
local function OnGuildBankFrameClosed()
|
||||
addon:UnregisterEvent("GUILDBANKFRAME_CLOSED")
|
||||
addon:UnregisterEvent("GUILDBANKBAGSLOTS_CHANGED")
|
||||
|
||||
local guildName = GetGuildInfo("player")
|
||||
if guildName then
|
||||
GuildBroadcast(MSG_SEND_BANK_TIMESTAMPS, GetBankTimestamps(guildName))
|
||||
|
||||
-- only broadcast guild bank timestamps for the actual guild bank
|
||||
if addon.coaBankType == "guild" then
|
||||
local guildName = GetGuildInfo("player")
|
||||
if guildName then
|
||||
GuildBroadcast(MSG_SEND_BANK_TIMESTAMPS, GetBankTimestamps(guildName))
|
||||
end
|
||||
end
|
||||
|
||||
addon.coaBankType = nil
|
||||
addon.coaBankAvailableTabs = nil
|
||||
end
|
||||
|
||||
local function OnGuildBankBagSlotsChanged()
|
||||
ScanContainer(GetCurrentGuildBankTab(), GUILDBANK)
|
||||
ScanGuildBankInfo()
|
||||
local currentTab = GetCurrentGuildBankTab()
|
||||
|
||||
if addon.coaBankType == "personal" then
|
||||
ScanContainer(currentTab, PERSONALBANK)
|
||||
ScanPersonalBankInfo(currentTab)
|
||||
elseif addon.coaBankType == "realm" then
|
||||
ScanContainer(currentTab, REALMBANK)
|
||||
ScanRealmBankInfo(currentTab)
|
||||
else
|
||||
-- regular guild bank, unchanged behaviour
|
||||
ScanContainer(currentTab, GUILDBANK)
|
||||
ScanGuildBankInfo()
|
||||
end
|
||||
end
|
||||
|
||||
local function OnGuildBankFrameOpened()
|
||||
-- CoA reuses the guild bank UI for the personal & realm banks; detect which
|
||||
-- one this is BEFORE doing anything guild-specific. Harmless ("guild") when
|
||||
-- the CoA JSON APIs are absent.
|
||||
addon.coaBankType = GetCoABankType()
|
||||
|
||||
addon:RegisterEvent("GUILDBANKFRAME_CLOSED", OnGuildBankFrameClosed)
|
||||
addon:RegisterEvent("GUILDBANKBAGSLOTS_CHANGED", OnGuildBankBagSlotsChanged)
|
||||
|
||||
|
||||
if addon.coaBankType == "personal" or addon.coaBankType == "realm" then
|
||||
-- Pre-query the other tabs so we snapshot the whole bank without the
|
||||
-- player having to click each tab. Each QueryGuildBankTab triggers a
|
||||
-- GUILDBANKBAGSLOTS_CHANGED for that tab, handled above.
|
||||
if QueryGuildBankTab then
|
||||
local currentTab = GetCurrentGuildBankTab and GetCurrentGuildBankTab() or 0
|
||||
for tabID = 1, MAX_BANK_TABS do
|
||||
local avail = GetGuildBankTabInfo(tabID)
|
||||
if type(avail) == "string" and tabID ~= currentTab then
|
||||
QueryGuildBankTab(tabID)
|
||||
end
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- regular guild bank
|
||||
local thisGuild = GetThisGuild()
|
||||
if thisGuild then
|
||||
thisGuild.money = GetGuildBankMoney()
|
||||
@@ -550,19 +714,22 @@ end
|
||||
local function _GetContainerItemCount(character, searchedID)
|
||||
local bagCount = 0
|
||||
local bankCount = 0
|
||||
local personalBankCount = 0
|
||||
local id
|
||||
|
||||
|
||||
for containerName, container in pairs(character.Containers) do
|
||||
for slotID=1, container.size do
|
||||
id = container.ids[slotID]
|
||||
|
||||
|
||||
if (id) and (id == searchedID) then
|
||||
local itemCount = container.counts[slotID] or 1
|
||||
|
||||
|
||||
if (containerName == "Bag100") then
|
||||
bankCount = bankCount + itemCount
|
||||
elseif (containerName == "Bag-2") then
|
||||
bagCount = bagCount + itemCount
|
||||
elseif string.sub(containerName, 1, #PERSONALBANK_PREFIX) == PERSONALBANK_PREFIX then
|
||||
personalBankCount = personalBankCount + itemCount -- CoA personal bank tab
|
||||
else
|
||||
local bagNum = tonumber(string.sub(containerName, 4))
|
||||
if (bagNum >= 0) and (bagNum <= 4) then
|
||||
@@ -575,7 +742,79 @@ local function _GetContainerItemCount(character, searchedID)
|
||||
end
|
||||
end
|
||||
|
||||
return bagCount, bankCount
|
||||
-- 3rd return value (personal bank) is additive and backward-compatible:
|
||||
-- existing callers that expect (bags, bank) just ignore it.
|
||||
return bagCount, bankCount, personalBankCount
|
||||
end
|
||||
|
||||
-- *** CoA personal bank (per-character) ***
|
||||
local function _GetPersonalBankItemCount(character, searchedID)
|
||||
local count = 0
|
||||
for containerName, container in pairs(character.Containers) do
|
||||
if string.sub(containerName, 1, #PERSONALBANK_PREFIX) == PERSONALBANK_PREFIX then
|
||||
for slotID = 1, container.size do
|
||||
if container.ids[slotID] == searchedID then
|
||||
count = count + (container.counts[slotID] or 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
local function _GetPersonalBankTabCount(character)
|
||||
-- number of personal bank tabs that have been scanned (have a size)
|
||||
local n = 0
|
||||
for tabID = 1, MAX_BANK_TABS do
|
||||
local container = character.Containers[PERSONALBANK_PREFIX .. tabID]
|
||||
if container and (container.size or 0) > 0 then
|
||||
n = n + 1
|
||||
end
|
||||
end
|
||||
return n
|
||||
end
|
||||
|
||||
-- *** CoA realm bank (per-realm, NOT char-based) ***
|
||||
-- These take a realm key string ("Account.Realm") directly and read the global
|
||||
-- RealmBanks table, so they bypass DataStore's char/guild "no value" wrapper.
|
||||
local function _GetRealmBankKey(realm, account)
|
||||
realm = realm or GetRealmName()
|
||||
account = account or THIS_ACCOUNT
|
||||
return format("%s.%s", account, realm)
|
||||
end
|
||||
|
||||
local function _GetRealmBank(realm, account)
|
||||
return addon.db.global.RealmBanks[_GetRealmBankKey(realm, account)]
|
||||
end
|
||||
|
||||
local function _GetRealmBankItemCount(realm, account, searchedID)
|
||||
local realmBank = _GetRealmBank(realm, account)
|
||||
if not realmBank then return 0 end
|
||||
|
||||
local count = 0
|
||||
for _, tab in pairs(realmBank.Tabs) do
|
||||
for slotID, id in pairs(tab.ids) do
|
||||
if id == searchedID then
|
||||
count = count + (tab.counts[slotID] or 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
local function _GetRealmBankTab(realm, account, tabID)
|
||||
local realmBank = _GetRealmBank(realm, account)
|
||||
return realmBank and realmBank.Tabs[tabID]
|
||||
end
|
||||
|
||||
local function _GetRealmBankTabName(realm, account, tabID)
|
||||
local tab = _GetRealmBankTab(realm, account, tabID)
|
||||
return tab and tab.name
|
||||
end
|
||||
|
||||
local function _GetRealmBankLastUpdate(realm, account)
|
||||
local realmBank = _GetRealmBank(realm, account)
|
||||
return realmBank and realmBank.lastUpdate
|
||||
end
|
||||
|
||||
local function _GetNumBagSlots(character)
|
||||
@@ -721,6 +960,14 @@ local PublicMethods = {
|
||||
RejectBankTabRequest = _RejectBankTabRequest,
|
||||
SendBankTabToGuildMember = _SendBankTabToGuildMember,
|
||||
GetGuildBankTabSuppliers = _GetGuildBankTabSuppliers,
|
||||
-- CoA personal bank (per-character)
|
||||
GetPersonalBankItemCount = _GetPersonalBankItemCount,
|
||||
GetPersonalBankTabCount = _GetPersonalBankTabCount,
|
||||
-- CoA realm bank (per-realm; takes realm/account, not a character/guild key)
|
||||
GetRealmBankItemCount = _GetRealmBankItemCount,
|
||||
GetRealmBankTab = _GetRealmBankTab,
|
||||
GetRealmBankTabName = _GetRealmBankTabName,
|
||||
GetRealmBankLastUpdate = _GetRealmBankLastUpdate,
|
||||
}
|
||||
|
||||
-- *** Guild Comm ***
|
||||
@@ -809,7 +1056,11 @@ function addon:OnInitialize()
|
||||
DataStore:SetCharacterBasedMethod("GetNumFreeBagSlots")
|
||||
DataStore:SetCharacterBasedMethod("GetNumBankSlots")
|
||||
DataStore:SetCharacterBasedMethod("GetNumFreeBankSlots")
|
||||
|
||||
DataStore:SetCharacterBasedMethod("GetPersonalBankItemCount")
|
||||
DataStore:SetCharacterBasedMethod("GetPersonalBankTabCount")
|
||||
-- Realm bank methods are intentionally NOT char/guild based: they take a
|
||||
-- realm/account string pair directly and read the realm-keyed global table.
|
||||
|
||||
DataStore:SetGuildBasedMethod("GetGuildBankItemCount")
|
||||
DataStore:SetGuildBasedMethod("GetGuildBankTab")
|
||||
DataStore:SetGuildBasedMethod("GetGuildBankTabName")
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Title: DataStore_Containers
|
||||
## Notes: Stores information about character bags, bank, and guild banks
|
||||
## Author: Thaoky (EU-Marécages de Zangar)
|
||||
## Version: 3.3.001
|
||||
## Version: 3.3.001-coa.9
|
||||
## Dependencies: DataStore
|
||||
## OptionalDeps: Ace3
|
||||
## SavedVariables: DataStore_ContainersDB
|
||||
|
||||
Reference in New Issue
Block a user