initial commit
This commit is contained in:
626
LibTSM/Service/AuctionTracking.lua
Normal file
626
LibTSM/Service/AuctionTracking.lua
Normal file
@@ -0,0 +1,626 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- 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
|
||||
Reference in New Issue
Block a user