initial commit
This commit is contained in:
88
Core/Service/Shopping/Core.lua
Normal file
88
Core/Service/Shopping/Core.lua
Normal file
@@ -0,0 +1,88 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster --
|
||||
-- https://tradeskillmaster.com --
|
||||
-- All Rights Reserved - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
local _, TSM = ...
|
||||
TSM:NewPackage("Shopping")
|
||||
local Threading = TSM.Include("Service.Threading")
|
||||
local ShoppingSearchContext = TSM.Include("LibTSMClass").DefineClass("ShoppingSearchContext")
|
||||
TSM.Shopping.ShoppingSearchContext = ShoppingSearchContext
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- ShoppingSearchContext - Public Class Methods
|
||||
-- ============================================================================
|
||||
|
||||
function ShoppingSearchContext.__init(self, threadId, marketValueFunc)
|
||||
assert(threadId and marketValueFunc)
|
||||
self._threadId = threadId
|
||||
self._marketValueFunc = marketValueFunc
|
||||
self._name = nil
|
||||
self._filterInfo = nil
|
||||
self._postContext = nil
|
||||
self._buyCallback = nil
|
||||
self._stateCallback = nil
|
||||
self._pctTooltip = nil
|
||||
end
|
||||
|
||||
function ShoppingSearchContext.SetScanContext(self, name, filterInfo, postContext, pctTooltip)
|
||||
assert(name)
|
||||
self._name = name
|
||||
self._filterInfo = filterInfo
|
||||
self._postContext = postContext
|
||||
-- clear the callbacks when the scan context changes
|
||||
self._buyCallback = nil
|
||||
self._stateCallback = nil
|
||||
self._pctTooltip = pctTooltip
|
||||
return self
|
||||
end
|
||||
|
||||
function ShoppingSearchContext.SetCallbacks(self, buyCallback, stateCallback)
|
||||
self._buyCallback = buyCallback
|
||||
self._stateCallback = stateCallback
|
||||
return self
|
||||
end
|
||||
|
||||
function ShoppingSearchContext.StartThread(self, callback, auctionScan)
|
||||
Threading.SetCallback(self._threadId, callback)
|
||||
Threading.Start(self._threadId, auctionScan, self._filterInfo, self._postContext)
|
||||
end
|
||||
|
||||
function ShoppingSearchContext.KillThread(self)
|
||||
Threading.Kill(self._threadId)
|
||||
end
|
||||
|
||||
function ShoppingSearchContext.GetMarketValueFunc(self)
|
||||
return self._marketValueFunc
|
||||
end
|
||||
|
||||
function ShoppingSearchContext.GetPctTooltip(self)
|
||||
return self._pctTooltip
|
||||
end
|
||||
|
||||
function ShoppingSearchContext.GetMaxCanBuy(self, itemString)
|
||||
return nil
|
||||
end
|
||||
|
||||
function ShoppingSearchContext.OnBuy(self, itemString, quantity)
|
||||
if self._buyCallback then
|
||||
self._buyCallback(itemString, quantity)
|
||||
end
|
||||
end
|
||||
|
||||
function ShoppingSearchContext.OnStateChanged(self, state)
|
||||
if self._stateCallback then
|
||||
self._stateCallback(state)
|
||||
end
|
||||
end
|
||||
|
||||
function ShoppingSearchContext.GetName(self)
|
||||
return self._name
|
||||
end
|
||||
|
||||
function ShoppingSearchContext.GetPostContext(self)
|
||||
return self._postContext
|
||||
end
|
||||
104
Core/Service/Shopping/DisenchantSearch.lua
Normal file
104
Core/Service/Shopping/DisenchantSearch.lua
Normal file
@@ -0,0 +1,104 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster --
|
||||
-- https://tradeskillmaster.com --
|
||||
-- All Rights Reserved - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
local _, TSM = ...
|
||||
local DisenchantSearch = TSM.Shopping:NewPackage("DisenchantSearch")
|
||||
local L = TSM.Include("Locale").GetTable()
|
||||
local Log = TSM.Include("Util.Log")
|
||||
local Threading = TSM.Include("Service.Threading")
|
||||
local ItemInfo = TSM.Include("Service.ItemInfo")
|
||||
local CustomPrice = TSM.Include("Service.CustomPrice")
|
||||
local private = {
|
||||
itemList = {},
|
||||
scanThreadId = nil,
|
||||
searchContext = nil,
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Module Functions
|
||||
-- ============================================================================
|
||||
|
||||
function DisenchantSearch.OnInitialize()
|
||||
-- initialize thread
|
||||
private.scanThreadId = Threading.New("DISENCHANT_SEARCH", private.ScanThread)
|
||||
private.searchContext = TSM.Shopping.ShoppingSearchContext(private.scanThreadId, private.MarketValueFunction)
|
||||
end
|
||||
|
||||
function DisenchantSearch.GetSearchContext()
|
||||
return private.searchContext:SetScanContext(L["Disenchant Search"], nil, nil, L["Disenchant Value"])
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Scan Thread
|
||||
-- ============================================================================
|
||||
|
||||
function private.ScanThread(auctionScan)
|
||||
if (TSM.AuctionDB.GetLastCompleteScanTime() or 0) < time() - 60 * 60 * 12 then
|
||||
Log.PrintUser(L["No recent AuctionDB scan data found."])
|
||||
return false
|
||||
end
|
||||
|
||||
-- create the list of items
|
||||
wipe(private.itemList)
|
||||
for _, itemString, _, minBuyout in TSM.AuctionDB.LastScanIteratorThreaded() do
|
||||
if minBuyout and private.ShouldInclude(itemString, minBuyout) then
|
||||
tinsert(private.itemList, itemString)
|
||||
end
|
||||
Threading.Yield()
|
||||
end
|
||||
|
||||
-- run the scan
|
||||
auctionScan:AddItemListQueriesThreaded(private.itemList)
|
||||
for _, query in auctionScan:QueryIterator() do
|
||||
query:AddCustomFilter(private.QueryFilter)
|
||||
end
|
||||
if not auctionScan:ScanQueriesThreaded() then
|
||||
Log.PrintUser(L["TSM failed to scan some auctions. Please rerun the scan."])
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function private.ShouldInclude(itemString, minBuyout)
|
||||
if not ItemInfo.IsDisenchantable(itemString) then
|
||||
return false
|
||||
end
|
||||
|
||||
local itemLevel = ItemInfo.GetItemLevel(itemString) or -1
|
||||
if itemLevel < TSM.db.global.shoppingOptions.minDeSearchLvl or itemLevel > TSM.db.global.shoppingOptions.maxDeSearchLvl then
|
||||
return false
|
||||
end
|
||||
|
||||
if private.IsItemBuyoutTooHigh(itemString, minBuyout) then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function private.QueryFilter(_, row)
|
||||
local itemString = row:GetItemString()
|
||||
if not itemString then
|
||||
return false
|
||||
end
|
||||
local _, itemBuyout = row:GetBuyouts()
|
||||
if not itemBuyout then
|
||||
return false
|
||||
end
|
||||
return private.IsItemBuyoutTooHigh(itemString, itemBuyout)
|
||||
end
|
||||
|
||||
function private.IsItemBuyoutTooHigh(itemString, itemBuyout)
|
||||
local disenchantValue = CustomPrice.GetItemPrice(itemString, "Destroy")
|
||||
return not disenchantValue or itemBuyout > TSM.db.global.shoppingOptions.maxDeSearchPercent / 100 * disenchantValue
|
||||
end
|
||||
|
||||
function private.MarketValueFunction(row)
|
||||
return CustomPrice.GetItemPrice(row:GetItemString() or row:GetBaseItemString(), "Destroy")
|
||||
end
|
||||
405
Core/Service/Shopping/FilterSearch.lua
Normal file
405
Core/Service/Shopping/FilterSearch.lua
Normal file
@@ -0,0 +1,405 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster --
|
||||
-- https://tradeskillmaster.com --
|
||||
-- All Rights Reserved - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
local _, TSM = ...
|
||||
local FilterSearch = TSM.Shopping:NewPackage("FilterSearch")
|
||||
local L = TSM.Include("Locale").GetTable()
|
||||
local DisenchantInfo = TSM.Include("Data.DisenchantInfo")
|
||||
local TempTable = TSM.Include("Util.TempTable")
|
||||
local String = TSM.Include("Util.String")
|
||||
local Log = TSM.Include("Util.Log")
|
||||
local Math = TSM.Include("Util.Math")
|
||||
local ItemString = TSM.Include("Util.ItemString")
|
||||
local Threading = TSM.Include("Service.Threading")
|
||||
local ItemFilter = TSM.Include("Service.ItemFilter")
|
||||
local CustomPrice = TSM.Include("Service.CustomPrice")
|
||||
local Conversions = TSM.Include("Service.Conversions")
|
||||
local ItemInfo = TSM.Include("Service.ItemInfo")
|
||||
local FilterSearchContext = TSM.Include("LibTSMClass").DefineClass("FilterSearchContext", TSM.Shopping.ShoppingSearchContext)
|
||||
local private = {
|
||||
scanThreadId = nil,
|
||||
itemFilter = nil,
|
||||
isSpecial = false,
|
||||
marketValueSource = nil,
|
||||
searchContext = nil,
|
||||
gatheringSearchContext = nil,
|
||||
targetItem = {},
|
||||
itemList = {},
|
||||
generalMaxQuantity = {},
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Module Functions
|
||||
-- ============================================================================
|
||||
|
||||
function FilterSearch.OnInitialize()
|
||||
-- initialize thread
|
||||
private.scanThreadId = Threading.New("FILTER_SEARCH", private.ScanThread)
|
||||
private.itemFilter = ItemFilter.New()
|
||||
private.searchContext = FilterSearchContext(private.scanThreadId, private.MarketValueFunction)
|
||||
private.gatheringSearchContext = FilterSearchContext(private.scanThreadId, private.MarketValueFunction)
|
||||
end
|
||||
|
||||
function FilterSearch.GetGreatDealsSearchContext(filterStr)
|
||||
filterStr = private.ValidateFilterStr(filterStr, "NORMAL")
|
||||
if not filterStr then
|
||||
return
|
||||
end
|
||||
private.marketValueSource = TSM.db.global.shoppingOptions.pctSource
|
||||
private.isSpecial = true
|
||||
return private.searchContext:SetScanContext(L["Great Deals Search"], filterStr, nil, L["Market Value"])
|
||||
end
|
||||
|
||||
function FilterSearch.GetSearchContext(filterStr, itemInfo)
|
||||
local errMsg = nil
|
||||
filterStr, errMsg = private.ValidateFilterStr(filterStr, "NORMAL")
|
||||
if not filterStr then
|
||||
return nil, errMsg
|
||||
end
|
||||
private.marketValueSource = TSM.db.global.shoppingOptions.pctSource
|
||||
private.isSpecial = false
|
||||
return private.searchContext:SetScanContext(filterStr, filterStr, itemInfo, L["Market Value"])
|
||||
end
|
||||
|
||||
function FilterSearch.GetGatheringSearchContext(filterStr, mode)
|
||||
filterStr = private.ValidateFilterStr(filterStr, mode)
|
||||
if not filterStr then
|
||||
return
|
||||
end
|
||||
private.marketValueSource = "matprice"
|
||||
private.isSpecial = true
|
||||
return private.gatheringSearchContext:SetScanContext(L["Gathering Search"], filterStr, nil, L["Material Cost"])
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Scan Thread
|
||||
-- ============================================================================
|
||||
|
||||
function private.ScanThread(auctionScan, filterStr)
|
||||
wipe(private.generalMaxQuantity)
|
||||
if not TSM.IsWowClassic() and filterStr == "" then
|
||||
auctionScan:NewQuery()
|
||||
:SetStr("")
|
||||
wipe(private.targetItem)
|
||||
wipe(private.itemList)
|
||||
else
|
||||
local hasFilter, errMsg = false, nil
|
||||
for filter in String.SplitIterator(filterStr, ";") do
|
||||
filter = strtrim(filter)
|
||||
if filter ~= "" then
|
||||
local filterIsValid, filterErrMsg = private.itemFilter:ParseStr(filter)
|
||||
if filterIsValid then
|
||||
hasFilter = true
|
||||
else
|
||||
errMsg = errMsg or filterErrMsg
|
||||
end
|
||||
end
|
||||
end
|
||||
if not hasFilter then
|
||||
Log.PrintUser(format(L["Invalid search filter (%s)."], filterStr).." "..errMsg)
|
||||
return false
|
||||
end
|
||||
wipe(private.targetItem)
|
||||
wipe(private.itemList)
|
||||
local itemFilter = private.itemFilter
|
||||
for filterPart in String.SplitIterator(filterStr, ";") do
|
||||
filterPart = strtrim(filterPart)
|
||||
if filterPart ~= "" and itemFilter:ParseStr(filterPart) then
|
||||
if itemFilter:GetCrafting() then
|
||||
wipe(private.itemList)
|
||||
local targetItem = Conversions.GetTargetItemByName(private.itemFilter:GetStr())
|
||||
assert(targetItem)
|
||||
-- populate the list of items
|
||||
private.targetItem[targetItem] = targetItem
|
||||
tinsert(private.itemList, targetItem)
|
||||
local conversionInfo = Conversions.GetSourceItems(targetItem)
|
||||
for itemString in pairs(conversionInfo) do
|
||||
if not private.targetItem[itemString] then
|
||||
private.targetItem[itemString] = targetItem
|
||||
tinsert(private.itemList, itemString)
|
||||
end
|
||||
end
|
||||
-- generate the queries and add our filter
|
||||
local queryOffset = auctionScan:GetNumQueries()
|
||||
auctionScan:AddItemListQueriesThreaded(private.itemList)
|
||||
local maxQuantity = itemFilter:GetMaxQuantity()
|
||||
local firstQuery = nil
|
||||
for _, query in auctionScan:QueryIterator(queryOffset) do
|
||||
private.targetItem[query] = targetItem
|
||||
query:AddCustomFilter(private.TargetItemQueryFilter)
|
||||
if maxQuantity then
|
||||
if firstQuery then
|
||||
-- redirect to the first query so the max quantity spans them all
|
||||
private.generalMaxQuantity[query] = firstQuery
|
||||
else
|
||||
private.generalMaxQuantity[query] = maxQuantity
|
||||
firstQuery = query
|
||||
end
|
||||
end
|
||||
end
|
||||
auctionScan:AddResultsUpdateCallback(private.ResultsUpdated)
|
||||
auctionScan:SetScript("OnQueryDone", private.OnQueryDone)
|
||||
elseif itemFilter:GetDisenchant() then
|
||||
local queryOffset = auctionScan:GetNumQueries()
|
||||
local targetItem = Conversions.GetTargetItemByName(itemFilter:GetStr())
|
||||
assert(targetItem)
|
||||
-- generate queries for groups of items that d/e into the target item
|
||||
local disenchantInfo = DisenchantInfo.GetInfo(targetItem)
|
||||
for _, info in ipairs(disenchantInfo.sourceInfo) do
|
||||
auctionScan:NewQuery()
|
||||
:SetLevelRange(disenchantInfo.minLevel, disenchantInfo.maxLevel)
|
||||
:SetQualityRange(info.quality, info.quality)
|
||||
:SetClass(info.classId)
|
||||
:SetItemLevelRange(info.minItemLevel, info.maxItemLevel)
|
||||
end
|
||||
-- add a query for the target item itself
|
||||
wipe(private.itemList)
|
||||
tinsert(private.itemList, targetItem)
|
||||
private.targetItem[targetItem] = targetItem
|
||||
auctionScan:AddItemListQueriesThreaded(private.itemList)
|
||||
-- add our filter to each query and generate a lookup from query to target item
|
||||
local maxQuantity = itemFilter:GetMaxQuantity()
|
||||
local firstQuery = nil
|
||||
for _, query in auctionScan:QueryIterator(queryOffset) do
|
||||
private.targetItem[query] = targetItem
|
||||
query:AddCustomFilter(private.TargetItemQueryFilter)
|
||||
if maxQuantity then
|
||||
if firstQuery then
|
||||
-- redirect to the first query so the max quantity spans them all
|
||||
private.generalMaxQuantity[query] = firstQuery
|
||||
else
|
||||
private.generalMaxQuantity[query] = maxQuantity
|
||||
firstQuery = query
|
||||
end
|
||||
end
|
||||
end
|
||||
auctionScan:AddResultsUpdateCallback(private.ResultsUpdated)
|
||||
auctionScan:SetScript("OnQueryDone", private.OnQueryDone)
|
||||
else
|
||||
local query = auctionScan:NewQuery()
|
||||
query:SetStr(itemFilter:GetStr(), itemFilter:GetExactOnly())
|
||||
query:SetQualityRange(itemFilter:GetMinQuality(), itemFilter:GetMaxQuality())
|
||||
query:SetLevelRange(itemFilter:GetMinLevel(), itemFilter:GetMaxLevel())
|
||||
query:SetItemLevelRange(itemFilter:GetMinItemLevel(), itemFilter:GetMaxItemLevel())
|
||||
query:SetClass(itemFilter:GetClass(), itemFilter:GetSubClass(), itemFilter:GetInvSlotId())
|
||||
query:SetUsable(itemFilter:GetUsableOnly())
|
||||
query:SetUncollected(itemFilter:GetUncollected())
|
||||
query:SetUpgrades(itemFilter:GetUpgrades())
|
||||
query:SetPriceRange(itemFilter:GetMinPrice(), itemFilter:GetMaxPrice())
|
||||
query:SetItems(itemFilter:GetItem())
|
||||
query:SetCanLearn(itemFilter:GetCanLearn())
|
||||
query:SetUnlearned(itemFilter:GetUnlearned())
|
||||
private.generalMaxQuantity[query] = itemFilter:GetMaxQuantity()
|
||||
end
|
||||
end
|
||||
end
|
||||
if not private.isSpecial then
|
||||
TSM.Shopping.SavedSearches.RecordFilterSearch(filterStr)
|
||||
end
|
||||
end
|
||||
|
||||
-- run the scan
|
||||
if not auctionScan:ScanQueriesThreaded() then
|
||||
Log.PrintUser(L["TSM failed to scan some auctions. Please rerun the scan."])
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- FilterSearchContext Class
|
||||
-- ============================================================================
|
||||
|
||||
function FilterSearchContext.GetMaxCanBuy(self, itemString)
|
||||
local targetItemString = private.targetItem[itemString]
|
||||
local maxNum = nil
|
||||
local itemQuery = private.GetMaxQuantityQuery(targetItemString or itemString)
|
||||
if itemQuery then
|
||||
maxNum = private.generalMaxQuantity[itemQuery]
|
||||
if targetItemString then
|
||||
local rate, chunkSize = private.GetTargetItemRate(targetItemString, itemString)
|
||||
maxNum = Math.Ceil(maxNum / rate, chunkSize)
|
||||
end
|
||||
end
|
||||
return maxNum
|
||||
end
|
||||
|
||||
function FilterSearchContext.OnBuy(self, itemString, quantity)
|
||||
local targetItemString = private.targetItem[itemString]
|
||||
if targetItemString then
|
||||
quantity = quantity * private.GetTargetItemRate(targetItemString, itemString)
|
||||
itemString = targetItemString
|
||||
end
|
||||
self.__super:OnBuy(itemString, quantity)
|
||||
|
||||
local itemQuery = private.GetMaxQuantityQuery(itemString)
|
||||
if itemQuery then
|
||||
private.generalMaxQuantity[itemQuery] = private.generalMaxQuantity[itemQuery] - quantity
|
||||
if private.generalMaxQuantity[itemQuery] <= 0 then
|
||||
itemQuery:WipeBrowseResults()
|
||||
for query, maxQuantity in pairs(private.generalMaxQuantity) do
|
||||
if maxQuantity == itemQuery then
|
||||
query:WipeBrowseResults()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Private Helper Functions
|
||||
-- ============================================================================
|
||||
|
||||
function private.ValidateFilterStr(filterStr, mode)
|
||||
assert(mode == "NORMAL" or mode == "CRAFTING" or mode == "DISENCHANT")
|
||||
filterStr = strtrim(filterStr)
|
||||
if mode == "NORMAL" and not TSM.IsWowClassic() and filterStr == "" then
|
||||
return filterStr
|
||||
end
|
||||
local isValid, errMsg = true, nil
|
||||
local filters = TempTable.Acquire()
|
||||
for filter in String.SplitIterator(filterStr, ";") do
|
||||
filter = strtrim(filter)
|
||||
if isValid and gsub(filter, "/", "") ~= "" then
|
||||
local filterIsValid, filterErrMsg = private.itemFilter:ParseStr(filter)
|
||||
if filterIsValid then
|
||||
local str = private.itemFilter:GetStr()
|
||||
if mode == "CRAFTING" and not strfind(strlower(filter), "/crafting") and str then
|
||||
filter = filter.."/crafting"
|
||||
elseif mode == "DISENCHANT" and not strfind(strlower(filter), "/disenchant") and str then
|
||||
filter = filter.."/disenchant"
|
||||
end
|
||||
if strfind(strlower(filter), "/crafting") then
|
||||
local craftingTargetItem = str and Conversions.GetTargetItemByName(str) or nil
|
||||
if not craftingTargetItem or not Conversions.GetSourceItems(craftingTargetItem) then
|
||||
isValid = false
|
||||
errMsg = errMsg or L["The specified item is not supported for crafting searches."]
|
||||
end
|
||||
end
|
||||
if strfind(strlower(filter), "/disenchant") then
|
||||
local targetItemString = str and Conversions.GetTargetItemByName(str) or nil
|
||||
if not DisenchantInfo.IsTargetItem(targetItemString) then
|
||||
isValid = false
|
||||
errMsg = errMsg or L["The specified item is not supported for disenchant searches."]
|
||||
end
|
||||
end
|
||||
else
|
||||
isValid = false
|
||||
errMsg = errMsg or filterErrMsg
|
||||
end
|
||||
else
|
||||
isValid = false
|
||||
end
|
||||
if isValid then
|
||||
tinsert(filters, filter)
|
||||
end
|
||||
end
|
||||
local result = table.concat(filters, ";")
|
||||
TempTable.Release(filters)
|
||||
result = isValid and result ~= "" and result or nil
|
||||
errMsg = errMsg or L["The specified filter was empty."]
|
||||
return result, errMsg
|
||||
end
|
||||
|
||||
function private.MarketValueFunction(subRow)
|
||||
local baseItemString = subRow:GetBaseItemString()
|
||||
local itemString = subRow:GetItemString()
|
||||
if next(private.targetItem) then
|
||||
local targetItemString = private.targetItem[itemString]
|
||||
if not itemString or not targetItemString then
|
||||
return nil
|
||||
end
|
||||
local targetItemRate = private.GetTargetItemRate(targetItemString, itemString)
|
||||
return Math.Round(targetItemRate * CustomPrice.GetValue(private.marketValueSource, targetItemString))
|
||||
else
|
||||
return CustomPrice.GetValue(private.marketValueSource, itemString or baseItemString)
|
||||
end
|
||||
end
|
||||
|
||||
function private.GetTargetItemRate(targetItemString, itemString)
|
||||
if itemString == targetItemString then
|
||||
return 1, 1
|
||||
end
|
||||
if DisenchantInfo.IsTargetItem(targetItemString) then
|
||||
local classId = ItemInfo.GetClassId(itemString)
|
||||
local ilvl = ItemInfo.GetItemLevel(ItemString.GetBaseFast(itemString))
|
||||
local quality = ItemInfo.GetQuality(itemString)
|
||||
local amountOfMats = DisenchantInfo.GetTargetItemSourceInfo(targetItemString, classId, quality, ilvl)
|
||||
if amountOfMats then
|
||||
return amountOfMats, 1
|
||||
end
|
||||
end
|
||||
local conversionInfo = Conversions.GetSourceItems(targetItemString)
|
||||
local conversionChunkSize = 1
|
||||
for _ in Conversions.TargetItemsByMethodIterator(itemString, Conversions.METHOD.MILL) do
|
||||
conversionChunkSize = 5
|
||||
end
|
||||
for _ in Conversions.TargetItemsByMethodIterator(itemString, Conversions.METHOD.PROSPECT) do
|
||||
conversionChunkSize = 5
|
||||
end
|
||||
return conversionInfo and conversionInfo[itemString] or 0, conversionChunkSize
|
||||
end
|
||||
|
||||
function private.TargetItemQueryFilter(query, row)
|
||||
local itemString = row:GetItemString()
|
||||
local targetItemString = private.targetItem[itemString] or private.targetItem[query]
|
||||
return itemString and targetItemString and private.GetTargetItemRate(targetItemString, itemString) == 0
|
||||
end
|
||||
|
||||
function private.ResultsUpdated(_, query)
|
||||
local targetItemString = private.targetItem[query]
|
||||
if not targetItemString then
|
||||
return
|
||||
end
|
||||
|
||||
-- populate the targetItem table for each item in the results
|
||||
for _, row in query:BrowseResultsIterator() do
|
||||
if row:HasItemInfo() then
|
||||
for _, subRow in row:SubRowIterator() do
|
||||
local itemString = subRow:GetItemString()
|
||||
if itemString then
|
||||
private.targetItem[itemString] = targetItemString
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function private.OnQueryDone(_, query)
|
||||
private.ResultsUpdated(nil, query)
|
||||
private.targetItem[query] = nil
|
||||
end
|
||||
|
||||
function private.GetMaxQuantityQuery(itemString)
|
||||
if not next(private.generalMaxQuantity) then
|
||||
return
|
||||
end
|
||||
|
||||
-- find the query this item belongs to
|
||||
local itemQuery = nil
|
||||
for query, value in pairs(private.generalMaxQuantity) do
|
||||
local containsItem = false
|
||||
for _ in query:ItemSubRowIterator(itemString) do
|
||||
containsItem = true
|
||||
end
|
||||
if containsItem then
|
||||
-- resolve any potential redirection to the base query
|
||||
itemQuery = type(value) == "number" and query or value
|
||||
break
|
||||
end
|
||||
end
|
||||
if not itemQuery or not private.generalMaxQuantity[itemQuery] then
|
||||
return
|
||||
end
|
||||
return itemQuery
|
||||
end
|
||||
45
Core/Service/Shopping/GreatDealsSearch.lua
Normal file
45
Core/Service/Shopping/GreatDealsSearch.lua
Normal file
@@ -0,0 +1,45 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster --
|
||||
-- https://tradeskillmaster.com --
|
||||
-- All Rights Reserved - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
local _, TSM = ...
|
||||
local GreatDealsSearch = TSM.Shopping:NewPackage("GreatDealsSearch")
|
||||
local Vararg = TSM.Include("Util.Vararg")
|
||||
local ItemInfo = TSM.Include("Service.ItemInfo")
|
||||
local private = {
|
||||
filter = nil,
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Module Functions
|
||||
-- ============================================================================
|
||||
|
||||
function GreatDealsSearch.OnEnable()
|
||||
local appData = TSMAPI.AppHelper and TSMAPI.AppHelper:FetchData("SHOPPING_SEARCHES")
|
||||
if not appData then
|
||||
return
|
||||
end
|
||||
for _, info in pairs(appData) do
|
||||
local realmName, data = unpack(info)
|
||||
if TSMAPI.AppHelper:IsCurrentRealm(realmName) then
|
||||
private.filter = assert(loadstring(data))().greatDeals
|
||||
if private.filter == "" then
|
||||
break
|
||||
end
|
||||
-- populate item info cache
|
||||
for _, item in Vararg.Iterator(strsplit(";", private.filter)) do
|
||||
item = strsplit("/", item)
|
||||
ItemInfo.FetchInfo(item)
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function GreatDealsSearch.GetFilter()
|
||||
return private.filter
|
||||
end
|
||||
172
Core/Service/Shopping/GroupSearch.lua
Normal file
172
Core/Service/Shopping/GroupSearch.lua
Normal file
@@ -0,0 +1,172 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster --
|
||||
-- https://tradeskillmaster.com --
|
||||
-- All Rights Reserved - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
local _, TSM = ...
|
||||
local GroupSearch = TSM.Shopping:NewPackage("GroupSearch")
|
||||
local L = TSM.Include("Locale").GetTable()
|
||||
local Log = TSM.Include("Util.Log")
|
||||
local TempTable = TSM.Include("Util.TempTable")
|
||||
local ItemString = TSM.Include("Util.ItemString")
|
||||
local Threading = TSM.Include("Service.Threading")
|
||||
local ItemInfo = TSM.Include("Service.ItemInfo")
|
||||
local GroupSearchContext = TSM.Include("LibTSMClass").DefineClass("GroupSearchContext", TSM.Shopping.ShoppingSearchContext)
|
||||
local private = {
|
||||
groups = {},
|
||||
itemList = {},
|
||||
maxQuantity = {},
|
||||
scanThreadId = nil,
|
||||
seenMaxPrice = {},
|
||||
searchContext = nil,
|
||||
queries = {},
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Module Functions
|
||||
-- ============================================================================
|
||||
|
||||
function GroupSearch.OnInitialize()
|
||||
-- initialize thread
|
||||
private.scanThreadId = Threading.New("GROUP_SEARCH", private.ScanThread)
|
||||
private.searchContext = GroupSearchContext(private.scanThreadId, private.MarketValueFunction)
|
||||
end
|
||||
|
||||
function GroupSearch.GetSearchContext(groupList)
|
||||
return private.searchContext:SetScanContext(L["Group Search"], groupList, nil, L["Max Price"])
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Scan Thread
|
||||
-- ============================================================================
|
||||
|
||||
function private.ScanThread(auctionScan, groupList)
|
||||
wipe(private.seenMaxPrice)
|
||||
|
||||
-- create the list of items, and add filters for them
|
||||
wipe(private.itemList)
|
||||
wipe(private.maxQuantity)
|
||||
wipe(private.queries)
|
||||
for _, groupPath in ipairs(groupList) do
|
||||
private.groups[groupPath] = true
|
||||
for _, itemString in TSM.Groups.ItemIterator(groupPath) do
|
||||
local isValid, maxQuantityOrErr = TSM.Operations.Shopping.ValidAndGetRestockQuantity(itemString)
|
||||
if isValid then
|
||||
private.maxQuantity[itemString] = maxQuantityOrErr
|
||||
tinsert(private.itemList, itemString)
|
||||
elseif maxQuantityOrErr then
|
||||
Log.PrintfUser(L["Invalid custom price source for %s. %s"], ItemInfo.GetLink(itemString), maxQuantityOrErr)
|
||||
end
|
||||
end
|
||||
end
|
||||
if #private.itemList == 0 then
|
||||
return false
|
||||
end
|
||||
|
||||
auctionScan:AddItemListQueriesThreaded(private.itemList)
|
||||
for _, query in auctionScan:QueryIterator() do
|
||||
query:SetIsBrowseDoneFunction(private.QueryIsBrowseDoneFunction)
|
||||
query:AddCustomFilter(private.QueryFilter)
|
||||
tinsert(private.queries, query)
|
||||
end
|
||||
|
||||
-- run the scan
|
||||
if not auctionScan:ScanQueriesThreaded() then
|
||||
Log.PrintUser(L["TSM failed to scan some auctions. Please rerun the scan."])
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- GroupSearchContext Class
|
||||
-- ============================================================================
|
||||
|
||||
function GroupSearchContext.GetMaxCanBuy(self, itemString)
|
||||
return private.maxQuantity[itemString]
|
||||
end
|
||||
|
||||
function GroupSearchContext.OnBuy(self, itemString, quantity)
|
||||
self.__super:OnBuy(itemString, quantity)
|
||||
if not private.maxQuantity[itemString] then
|
||||
return
|
||||
end
|
||||
|
||||
private.maxQuantity[itemString] = private.maxQuantity[itemString] - quantity
|
||||
if private.maxQuantity[itemString] <= 0 then
|
||||
private.maxQuantity[itemString] = nil
|
||||
local toRemove = TempTable.Acquire()
|
||||
for _, query in ipairs(private.queries) do
|
||||
for _, row in query:BrowseResultsIterator() do
|
||||
if row:HasItemInfo() then
|
||||
for _, subRow in row:SubRowIterator() do
|
||||
if subRow:GetItemString() == itemString then
|
||||
tinsert(toRemove, subRow)
|
||||
end
|
||||
end
|
||||
for _, subRow in ipairs(toRemove) do
|
||||
row:RemoveSubRow(subRow)
|
||||
end
|
||||
wipe(toRemove)
|
||||
end
|
||||
end
|
||||
end
|
||||
TempTable.Release(toRemove)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Private Helper Functions
|
||||
-- ============================================================================
|
||||
|
||||
function private.QueryIsBrowseDoneFunction(query)
|
||||
local isDone = true
|
||||
for itemString in query:ItemIterator() do
|
||||
if TSM.Operations.Shopping.ShouldShowAboveMaxPrice(itemString) then
|
||||
-- need to scan all the auctions
|
||||
isDone = false
|
||||
elseif not private.seenMaxPrice[itemString] then
|
||||
-- we haven't seen any auctions above the max price, so need to keep scanning
|
||||
isDone = false
|
||||
end
|
||||
end
|
||||
return isDone
|
||||
end
|
||||
|
||||
function private.QueryFilter(query, row)
|
||||
local baseItemString = row:GetBaseItemString()
|
||||
local itemString = row:GetItemString()
|
||||
local _, itemBuyout, minItemBuyout = row:GetBuyouts()
|
||||
itemBuyout = itemBuyout or minItemBuyout
|
||||
if not itemBuyout then
|
||||
return false
|
||||
elseif itemBuyout == 0 then
|
||||
return true
|
||||
end
|
||||
if itemString then
|
||||
local isFiltered, aboveMax = TSM.Operations.Shopping.IsFiltered(itemString, itemBuyout)
|
||||
private.seenMaxPrice[itemString] = private.seenMaxPrice[itemString] or aboveMax
|
||||
return isFiltered
|
||||
else
|
||||
local allFiltered = true
|
||||
for queryItemString in query:ItemIterator() do
|
||||
if ItemString.GetBaseFast(queryItemString) == baseItemString and not TSM.Operations.Shopping.IsFiltered(queryItemString, itemBuyout) then
|
||||
allFiltered = false
|
||||
end
|
||||
end
|
||||
return allFiltered
|
||||
end
|
||||
end
|
||||
|
||||
function private.MarketValueFunction(row)
|
||||
local itemString = row:GetItemString()
|
||||
return itemString and TSM.Operations.Shopping.GetMaxPrice(itemString) or nil
|
||||
end
|
||||
143
Core/Service/Shopping/SavedSearches.lua
Normal file
143
Core/Service/Shopping/SavedSearches.lua
Normal file
@@ -0,0 +1,143 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster --
|
||||
-- https://tradeskillmaster.com --
|
||||
-- All Rights Reserved - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
local _, TSM = ...
|
||||
local SavedSearches = TSM.Shopping:NewPackage("SavedSearches")
|
||||
local Log = TSM.Include("Util.Log")
|
||||
local Database = TSM.Include("Util.Database")
|
||||
local TempTable = TSM.Include("Util.TempTable")
|
||||
local Settings = TSM.Include("Service.Settings")
|
||||
local private = {
|
||||
settings = nil,
|
||||
db = nil,
|
||||
}
|
||||
local MAX_RECENT_SEARCHES = 2000
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Module Functions
|
||||
-- ============================================================================
|
||||
|
||||
function SavedSearches.OnInitialize()
|
||||
private.settings = Settings.NewView()
|
||||
:AddKey("global", "userData", "savedShoppingSearches")
|
||||
|
||||
-- remove duplicates
|
||||
local seen = TempTable.Acquire()
|
||||
for i = #private.settings.savedShoppingSearches.filters, 1, -1 do
|
||||
local filter = private.settings.savedShoppingSearches.filters[i]
|
||||
local filterLower = strlower(private.settings.savedShoppingSearches.filters[i])
|
||||
if seen[filterLower] then
|
||||
tremove(private.settings.savedShoppingSearches.filters, i)
|
||||
private.settings.savedShoppingSearches.name[filter] = nil
|
||||
private.settings.savedShoppingSearches.isFavorite[filter] = nil
|
||||
else
|
||||
seen[filterLower] = true
|
||||
end
|
||||
end
|
||||
TempTable.Release(seen)
|
||||
|
||||
-- remove old recent searches
|
||||
local remainingRecentSearches = MAX_RECENT_SEARCHES
|
||||
local numRemoved = 0
|
||||
for i = #private.settings.savedShoppingSearches.filters, 1, -1 do
|
||||
local filter = private.settings.savedShoppingSearches.filters
|
||||
if not private.settings.savedShoppingSearches.isFavorite[filter] then
|
||||
if remainingRecentSearches > 0 then
|
||||
remainingRecentSearches = remainingRecentSearches - 1
|
||||
else
|
||||
tremove(private.settings.savedShoppingSearches.filters, i)
|
||||
private.settings.savedShoppingSearches.name[filter] = nil
|
||||
numRemoved = numRemoved + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
if numRemoved > 0 then
|
||||
Log.Info("Removed %d old recent searches", numRemoved)
|
||||
end
|
||||
|
||||
private.db = Database.NewSchema("SHOPPING_SAVED_SEARCHES")
|
||||
:AddUniqueNumberField("index")
|
||||
:AddStringField("name")
|
||||
:AddBooleanField("isFavorite")
|
||||
:AddStringField("filter")
|
||||
:AddIndex("index")
|
||||
:AddIndex("name")
|
||||
:Commit()
|
||||
private.RebuildDB()
|
||||
end
|
||||
|
||||
function SavedSearches.CreateRecentSearchesQuery()
|
||||
return private.db:NewQuery()
|
||||
:OrderBy("index", false)
|
||||
end
|
||||
|
||||
function SavedSearches.CreateFavoriteSearchesQuery()
|
||||
return private.db:NewQuery()
|
||||
:Equal("isFavorite", true)
|
||||
:OrderBy("name", true)
|
||||
end
|
||||
|
||||
function SavedSearches.SetSearchIsFavorite(dbRow, isFavorite)
|
||||
local filter = dbRow:GetField("filter")
|
||||
private.settings.savedShoppingSearches.isFavorite[filter] = isFavorite or nil
|
||||
dbRow:SetField("isFavorite", isFavorite)
|
||||
:Update()
|
||||
end
|
||||
|
||||
function SavedSearches.RenameSearch(dbRow, newName)
|
||||
local filter = dbRow:GetField("filter")
|
||||
private.settings.savedShoppingSearches.name[filter] = newName ~= filter and newName or nil
|
||||
dbRow:SetField("name", newName)
|
||||
:Update()
|
||||
end
|
||||
|
||||
function SavedSearches.DeleteSearch(dbRow)
|
||||
local index, filter = dbRow:GetFields("index", "filter")
|
||||
tremove(private.settings.savedShoppingSearches.filters, index)
|
||||
private.settings.savedShoppingSearches.name[filter] = nil
|
||||
private.settings.savedShoppingSearches.isFavorite[filter] = nil
|
||||
private.RebuildDB()
|
||||
end
|
||||
|
||||
function SavedSearches.RecordFilterSearch(filter)
|
||||
for i, existingFilter in ipairs(private.settings.savedShoppingSearches.filters) do
|
||||
if strlower(existingFilter) == strlower(filter) then
|
||||
-- move this to the end of the list and rebuild the DB
|
||||
-- insert the existing filter so we don't need to update the isFavorite and name tables
|
||||
tremove(private.settings.savedShoppingSearches.filters, i)
|
||||
tinsert(private.settings.savedShoppingSearches.filters, existingFilter)
|
||||
private.RebuildDB()
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- didn't find an existing entry, so add a new one
|
||||
tinsert(private.settings.savedShoppingSearches.filters, filter)
|
||||
private.db:NewRow()
|
||||
:SetField("index", #private.settings.savedShoppingSearches.filters)
|
||||
:SetField("name", filter)
|
||||
:SetField("isFavorite", false)
|
||||
:SetField("filter", filter)
|
||||
:Create()
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Private Helper Functions
|
||||
-- ============================================================================
|
||||
|
||||
function private.RebuildDB()
|
||||
private.db:TruncateAndBulkInsertStart()
|
||||
for index, filter in ipairs(private.settings.savedShoppingSearches.filters) do
|
||||
local name = private.settings.savedShoppingSearches.name[filter] or filter
|
||||
local isFavorite = private.settings.savedShoppingSearches.isFavorite[filter] and true or false
|
||||
private.db:BulkInsertNewRow(index, name, isFavorite, filter)
|
||||
end
|
||||
private.db:BulkInsertEnd()
|
||||
end
|
||||
77
Core/Service/Shopping/SearchCommon.lua
Normal file
77
Core/Service/Shopping/SearchCommon.lua
Normal file
@@ -0,0 +1,77 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster --
|
||||
-- https://tradeskillmaster.com --
|
||||
-- All Rights Reserved - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
local _, TSM = ...
|
||||
local SearchCommon = TSM.Shopping:NewPackage("SearchCommon")
|
||||
local Delay = TSM.Include("Util.Delay")
|
||||
local Threading = TSM.Include("Service.Threading")
|
||||
local private = {
|
||||
findThreadId = nil,
|
||||
callback = nil,
|
||||
isRunning = false,
|
||||
pendingStartArgs = {},
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Module Functions
|
||||
-- ============================================================================
|
||||
|
||||
function SearchCommon.OnInitialize()
|
||||
-- initialize threads
|
||||
private.findThreadId = Threading.New("FIND_SEARCH", private.FindThread)
|
||||
Threading.SetCallback(private.findThreadId, private.ThreadCallback)
|
||||
end
|
||||
|
||||
function SearchCommon.StartFindAuction(auctionScan, auction, callback, noSeller)
|
||||
wipe(private.pendingStartArgs)
|
||||
private.pendingStartArgs.auctionScan = auctionScan
|
||||
private.pendingStartArgs.auction = auction
|
||||
private.pendingStartArgs.callback = callback
|
||||
private.pendingStartArgs.noSeller = noSeller
|
||||
Delay.AfterTime("SEARCH_COMMON_THREAD_START", 0, private.StartThread)
|
||||
end
|
||||
|
||||
function SearchCommon.StopFindAuction(noKill)
|
||||
wipe(private.pendingStartArgs)
|
||||
private.callback = nil
|
||||
if not noKill then
|
||||
Threading.Kill(private.findThreadId)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Find Thread
|
||||
-- ============================================================================
|
||||
|
||||
|
||||
function private.FindThread(auctionScan, row, noSeller)
|
||||
return auctionScan:FindAuctionThreaded(row, noSeller)
|
||||
end
|
||||
|
||||
function private.StartThread()
|
||||
if not private.pendingStartArgs.auctionScan then
|
||||
return
|
||||
end
|
||||
if private.isRunning then
|
||||
Delay.AfterTime("SEARCH_COMMON_THREAD_START", 0.1, private.StartThread)
|
||||
return
|
||||
end
|
||||
private.isRunning = true
|
||||
private.callback = private.pendingStartArgs.callback
|
||||
Threading.Start(private.findThreadId, private.pendingStartArgs.auctionScan, private.pendingStartArgs.auction, private.pendingStartArgs.noSeller)
|
||||
wipe(private.pendingStartArgs)
|
||||
end
|
||||
|
||||
function private.ThreadCallback(...)
|
||||
private.isRunning = false
|
||||
if private.callback then
|
||||
private.callback(...)
|
||||
end
|
||||
end
|
||||
83
Core/Service/Shopping/VendorSearch.lua
Normal file
83
Core/Service/Shopping/VendorSearch.lua
Normal file
@@ -0,0 +1,83 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster --
|
||||
-- https://tradeskillmaster.com --
|
||||
-- All Rights Reserved - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
local _, TSM = ...
|
||||
local VendorSearch = TSM.Shopping:NewPackage("VendorSearch")
|
||||
local L = TSM.Include("Locale").GetTable()
|
||||
local Log = TSM.Include("Util.Log")
|
||||
local Threading = TSM.Include("Service.Threading")
|
||||
local ItemInfo = TSM.Include("Service.ItemInfo")
|
||||
local private = {
|
||||
itemList = {},
|
||||
scanThreadId = nil,
|
||||
searchContext = nil,
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Module Functions
|
||||
-- ============================================================================
|
||||
|
||||
function VendorSearch.OnInitialize()
|
||||
-- initialize thread
|
||||
private.scanThreadId = Threading.New("VENDOR_SEARCH", private.ScanThread)
|
||||
private.searchContext = TSM.Shopping.ShoppingSearchContext(private.scanThreadId, private.MarketValueFunction)
|
||||
end
|
||||
|
||||
function VendorSearch.GetSearchContext()
|
||||
return private.searchContext:SetScanContext(L["Vendor Search"], nil, nil, L["Vendor Sell Price"])
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Scan Thread
|
||||
-- ============================================================================
|
||||
|
||||
function private.ScanThread(auctionScan)
|
||||
if (TSM.AuctionDB.GetLastCompleteScanTime() or 0) < time() - 60 * 60 * 12 then
|
||||
Log.PrintUser(L["No recent AuctionDB scan data found."])
|
||||
return false
|
||||
end
|
||||
|
||||
-- create the list of items
|
||||
wipe(private.itemList)
|
||||
for _, itemString, _, minBuyout in TSM.AuctionDB.LastScanIteratorThreaded() do
|
||||
local vendorSell = ItemInfo.GetVendorSell(itemString) or 0
|
||||
if vendorSell and minBuyout and minBuyout < vendorSell then
|
||||
tinsert(private.itemList, itemString)
|
||||
end
|
||||
Threading.Yield()
|
||||
end
|
||||
|
||||
-- run the scan
|
||||
auctionScan:AddItemListQueriesThreaded(private.itemList)
|
||||
for _, query in auctionScan:QueryIterator() do
|
||||
query:AddCustomFilter(private.QueryFilter)
|
||||
end
|
||||
if not auctionScan:ScanQueriesThreaded() then
|
||||
Log.PrintUser(L["TSM failed to scan some auctions. Please rerun the scan."])
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function private.QueryFilter(_, row)
|
||||
local itemString = row:GetItemString()
|
||||
if not itemString then
|
||||
return false
|
||||
end
|
||||
local _, itemBuyout = row:GetBuyouts()
|
||||
if not itemBuyout then
|
||||
return false
|
||||
end
|
||||
local vendorSell = ItemInfo.GetVendorSell(itemString)
|
||||
return not vendorSell or itemBuyout == 0 or itemBuyout >= vendorSell
|
||||
end
|
||||
|
||||
function private.MarketValueFunction(row)
|
||||
return ItemInfo.GetVendorSell(row:GetItemString() or row:GetBaseItemString())
|
||||
end
|
||||
Reference in New Issue
Block a user