init
This commit is contained in:
@@ -0,0 +1,368 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster_ItemTracker --
|
||||
-- http://www.curse.com/addons/wow/tradeskillmaster_itemtracker --
|
||||
-- --
|
||||
-- A TradeSkillMaster Addon (http://tradeskillmaster.com) --
|
||||
-- All Rights Reserved* - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
-- load the parent file (TSM) into a local variable and register this file as a module
|
||||
local TSM = select(2, ...)
|
||||
local Config = TSM:NewModule("Config", "AceEvent-3.0", "AceHook-3.0")
|
||||
local AceGUI = LibStub("AceGUI-3.0") -- load the AceGUI libraries
|
||||
local L = LibStub("AceLocale-3.0"):GetLocale("TradeSkillMaster_ItemTracker")
|
||||
|
||||
local viewerST
|
||||
local filters = { characters = {}, guilds = {}, name = "", group = nil }
|
||||
|
||||
function Config:Load(container)
|
||||
local tabGroup = AceGUI:Create("TSMTabGroup")
|
||||
tabGroup:SetLayout("Fill")
|
||||
tabGroup:SetTabs({ { text = L["Inventory Viewer"], value = 1 }, { text = L["Options"], value = 2 } })
|
||||
tabGroup:SetCallback("OnGroupSelected", function(self, _, value)
|
||||
tabGroup:ReleaseChildren()
|
||||
if viewerST then viewerST:Hide() end
|
||||
if value == 1 then
|
||||
Config:LoadInventoryViewer(self)
|
||||
elseif value == 2 then
|
||||
Config:LoadOptions(self)
|
||||
end
|
||||
tabGroup.children[1]:DoLayout()
|
||||
end)
|
||||
container:AddChild(tabGroup)
|
||||
tabGroup:SelectTab(1)
|
||||
|
||||
Config:HookScript(tabGroup.frame, "OnHide", function()
|
||||
Config:UnhookAll()
|
||||
if viewerST then viewerST:Hide() end
|
||||
end)
|
||||
end
|
||||
|
||||
local function GetSTData()
|
||||
local items, rowData = {}, {}
|
||||
|
||||
local function AddItem(itemString, key, quantity)
|
||||
items[itemString] = items[itemString] or { total = 0, bags = 0, bank = 0, guild = 0, auctions = 0, mail = 0 }
|
||||
items[itemString].total = items[itemString].total + quantity
|
||||
items[itemString][key] = items[itemString][key] + quantity
|
||||
end
|
||||
|
||||
for name, selected in pairs(filters.characters) do
|
||||
if selected then
|
||||
for itemString, quantity in pairs(TSM:GetPlayerBags(name) or {}) do
|
||||
AddItem(itemString, "bags", quantity)
|
||||
end
|
||||
for itemString, quantity in pairs(TSM:GetPlayerBank(name) or {}) do
|
||||
AddItem(itemString, "bank", quantity)
|
||||
end
|
||||
for itemString, quantity in pairs(TSM:GetPlayerMail(name) or {}) do
|
||||
AddItem(itemString, "mail", quantity)
|
||||
end
|
||||
for itemString, quantity in pairs(TSM:GetPlayerAuctions(name) or {}) do
|
||||
if itemString ~= "time" then
|
||||
AddItem(itemString, "auctions", quantity)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for name, selected in pairs(filters.guilds) do
|
||||
if selected then
|
||||
for itemString, quantity in pairs(TSM:GetGuildBank(name) or {}) do
|
||||
AddItem(itemString, "guild", quantity)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for itemString, data in pairs(items) do
|
||||
local name, itemLink = TSMAPI:GetSafeItemInfo(itemString)
|
||||
local marketValue = TSMAPI:GetItemValue(itemString, TSM.db.profile.marketValue) or 0
|
||||
local groupPath = TSMAPI:GetGroupPath(itemString)
|
||||
if (not name or filters.name == "" or strfind(strlower(name), filters.name)) and (not filters.group or groupPath and strfind(groupPath, "^" .. TSMAPI:StrEscape(filters.group))) then
|
||||
tinsert(rowData, {
|
||||
cols = {
|
||||
{
|
||||
value = itemLink or name or itemString,
|
||||
sortArg = name or "",
|
||||
},
|
||||
{
|
||||
value = data.bags,
|
||||
sortArg = data.bags,
|
||||
},
|
||||
{
|
||||
value = data.bank,
|
||||
sortArg = data.bank,
|
||||
},
|
||||
{
|
||||
value = data.mail,
|
||||
sortArg = data.mail,
|
||||
},
|
||||
{
|
||||
value = data.guild,
|
||||
sortArg = data.guild,
|
||||
},
|
||||
{
|
||||
value = data.auctions,
|
||||
sortArg = data.auctions,
|
||||
},
|
||||
{
|
||||
value = data.total,
|
||||
sortArg = data.total,
|
||||
},
|
||||
{
|
||||
value = TSMAPI:FormatTextMoney(data.total * marketValue) or "---",
|
||||
sortArg = data.total * marketValue,
|
||||
},
|
||||
},
|
||||
itemString = itemString,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
sort(rowData, function(a, b) return a.cols[#a.cols].value > b.cols[#a.cols].value end)
|
||||
return rowData
|
||||
end
|
||||
|
||||
function Config:LoadInventoryViewer(container)
|
||||
-- top AceGUI widgets
|
||||
local playerList, guildList = {}, {}
|
||||
for name in pairs(TSM.characters) do
|
||||
playerList[name] = name
|
||||
filters.characters[name] = true
|
||||
end
|
||||
for name in pairs(TSM.guilds) do
|
||||
if not TSM.db.factionrealm.ignoreGuilds[name] then
|
||||
guildList[name] = name
|
||||
filters.guilds[name] = true
|
||||
end
|
||||
end
|
||||
filters.group = nil
|
||||
|
||||
local page = {
|
||||
{
|
||||
type = "SimpleGroup",
|
||||
layout = "Flow",
|
||||
fullHeight = true,
|
||||
children = {
|
||||
{
|
||||
type = "EditBox",
|
||||
label = L["Item Search"],
|
||||
relativeWidth = 0.24,
|
||||
onTextChanged = true,
|
||||
callback = function(_, _, value)
|
||||
filters.name = value:trim()
|
||||
viewerST:SetData(GetSTData())
|
||||
end,
|
||||
},
|
||||
{
|
||||
type = "GroupBox",
|
||||
label = "Group",
|
||||
relativeWidth = 0.25,
|
||||
callback = function(_, _, value)
|
||||
filters.group = value
|
||||
viewerST:SetData(GetSTData())
|
||||
end,
|
||||
},
|
||||
{
|
||||
type = "Dropdown",
|
||||
label = L["Characters"],
|
||||
relativeWidth = 0.25,
|
||||
list = playerList,
|
||||
value = filters.characters,
|
||||
multiselect = true,
|
||||
callback = function(_, _, key, value)
|
||||
filters.characters[key] = value
|
||||
viewerST:SetData(GetSTData())
|
||||
end,
|
||||
},
|
||||
{
|
||||
type = "Dropdown",
|
||||
label = L["Guilds"],
|
||||
relativeWidth = 0.25,
|
||||
list = guildList,
|
||||
value = filters.guilds,
|
||||
multiselect = true,
|
||||
callback = function(_, _, key, value)
|
||||
filters.guilds[key] = value
|
||||
viewerST:SetData(GetSTData())
|
||||
end,
|
||||
},
|
||||
{
|
||||
type = "ScrollFrame", -- simple group didn't work here for some reason
|
||||
fullHeight = true,
|
||||
layout = "Flow",
|
||||
children = {},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
TSMAPI:BuildPage(container, page)
|
||||
|
||||
-- scrolling table
|
||||
local stParent = container.children[1].children[#container.children[1].children].frame
|
||||
|
||||
if not viewerST then
|
||||
local stCols = {
|
||||
{
|
||||
name = L["Item Name"],
|
||||
width = 0.35,
|
||||
},
|
||||
{
|
||||
name = L["Bags"],
|
||||
width = 0.08,
|
||||
},
|
||||
{
|
||||
name = L["Bank"],
|
||||
width = 0.08,
|
||||
},
|
||||
{
|
||||
name = L["Mail"],
|
||||
width = 0.08,
|
||||
},
|
||||
{
|
||||
name = L["GBank"],
|
||||
width = 0.08,
|
||||
},
|
||||
{
|
||||
name = L["AH"],
|
||||
width = 0.08,
|
||||
},
|
||||
{
|
||||
name = L["Total"],
|
||||
width = 0.08,
|
||||
},
|
||||
{
|
||||
name = L["Total Value"],
|
||||
width = 0.17,
|
||||
}
|
||||
}
|
||||
local handlers = {
|
||||
OnEnter = function(_, data, self)
|
||||
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
||||
TSMAPI:SafeTooltipLink(data.itemString)
|
||||
GameTooltip:Show()
|
||||
end,
|
||||
OnLeave = function()
|
||||
GameTooltip:ClearLines()
|
||||
GameTooltip:Hide()
|
||||
end
|
||||
}
|
||||
viewerST = TSMAPI:CreateScrollingTable(stParent, stCols, handlers)
|
||||
viewerST:EnableSorting(true)
|
||||
end
|
||||
|
||||
viewerST:Show()
|
||||
viewerST:SetParent(stParent)
|
||||
viewerST:SetAllPoints()
|
||||
viewerST:SetData(GetSTData())
|
||||
end
|
||||
|
||||
function Config:LoadOptions(container)
|
||||
local players, guildList = {}, {}
|
||||
for _, v in ipairs(TSM:GetPlayers()) do
|
||||
players[v] = v
|
||||
end
|
||||
|
||||
for name in pairs(TSM.guilds) do
|
||||
guildList[name] = name
|
||||
end
|
||||
|
||||
local page = {
|
||||
{
|
||||
-- scroll frame to contain everything
|
||||
type = "ScrollFrame",
|
||||
layout = "flow",
|
||||
children = {
|
||||
{
|
||||
type = "InlineGroup",
|
||||
title = L["Options"],
|
||||
layout = "flow",
|
||||
children = {
|
||||
{
|
||||
type = "Dropdown",
|
||||
label = L["Delete Character:"],
|
||||
list = players,
|
||||
relativeWidth = 0.49,
|
||||
callback = function(self, _, value)
|
||||
if value == UnitName("player") then
|
||||
-- don't delete the current player, just reset to defaults
|
||||
TSM.characters[value] = TSM.characterDefaults
|
||||
TSM:Print(L["Reset current player's inventory data."])
|
||||
self:SetValue()
|
||||
return
|
||||
end
|
||||
local charGuild = TSM.characters[value].guild
|
||||
if charGuild then
|
||||
local hasMembersLeft = false
|
||||
for player, data in pairs(TSM.characters) do
|
||||
if player ~= value and data.guild == charGuild then
|
||||
hasMembersLeft = true
|
||||
end
|
||||
end
|
||||
if not hasMembersLeft then
|
||||
TSM.guilds[charGuild] = nil
|
||||
end
|
||||
end
|
||||
|
||||
TSM.characters[value] = nil
|
||||
TSM:Printf(L["\"%s\" removed from ItemTracker."], value)
|
||||
players[value] = nil
|
||||
self:SetList(players)
|
||||
self:SetValue()
|
||||
end,
|
||||
tooltip = L["If you rename / transfer / delete one of your characters, use this dropdown to remove that character from ItemTracker. There is no confirmation. If you accidentally delete a character that still exists, simply log onto that character to re-add it to ItemTracker."],
|
||||
},
|
||||
{
|
||||
type = "Dropdown",
|
||||
label = L["Guilds (Guild Banks) to Ignore:"],
|
||||
value = TSM.db.factionrealm.ignoreGuilds,
|
||||
list = guildList,
|
||||
relativeWidth = 0.49,
|
||||
multiselect = true,
|
||||
callback = function(_, _, key, value)
|
||||
TSM.db.factionrealm.ignoreGuilds[key] = value
|
||||
end,
|
||||
tooltip = L["Select guilds to ingore in ItemTracker. Inventory will still be tracked but not displayed or taken into consideration by Itemtracker."],
|
||||
},
|
||||
{
|
||||
type = "Dropdown",
|
||||
label = L["Market Value Price Source"],
|
||||
relativeWidth = 1,
|
||||
list = TSMAPI:GetPriceSources(),
|
||||
value = TSM.db.profile.marketValue,
|
||||
callback = function(_, _, value) TSM.db.profile.marketValue = value end,
|
||||
tooltip = L["Specifies the market value price source used for \"Total Market Value\" in the Inventory Viewer."],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
TSMAPI:BuildPage(container, page)
|
||||
end
|
||||
|
||||
function Config:LoadTooltipOptions(container)
|
||||
local page = {
|
||||
{
|
||||
type = "SimpleGroup",
|
||||
layout = "Flow",
|
||||
fullHeight = true,
|
||||
children = {
|
||||
{
|
||||
type = "Dropdown",
|
||||
label = "Tooltip:",
|
||||
value = TSM.db.global.tooltip,
|
||||
list = { hide = L["No Tooltip Info"], simple = L["Simple"], full = L["Full"] },
|
||||
relativeWidth = 0.49,
|
||||
callback = function(_, _, value)
|
||||
TSM.db.global.tooltip = value
|
||||
end,
|
||||
tooltip = L["Here, you can choose what ItemTracker info, if any, to show in tooltips. \"Simple\" will only show totals for bags/banks and for guild banks. \"Full\" will show detailed information for every character and guild."],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
TSMAPI:BuildPage(container, page)
|
||||
end
|
||||
@@ -0,0 +1,444 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster_ItemTracker --
|
||||
-- http://www.curse.com/addons/wow/tradeskillmaster_itemtracker --
|
||||
-- --
|
||||
-- A TradeSkillMaster Addon (http://tradeskillmaster.com) --
|
||||
-- All Rights Reserved* - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
-- load the parent file (TSM) into a local variable and register this file as a module
|
||||
local TSM = select(2, ...)
|
||||
local Data = TSM:NewModule("Data", "AceEvent-3.0", "AceHook-3.0")
|
||||
local L = LibStub("AceLocale-3.0"):GetLocale("TradeSkillMaster_ItemTracker")
|
||||
|
||||
TSM.CURRENT_PLAYER, TSM.CURRENT_GUILD = UnitName("player"), GetGuildInfo("player")
|
||||
local BUCKET_TIME = 0.2 -- wait at least this amount of time between throttled events firing
|
||||
local throttleFrames = {}
|
||||
local isScanning = false
|
||||
|
||||
function Data:Initialize()
|
||||
Data:RegisterEvent("GUILDBANKFRAME_OPENED", "EventHandler")
|
||||
Data:RegisterEvent("GUILDBANKBAGSLOTS_CHANGED", "EventHandler")
|
||||
Data:RegisterEvent("AUCTION_OWNED_LIST_UPDATE", "EventHandler")
|
||||
TSMAPI:RegisterForBagChange(function(...) Data:GetBagData(...) end)
|
||||
TSMAPI:RegisterForBankChange(function(...) Data:GetBankData(...) end)
|
||||
|
||||
TSM.CURRENT_PLAYER, TSM.CURRENT_GUILD = UnitName("player"), GetGuildInfo("player")
|
||||
Data:StoreCurrentGuildInfo()
|
||||
end
|
||||
|
||||
local guildThrottle = CreateFrame("frame")
|
||||
guildThrottle:Hide()
|
||||
guildThrottle.attemptsLeft = 20
|
||||
guildThrottle:SetScript("OnUpdate", function(self, elapsed)
|
||||
self.timeLeft = self.timeLeft - elapsed
|
||||
if self.timeLeft <= 0 then
|
||||
self.attemptsLeft = self.attemptsLeft - 1
|
||||
Data:StoreCurrentGuildInfo(self.attemptsLeft == 0)
|
||||
end
|
||||
end)
|
||||
|
||||
function Data:StoreCurrentGuildInfo(noDelay)
|
||||
TSM.CURRENT_GUILD = GetGuildInfo("player")
|
||||
if TSM.CURRENT_GUILD then
|
||||
TSM.guilds[TSM.CURRENT_GUILD] = TSM.guilds[TSM.CURRENT_GUILD] or { items = {} }
|
||||
TSM.guilds[TSM.CURRENT_GUILD].items = TSM.guilds[TSM.CURRENT_GUILD].items or {}
|
||||
guildThrottle:Hide()
|
||||
elseif not noDelay then
|
||||
guildThrottle.timeLeft = 0.5
|
||||
guildThrottle:Show()
|
||||
else
|
||||
guildThrottle:Hide()
|
||||
end
|
||||
TSM.characters[TSM.CURRENT_PLAYER].guild = TSM.CURRENT_GUILD
|
||||
TSM.characters[TSM.CURRENT_PLAYER].lastUpdate.guild = time()
|
||||
TSM.Sync:BroadcastUpdateRequest()
|
||||
end
|
||||
|
||||
function Data:ThrottleEvent(event)
|
||||
if not throttleFrames[event] then
|
||||
local frame = CreateFrame("Frame")
|
||||
frame.baseTime = BUCKET_TIME
|
||||
frame.event = event
|
||||
frame:Hide()
|
||||
frame:SetScript("OnShow", function(self) Data:UnregisterEvent(self.event) self.timeLeft = self.baseTime end)
|
||||
frame:SetScript("OnUpdate", function(self, elapsed)
|
||||
self.timeLeft = self.timeLeft - elapsed
|
||||
if self.timeLeft <= 0 then
|
||||
Data:EventHandler(self.event, "FIRE")
|
||||
self:Hide()
|
||||
Data:RegisterEvent(self.event, "EventHandler")
|
||||
end
|
||||
end)
|
||||
throttleFrames[event] = frame
|
||||
end
|
||||
|
||||
-- resets the delay time on the frame
|
||||
throttleFrames[event]:Hide()
|
||||
throttleFrames[event]:Show()
|
||||
end
|
||||
|
||||
function Data:EventHandler(event, fire)
|
||||
if isScanning then return end
|
||||
if fire ~= "FIRE" then
|
||||
Data:ThrottleEvent(event)
|
||||
else
|
||||
if event == "GUILDBANKFRAME_OPENED" then
|
||||
-- Query all tabs of the gbank to ensure all tabs will be scanned.
|
||||
local initialTab = GetCurrentGuildBankTab()
|
||||
for tab = 1, GetNumGuildBankTabs() do
|
||||
if select(5, GetGuildBankTabInfo(tab)) > 0 or IsGuildLeader(UnitName("player")) then
|
||||
QueryGuildBankTab(tab)
|
||||
end
|
||||
end
|
||||
QueryGuildBankTab(initialTab)
|
||||
elseif event == "GUILDBANKBAGSLOTS_CHANGED" then
|
||||
Data:GetGuildBankData()
|
||||
elseif event == "AUCTION_OWNED_LIST_UPDATE" then
|
||||
Data:ScanPlayerAuctions()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- scan the player's bags
|
||||
function Data:GetBagData(state)
|
||||
wipe(TSM.characters[TSM.CURRENT_PLAYER].bags)
|
||||
for itemString, quantity in pairs(state) do
|
||||
local baseItemString = TSMAPI:GetBaseItemString(itemString)
|
||||
TSM.characters[TSM.CURRENT_PLAYER].bags[itemString] = quantity
|
||||
if itemString ~= baseItemString then
|
||||
TSM.characters[TSM.CURRENT_PLAYER].bags[baseItemString] = (TSM.characters[TSM.CURRENT_PLAYER].bags[baseItemString] or 0) + quantity
|
||||
end
|
||||
end
|
||||
TSM.characters[TSM.CURRENT_PLAYER].lastUpdate.bags = time()
|
||||
TSM.Sync:BroadcastUpdateRequest()
|
||||
end
|
||||
|
||||
-- scan the player's bank
|
||||
function Data:GetBankData(state)
|
||||
wipe(TSM.characters[TSM.CURRENT_PLAYER].bank)
|
||||
for itemString, quantity in pairs(state) do
|
||||
local baseItemString = TSMAPI:GetBaseItemString(itemString)
|
||||
TSM.characters[TSM.CURRENT_PLAYER].bank[itemString] = quantity
|
||||
if itemString ~= baseItemString then
|
||||
TSM.characters[TSM.CURRENT_PLAYER].bank[baseItemString] = (TSM.characters[TSM.CURRENT_PLAYER].bank[baseItemString] or 0) + quantity
|
||||
end
|
||||
end
|
||||
TSM.characters[TSM.CURRENT_PLAYER].lastUpdate.bank = time()
|
||||
TSM.Sync:BroadcastUpdateRequest()
|
||||
end
|
||||
|
||||
-- scan the guild bank
|
||||
function Data:GetGuildBankData()
|
||||
if not TSM.CURRENT_GUILD then
|
||||
Data:StoreCurrentGuildInfo(true)
|
||||
if not TSM.CURRENT_GUILD then return end
|
||||
end
|
||||
wipe(TSM.guilds[TSM.CURRENT_GUILD].items)
|
||||
|
||||
for tab = 1, GetNumGuildBankTabs() do
|
||||
if select(5, GetGuildBankTabInfo(tab)) > 0 or IsGuildLeader(UnitName("player")) then
|
||||
for slot = 1, MAX_GUILDBANK_SLOTS_PER_TAB or 98 do
|
||||
local itemString = TSMAPI:GetItemString(GetGuildBankItemLink(tab, slot))
|
||||
local baseItemString = TSMAPI:GetBaseItemString(GetGuildBankItemLink(tab, slot))
|
||||
if itemString then
|
||||
local quantity = select(2, GetGuildBankItemInfo(tab, slot))
|
||||
TSM.guilds[TSM.CURRENT_GUILD].items[itemString] = (TSM.guilds[TSM.CURRENT_GUILD].items[itemString] or 0) + quantity
|
||||
if itemString ~= baseItemString then
|
||||
TSM.guilds[TSM.CURRENT_GUILD].items[baseItemString] = (TSM.guilds[TSM.CURRENT_GUILD].items[baseItemString] or 0) + quantity
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if GuildBankFrame and GuildBankFrame:IsVisible() then
|
||||
TSM.guilds[TSM.CURRENT_GUILD].lastUpdate = time()
|
||||
end
|
||||
TSM.Sync:BroadcastUpdateRequest()
|
||||
end
|
||||
|
||||
function Data:ScanPlayerAuctions()
|
||||
wipe(TSM.characters[TSM.CURRENT_PLAYER].auctions)
|
||||
TSM.characters[TSM.CURRENT_PLAYER].auctions.time = time()
|
||||
|
||||
for i = 1, GetNumAuctionItems("owner") do
|
||||
local link = GetAuctionItemLink("owner", i)
|
||||
local itemString = TSMAPI:GetItemString(link)
|
||||
local baseItemString = TSMAPI:GetBaseItemString(link)
|
||||
--local name, _, quantity, _, _, _, _, _, _, buyout, _, _, _, wasSold, _, wasSold_54 = GetAuctionItemInfo("owner", i)
|
||||
local name, _, quantity, _, _, _, _, _, buyout, _, _, _, wasSold = GetAuctionItemInfo("owner", i)
|
||||
if wasSold == 0 and itemString then
|
||||
TSM.characters[TSM.CURRENT_PLAYER].auctions[itemString] = (TSM.characters[TSM.CURRENT_PLAYER].auctions[itemString] or 0) + quantity
|
||||
if itemString ~= baseItemString then
|
||||
TSM.characters[TSM.CURRENT_PLAYER].auctions[baseItemString] = (TSM.characters[TSM.CURRENT_PLAYER].auctions[baseItemString] or 0) + quantity
|
||||
end
|
||||
end
|
||||
end
|
||||
TSM.characters[TSM.CURRENT_PLAYER].lastUpdate.auctions = time()
|
||||
TSM.Sync:BroadcastUpdateRequest()
|
||||
end
|
||||
|
||||
|
||||
-- ***************************************************************************
|
||||
-- MAIL TRACKING FUNCTIONS
|
||||
-- ***************************************************************************
|
||||
|
||||
local playersToUpdate = {}
|
||||
local function UpdateMailQuantitiesThread(self)
|
||||
-- this runs in the background forever, updating mail quantities as necessary
|
||||
while true do
|
||||
if #playersToUpdate > 0 then
|
||||
local player = tremove(playersToUpdate)
|
||||
if TSM.characters[player] then
|
||||
local playerMail = TSM.characters[player].mail
|
||||
wipe(playerMail)
|
||||
for _, data in ipairs(TSM.characters[player].mailInbox) do
|
||||
for _, itemData in ipairs(data.items) do
|
||||
local itemString = TSMAPI:GetItemString(itemData.link)
|
||||
local baseItemString = TSMAPI:GetBaseItemString(itemData.link)
|
||||
playerMail[itemString] = (playerMail[itemString] or 0) + itemData.count
|
||||
if itemString ~= baseItemString then
|
||||
playerMail[baseItemString] = (playerMail[baseItemString] or 0) + itemData.count
|
||||
end
|
||||
end
|
||||
self:Yield()
|
||||
end
|
||||
TSM.characters[player].lastUpdate.mail = time()
|
||||
TSM.Sync:BroadcastUpdateRequest()
|
||||
end
|
||||
else
|
||||
self:Sleep(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local function InsertInboxMail(player, index, data)
|
||||
local playerMail = TSM.characters[player].mail
|
||||
for _, itemData in ipairs(data.items) do
|
||||
local itemString = TSMAPI:GetItemString(itemData.link)
|
||||
local baseItemString = TSMAPI:GetBaseItemString(itemData.link)
|
||||
playerMail[itemString] = (playerMail[itemString] or 0) + itemData.count
|
||||
if itemString ~= baseItemString then
|
||||
playerMail[baseItemString] = (playerMail[baseItemString] or 0) + itemData.count
|
||||
end
|
||||
end
|
||||
tinsert(TSM.characters[player].mailInbox, index, data)
|
||||
end
|
||||
|
||||
local function RemoveInboxMail(player, index)
|
||||
local playerMail = TSM.characters[player].mail
|
||||
for _, itemData in ipairs(TSM.characters[player].mailInbox[index].items) do
|
||||
local itemString = TSMAPI:GetItemString(itemData.link)
|
||||
local baseItemString = TSMAPI:GetBaseItemString(itemData.link)
|
||||
if playerMail[itemString] then
|
||||
playerMail[itemString] = max(playerMail[itemString] - itemData.count, 0)
|
||||
if playerMail[itemString] == 0 then
|
||||
playerMail[itemString] = nil
|
||||
end
|
||||
end
|
||||
if itemString ~= baseItemString and playerMail[baseItemString] then
|
||||
playerMail[baseItemString] = max(playerMail[baseItemString] - itemData.count, 0)
|
||||
if playerMail[baseItemString] == 0 then
|
||||
playerMail[baseItemString] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
tremove(TSM.characters[player].mailInbox, index)
|
||||
end
|
||||
|
||||
local function RemoveInboxMailItem(player, index, itemIndex)
|
||||
local playerMail = TSM.characters[player].mail
|
||||
local itemData = TSM.characters[player].mailInbox[index].items[itemIndex]
|
||||
local itemString = TSMAPI:GetItemString(itemData.link)
|
||||
local baseItemString = TSMAPI:GetBaseItemString(itemData.link)
|
||||
if playerMail[itemString] then
|
||||
playerMail[itemString] = max(playerMail[itemString] - itemData.count, 0)
|
||||
if playerMail[itemString] == 0 then
|
||||
playerMail[itemString] = nil
|
||||
end
|
||||
end
|
||||
if itemString ~= baseItemString and playerMail[baseItemString] then
|
||||
playerMail[baseItemString] = max(playerMail[baseItemString] - itemData.count, 0)
|
||||
if playerMail[baseItemString] == 0 then
|
||||
playerMail[baseItemString] = nil
|
||||
end
|
||||
end
|
||||
tremove(TSM.characters[player].mailInbox[index].items, itemIndex)
|
||||
end
|
||||
|
||||
local function AddIncomingMail(player, ...)
|
||||
if not TSM.characters[player] then return end
|
||||
TSM.characters[player].mailInbox = TSM.characters[player].mailInbox or {}
|
||||
local items
|
||||
if select('#', ...) == 1 then
|
||||
items = ...
|
||||
else
|
||||
local link, count = ...
|
||||
items = {{link=link, count=count}}
|
||||
end
|
||||
if not items then error() end
|
||||
InsertInboxMail(player, 1, {items=items, index=nil})
|
||||
end
|
||||
|
||||
local function RemoveMailItem(index, itemIndex)
|
||||
local link = GetInboxItemLink(index, itemIndex)
|
||||
if not link then return end
|
||||
local count = select(3, GetInboxItem(index, itemIndex))
|
||||
for i, data in ipairs(TSM.characters[TSM.CURRENT_PLAYER].mailInbox) do
|
||||
if data.index == index then
|
||||
for j, itemData in ipairs(data.items) do
|
||||
if itemData.link == link and itemData.count == count then
|
||||
RemoveInboxMailItem(TSM.CURRENT_PLAYER, i, j)
|
||||
break
|
||||
end
|
||||
end
|
||||
if #data.items == 0 then
|
||||
RemoveInboxMail(TSM.CURRENT_PLAYER, i)
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local tmpBuyouts = {}
|
||||
local function OnAuctionBid(listType, index, bidPlaced)
|
||||
local link = GetAuctionItemLink(listType, index)
|
||||
--local name, _, count, _, _, _, _, _, _, buyout = GetAuctionItemInfo(listType, index)
|
||||
local name, _, count, _, _, _, _, _, buyout = GetAuctionItemInfo(listType, index)
|
||||
if bidPlaced == buyout then
|
||||
tinsert(tmpBuyouts, { name = name, link = link, count = count })
|
||||
end
|
||||
end
|
||||
local function OnChatMsg(_, msg)
|
||||
if msg:match(gsub(ERR_AUCTION_WON_S, "%%s", "")) then
|
||||
while #tmpBuyouts > 0 do
|
||||
local info = tremove(tmpBuyouts, 1)
|
||||
if msg == format(ERR_AUCTION_WON_S, info.name) then
|
||||
AddIncomingMail(TSM.CURRENT_PLAYER, info.link, info.count)
|
||||
tinsert(playersToUpdate, TSM.CURRENT_PLAYER)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function OnAuctionCanceled(index)
|
||||
local link = GetAuctionItemLink("owner", index)
|
||||
local count = select(3, GetAuctionItemInfo("owner", index))
|
||||
AddIncomingMail(TSM.CURRENT_PLAYER, link, count)
|
||||
tinsert(playersToUpdate, TSM.CURRENT_PLAYER)
|
||||
end
|
||||
|
||||
local function OnSendMail(target)
|
||||
local altName
|
||||
for name in pairs(TSM.characters) do
|
||||
if strlower(name) == strlower(target) then
|
||||
altName = name
|
||||
break
|
||||
end
|
||||
end
|
||||
if not altName then return end
|
||||
local items = {}
|
||||
for i = 1, ATTACHMENTS_MAX_SEND do
|
||||
local link = GetSendMailItemLink(i)
|
||||
if link then
|
||||
local count = select(3, GetSendMailItem(i))
|
||||
tinsert(items, {link=link, count=count})
|
||||
end
|
||||
end
|
||||
AddIncomingMail(altName, items)
|
||||
tinsert(playersToUpdate, altName)
|
||||
end
|
||||
|
||||
local function OnTakeInboxItem(index, itemIndex)
|
||||
for i = (itemIndex or 1), (itemIndex or ATTACHMENTS_MAX_RECEIVE) do
|
||||
local link = GetInboxItemLink(index, i)
|
||||
if link then
|
||||
RemoveMailItem(index, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function OnReturnMail(index)
|
||||
local sender = select(3, GetInboxHeaderInfo(index))
|
||||
local items = {}
|
||||
for itemIndex = 1, ATTACHMENTS_MAX_RECEIVE do
|
||||
local link = GetInboxItemLink(index, itemIndex)
|
||||
if link then
|
||||
local count = select(3, GetInboxItem(index, itemIndex))
|
||||
tinsert(items, {link=link, count=count})
|
||||
RemoveMailItem(index, itemIndex)
|
||||
end
|
||||
end
|
||||
AddIncomingMail(sender, items)
|
||||
tinsert(playersToUpdate, sender)
|
||||
tinsert(playersToUpdate, TSM.CURRENT_PLAYER)
|
||||
end
|
||||
|
||||
local function OnInboxUpdate()
|
||||
local player = TSM.characters[TSM.CURRENT_PLAYER]
|
||||
player.mailInbox = player.mailInbox or {}
|
||||
local numItems, totalItems = GetInboxNumItems()
|
||||
if numItems == totalItems then
|
||||
wipe(player.mailInbox)
|
||||
end
|
||||
|
||||
local index = 1
|
||||
for i=1, numItems do
|
||||
local items = {}
|
||||
if select(8, GetInboxHeaderInfo(i)) then
|
||||
for j=1, ATTACHMENTS_MAX_RECEIVE do
|
||||
local link = GetInboxItemLink(i, j)
|
||||
if link then
|
||||
tinsert(items, {link=link, count=select(3, GetInboxItem(i, j))})
|
||||
end
|
||||
end
|
||||
local matchIndex
|
||||
for k=index, #player.mailInbox do
|
||||
if #player.mailInbox[k].items == #items then
|
||||
local temp = {}
|
||||
for _, data in ipairs(player.mailInbox[k].items) do
|
||||
temp[data.link] = (temp[data.link] or 0) + data.count
|
||||
end
|
||||
for _, data in ipairs(items) do
|
||||
if not temp[data.link] then break end
|
||||
temp[data.link] = temp[data.link] - data.count
|
||||
if temp[data.link] == 0 then temp[data.link] = nil end
|
||||
end
|
||||
|
||||
if not next(temp) then
|
||||
matchIndex = k
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if matchIndex then
|
||||
if index == matchIndex then
|
||||
player.mailInbox[matchIndex].index = i
|
||||
index = index + 1
|
||||
elseif matchIndex > index then
|
||||
for k=1, matchIndex-index do
|
||||
RemoveInboxMail(TSM.CURRENT_PLAYER, index)
|
||||
end
|
||||
end
|
||||
else
|
||||
InsertInboxMail(TSM.CURRENT_PLAYER, index, {items=items, index=i})
|
||||
index = index + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
tinsert(playersToUpdate, TSM.CURRENT_PLAYER)
|
||||
end
|
||||
|
||||
Data:RegisterEvent("CHAT_MSG_SYSTEM", OnChatMsg)
|
||||
TSMAPI:CreateEventBucket("MAIL_INBOX_UPDATE", OnInboxUpdate, 0)
|
||||
Data:Hook("PlaceAuctionBid", OnAuctionBid, true)
|
||||
Data:Hook("CancelAuction", OnAuctionCanceled, true)
|
||||
Data:Hook("TakeInboxItem", OnTakeInboxItem, true)
|
||||
Data:Hook("AutoLootMailItem", OnTakeInboxItem, true)
|
||||
Data:Hook("SendMail", OnSendMail, true)
|
||||
Data:Hook("ReturnInboxItem", OnReturnMail, true)
|
||||
TSMAPI.Threading:Start(UpdateMailQuantitiesThread, 0.1)
|
||||
end
|
||||
@@ -0,0 +1,92 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster_ItemTracker --
|
||||
-- http://www.curse.com/addons/wow/tradeskillmaster_itemtracker --
|
||||
-- --
|
||||
-- A TradeSkillMaster Addon (http://tradeskillmaster.com) --
|
||||
-- All Rights Reserved* - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
-- load the parent file (TSM) into a local variable and register this file as a module
|
||||
local TSM = select(2, ...)
|
||||
local Sync = TSM:NewModule("Sync")
|
||||
|
||||
|
||||
function Sync:BroadcastUpdateRequest(timerUp)
|
||||
if not timerUp then
|
||||
TSMAPI:CreateTimeDelay("itemTrackerSyncDelay", 3, function() Sync:BroadcastUpdateRequest(true) end)
|
||||
return
|
||||
end
|
||||
local packet = {characters={}, guilds={}}
|
||||
for player, data in pairs(TSM.characters or {}) do
|
||||
if data.account == TSMAPI.Sync:GetAccountKey() then
|
||||
packet.characters[player] = CopyTable(data.lastUpdate)
|
||||
end
|
||||
end
|
||||
for guild, data in pairs(TSM.guilds or {}) do
|
||||
packet.guilds[guild] = data.lastUpdate
|
||||
end
|
||||
TSMAPI.Sync:BroadcastData("ItemTracker", "REQUEST", packet)
|
||||
end
|
||||
|
||||
function Sync:SendUpdateResponse(target, request)
|
||||
local response = {characters={}, guilds={}}
|
||||
for player, lastUpdate in pairs(request.characters or {}) do
|
||||
for key, updateTime in pairs(lastUpdate) do
|
||||
if not TSM.characters[player] or (TSM.characters[player].lastUpdate[key] or 0) < updateTime then
|
||||
response.characters[player] = response.characters[player] or {}
|
||||
tinsert(response.characters[player], key)
|
||||
end
|
||||
end
|
||||
end
|
||||
for guild, lastUpdate in pairs(request.guilds or {}) do
|
||||
if not TSM.guilds[guild] or (TSM.guilds[guild].lastUpdate or 0) < lastUpdate then
|
||||
tinsert(response.guilds, guild)
|
||||
end
|
||||
end
|
||||
|
||||
if next(response.characters) or #response.guilds > 0 then
|
||||
TSMAPI.Sync:SendData("ItemTracker", "RESPONSE", response, target)
|
||||
end
|
||||
end
|
||||
|
||||
function Sync:SendUpdateData(target, response)
|
||||
local data = {characters={}, guilds={}}
|
||||
for player, keys in pairs(response.characters or {}) do
|
||||
data.characters[player] = {}
|
||||
for _, key in ipairs(keys) do
|
||||
data.characters[player][key] = TSM.characters[player][key]
|
||||
data.characters[player].lastUpdate = data.characters[player].lastUpdate or {}
|
||||
data.characters[player].lastUpdate[key] = TSM.characters[player].lastUpdate[key]
|
||||
end
|
||||
end
|
||||
for _, guild in ipairs(response.guilds or {}) do
|
||||
data.guilds[guild] = TSM.guilds[guild]
|
||||
end
|
||||
|
||||
if next(data) then
|
||||
TSMAPI.Sync:SendData("ItemTracker", "DATA", data, target)
|
||||
end
|
||||
end
|
||||
|
||||
function Sync:ProcessUpdateData(data)
|
||||
for player, info in pairs(data.characters or {}) do
|
||||
TSM.characters[player] = TSM.characters[player] or CopyTable(TSM.characterDefaults)
|
||||
for key, updateTime in pairs(info.lastUpdate or {}) do
|
||||
TSM.characters[player][key] = info[key]
|
||||
TSM.characters[player].lastUpdate[key] = updateTime
|
||||
end
|
||||
end
|
||||
for player, info in pairs(data.guilds or {}) do
|
||||
TSM.guilds[player] = info
|
||||
end
|
||||
end
|
||||
|
||||
function Sync:Callback(key, data, source)
|
||||
if key == "REQUEST" then
|
||||
Sync:SendUpdateResponse(source, data)
|
||||
elseif key == "RESPONSE" then
|
||||
Sync:SendUpdateData(source, data)
|
||||
elseif key == "DATA" then
|
||||
Sync:ProcessUpdateData(data)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user