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.

288 lines
10 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")
local Table = TSM.Include("Util.Table")
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 = {},
callbacks = {},
3 years ago
}
local CACHE_SEP = "\001"
local MIRROR_SETTING_KEYS = {
bagQuantity = true,
bankQuantity = true,
reagentBankQuantity = true,
auctionQuantity = true,
mailQuantity = true,
}
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")
:AddKey("global", "coreOptions", "regionWide")
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(function(settingKey)
if MIRROR_SETTING_KEYS[settingKey] then
private.UpdateDB()
end
end)
end)
-- ============================================================================
-- Module Functions
-- ============================================================================
function AltTracking.RegisterCallback(callback)
tinsert(private.callbacks, callback)
end
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)
Table.InsertMultiple(result, character, 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
Table.InsertMultiple(result, guildName, 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, _, isConnected in private.settings:AccessibleValueIterator(key) do
if not Wow.IsPlayer(character, factionrealm) and (isConnected or private.settings.regionWide) 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 quantity <= 0 then
data[levelItemString] = nil
else
if key == "auctionQuantity" then
auctionQuantity[levelItemString] = (auctionQuantity[levelItemString] or 0) + quantity
end
totalQuantity[levelItemString] = (totalQuantity[levelItemString] or 0) + quantity
end
end
end
end
end
for _, data, factionrealm, isConnected in private.settings:AccessibleValueIterator("pendingMail") do
if isConnected or private.settings.regionWide then
for character, pendingQuantity in pairs(data) do
local isValid = true
for levelItemString, quantity in pairs(pendingQuantity) do
if type(quantity) ~= "number" or quantity < 0 then
isValid = false
break
end
if not Wow.IsPlayer(character, factionrealm) then
totalQuantity[levelItemString] = (totalQuantity[levelItemString] or 0) + quantity
end
3 years ago
end
if not isValid then
data[character] = nil
end
end
3 years ago
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)
for _, callback in ipairs(private.callbacks) do
callback()
end
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