627 lines
22 KiB
Lua
627 lines
22 KiB
Lua
-- ------------------------------------------------------------------------------ --
|
|
-- TradeSkillMaster --
|
|
-- https://tradeskillmaster.com --
|
|
-- All Rights Reserved - Detailed license information included with addon. --
|
|
-- ------------------------------------------------------------------------------ --
|
|
|
|
local _, TSM = ...
|
|
local AuctionTracking = TSM.Init("Service.AuctionTracking")
|
|
local L = TSM.Include("Locale").GetTable()
|
|
local Database = TSM.Include("Util.Database")
|
|
local Delay = TSM.Include("Util.Delay")
|
|
local Event = TSM.Include("Util.Event")
|
|
local Log = TSM.Include("Util.Log")
|
|
local ItemString = TSM.Include("Util.ItemString")
|
|
local TempTable = TSM.Include("Util.TempTable")
|
|
local Sound = TSM.Include("Util.Sound")
|
|
local Money = TSM.Include("Util.Money")
|
|
local Analytics = TSM.Include("Util.Analytics")
|
|
local ItemInfo = TSM.Include("Service.ItemInfo")
|
|
local Settings = TSM.Include("Service.Settings")
|
|
local AuctionHouseWrapper = TSM.Include("Service.AuctionHouseWrapper")
|
|
local private = {
|
|
settings = nil,
|
|
indexDB = nil,
|
|
quantityDB = nil,
|
|
updateQuery = nil, -- luacheck: ignore 1004 - just stored for GC reasons
|
|
isAHOpen = false,
|
|
callbacks = {},
|
|
expiresCallbacks = {},
|
|
indexUpdates = {
|
|
list = {},
|
|
pending = {},
|
|
},
|
|
cancelAuctionId = nil,
|
|
lastScanNum = nil,
|
|
ignoreUpdateEvent = nil,
|
|
lastPurchase = {},
|
|
prevLineId = nil,
|
|
prevLineResult = nil,
|
|
origChatFrameOnEvent = nil,
|
|
pendingFuture = nil,
|
|
auctionIdToLink = {},
|
|
auctionIdToItemBuyout = {},
|
|
prevLogTime = 0,
|
|
prevLogNum = math.huge,
|
|
}
|
|
local PLAYER_NAME = UnitName("player")
|
|
local SALE_HINT_SEP = "\001"
|
|
local SALE_HINT_EXPIRE_TIME = 33 * 24 * 60 * 60
|
|
local SORT_ORDER = not TSM.IsWowClassic() and {
|
|
{ sortOrder = Enum.AuctionHouseSortOrder.Name, reverseSort = false },
|
|
{ sortOrder = Enum.AuctionHouseSortOrder.Price, reverseSort = false },
|
|
}
|
|
local AUCTIONABLE_WOW_TOKEN_ITEM_ID = 122270
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Module Loading
|
|
-- ============================================================================
|
|
|
|
AuctionTracking:OnSettingsLoad(function()
|
|
private.settings = Settings.NewView()
|
|
:AddKey("char", "internalData", "auctionSaleHints")
|
|
:AddKey("char", "internalData", "auctionPrices")
|
|
:AddKey("char", "internalData", "auctionMessages")
|
|
:AddKey("factionrealm", "internalData", "expiringAuction")
|
|
:AddKey("sync", "internalData", "auctionQuantity")
|
|
:AddKey("global", "coreOptions", "auctionSaleSound")
|
|
Event.Register("AUCTION_HOUSE_SHOW", private.AuctionHouseShowHandler)
|
|
Event.Register("AUCTION_HOUSE_CLOSED", private.AuctionHouseClosedHandler)
|
|
if TSM.IsWowClassic() then
|
|
Event.Register("AUCTION_OWNED_LIST_UPDATE", private.AuctionOwnedListUpdateHandler)
|
|
else
|
|
Event.Register("OWNED_AUCTIONS_UPDATED", private.AuctionOwnedListUpdateHandler)
|
|
Event.Register("AUCTION_CANCELED", private.AuctionCanceledHandler)
|
|
end
|
|
private.indexDB = Database.NewSchema("AUCTION_TRACKING_INDEXES")
|
|
:AddUniqueNumberField("index")
|
|
:AddStringField("itemString")
|
|
:AddSmartMapField("baseItemString", ItemString.GetBaseMap(), "itemString")
|
|
:AddStringField("itemLink")
|
|
:AddNumberField("itemTexture")
|
|
:AddStringField("itemName")
|
|
:AddNumberField("itemQuality")
|
|
:AddNumberField("duration")
|
|
:AddStringField("highBidder")
|
|
:AddNumberField("currentBid")
|
|
:AddNumberField("buyout")
|
|
:AddNumberField("stackSize")
|
|
:AddNumberField("saleStatus")
|
|
:AddNumberField("auctionId")
|
|
:AddIndex("index")
|
|
:AddIndex("saleStatus")
|
|
:AddIndex("auctionId")
|
|
:Commit()
|
|
private.quantityDB = Database.NewSchema("AUCTION_TRACKING_QUANTITY")
|
|
:AddUniqueStringField("itemString")
|
|
:AddNumberField("quantity")
|
|
:Commit()
|
|
private.updateQuery = private.indexDB:NewQuery()
|
|
:SetUpdateCallback(private.OnCallbackQueryUpdated)
|
|
|
|
private.RebuildQuantityDB()
|
|
for info, timestamp in pairs(private.settings.auctionSaleHints) do
|
|
if time() > timestamp + SALE_HINT_EXPIRE_TIME then
|
|
private.settings.auctionSaleHints[info] = nil
|
|
end
|
|
end
|
|
|
|
if TSM.IsWowClassic() then
|
|
hooksecurefunc("PostAuction", function(_, _, duration)
|
|
private.PostAuctionHookHandler(duration)
|
|
end)
|
|
else
|
|
hooksecurefunc(C_AuctionHouse, "PostCommodity", function(_, duration)
|
|
private.PostAuctionHookHandler(duration)
|
|
end)
|
|
hooksecurefunc(C_AuctionHouse, "PostItem", function(_, duration)
|
|
private.PostAuctionHookHandler(duration)
|
|
end)
|
|
hooksecurefunc(C_AuctionHouse, "CancelAuction", function(auctionId)
|
|
private.cancelAuctionId = auctionId
|
|
end)
|
|
end
|
|
|
|
-- setup enhanced sale / buy messages
|
|
ChatFrame_AddMessageEventFilter("CHAT_MSG_SYSTEM", private.FilterSystemMsg)
|
|
if TSM.IsWowClassic() then
|
|
hooksecurefunc("PlaceAuctionBid", function(_, index, amountPaid)
|
|
local link = GetAuctionItemLink("list", index)
|
|
local name, _, stackSize, _, _, _, _, _, _, buyout = GetAuctionItemInfo("list", index)
|
|
if amountPaid == buyout then
|
|
wipe(private.lastPurchase)
|
|
private.lastPurchase.name = name
|
|
private.lastPurchase.link = link
|
|
private.lastPurchase.stackSize = stackSize
|
|
private.lastPurchase.buyout = buyout
|
|
end
|
|
end)
|
|
else
|
|
Event.Register("ITEM_SEARCH_RESULTS_UPDATED", function(_, itemKey)
|
|
wipe(private.auctionIdToLink)
|
|
wipe(private.auctionIdToItemBuyout)
|
|
for i = 1, C_AuctionHouse.GetNumItemSearchResults(itemKey) do
|
|
local info = C_AuctionHouse.GetItemSearchResultInfo(itemKey, i)
|
|
if info.buyoutAmount then
|
|
private.auctionIdToLink[info.auctionID] = info.itemLink
|
|
private.auctionIdToItemBuyout[info.auctionID] = info.buyoutAmount
|
|
end
|
|
end
|
|
end)
|
|
hooksecurefunc(C_AuctionHouse, "PlaceBid", function(auctionId, bidPlaced)
|
|
local link = private.auctionIdToLink[auctionId]
|
|
local buyout = private.auctionIdToItemBuyout[auctionId]
|
|
if not link or buyout ~= bidPlaced then
|
|
return
|
|
end
|
|
wipe(private.lastPurchase)
|
|
private.lastPurchase.name = ItemInfo.GetName(link)
|
|
private.lastPurchase.link = link
|
|
private.lastPurchase.stackSize = 1
|
|
private.lastPurchase.buyout = bidPlaced
|
|
end)
|
|
hooksecurefunc(C_AuctionHouse, "ConfirmCommoditiesPurchase", function(itemId, quantity)
|
|
local link = ItemInfo.GetLink("i:"..itemId)
|
|
if not link then
|
|
return
|
|
end
|
|
local origQuantity = quantity
|
|
local buyout = 0
|
|
for i = 1, C_AuctionHouse.GetNumCommoditySearchResults(itemId) do
|
|
local info = C_AuctionHouse.GetCommoditySearchResultInfo(itemId, i)
|
|
local resultQuantity = min(quantity, info.quantity - info.numOwnerItems)
|
|
buyout = buyout + resultQuantity * info.unitPrice
|
|
quantity = quantity - resultQuantity
|
|
if quantity == 0 then
|
|
break
|
|
end
|
|
end
|
|
if quantity > 0 then
|
|
return
|
|
end
|
|
private.lastPurchase.name = ItemInfo.GetName(link)
|
|
private.lastPurchase.link = link
|
|
private.lastPurchase.stackSize = origQuantity
|
|
private.lastPurchase.buyout = buyout
|
|
end)
|
|
end
|
|
end)
|
|
|
|
AuctionTracking:OnGameDataLoad(function()
|
|
-- setup auction created / cancelled filtering
|
|
-- NOTE: this is delayed until the game is loaded to avoid taint issues
|
|
local ElvUIChat, ElvUIChatIsEnabled = nil, nil
|
|
if IsAddOnLoaded("ElvUI") and ElvUI then
|
|
ElvUIChat = ElvUI[1]:GetModule("Chat")
|
|
if ElvUI[3].chat.enable then
|
|
ElvUIChatIsEnabled = true
|
|
end
|
|
end
|
|
if ElvUIChatIsEnabled then
|
|
private.origChatFrameOnEvent = ElvUIChat.ChatFrame_OnEvent
|
|
ElvUIChat.ChatFrame_OnEvent = private.ChatFrameOnEvent
|
|
else
|
|
private.origChatFrameOnEvent = ChatFrame_OnEvent
|
|
ChatFrame_OnEvent = private.ChatFrameOnEvent
|
|
end
|
|
end)
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Module Functions
|
|
-- ============================================================================
|
|
|
|
function AuctionTracking.RegisterCallback(callback)
|
|
tinsert(private.callbacks, callback)
|
|
end
|
|
|
|
function AuctionTracking.RegisterExpiresCallback(callback)
|
|
tinsert(private.expiresCallbacks, callback)
|
|
end
|
|
|
|
function AuctionTracking.DatabaseFieldIterator()
|
|
return private.indexDB:FieldIterator()
|
|
end
|
|
|
|
function AuctionTracking.BaseItemIterator()
|
|
return private.quantityDB:NewQuery()
|
|
:Select("itemString")
|
|
:IteratorAndRelease()
|
|
end
|
|
|
|
function AuctionTracking.CreateQuery()
|
|
return private.indexDB:NewQuery()
|
|
end
|
|
|
|
function AuctionTracking.CreateQueryUnsold()
|
|
return AuctionTracking.CreateQuery()
|
|
:Equal("saleStatus", 0)
|
|
end
|
|
|
|
function AuctionTracking.CreateQueryUnsoldItem(itemString)
|
|
return AuctionTracking.CreateQueryUnsold()
|
|
:Equal(itemString == ItemString.GetBaseFast(itemString) and "baseItemString" or "itemString", itemString)
|
|
end
|
|
|
|
function AuctionTracking.GetSaleHintItemString(name, stackSize, buyout)
|
|
for info in pairs(private.settings.auctionSaleHints) do
|
|
local infoName, itemString, infoStackSize, infoBuyout = strsplit(SALE_HINT_SEP, info)
|
|
if infoName == name and tonumber(infoStackSize) == stackSize and tonumber(infoBuyout) == buyout then
|
|
return itemString
|
|
end
|
|
end
|
|
end
|
|
|
|
function AuctionTracking.GetQuantityByBaseItemString(baseItemString)
|
|
return private.quantityDB:GetUniqueRowField("itemString", baseItemString, "quantity") or 0
|
|
end
|
|
|
|
function AuctionTracking.QueryOwnedAuctions()
|
|
if not private.isAHOpen then
|
|
return
|
|
end
|
|
if TSM.IsWowClassic() then
|
|
GetOwnerAuctionItems()
|
|
else
|
|
if private.pendingFuture then
|
|
return
|
|
end
|
|
private.pendingFuture = AuctionHouseWrapper.QueryOwnedAuctions(SORT_ORDER)
|
|
if not private.pendingFuture then
|
|
Delay.AfterTime(0.5, AuctionTracking.QueryOwnedAuctions)
|
|
return
|
|
end
|
|
private.pendingFuture:SetScript("OnDone", private.PendingFutureOnDone)
|
|
end
|
|
end
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Event Handlers
|
|
-- ============================================================================
|
|
|
|
function private.AuctionHouseShowHandler()
|
|
private.isAHOpen = true
|
|
if TSM.IsWowClassic() then
|
|
AuctionTracking.QueryOwnedAuctions()
|
|
-- We don't always get AUCTION_OWNED_LIST_UPDATE events, so do our own scanning if needed
|
|
Delay.AfterTime("AUCTION_BACKGROUND_SCAN", 1, private.DoBackgroundScan, 1)
|
|
else
|
|
Delay.AfterTime(0.1, AuctionTracking.QueryOwnedAuctions)
|
|
end
|
|
end
|
|
|
|
function private.AuctionHouseClosedHandler()
|
|
private.isAHOpen = false
|
|
Delay.Cancel("AUCTION_BACKGROUND_SCAN")
|
|
end
|
|
|
|
function private.DoBackgroundScan()
|
|
if private.GetNumOwnedAuctions() ~= private.lastScanNum then
|
|
private.AuctionOwnedListUpdateHandler()
|
|
end
|
|
end
|
|
|
|
function private.AuctionOwnedListUpdateHandler()
|
|
if private.ignoreUpdateEvent then
|
|
return
|
|
end
|
|
wipe(private.indexUpdates.pending)
|
|
wipe(private.indexUpdates.list)
|
|
local numOwned = private.GetNumOwnedAuctions()
|
|
for i = 1, numOwned do
|
|
if not private.indexUpdates.pending[i] then
|
|
private.indexUpdates.pending[i] = true
|
|
tinsert(private.indexUpdates.list, i)
|
|
end
|
|
end
|
|
if numOwned == 0 and private.settings.expiringAuction[PLAYER_NAME] then
|
|
private.settings.expiringAuction[PLAYER_NAME] = nil
|
|
for _, callback in ipairs(private.expiresCallbacks) do
|
|
callback()
|
|
end
|
|
end
|
|
Delay.AfterFrame("AUCTION_OWNED_LIST_SCAN", 2, private.AuctionOwnedListUpdateDelayed)
|
|
end
|
|
|
|
function private.AuctionCanceledHandler(_, auctionId)
|
|
if not private.cancelAuctionId or auctionId ~= 0 then
|
|
-- an auction was bought, so rescan the owned auctions
|
|
AuctionTracking.QueryOwnedAuctions()
|
|
return
|
|
end
|
|
local row = private.indexDB:NewQuery()
|
|
:Equal("auctionId", private.cancelAuctionId)
|
|
:GetFirstResultAndRelease()
|
|
private.cancelAuctionId = nil
|
|
if not row then
|
|
return
|
|
end
|
|
|
|
local baseItemString = row:GetField("baseItemString")
|
|
local stackSize = row:GetField("stackSize")
|
|
assert(stackSize <= private.settings.auctionQuantity[baseItemString])
|
|
private.settings.auctionQuantity[baseItemString] = private.settings.auctionQuantity[baseItemString] - stackSize
|
|
private.RebuildQuantityDB()
|
|
private.indexDB:DeleteRow(row)
|
|
row:Release()
|
|
end
|
|
|
|
function private.AuctionOwnedListUpdateDelayed()
|
|
if not private.isAHOpen then
|
|
return
|
|
elseif AuctionFrame and AuctionFrame:IsVisible() and AuctionFrame.selectedTab == 3 then
|
|
-- default UI auctions tab is visible, so scan later
|
|
Delay.AfterFrame("AUCTION_OWNED_LIST_SCAN", 2, private.AuctionOwnedListUpdateDelayed)
|
|
return
|
|
elseif not TSM.IsWowClassic() and not C_AuctionHouse.HasFullOwnedAuctionResults() then
|
|
-- don't have all the results yet, so try again in a moment
|
|
Delay.AfterFrame("AUCTION_OWNED_LIST_SCAN", 0.1, private.AuctionOwnedListUpdateDelayed)
|
|
return
|
|
end
|
|
if TSM.IsWowClassic() then
|
|
-- check if we need to change the sort
|
|
local needsSort = false
|
|
local numColumns = #AuctionSort.owner_duration
|
|
for i, info in ipairs(AuctionSort.owner_duration) do
|
|
local col, reversed = GetAuctionSort("owner", numColumns - i + 1)
|
|
-- we want to do the opposite order
|
|
reversed = not reversed
|
|
if col ~= info.column or info.reverse ~= reversed then
|
|
needsSort = true
|
|
break
|
|
end
|
|
end
|
|
if needsSort then
|
|
Log.Info("Sorting owner auctions")
|
|
-- ignore events while changing the sort
|
|
private.ignoreUpdateEvent = true
|
|
AuctionFrame_SetSort("owner", "duration", true)
|
|
SortAuctionApplySort("owner")
|
|
private.ignoreUpdateEvent = nil
|
|
end
|
|
end
|
|
|
|
-- scan the auctions
|
|
local shouldLog = GetTime() - private.prevLogTime > 5
|
|
if shouldLog then
|
|
private.prevLogTime = GetTime()
|
|
end
|
|
wipe(private.settings.auctionQuantity)
|
|
private.indexDB:TruncateAndBulkInsertStart()
|
|
local expire = math.huge
|
|
for i = #private.indexUpdates.list, 1, -1 do
|
|
local index = private.indexUpdates.list[i]
|
|
local auctionId, link, name, texture, stackSize, quality, minBid, buyout, bid, highBidder, saleStatus, duration, shouldIgnore = private.GetOwnedAuctionInfo(index)
|
|
if shouldIgnore then
|
|
private.indexUpdates.pending[index] = nil
|
|
tremove(private.indexUpdates.list, i)
|
|
else
|
|
name = name or ItemInfo.GetName(link)
|
|
texture = texture or ItemInfo.GetTexture(link)
|
|
quality = quality or ItemInfo.GetQuality(link)
|
|
if link and name and texture and quality then
|
|
assert(saleStatus == 0 or saleStatus == 1)
|
|
highBidder = highBidder or ""
|
|
local itemString = ItemString.Get(link)
|
|
local currentBid = highBidder ~= "" and bid or minBid
|
|
if not currentBid and saleStatus == 1 and not TSM.IsWowClassic() then
|
|
-- sometimes wow doesn't tell us the current bid on sold auctions on retail
|
|
currentBid = 0
|
|
end
|
|
if saleStatus == 0 then
|
|
if TSM.IsWowClassic() then
|
|
if duration == 1 then -- 30 min
|
|
expire = min(expire, time() + 0.5 * 60 * 60)
|
|
elseif duration == 2 then -- 2 hours
|
|
expire = min(expire, time() + 2 * 60 * 60)
|
|
elseif duration == 3 then -- 12 hours
|
|
expire = min(expire, time() + 12 * 60 * 60)
|
|
end
|
|
else
|
|
duration = time() + duration
|
|
expire = min(expire, duration)
|
|
end
|
|
local baseItemString = ItemString.GetBaseFast(itemString)
|
|
private.settings.auctionQuantity[baseItemString] = (private.settings.auctionQuantity[baseItemString] or 0) + stackSize
|
|
local hintInfo = strjoin(SALE_HINT_SEP, ItemInfo.GetName(link), itemString, stackSize, buyout)
|
|
private.settings.auctionSaleHints[hintInfo] = time()
|
|
else
|
|
duration = time() + duration
|
|
end
|
|
private.indexUpdates.pending[index] = nil
|
|
tremove(private.indexUpdates.list, i)
|
|
private.indexDB:BulkInsertNewRow(index, itemString, link, texture, name, quality, duration, highBidder, currentBid, buyout, stackSize, saleStatus, auctionId)
|
|
elseif shouldLog then
|
|
Log.Warn("Missing info (%s, %s, %s, %s)", gsub(tostring(link), "\124", "\\124"), tostring(name), tostring(texture), tostring(quality))
|
|
if link and strmatch(link, "item:") and not TSM.IsWowClassic() then
|
|
Analytics.Action("AUCTION_TRACKING_MISSING_INFO", link)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
private.RebuildQuantityDB()
|
|
private.indexDB:BulkInsertEnd()
|
|
|
|
if expire ~= math.huge and (private.settings.expiringAuction[PLAYER_NAME] or math.huge) > expire then
|
|
private.settings.expiringAuction[PLAYER_NAME] = expire
|
|
for _, callback in ipairs(private.expiresCallbacks) do
|
|
callback()
|
|
end
|
|
end
|
|
|
|
if shouldLog or #private.indexUpdates.list ~= private.prevLogNum then
|
|
Log.Info("Scanned auctions (left=%d)", #private.indexUpdates.list)
|
|
private.prevLogNum = #private.indexUpdates.list
|
|
end
|
|
if #private.indexUpdates.list > 0 then
|
|
-- some failed to scan so try again
|
|
Delay.AfterFrame("AUCTION_OWNED_LIST_SCAN", 2, private.AuctionOwnedListUpdateDelayed)
|
|
else
|
|
private.lastScanNum = private.GetNumOwnedAuctions()
|
|
end
|
|
end
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Private Helper Functions
|
|
-- ============================================================================
|
|
|
|
function private.RebuildQuantityDB()
|
|
private.quantityDB:TruncateAndBulkInsertStart()
|
|
for itemString, quantity in pairs(private.settings.auctionQuantity) do
|
|
if quantity > 0 then
|
|
private.quantityDB:BulkInsertNewRow(itemString, quantity)
|
|
else
|
|
private.settings.auctionQuantity[itemString] = nil
|
|
end
|
|
end
|
|
private.quantityDB:BulkInsertEnd()
|
|
end
|
|
|
|
function private.GetNumOwnedAuctions()
|
|
if TSM.IsWowClassic() then
|
|
return GetNumAuctionItems("owner")
|
|
else
|
|
return C_AuctionHouse.GetNumOwnedAuctions()
|
|
end
|
|
end
|
|
|
|
function private.GetOwnedAuctionInfo(index)
|
|
if TSM.IsWowClassic() then
|
|
local name, texture, stackSize, quality, _, _, _, minBid, _, buyout, bid, highBidder, _, _, _, saleStatus = GetAuctionItemInfo("owner", index)
|
|
local link = name and name ~= "" and GetAuctionItemLink("owner", index)
|
|
if not link then
|
|
return
|
|
end
|
|
local duration = GetAuctionItemTimeLeft("owner", index)
|
|
return index, link, name, texture, stackSize, quality, minBid, buyout, bid, highBidder, saleStatus, duration
|
|
else
|
|
local info = C_AuctionHouse.GetOwnedAuctionInfo(index)
|
|
if info.itemKey.itemID == AUCTIONABLE_WOW_TOKEN_ITEM_ID then
|
|
-- this is a token, so just ignore it
|
|
return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, true
|
|
end
|
|
local link = info and info.itemLink
|
|
if not link then
|
|
return
|
|
end
|
|
local bid = info.bidAmount or info.buyoutAmount
|
|
local minBid = bid
|
|
return info.auctionID, link, nil, nil, info.quantity, nil, minBid, info.buyoutAmount or 0, bid, info.bidder or "", info.status, info.timeLeftSeconds
|
|
end
|
|
end
|
|
|
|
function private.OnCallbackQueryUpdated()
|
|
for _, callback in ipairs(private.callbacks) do
|
|
callback()
|
|
end
|
|
-- updating the auction prices / messages is very low-priority, so throttle it to at most every 0.5 seconds
|
|
Delay.AfterTime("UPDATE_AUCTION_PRICES_MESSAGES_THROTTLE", 0.5, private.UpdateAuctionPricesMessages)
|
|
end
|
|
|
|
function private.PostAuctionHookHandler(duration)
|
|
local days = nil
|
|
if duration == 1 then
|
|
days = 0.5
|
|
elseif duration == 2 then
|
|
days = 1
|
|
elseif duration == 3 then
|
|
days = 2
|
|
end
|
|
|
|
local expiration = time() + (days * 24 * 60 * 60)
|
|
if (private.settings.expiringAuction[PLAYER_NAME] or math.huge) < expiration then
|
|
return
|
|
end
|
|
private.settings.expiringAuction[PLAYER_NAME] = expiration
|
|
for _, callback in ipairs(private.expiresCallbacks) do
|
|
callback()
|
|
end
|
|
end
|
|
|
|
function private.UpdateAuctionPricesMessages()
|
|
local INVALID_STACK_SIZE = -1
|
|
-- recycle tables from private.settings.auctionPrices if we can so we're not creating a ton of garbage
|
|
local freeTables = TempTable.Acquire()
|
|
for _, tbl in pairs(private.settings.auctionPrices) do
|
|
wipe(tbl)
|
|
tinsert(freeTables, tbl)
|
|
end
|
|
wipe(private.settings.auctionPrices)
|
|
wipe(private.settings.auctionMessages)
|
|
local auctionPrices = TempTable.Acquire()
|
|
local auctionStackSizes = TempTable.Acquire()
|
|
local query = AuctionTracking.CreateQueryUnsold()
|
|
:Select("itemLink", "stackSize", "buyout")
|
|
:GreaterThan("buyout", 0)
|
|
:OrderBy("index", true)
|
|
for _, link, stackSize, buyout in query:IteratorAndRelease() do
|
|
auctionPrices[link] = auctionPrices[link] or tremove(freeTables) or {}
|
|
if stackSize ~= auctionStackSizes[link] then
|
|
auctionStackSizes[link] = stackSize
|
|
end
|
|
tinsert(auctionPrices[link], buyout)
|
|
end
|
|
for link, prices in pairs(auctionPrices) do
|
|
local name = ItemInfo.GetName(link)
|
|
if auctionStackSizes[link] ~= INVALID_STACK_SIZE then
|
|
sort(prices)
|
|
private.settings.auctionPrices[link] = prices
|
|
private.settings.auctionMessages[format(ERR_AUCTION_SOLD_S, name)] = link
|
|
end
|
|
end
|
|
TempTable.Release(freeTables)
|
|
TempTable.Release(auctionPrices)
|
|
TempTable.Release(auctionStackSizes)
|
|
end
|
|
|
|
function private.ChatFrameOnEvent(self, event, msg, ...)
|
|
-- surpress auction created / cancelled spam
|
|
if event == "CHAT_MSG_SYSTEM" and (msg == ERR_AUCTION_STARTED or msg == ERR_AUCTION_REMOVED) then
|
|
return
|
|
end
|
|
return private.origChatFrameOnEvent(self, event, msg, ...)
|
|
end
|
|
|
|
function private.FilterSystemMsg(_, _, msg, ...)
|
|
local lineID = select(10, ...)
|
|
if lineID ~= private.prevLineId then
|
|
private.prevLineId = lineID
|
|
private.prevLineResult = nil
|
|
local link = private.settings.auctionMessages and private.settings.auctionMessages[msg]
|
|
if private.lastPurchase.name and msg == format(ERR_AUCTION_WON_S, private.lastPurchase.name) then
|
|
-- we just bought an auction
|
|
private.prevLineResult = format(L["You won an auction for %sx%d for %s"], private.lastPurchase.link, private.lastPurchase.stackSize, Money.ToString(private.lastPurchase.buyout, "|cffffffff"))
|
|
return nil, private.prevLineResult, ...
|
|
elseif link then
|
|
-- we may have just sold an auction
|
|
local price = tremove(private.settings.auctionPrices[link], 1)
|
|
local numAuctions = #private.settings.auctionPrices[link]
|
|
if not price then
|
|
-- couldn't determine the price, so just replace the link
|
|
private.prevLineResult = format(ERR_AUCTION_SOLD_S, link)
|
|
Sound.PlaySound(private.settings.auctionSaleSound)
|
|
return nil, private.prevLineResult, ...
|
|
end
|
|
if numAuctions == 0 then -- this was the last auction
|
|
private.settings.auctionMessages[msg] = nil
|
|
end
|
|
private.prevLineResult = format(L["Your auction of %s has sold for %s!"], link, Money.ToString(price, "|cffffffff"))
|
|
Sound.PlaySound(private.settings.auctionSaleSound)
|
|
return nil, private.prevLineResult, ...
|
|
end
|
|
end
|
|
end
|
|
|
|
function private.PendingFutureOnDone()
|
|
-- we also hook the event, so don't care what the result is
|
|
private.pendingFuture:GetValue()
|
|
private.pendingFuture = nil
|
|
end
|