You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

263 lines
9.8 KiB

3 years ago
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local TSM = select(2, ...) ---@type TSM
local AltTracking = TSM.Init("Service.AltTracking") ---@class Service.AltTracking
3 years ago
local Database = TSM.Include("Util.Database")
local TempTable = TSM.Include("Util.TempTable")
local ItemString = TSM.Include("Util.ItemString")
3 years ago
local Vararg = TSM.Include("Util.Vararg")
local Wow = TSM.Include("Util.Wow")
3 years ago
local Settings = TSM.Include("Service.Settings")
local Sync = TSM.Include("Service.Sync")
local PlayerInfo = TSM.Include("Service.PlayerInfo")
3 years ago
local private = {
settings = nil,
3 years ago
quantityDB = nil,
baseItemQuantityQuery = nil,
characterFactionrealmCache = {},
3 years ago
}
local CACHE_SEP = "\001"
3 years ago
-- ============================================================================
-- Module Loading
-- ============================================================================
AltTracking:OnSettingsLoad(function()
private.settings = Settings.NewView()
:AddKey("factionrealm", "internalData", "pendingMail")
:AddKey("factionrealm", "internalData", "guildVaults")
:AddKey("factionrealm", "coreOptions", "ignoreGuilds")
:AddKey("sync", "internalData", "bagQuantity")
:AddKey("sync", "internalData", "bankQuantity")
:AddKey("sync", "internalData", "reagentBankQuantity")
:AddKey("sync", "internalData", "auctionQuantity")
:AddKey("sync", "internalData", "mailQuantity")
3 years ago
private.quantityDB = Database.NewSchema("INVENTORY_ALT_QUANTITY")
:AddUniqueStringField("levelItemString")
:AddNumberField("total")
:AddNumberField("inventory")
:AddNumberField("auctions")
:AddSmartMapField("baseItemString", ItemString.GetBaseMap(), "levelItemString")
:AddIndex("baseItemString")
3 years ago
:Commit()
private.baseItemQuantityQuery = private.quantityDB:NewQuery()
:Equal("baseItemString", Database.BoundQueryParam())
private.UpdateDB()
Sync.RegisterMirrorCallback(private.UpdateDB)
end)
-- ============================================================================
-- Module Functions
-- ============================================================================
function AltTracking.QuantityIterator()
return private.quantityDB:NewQuery()
:Select("levelItemString", "total")
:IteratorAndRelease()
end
function AltTracking.GetTotalQuantity(itemString)
if not ItemString.IsLevel(itemString) and itemString == ItemString.GetBaseFast(itemString) then
private.baseItemQuantityQuery:BindParams(itemString)
return private.baseItemQuantityQuery:Sum("total")
else
local levelItemString = ItemString.ToLevel(itemString)
return private.quantityDB:GetUniqueRowField("levelItemString", levelItemString, "total") or 0
end
end
3 years ago
function AltTracking.GetTotalGuildQuantity(itemString)
local total = 0
for _, guildName, factionrealm in PlayerInfo.GuildIterator() do
total = total + AltTracking.GetGuildQuantity(itemString, guildName, factionrealm)
end
return total
end
function AltTracking.GetQuantity(itemString)
if not ItemString.IsLevel(itemString) and itemString == ItemString.GetBaseFast(itemString) then
private.baseItemQuantityQuery:BindParams(itemString)
return private.baseItemQuantityQuery:Sum("inventory"), private.baseItemQuantityQuery:Sum("auctions")
else
local levelItemString = ItemString.ToLevel(itemString)
return private.quantityDB:GetUniqueRowField("levelItemString", levelItemString, "inventory") or 0, private.quantityDB:GetUniqueRowField("levelItemString", levelItemString, "auctions") or 0
end
end
function AltTracking.GetBagQuantity(itemString, character, factionrealm)
return private.GetInventoryValue(itemString, "bagQuantity", character, factionrealm)
end
function AltTracking.GetBankQuantity(itemString, character, factionrealm)
return private.GetInventoryValue(itemString, "bankQuantity", character, factionrealm)
end
function AltTracking.GetReagentBankQuantity(itemString, character, factionrealm)
return private.GetInventoryValue(itemString, "reagentBankQuantity", character, factionrealm)
end
function AltTracking.GetAuctionQuantity(itemString, character, factionrealm)
return private.GetInventoryValue(itemString, "auctionQuantity", character, factionrealm)
end
function AltTracking.GetMailQuantity(itemString, character, factionrealm)
local pendingQuantity = private.GetPendingMailQuantity(itemString, character, factionrealm)
return private.GetInventoryValue(itemString, "mailQuantity", character, factionrealm) + pendingQuantity
end
function AltTracking.GetGuildItems(result)
for _, guildName, factionrealm in PlayerInfo.GuildIterator() do
local guildItems = private.settings:GetForScopeKey("guildVaults", factionrealm)[guildName]
if guildItems then
for levelItemString, quantity in pairs(guildItems) do
result[levelItemString] = (result[levelItemString] or 0) + quantity
3 years ago
end
end
end
end
function AltTracking.GetGuildQuantity(itemString, guild, factionrealm)
assert(guild)
local ignoreGuilds = private.settings:GetForScopeKey("ignoreGuilds", factionrealm)
local guildVaults = private.settings:GetForScopeKey("guildVaults", factionrealm)
if not ignoreGuilds or not guildVaults or ignoreGuilds[guild] then
return 0
end
return private.GetItemQuantityFromSettingsTable(guildVaults[guild], itemString)
end
function AltTracking.CharacterIterator()
local result = TempTable.Acquire()
for _, cacheKey in ipairs(private.characterFactionrealmCache) do
local character, factionrealm = strsplit(CACHE_SEP, cacheKey)
tinsert(result, character)
tinsert(result, factionrealm)
end
return TempTable.Iterator(result, 2)
end
function AltTracking.GuildQuantityIterator(itemString)
local result = TempTable.Acquire()
for _, guildName, factionrealm in PlayerInfo.GuildIterator() do
local quantity = AltTracking.GetGuildQuantity(itemString, guildName, factionrealm)
if quantity > 0 then
tinsert(result, guildName)
tinsert(result, quantity)
end
end
return TempTable.Iterator(result, 2)
end
-- ============================================================================
-- Private Helper Functions
-- ============================================================================
function private.UpdateDB()
wipe(private.characterFactionrealmCache)
local totalQuantity = TempTable.Acquire()
local auctionQuantity = TempTable.Acquire()
for _, key in Vararg.Iterator("bagQuantity", "bankQuantity", "reagentBankQuantity", "auctionQuantity", "mailQuantity") do
for _, data, character, factionrealm in private.settings:AccessibleValueIterator(key) do
if not Wow.IsPlayer(character, factionrealm) then
local cacheKey = character..CACHE_SEP..factionrealm
if not private.characterFactionrealmCache[cacheKey] then
private.characterFactionrealmCache[cacheKey] = true
tinsert(private.characterFactionrealmCache, cacheKey)
end
for levelItemString, quantity in pairs(data) do
if key == "auctionQuantity" then
auctionQuantity[levelItemString] = (auctionQuantity[levelItemString] or 0) + quantity
end
totalQuantity[levelItemString] = (totalQuantity[levelItemString] or 0) + quantity
end
end
end
end
for _, data, _, factionrealm in private.settings:AccessibleValueIterator("pendingMail") do
for character, pendingQuantity in pairs(data) do
local isValid = true
for levelItemString, quantity in pairs(pendingQuantity) do
3 years ago
if type(quantity) ~= "number" then
isValid = false
break
end
if not Wow.IsPlayer(character, factionrealm) then
totalQuantity[levelItemString] = (totalQuantity[levelItemString] or 0) + quantity
end
end
if not isValid then
data[character] = nil
3 years ago
end
end
end
sort(private.characterFactionrealmCache)
private.quantityDB:TruncateAndBulkInsertStart()
for levelItemString, quantity in pairs(totalQuantity) do
local auction = (auctionQuantity[levelItemString] or 0)
assert(quantity >= auction)
private.quantityDB:BulkInsertNewRow(levelItemString, quantity, quantity - auction, auction)
3 years ago
end
private.quantityDB:BulkInsertEnd()
TempTable.Release(totalQuantity)
TempTable.Release(auctionQuantity)
end
3 years ago
function private.GetInventoryValue(itemString, settingKey, character, factionrealm)
local tbl = nil
if character then
tbl = private.settings:GetForScopeKey(settingKey, character, factionrealm)
else
tbl = private.settings:GetForScopeKey(settingKey, nil)
end
return private.GetItemQuantityFromSettingsTable(tbl, itemString)
end
3 years ago
function private.GetPendingMailQuantity(itemString, character, factionrealm)
character = character or Wow.GetCharacterName()
-- TODO: Figure out how to track pendingMail across accounts
-- TODO: Update this code to support pendingMail across connected realms
if factionrealm and factionrealm ~= Wow.GetFactionrealmName() then
return 0
end
return private.GetItemQuantityFromSettingsTable(private.settings.pendingMail[character], itemString)
end
3 years ago
function private.GetItemQuantityFromSettingsTable(tbl, itemString)
if not tbl then
return 0
end
3 years ago
-- If we got passed a non-base item, return the quantity for the item level version
if itemString ~= ItemString.GetBaseFast(itemString) then
local levelItemString = ItemString.ToLevel(itemString)
return tbl[levelItemString] or 0
end
-- If there is a value within the table for this item, then there aren't any non-base versions of it
if tbl[itemString] then
return tbl[itemString]
end
-- Get the sum of all the item level versions of the base item we're looking up
local totalQuantity = 0
for entryItemString, quantity in pairs(tbl) do
if ItemString.GetBaseFast(entryItemString) == itemString then
totalQuantity = totalQuantity + quantity
end
end
3 years ago
return totalQuantity
3 years ago
end