327 lines
12 KiB
Lua
327 lines
12 KiB
Lua
-- ------------------------------------------------------------------------------ --
|
|
-- TradeSkillMaster --
|
|
-- https://tradeskillmaster.com --
|
|
-- All Rights Reserved - Detailed license information included with addon. --
|
|
-- ------------------------------------------------------------------------------ --
|
|
|
|
local _, TSM = ...
|
|
local Util = TSM.Auctioning:NewPackage("Util")
|
|
local TempTable = TSM.Include("Util.TempTable")
|
|
local Vararg = TSM.Include("Util.Vararg")
|
|
local String = TSM.Include("Util.String")
|
|
local Math = TSM.Include("Util.Math")
|
|
local CustomPrice = TSM.Include("Service.CustomPrice")
|
|
local PlayerInfo = TSM.Include("Service.PlayerInfo")
|
|
local private = {
|
|
priceCache = {},
|
|
}
|
|
local INVALID_PRICE = {}
|
|
local VALID_PRICE_KEYS = {
|
|
minPrice = true,
|
|
normalPrice = true,
|
|
maxPrice = true,
|
|
undercut = true,
|
|
cancelRepostThreshold = true,
|
|
priceReset = true,
|
|
aboveMax = true,
|
|
postCap = true,
|
|
stackSize = true,
|
|
keepQuantity = true,
|
|
maxExpires = true,
|
|
}
|
|
local IS_GOLD_PRICE_KEY = {
|
|
minPrice = true,
|
|
normalPrice = true,
|
|
maxPrice = true,
|
|
undercut = TSM.IsWowClassic(),
|
|
priceReset = true,
|
|
aboveMax = true,
|
|
}
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Module Functions
|
|
-- ============================================================================
|
|
|
|
function Util.GetPrice(key, operation, itemString)
|
|
assert(VALID_PRICE_KEYS[key])
|
|
local cacheKey = key..tostring(operation)..itemString
|
|
if private.priceCache.updateTime ~= GetTime() then
|
|
wipe(private.priceCache)
|
|
private.priceCache.updateTime = GetTime()
|
|
end
|
|
if not private.priceCache[cacheKey] then
|
|
local value = nil
|
|
if key == "aboveMax" or key == "priceReset" then
|
|
-- redirect to the selected price (if applicable)
|
|
local priceKey = operation[key]
|
|
if VALID_PRICE_KEYS[priceKey] then
|
|
value = Util.GetPrice(priceKey, operation, itemString)
|
|
end
|
|
else
|
|
value = CustomPrice.GetValue(operation[key], itemString, not IS_GOLD_PRICE_KEY[key])
|
|
end
|
|
if not TSM.IsWowClassic() and IS_GOLD_PRICE_KEY[key] then
|
|
value = value and Math.Ceil(value, COPPER_PER_SILVER) or nil
|
|
else
|
|
value = value and Math.Round(value) or nil
|
|
end
|
|
local minValue, maxValue = TSM.Operations.Auctioning.GetMinMaxValues(key)
|
|
private.priceCache[cacheKey] = (value and value >= minValue and value <= maxValue) and value or INVALID_PRICE
|
|
end
|
|
if private.priceCache[cacheKey] == INVALID_PRICE then
|
|
return nil
|
|
end
|
|
return private.priceCache[cacheKey]
|
|
end
|
|
|
|
function Util.GetLowestAuction(subRows, itemString, operationSettings, resultTbl)
|
|
if not TSM.IsWowClassic() then
|
|
local foundLowest = false
|
|
for _, subRow in ipairs(subRows) do
|
|
local _, itemBuyout = subRow:GetBuyouts()
|
|
local quantity = subRow:GetQuantities()
|
|
local timeLeft = subRow:GetListingInfo()
|
|
if not foundLowest and not Util.IsFiltered(itemString, operationSettings, itemBuyout, quantity, timeLeft) then
|
|
local ownerStr = subRow:GetOwnerInfo()
|
|
local _, auctionId = subRow:GetListingInfo()
|
|
local _, itemMinBid = subRow:GetBidInfo()
|
|
local firstSeller = strsplit(",", ownerStr)
|
|
resultTbl.buyout = itemBuyout
|
|
resultTbl.bid = itemMinBid
|
|
resultTbl.seller = firstSeller
|
|
resultTbl.auctionId = auctionId
|
|
resultTbl.isWhitelist = TSM.db.factionrealm.auctioningOptions.whitelist[strlower(firstSeller)] and true or false
|
|
resultTbl.isPlayer = PlayerInfo.IsPlayer(firstSeller, true, true, true)
|
|
if not subRow:HasOwners() then
|
|
resultTbl.hasInvalidSeller = true
|
|
end
|
|
foundLowest = true
|
|
end
|
|
end
|
|
return foundLowest
|
|
else
|
|
local hasInvalidSeller = nil
|
|
local ignoreWhitelist = nil
|
|
local lowestItemBuyout = nil
|
|
local lowestAuction = nil
|
|
for _, subRow in ipairs(subRows) do
|
|
local _, itemBuyout = subRow:GetBuyouts()
|
|
local quantity = subRow:GetQuantities()
|
|
local timeLeft = subRow:GetListingInfo()
|
|
if not Util.IsFiltered(itemString, operationSettings, itemBuyout, quantity, timeLeft) then
|
|
assert(itemBuyout and itemBuyout > 0)
|
|
lowestItemBuyout = lowestItemBuyout or itemBuyout
|
|
if itemBuyout == lowestItemBuyout then
|
|
local ownerStr = subRow:GetOwnerInfo()
|
|
local _, auctionId = subRow:GetListingInfo()
|
|
local _, itemMinBid = subRow:GetBidInfo()
|
|
local temp = TempTable.Acquire()
|
|
temp.buyout = itemBuyout
|
|
temp.bid = itemMinBid
|
|
temp.seller = ownerStr
|
|
temp.auctionId = auctionId
|
|
temp.isWhitelist = TSM.db.factionrealm.auctioningOptions.whitelist[strlower(ownerStr)] and true or false
|
|
temp.isPlayer = PlayerInfo.IsPlayer(ownerStr, true, true, true)
|
|
if not temp.isWhitelist and not temp.isPlayer then
|
|
-- there is a non-whitelisted competitor, so we don't care if a whitelisted competitor also posts at this price
|
|
ignoreWhitelist = true
|
|
end
|
|
if not subRow:HasOwners() and next(TSM.db.factionrealm.auctioningOptions.whitelist) then
|
|
hasInvalidSeller = true
|
|
end
|
|
if operationSettings.blacklist then
|
|
for _, player in Vararg.Iterator(strsplit(",", operationSettings.blacklist)) do
|
|
if String.SeparatedContains(strlower(ownerStr), ",", strlower(strtrim(player))) then
|
|
temp.isBlacklist = true
|
|
end
|
|
end
|
|
end
|
|
if not lowestAuction then
|
|
lowestAuction = temp
|
|
elseif private.LowestAuctionCompare(temp, lowestAuction) then
|
|
TempTable.Release(lowestAuction)
|
|
lowestAuction = temp
|
|
else
|
|
TempTable.Release(temp)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
if not lowestAuction then
|
|
return false
|
|
end
|
|
for k, v in pairs(lowestAuction) do
|
|
resultTbl[k] = v
|
|
end
|
|
TempTable.Release(lowestAuction)
|
|
if resultTbl.isWhitelist and ignoreWhitelist then
|
|
resultTbl.isWhitelist = false
|
|
end
|
|
resultTbl.hasInvalidSeller = hasInvalidSeller
|
|
return true
|
|
end
|
|
end
|
|
|
|
function Util.GetPlayerAuctionCount(subRows, itemString, operationSettings, findBid, findBuyout, findStackSize)
|
|
local playerQuantity = 0
|
|
for _, subRow in ipairs(subRows) do
|
|
local _, itemBuyout = subRow:GetBuyouts()
|
|
local quantity = subRow:GetQuantities()
|
|
local timeLeft = subRow:GetListingInfo()
|
|
if not Util.IsFiltered(itemString, operationSettings, itemBuyout, quantity, timeLeft) then
|
|
local _, itemMinBid = subRow:GetBidInfo()
|
|
if itemMinBid == findBid and itemBuyout == findBuyout and (not TSM.IsWowClassic() or quantity == findStackSize) then
|
|
local count = private.GetPlayerAuctionCount(subRow)
|
|
if not TSM.IsWowClassic() and count == 0 and playerQuantity > 0 then
|
|
-- there's another player's auction after ours, so stop counting
|
|
break
|
|
end
|
|
playerQuantity = playerQuantity + count
|
|
end
|
|
end
|
|
end
|
|
return playerQuantity
|
|
end
|
|
|
|
function Util.GetPlayerLowestBuyout(subRows, itemString, operationSettings)
|
|
local lowestItemBuyout, lowestItemAuctionId = nil, nil
|
|
for _, subRow in ipairs(subRows) do
|
|
local _, itemBuyout = subRow:GetBuyouts()
|
|
local quantity = subRow:GetQuantities()
|
|
local timeLeft, auctionId = subRow:GetListingInfo()
|
|
if not lowestItemBuyout and not Util.IsFiltered(itemString, operationSettings, itemBuyout, quantity, timeLeft) and private.GetPlayerAuctionCount(subRow) > 0 then
|
|
lowestItemBuyout = itemBuyout
|
|
lowestItemAuctionId = auctionId
|
|
end
|
|
end
|
|
return lowestItemBuyout, lowestItemAuctionId
|
|
end
|
|
|
|
function Util.GetLowestNonPlayerAuctionId(subRows, itemString, operationSettings, lowestItemBuyout)
|
|
local lowestItemAuctionId = nil
|
|
for _, subRow in ipairs(subRows) do
|
|
local _, itemBuyout = subRow:GetBuyouts()
|
|
local quantity = subRow:GetQuantities()
|
|
local timeLeft, auctionId = subRow:GetListingInfo()
|
|
if not lowestItemAuctionId and not Util.IsFiltered(itemString, operationSettings, itemBuyout, quantity, timeLeft) and private.GetPlayerAuctionCount(subRow) == 0 and itemBuyout == lowestItemBuyout then
|
|
lowestItemAuctionId = auctionId
|
|
end
|
|
end
|
|
return lowestItemAuctionId
|
|
end
|
|
|
|
function Util.IsPlayerOnlySeller(subRows, itemString, operationSettings)
|
|
local isOnly = true
|
|
for _, subRow in ipairs(subRows) do
|
|
local _, itemBuyout = subRow:GetBuyouts()
|
|
local quantity = subRow:GetQuantities()
|
|
local timeLeft = subRow:GetListingInfo()
|
|
if isOnly and not Util.IsFiltered(itemString, operationSettings, itemBuyout, quantity, timeLeft) and private.GetPlayerAuctionCount(subRow) < (TSM.IsWowClassic() and 1 or quantity) then
|
|
isOnly = false
|
|
end
|
|
end
|
|
return isOnly
|
|
end
|
|
|
|
function Util.GetNextLowestItemBuyout(subRows, itemString, lowestAuction, operationSettings)
|
|
local nextLowestItemBuyout = nil
|
|
for _, subRow in ipairs(subRows) do
|
|
local _, itemBuyout = subRow:GetBuyouts()
|
|
local quantity = subRow:GetQuantities()
|
|
local timeLeft, auctionId = subRow:GetListingInfo()
|
|
local isLower = itemBuyout > lowestAuction.buyout or (itemBuyout == lowestAuction.buyout and auctionId < lowestAuction.auctionId)
|
|
if not nextLowestItemBuyout and not Util.IsFiltered(itemString, operationSettings, itemBuyout, quantity, timeLeft) and isLower then
|
|
nextLowestItemBuyout = itemBuyout
|
|
end
|
|
end
|
|
return nextLowestItemBuyout
|
|
end
|
|
|
|
function Util.GetQueueStatus(query)
|
|
local numProcessed, numConfirmed, numFailed, totalNum = 0, 0, 0, 0
|
|
query:OrderBy("auctionId", true)
|
|
for _, row in query:Iterator() do
|
|
local rowNumStacks, rowNumProcessed, rowNumConfirmed, rowNumFailed = row:GetFields("numStacks", "numProcessed", "numConfirmed", "numFailed")
|
|
totalNum = totalNum + rowNumStacks
|
|
numProcessed = numProcessed + rowNumProcessed
|
|
numConfirmed = numConfirmed + rowNumConfirmed
|
|
numFailed = numFailed + rowNumFailed
|
|
end
|
|
query:Release()
|
|
return numProcessed, numConfirmed, numFailed, totalNum
|
|
end
|
|
|
|
function Util.IsFiltered(itemString, operationSettings, itemBuyout, quantity, timeLeft)
|
|
if timeLeft <= operationSettings.ignoreLowDuration then
|
|
-- ignoring low duration
|
|
return true
|
|
elseif TSM.IsWowClassic() and operationSettings.matchStackSize and quantity ~= Util.GetPrice("stackSize", operationSettings, itemString) then
|
|
-- matching stack size
|
|
return true
|
|
elseif operationSettings.priceReset == "ignore" then
|
|
local minPrice = Util.GetPrice("minPrice", operationSettings, itemString)
|
|
local undercut = Util.GetPrice("undercut", operationSettings, itemString)
|
|
if minPrice and itemBuyout - undercut < minPrice then
|
|
-- ignoring auctions below threshold
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function Util.GetFilteredSubRows(query, itemString, operationSettings, result)
|
|
for _, subRow in query:ItemSubRowIterator(itemString) do
|
|
local _, itemBuyout = subRow:GetBuyouts()
|
|
local quantity = subRow:GetQuantities()
|
|
local timeLeft = subRow:GetListingInfo()
|
|
if not Util.IsFiltered(itemString, operationSettings, itemBuyout, quantity, timeLeft) then
|
|
tinsert(result, subRow)
|
|
end
|
|
end
|
|
sort(result, private.SubRowSortHelper)
|
|
end
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Private Helper Functions
|
|
-- ============================================================================
|
|
|
|
function private.SubRowSortHelper(a, b)
|
|
local _, aItemBuyout = a:GetBuyouts()
|
|
local _, bItemBuyout = b:GetBuyouts()
|
|
if aItemBuyout ~= bItemBuyout then
|
|
return aItemBuyout < bItemBuyout
|
|
end
|
|
local _, aAuctionId = a:GetListingInfo()
|
|
local _, bAuctionId = b:GetListingInfo()
|
|
return aAuctionId > bAuctionId
|
|
end
|
|
|
|
function private.LowestAuctionCompare(a, b)
|
|
if a.isBlacklist ~= b.isBlacklist then
|
|
return a.isBlacklist
|
|
end
|
|
if a.isWhitelist ~= b.isWhitelist then
|
|
return a.isWhitelist
|
|
end
|
|
if a.auctionId ~= b.auctionId then
|
|
return a.auctionId > b.auctionId
|
|
end
|
|
if a.isPlayer ~= b.isPlayer then
|
|
return b.isPlayer
|
|
end
|
|
return tostring(a) < tostring(b)
|
|
end
|
|
|
|
function private.GetPlayerAuctionCount(subRow)
|
|
local ownerStr, numOwnerItems = subRow:GetOwnerInfo()
|
|
if TSM.IsWowClassic() then
|
|
return PlayerInfo.IsPlayer(ownerStr, true, true, true) and select(2, subRow:GetQuantities()) or 0
|
|
else
|
|
return numOwnerItems
|
|
end
|
|
end
|