This commit is contained in:
Andrew6810
2022-10-21 06:37:39 -07:00
parent 9fd56e0908
commit 4e3aff9d89
96 changed files with 13384 additions and 2 deletions
+11
View File
@@ -0,0 +1,11 @@
## Interface: 30300
## Title: Bagnon Forever
## Notes: Stores inventory information about your characters
## Notes-zhTW: 儲存角色背包和銀行的物品資訊
## Notes-zhCN: 保存角色背包与银行内物品的信息
## Author: Tuller
## Version: 1.1.2
## SavedVariables: BagnonForeverDB
## LoadOnDemand: 0
db.lua
ui.xml
+454
View File
@@ -0,0 +1,454 @@
--[[
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')
--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+)')
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 == '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]
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('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: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
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)
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
--saves all information about the given bag, EXCEPT the bag's contents
function BagnonDB:SaveBag(bag)
local data = self.pdb
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
--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
+97
View File
@@ -0,0 +1,97 @@
--[[
BagnonDBUI
Functions for the dropdown menu for showing cached data
No alterations if this code should be needed to make it work with other databases
Essentially the dropdown is used to switch between the inventory of other characters
Why not use a normal dropdown? It takes a lot of memory
--]]
local currentFrame
local dropdown
local info = {}
--adds a checkable item to a dropdown menu
local function AddCheckItem(text, value, func, checked, hasArrow, level, arg1, arg2)
info.text = text
info.func = func
info.value = value
info.hasArrow = (hasArrow and true) or nil
info.notCheckable = false
info.checked = checked
info.arg1 = arg1
info.arg2 = arg2
UIDropDownMenu_AddButton(info, level)
end
--adds an uncheckable item to a dropdown menu
local function AddItem(text, value, func, level, arg1, arg2)
info.text = text
info.func = func
info.value = value
info.hasArrow = false
info.notCheckable = true
info.checked = false
info.arg1 = arg1
info.arg2 = arg2
UIDropDownMenu_AddButton(info, level)
end
local function CharSelect_OnClick(self, player, delete)
local newPlayer
if delete then
--remove the selected player
BagnonDB:RemovePlayer(player)
--select the current player
newPlayer = UnitName('player')
else
--select the clicked player
newPlayer = player
end
--show the given player, and check the selected one
currentFrame:SetPlayer(newPlayer)
--hide the previous dropdown menus (hack)
for i = 1, UIDROPDOWNMENU_MENU_LEVEL-1 do
getglobal("DropDownList"..i):Hide()
end
end
--populate the list, add a delete button to all characters that aren't the current player
local function CharSelect_Initialize(self, level)
local playerList = BagnonDB:GetPlayerList()
local level = level or 1
if level == 1 then
local selected = currentFrame:GetPlayer()
local current = UnitName('player')
for i,player in ipairs(playerList) do
AddCheckItem(player, i, CharSelect_OnClick, player == selected, player ~= current, level, player)
end
elseif level == 2 then
AddItem(REMOVE, nil, CharSelect_OnClick, level, playerList[UIDROPDOWNMENU_MENU_VALUE], true)
end
end
local function CharSelect_Create()
dropdown = CreateFrame("Frame", "BagnonDBCharSelect", UIParent, "UIDropDownMenuTemplate")
dropdown:SetID(1)
UIDropDownMenu_Initialize(dropdown, CharSelect_Initialize, "MENU")
return dropdown
end
--[[ Usable Functions ]]--
--set which frame to "parent" the dropdown to
function BagnonDB:SetDropdownFrame(frame)
currentFrame = frame
end
--show the character select list at the given location
function BagnonDB:ToggleDropdown(anchor, offX, offY)
ToggleDropDownMenu(1, nil, dropdown or CharSelect_Create(), anchor, offX, offY)
end
+19
View File
@@ -0,0 +1,19 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script file="ui.lua"/>
<!-- a button added to each frame, shows the character selection list when clicked -->
<Button name="BagnonDBUIDropDownButton" topLevel="true" virtual="true">
<Size x="24" y="24"/>
<Scripts>
<OnClick>
BagnonDB:SetDropdownFrame(self:GetParent())
BagnonDB:ToggleDropdown(self, 0, 2)
</OnClick>
</Scripts>
<NormalTexture file="Interface\ChatFrame\UI-ChatIcon-ScrollDown-Up" setAllPoints="true"/>
<PushedTexture file="Interface\ChatFrame\UI-ChatIcon-ScrollDown-Down" setAllPoints="true"/>
<HighlightTexture file="Interface\Buttons\UI-Common-MouseHilight" alphaMode="ADD" setAllPoints="true"/>
</Button>
</Ui>