6bae860635
* Update db.lua Add support for realm bank. Treat realm as a separate character * Update localization.lua * Update tooltips.lua
597 lines
13 KiB
Lua
597 lines
13 KiB
Lua
--[[
|
|
Database.lua
|
|
BagnonForever's implementation of BagnonDB
|
|
--]]
|
|
|
|
BagnonDB = CreateFrame('GameTooltip', 'BagnonDB', nil, 'GameTooltipTemplate')
|
|
BagnonDB:SetScript('OnEvent', function(self, event, arg1)
|
|
if arg1 == 'Bagnon_Forever' then
|
|
self:UnregisterEvent('ADDON_LOADED')
|
|
self:Initialize()
|
|
end
|
|
end)
|
|
BagnonDB:RegisterEvent('ADDON_LOADED')
|
|
|
|
ASC_PERSONAL_BANK_OFFSET = 1000;
|
|
ASC_REALM_BANK_OFFSET = 2000;
|
|
|
|
--constants
|
|
local L = BAGNON_FOREVER_LOCALS
|
|
local CURRENT_VERSION = GetAddOnMetadata('Bagnon_Forever', 'Version')
|
|
local NUM_EQUIPMENT_SLOTS = 19
|
|
|
|
--locals
|
|
local currentPlayer = UnitName('player') --the name of the current player that's logged on
|
|
local currentRealm = GetRealmName() --what currentRealm we're on
|
|
local playerList --a sorted list of players
|
|
|
|
|
|
--[[ Local Functions ]]--
|
|
|
|
local function ToIndex(bag, slot)
|
|
if tonumber(bag) then
|
|
return (bag < 0 and bag*100 - slot) or bag*100 + slot
|
|
end
|
|
return bag .. slot
|
|
end
|
|
|
|
local function ToBagIndex(bag)
|
|
return (tonumber(bag) and bag*100) or bag
|
|
end
|
|
|
|
--returns the full item link only for items that have enchants/suffixes, otherwise returns the item's ID
|
|
local function ToShortLink(link)
|
|
if link then
|
|
local a,b,c,d,e,f,g,h = link:match('(%-?%d+):(%-?%d+):(%-?%d+):(%-?%d+):(%-?%d+):(%-?%d+):(%-?%d+):(%-?%d+)')
|
|
|
|
--ASC sets this to unique id in the personal bank, clear it
|
|
c = 0;
|
|
|
|
if(b == '0' and b == c and c == d and d == e and e == f and f == g) then
|
|
return a
|
|
end
|
|
return format('item:%s:%s:%s:%s:%s:%s:%s:%s', a, b, c, d, e, f, g, h)
|
|
end
|
|
end
|
|
|
|
local function GetBagSize(bag)
|
|
if bag == KEYRING_CONTAINER then
|
|
return GetKeyRingSize()
|
|
end
|
|
|
|
if (bag >= ASC_PERSONAL_BANK_OFFSET) then
|
|
return 98
|
|
end
|
|
|
|
if bag == 'e' then
|
|
return NUM_EQUIPMENT_SLOTS
|
|
end
|
|
return GetContainerNumSlots(bag)
|
|
end
|
|
|
|
|
|
--[[ Addon Loading ]]--
|
|
|
|
function BagnonDB:Initialize()
|
|
self:LoadSettings()
|
|
|
|
self:SetScript('OnEvent', function(self, event, ...)
|
|
if self[event] then
|
|
self[event](self, event, ...)
|
|
end
|
|
end)
|
|
|
|
if IsLoggedIn() then
|
|
self:PLAYER_LOGIN()
|
|
else
|
|
self:RegisterEvent('PLAYER_LOGIN')
|
|
end
|
|
end
|
|
|
|
function BagnonDB:LoadSettings()
|
|
if not(BagnonForeverDB and BagnonForeverDB.version) then
|
|
BagnonForeverDB = {version = CURRENT_VERSION}
|
|
else
|
|
local cMajor, cMinor = CURRENT_VERSION:match('(%d+)%.(%d+)')
|
|
local major, minor = BagnonForeverDB.version:match('(%d+)%.(%d+)')
|
|
|
|
if major ~= cMajor then
|
|
BagnonForeverDB = {version = cVersion}
|
|
elseif minor ~= cMinor then
|
|
self:UpdateSettings()
|
|
end
|
|
|
|
if BagnonForeverDB.version ~= CURRENT_VERSION then
|
|
self:UpdateVersion()
|
|
end
|
|
end
|
|
|
|
self.db = BagnonForeverDB
|
|
if not self.db[currentRealm] then
|
|
self.db[currentRealm] = {}
|
|
end
|
|
self.rdb = self.db[currentRealm]
|
|
|
|
if not self.rdb[currentPlayer] then
|
|
self.rdb[currentPlayer] = {}
|
|
end
|
|
self.pdb = self.rdb[currentPlayer]
|
|
|
|
|
|
if not self.rdb[currentRealm] then
|
|
self.rdb[currentRealm] = {}
|
|
end
|
|
self.realmdb = self.rdb[currentRealm]
|
|
end
|
|
|
|
function BagnonDB:UpdateSettings()
|
|
end
|
|
|
|
function BagnonDB:UpdateVersion()
|
|
BagnonForeverDB.version = CURRENT_VERSION
|
|
print(format('BagnonForever: Updated to v%s', BagnonForeverDB.version))
|
|
end
|
|
|
|
|
|
--[[ Events ]]--
|
|
|
|
function BagnonDB:PLAYER_LOGIN()
|
|
self:SaveMoney()
|
|
self:UpdateBag(BACKPACK_CONTAINER)
|
|
self:UpdateBag(KEYRING_CONTAINER)
|
|
self:SaveEquipment()
|
|
self:SaveNumBankSlots()
|
|
|
|
|
|
self:RegisterEvent('GUILDBANKFRAME_OPENED')
|
|
self:RegisterEvent('GUILDBANKFRAME_CLOSED')
|
|
self:RegisterEvent('GUILDBANKBAGSLOTS_CHANGED')
|
|
self:RegisterEvent('BANKFRAME_OPENED')
|
|
self:RegisterEvent('BANKFRAME_CLOSED')
|
|
self:RegisterEvent('PLAYER_MONEY')
|
|
self:RegisterEvent('BAG_UPDATE')
|
|
self:RegisterEvent('PLAYERBANKSLOTS_CHANGED')
|
|
self:RegisterEvent('UNIT_INVENTORY_CHANGED')
|
|
self:RegisterEvent('PLAYERBANKBAGSLOTS_CHANGED')
|
|
end
|
|
|
|
function BagnonDB:PLAYER_MONEY()
|
|
self:SaveMoney()
|
|
end
|
|
|
|
function BagnonDB:BAG_UPDATE(event, bag)
|
|
if not(bag == BANK_CONTAINER or bag > NUM_BAG_SLOTS) or self.atBank then
|
|
self:OnBagUpdate(bag)
|
|
end
|
|
end
|
|
|
|
function BagnonDB:PLAYERBANKSLOTS_CHANGED()
|
|
self:UpdateBag(BANK_CONTAINER)
|
|
end
|
|
|
|
function BagnonDB:PLAYERBANKBAGSLOTS_CHANGED()
|
|
self:SaveNumBankSlots()
|
|
end
|
|
|
|
function BagnonDB:BANKFRAME_OPENED()
|
|
self.atBank = true
|
|
|
|
self:UpdateBag(BANK_CONTAINER)
|
|
for i = 1, GetNumBankSlots() do
|
|
self:UpdateBag(i + 4)
|
|
end
|
|
end
|
|
|
|
function BagnonDB:BANKFRAME_CLOSED()
|
|
self.atBank = nil
|
|
end
|
|
|
|
|
|
|
|
function BagnonDB:GUILDBANKFRAME_OPENED()
|
|
if HasJsonCacheData("BANK_PERMISSIONS_PAYLOAD", 0) then
|
|
local json = GetJsonCacheData("BANK_PERMISSIONS_PAYLOAD", 0)
|
|
if json then
|
|
local jsonObject = C_Serialize:FromJSON(json)
|
|
if jsonObject then
|
|
self.IsPersonalBank = jsonObject.IsPersonalBank
|
|
self.IsRealmBank = jsonObject.IsRealmBank
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
if (self.IsPersonalBank) then
|
|
for i = 1, 6 do
|
|
local avail = GetGuildBankTabInfo(i)
|
|
if type(avail) == "string" then
|
|
self:UpdateBag(i + ASC_PERSONAL_BANK_OFFSET)
|
|
end
|
|
end
|
|
return
|
|
end
|
|
|
|
if (self.IsRealmBank) then
|
|
for i = 1, 6 do
|
|
local avail = GetGuildBankTabInfo(i)
|
|
if type(avail) == "string" then
|
|
self:UpdateBag(i + ASC_REALM_BANK_OFFSET)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function BagnonDB:GUILDBANKFRAME_CLOSED()
|
|
self.IsPersonalBank = nil
|
|
self.IsRealmBank = nil
|
|
end
|
|
|
|
function BagnonDB:GUILDBANKBAGSLOTS_CHANGED()
|
|
if (self.IsPersonalBank) then
|
|
for i = 1, 6 do
|
|
local avail = GetGuildBankTabInfo(i)
|
|
if type(avail) == "string" then
|
|
self:UpdateBag(i + ASC_PERSONAL_BANK_OFFSET)
|
|
end
|
|
end
|
|
return
|
|
end
|
|
|
|
if (self.IsRealmBank) then
|
|
for i = 1, 6 do
|
|
local avail = GetGuildBankTabInfo(i)
|
|
if type(avail) == "string" then
|
|
self:UpdateBag(i + ASC_REALM_BANK_OFFSET)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
function BagnonDB:UNIT_INVENTORY_CHANGED(event, unit)
|
|
if unit == 'player' then
|
|
self:SaveEquipment()
|
|
end
|
|
end
|
|
|
|
|
|
--[[
|
|
Access Functions
|
|
Bagnon requires all of these functions to be present when attempting to view cached data
|
|
--]]
|
|
|
|
--[[
|
|
BagnonDB:GetPlayerList()
|
|
returns:
|
|
iterator of all players on this realm with data
|
|
usage:
|
|
for playerName, data in BagnonDB:GetPlayers()
|
|
--]]
|
|
function BagnonDB:GetPlayerList()
|
|
if(not playerList) then
|
|
playerList = {}
|
|
|
|
for player in self:GetPlayers() do
|
|
table.insert(playerList, player)
|
|
end
|
|
|
|
--sort by currentPlayer first, then alphabetically
|
|
table.sort(playerList, function(a, b)
|
|
if(a == currentPlayer) then
|
|
return true
|
|
elseif(b == currentPlayer) then
|
|
return false
|
|
end
|
|
return a < b
|
|
end)
|
|
end
|
|
return playerList
|
|
end
|
|
|
|
function BagnonDB:GetPlayers()
|
|
return pairs(self.rdb)
|
|
end
|
|
|
|
|
|
--[[
|
|
BagnonDB:GetMoney(player)
|
|
args:
|
|
player (string)
|
|
the name of the player we're looking at. This is specific to the current realm we're on
|
|
|
|
returns:
|
|
(number) How much money, in copper, the given player has
|
|
--]]
|
|
function BagnonDB:GetMoney(player)
|
|
local playerData = self.rdb[player]
|
|
if playerData then
|
|
return playerData.g or 0
|
|
end
|
|
return 0
|
|
end
|
|
|
|
|
|
|
|
--[[
|
|
BagnonDB:GetNumBankSlots(player)
|
|
args:
|
|
player (string)
|
|
the name of the player we're looking at. This is specific to the current realm we're on
|
|
|
|
returns:
|
|
(number or nil) How many bank slots the current player has purchased
|
|
--]]
|
|
function BagnonDB:GetNumBankSlots(player)
|
|
local playerData = self.rdb[player]
|
|
if playerData then
|
|
return playerData.numBankSlots
|
|
end
|
|
end
|
|
|
|
|
|
--[[
|
|
BagnonDB:GetBagData(bag, player)
|
|
args:
|
|
player (string)
|
|
the name of the player we're looking at. This is specific to the current realm we're on
|
|
bag (number)
|
|
the number of the bag we're looking at.
|
|
|
|
returns:
|
|
size (number)
|
|
How many items the bag can hold (number)
|
|
hyperlink (string)
|
|
The hyperlink of the bag
|
|
count (number)
|
|
How many items are in the bag. This is used by ammo and soul shard bags
|
|
--]]
|
|
function BagnonDB:GetBagData(bag, player)
|
|
local playerDB = self.rdb[player]
|
|
if playerDB then
|
|
local bagInfo = playerDB[ToBagIndex(bag)]
|
|
if bagInfo then
|
|
local size, link, count = strsplit(',', bagInfo)
|
|
local hyperLink = (link and select(2, GetItemInfo(link))) or nil
|
|
return tonumber(size), hyperLink, tonumber(count) or 1, GetItemIcon(link)
|
|
end
|
|
end
|
|
end
|
|
|
|
--[[
|
|
BagnonDB:GetItemData(bag, slot, player)
|
|
args:
|
|
player (string)
|
|
the name of the player we're looking at. This is specific to the current realm we're on
|
|
bag (number)
|
|
the number of the bag we're looking at.
|
|
itemSlot (number)
|
|
the specific item slot we're looking at
|
|
|
|
returns:
|
|
hyperLink (string)
|
|
The hyperLink of the item
|
|
count (number)
|
|
How many of there are of the specific item
|
|
texture (string)
|
|
The filepath of the item's texture
|
|
quality (number)
|
|
The numeric representaiton of the item's quality: from 0 (poor) to 7 (artifcat)
|
|
--]]
|
|
function BagnonDB:GetItemData(bag, slot, player)
|
|
local playerDB = self.rdb[player]
|
|
if playerDB then
|
|
local itemInfo = playerDB[ToIndex(bag, slot)]
|
|
if itemInfo then
|
|
local link, count = strsplit(',', itemInfo)
|
|
if link then
|
|
local hyperLink, quality = select(2, GetItemInfo(link))
|
|
return hyperLink, tonumber(count) or 1, GetItemIcon(link), tonumber(quality)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--[[
|
|
Returns how many of the specific item id the given player has in the given bag
|
|
--]]
|
|
function BagnonDB:GetItemCount(itemLink, bag, player)
|
|
local total = 0
|
|
local itemLink = select(2, GetItemInfo(ToShortLink(itemLink)))
|
|
local size = (self:GetBagData(bag, player)) or 0
|
|
|
|
if (bag == "e") then
|
|
size = NUM_EQUIPMENT_SLOTS
|
|
end
|
|
|
|
for slot = 1, size do
|
|
local link, count = self:GetItemData(bag, slot, player)
|
|
if link == itemLink then
|
|
total = total + (count or 1)
|
|
end
|
|
end
|
|
|
|
return total
|
|
end
|
|
|
|
--[[
|
|
Storage Functions
|
|
How we store the data (duh)
|
|
--]]
|
|
|
|
|
|
--[[ Storage Functions ]]--
|
|
|
|
function BagnonDB:SaveMoney()
|
|
self.pdb.g = GetMoney()
|
|
end
|
|
|
|
function BagnonDB:SaveNumBankSlots()
|
|
self.pdb.numBankSlots = GetNumBankSlots()
|
|
end
|
|
|
|
--saves all the player's equipment data information
|
|
function BagnonDB:SaveEquipment()
|
|
for slot = 0, NUM_EQUIPMENT_SLOTS do
|
|
local link = GetInventoryItemLink('player', slot)
|
|
local index = ToIndex('e', slot)
|
|
|
|
if link then
|
|
local link = ToShortLink(link)
|
|
local count = GetInventoryItemCount('player', slot)
|
|
count = count > 1 and count or nil
|
|
|
|
if(link and count) then
|
|
self.pdb[index] = format('%s,%d', link, count)
|
|
else
|
|
self.pdb[index] = link
|
|
end
|
|
else
|
|
self.pdb[index] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
--saves data about a specific item the current player has
|
|
function BagnonDB:SaveItem(bag, slot)
|
|
|
|
|
|
if (bag > ASC_REALM_BANK_OFFSET) then
|
|
local texture, count = GetGuildBankItemInfo(bag - ASC_REALM_BANK_OFFSET, slot)
|
|
|
|
local index = ToIndex(bag, slot)
|
|
|
|
if texture then
|
|
local link = ToShortLink(GetGuildBankItemLink(bag - ASC_REALM_BANK_OFFSET, slot))
|
|
count = count > 1 and count or nil
|
|
if(link and count) then
|
|
self.realmdb[index] = format('%s,%d', link, count)
|
|
else
|
|
self.realmdb[index] = link
|
|
end
|
|
else
|
|
self.realmdb[index] = nil
|
|
end
|
|
elseif (bag > ASC_PERSONAL_BANK_OFFSET) then
|
|
local texture, count = GetGuildBankItemInfo(bag - ASC_PERSONAL_BANK_OFFSET, slot)
|
|
|
|
local index = ToIndex(bag, slot)
|
|
|
|
if texture then
|
|
local link = ToShortLink(GetGuildBankItemLink(bag - ASC_PERSONAL_BANK_OFFSET, slot))
|
|
count = count > 1 and count or nil
|
|
if(link and count) then
|
|
self.pdb[index] = format('%s,%d', link, count)
|
|
else
|
|
self.pdb[index] = link
|
|
end
|
|
else
|
|
self.pdb[index] = nil
|
|
end
|
|
else
|
|
local texture, count = GetContainerItemInfo(bag, slot)
|
|
|
|
local index = ToIndex(bag, slot)
|
|
|
|
if texture then
|
|
local link = ToShortLink(GetContainerItemLink(bag, slot))
|
|
count = count > 1 and count or nil
|
|
|
|
if(link and count) then
|
|
self.pdb[index] = format('%s,%d', link, count)
|
|
else
|
|
self.pdb[index] = link
|
|
end
|
|
else
|
|
self.pdb[index] = nil
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
--saves all information about the given bag, EXCEPT the bag's contents
|
|
function BagnonDB:SaveBag(bag)
|
|
local data = self.pdb
|
|
|
|
if (bag >= ASC_REALM_BANK_OFFSET) then
|
|
local size = GetBagSize(bag)
|
|
local index = ToBagIndex(bag)
|
|
self.realmdb[index] = size
|
|
elseif (bag >= ASC_PERSONAL_BANK_OFFSET) then
|
|
local size = GetBagSize(bag)
|
|
local index = ToBagIndex(bag)
|
|
self.pdb[index] = size
|
|
else
|
|
local size = GetBagSize(bag)
|
|
local index = ToBagIndex(bag)
|
|
|
|
if size > 0 then
|
|
local equipSlot = bag > 0 and ContainerIDToInventoryID(bag)
|
|
local link = ToShortLink(GetInventoryItemLink('player', equipSlot))
|
|
local count = GetInventoryItemCount('player', equipSlot)
|
|
if count < 1 then
|
|
count = nil
|
|
end
|
|
|
|
if(size and link and count) then
|
|
self.pdb[index] = format('%d,%s,%d', size, link, count)
|
|
elseif(size and link) then
|
|
self.pdb[index] = format('%d,%s', size, link)
|
|
else
|
|
self.pdb[index] = size
|
|
end
|
|
else
|
|
self.pdb[index] = nil
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
--saves both relevant information about the given bag, and all information about items in the given bag
|
|
function BagnonDB:UpdateBag(bag)
|
|
self:SaveBag(bag)
|
|
for slot = 1, GetBagSize(bag) do
|
|
self:SaveItem(bag, slot)
|
|
end
|
|
end
|
|
|
|
function BagnonDB:OnBagUpdate(bag)
|
|
if self.atBank then
|
|
for i = 1, (NUM_BAG_SLOTS + GetNumBankSlots()) do
|
|
self:SaveBag(i)
|
|
end
|
|
else
|
|
for i = 1, NUM_BAG_SLOTS do
|
|
self:SaveBag(i)
|
|
end
|
|
end
|
|
|
|
for slot = 1, GetBagSize(bag) do
|
|
self:SaveItem(bag, slot)
|
|
end
|
|
end
|
|
|
|
|
|
--[[ Removal Functions ]]--
|
|
|
|
--removes all saved data about the given player
|
|
function BagnonDB:RemovePlayer(player, realm)
|
|
local realm = realm or currentRealm
|
|
local rdb = self.db[realm]
|
|
if rdb then
|
|
rdb[player] = nil
|
|
end
|
|
|
|
if realm == currentRealm and playerList then
|
|
for i,character in pairs(playerList) do
|
|
if(character == player) then
|
|
table.remove(playerList, i)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|