264 lines
8.5 KiB
Lua
264 lines
8.5 KiB
Lua
-- ------------------------------------------------------------------------------ --
|
|
-- TradeSkillMaster --
|
|
-- https://tradeskillmaster.com --
|
|
-- All Rights Reserved - Detailed license information included with addon. --
|
|
-- ------------------------------------------------------------------------------ --
|
|
|
|
local _, TSM = ...
|
|
local MyAuctions = TSM:NewPackage("MyAuctions")
|
|
local L = TSM.Include("Locale").GetTable()
|
|
local Database = TSM.Include("Util.Database")
|
|
local Event = TSM.Include("Util.Event")
|
|
local TempTable = TSM.Include("Util.TempTable")
|
|
local Log = TSM.Include("Util.Log")
|
|
local AuctionTracking = TSM.Include("Service.AuctionTracking")
|
|
local ItemInfo = TSM.Include("Service.ItemInfo")
|
|
local AuctionHouseWrapper = TSM.Include("Service.AuctionHouseWrapper")
|
|
local private = {
|
|
pendingDB = nil,
|
|
ahOpen = false,
|
|
pendingHashes = {},
|
|
expectedCounts = {},
|
|
auctionInfo = { numPosted = 0, numSold = 0, postedGold = 0, soldGold = 0 },
|
|
dbHashFields = {},
|
|
pendingFuture = nil,
|
|
}
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Module Functions
|
|
-- ============================================================================
|
|
|
|
function MyAuctions.OnInitialize()
|
|
private.pendingDB = Database.NewSchema("MY_AUCTIONS_PENDING")
|
|
:AddUniqueNumberField("index")
|
|
:AddNumberField("hash")
|
|
:AddBooleanField("isPending")
|
|
:AddNumberField("pendingAuctionId")
|
|
:AddIndex("index")
|
|
:Commit()
|
|
for field in AuctionTracking.DatabaseFieldIterator() do
|
|
if field ~= "index" and field ~= "auctionId" then
|
|
tinsert(private.dbHashFields, field)
|
|
end
|
|
end
|
|
|
|
Event.Register("AUCTION_HOUSE_SHOW", private.AuctionHouseShowEventHandler)
|
|
Event.Register("AUCTION_HOUSE_CLOSED", private.AuctionHouseHideEventHandler)
|
|
Event.Register("CHAT_MSG_SYSTEM", private.ChatMsgSystemEventHandler)
|
|
Event.Register("UI_ERROR_MESSAGE", private.UIErrorMessageEventHandler)
|
|
AuctionTracking.RegisterCallback(private.OnAuctionsUpdated)
|
|
end
|
|
|
|
function MyAuctions.CreateQuery()
|
|
local query = AuctionTracking.CreateQuery()
|
|
:LeftJoin(private.pendingDB, "index")
|
|
:InnerJoin(ItemInfo.GetDBForJoin(), "itemString")
|
|
:VirtualField("group", "string", private.AuctionsGetGroupText, "itemString")
|
|
if TSM.IsWowClassic() then
|
|
query:OrderBy("index", false)
|
|
else
|
|
query:OrderBy("saleStatus", false)
|
|
query:OrderBy("name", true)
|
|
query:OrderBy("auctionId", true)
|
|
end
|
|
return query
|
|
end
|
|
|
|
function MyAuctions.CancelAuction(auctionId)
|
|
local row = private.pendingDB:NewQuery()
|
|
:Equal("pendingAuctionId", auctionId)
|
|
:GetFirstResultAndRelease()
|
|
local hash = row:GetField("hash")
|
|
assert(hash)
|
|
|
|
Log.Info("Canceling (auctionId=%d, hash=%d)", auctionId, hash)
|
|
if TSM.IsWowClassic() then
|
|
CancelAuction(auctionId)
|
|
else
|
|
private.pendingFuture = AuctionHouseWrapper.CancelAuction(auctionId)
|
|
if not private.pendingFuture then
|
|
Log.PrintUser(L["Failed to cancel auction due to the auction house being busy. Ensure no other addons are scanning the AH and try again."])
|
|
return
|
|
end
|
|
private.pendingFuture:SetScript("OnDone", private.PendingFutureOnDone)
|
|
end
|
|
|
|
if private.expectedCounts[hash] and private.expectedCounts[hash] > 0 then
|
|
private.expectedCounts[hash] = private.expectedCounts[hash] - 1
|
|
else
|
|
private.expectedCounts[hash] = private.GetNumRowsByHash(hash) - 1
|
|
end
|
|
assert(private.expectedCounts[hash] >= 0)
|
|
assert(not row:GetField("isPending"))
|
|
row:SetField("isPending", true)
|
|
:Update()
|
|
row:Release()
|
|
|
|
tinsert(private.pendingHashes, hash)
|
|
end
|
|
|
|
function MyAuctions.CanCancel(index)
|
|
if TSM.IsWowClassic() then
|
|
local numPending = private.pendingDB:NewQuery()
|
|
:Equal("isPending", true)
|
|
:LessThanOrEqual("index", index)
|
|
:CountAndRelease()
|
|
return numPending == 0
|
|
else
|
|
return not private.pendingFuture
|
|
end
|
|
end
|
|
|
|
function MyAuctions.GetNumPending()
|
|
if TSM.IsWowClassic() then
|
|
return private.pendingDB:NewQuery()
|
|
:Equal("isPending", true)
|
|
:CountAndRelease()
|
|
else
|
|
return private.pendingFuture and 1 or 0
|
|
end
|
|
end
|
|
|
|
function MyAuctions.GetAuctionInfo()
|
|
if not private.ahOpen then
|
|
return
|
|
end
|
|
return private.auctionInfo.numPosted, private.auctionInfo.numSold, private.auctionInfo.postedGold, private.auctionInfo.soldGold
|
|
end
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Private Helper Functions
|
|
-- ============================================================================
|
|
|
|
function private.AuctionHouseShowEventHandler()
|
|
private.ahOpen = true
|
|
end
|
|
|
|
function private.AuctionHouseHideEventHandler()
|
|
private.ahOpen = false
|
|
if private.pendingFuture then
|
|
private.pendingFuture:Cancel()
|
|
private.pendingFuture = nil
|
|
end
|
|
end
|
|
|
|
function private.ChatMsgSystemEventHandler(_, msg)
|
|
if msg == ERR_AUCTION_REMOVED and #private.pendingHashes > 0 and TSM.IsWowClassic() then
|
|
local hash = tremove(private.pendingHashes, 1)
|
|
assert(hash)
|
|
Log.Info("Confirmed (hash=%d)", hash)
|
|
end
|
|
end
|
|
|
|
function private.UIErrorMessageEventHandler(_, _, msg)
|
|
if (msg == ERR_ITEM_NOT_FOUND or msg == ERR_NOT_ENOUGH_MONEY) and #private.pendingHashes > 0 and TSM.IsWowClassic() then
|
|
local hash = tremove(private.pendingHashes, 1)
|
|
assert(hash)
|
|
Log.Info("Failed to cancel (hash=%d)", hash)
|
|
if private.expectedCounts[hash] then
|
|
private.expectedCounts[hash] = private.expectedCounts[hash] + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
function private.PendingFutureOnDone()
|
|
local result = private.pendingFuture:GetValue()
|
|
private.pendingFuture = nil
|
|
local hash = tremove(private.pendingHashes, 1)
|
|
assert(hash)
|
|
if result then
|
|
Log.Info("Confirmed (hash=%d)", hash)
|
|
else
|
|
Log.Info("Failed to cancel (hash=%d)", hash)
|
|
if private.expectedCounts[hash] then
|
|
private.expectedCounts[hash] = private.expectedCounts[hash] + 1
|
|
end
|
|
private.OnAuctionsUpdated()
|
|
AuctionTracking.QueryOwnedAuctions()
|
|
end
|
|
end
|
|
|
|
function private.GetNumRowsByHash(hash)
|
|
return private.pendingDB:NewQuery()
|
|
:Equal("hash", hash)
|
|
:CountAndRelease()
|
|
end
|
|
|
|
function private.AuctionsGetGroupText(itemString)
|
|
local groupPath = TSM.Groups.GetPathByItem(itemString)
|
|
if not groupPath then
|
|
return ""
|
|
end
|
|
return groupPath
|
|
end
|
|
|
|
function private.OnAuctionsUpdated()
|
|
local minPendingIndexByHash = TempTable.Acquire()
|
|
local numByHash = TempTable.Acquire()
|
|
local query = AuctionTracking.CreateQuery()
|
|
:OrderBy("index", true)
|
|
for _, row in query:Iterator() do
|
|
local index = row:GetField("index")
|
|
local hash = row:CalculateHash(private.dbHashFields)
|
|
numByHash[hash] = (numByHash[hash] or 0) + 1
|
|
if not minPendingIndexByHash[hash] and private.pendingDB:GetUniqueRowField("index", index, "isPending") then
|
|
minPendingIndexByHash[hash] = index
|
|
end
|
|
end
|
|
local numUsed = TempTable.Acquire()
|
|
private.pendingDB:TruncateAndBulkInsertStart()
|
|
for _, row in query:Iterator() do
|
|
local hash = row:CalculateHash(private.dbHashFields)
|
|
assert(numByHash[hash] > 0)
|
|
local expectedCount = private.expectedCounts[hash]
|
|
local isPending = nil
|
|
if not expectedCount then
|
|
-- this was never pending
|
|
isPending = false
|
|
elseif numByHash[hash] <= expectedCount then
|
|
-- this is no longer pending
|
|
isPending = false
|
|
private.expectedCounts[hash] = nil
|
|
elseif row:GetField("index") >= (minPendingIndexByHash[hash] or math.huge) then
|
|
local numPending = numByHash[hash] - expectedCount
|
|
assert(numPending > 0)
|
|
numUsed[hash] = (numUsed[hash] or 0) + 1
|
|
isPending = numUsed[hash] <= numPending
|
|
else
|
|
-- it's a later auction which is pending
|
|
isPending = false
|
|
end
|
|
private.pendingDB:BulkInsertNewRow(row:GetField("index"), hash, isPending, row:GetField("auctionId"))
|
|
end
|
|
private.pendingDB:BulkInsertEnd()
|
|
TempTable.Release(numByHash)
|
|
TempTable.Release(numUsed)
|
|
TempTable.Release(minPendingIndexByHash)
|
|
|
|
-- update the player's auction status
|
|
private.auctionInfo.numPosted = 0
|
|
private.auctionInfo.numSold = 0
|
|
private.auctionInfo.postedGold = 0
|
|
private.auctionInfo.soldGold = 0
|
|
for _, row in query:Iterator() do
|
|
local itemString, saleStatus, buyout, currentBid, stackSize = row:GetFields("itemString", "saleStatus", "buyout", "currentBid", "stackSize")
|
|
if saleStatus == 1 then
|
|
private.auctionInfo.numSold = private.auctionInfo.numSold + 1
|
|
-- if somebody did a buyout, then bid will be equal to buyout, otherwise it'll be the winning bid
|
|
private.auctionInfo.soldGold = private.auctionInfo.soldGold + currentBid
|
|
else
|
|
private.auctionInfo.numPosted = private.auctionInfo.numPosted + 1
|
|
if ItemInfo.IsCommodity(itemString) then
|
|
private.auctionInfo.postedGold = private.auctionInfo.postedGold + (buyout * stackSize)
|
|
else
|
|
private.auctionInfo.postedGold = private.auctionInfo.postedGold + buyout
|
|
end
|
|
end
|
|
end
|
|
query:Release()
|
|
end
|