initial commit
This commit is contained in:
55
Core/Service/Mailing/Core.lua
Normal file
55
Core/Service/Mailing/Core.lua
Normal file
@@ -0,0 +1,55 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster --
|
||||
-- https://tradeskillmaster.com --
|
||||
-- All Rights Reserved - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
local _, TSM = ...
|
||||
local Mailing = TSM:NewPackage("Mailing")
|
||||
local Event = TSM.Include("Util.Event")
|
||||
local private = {
|
||||
mailOpen = false,
|
||||
frameCallbacks = {},
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Module Functions
|
||||
-- ============================================================================
|
||||
|
||||
function Mailing.OnInitialize()
|
||||
Event.Register("MAIL_SHOW", private.MailShow)
|
||||
Event.Register("MAIL_CLOSED", private.MailClosed)
|
||||
end
|
||||
|
||||
function Mailing.RegisterFrameCallback(callback)
|
||||
tinsert(private.frameCallbacks, callback)
|
||||
end
|
||||
|
||||
function Mailing.IsOpen()
|
||||
return private.mailOpen
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Private Helper Functions
|
||||
-- ============================================================================
|
||||
|
||||
function private.MailShow()
|
||||
private.mailOpen = true
|
||||
for _, callback in ipairs(private.frameCallbacks) do
|
||||
callback(true)
|
||||
end
|
||||
end
|
||||
|
||||
function private.MailClosed()
|
||||
if not private.mailOpen then
|
||||
return
|
||||
end
|
||||
private.mailOpen = false
|
||||
for _, callback in ipairs(private.frameCallbacks) do
|
||||
callback(false)
|
||||
end
|
||||
end
|
||||
161
Core/Service/Mailing/Groups.lua
Normal file
161
Core/Service/Mailing/Groups.lua
Normal file
@@ -0,0 +1,161 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster --
|
||||
-- https://tradeskillmaster.com --
|
||||
-- All Rights Reserved - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
local _, TSM = ...
|
||||
local Groups = TSM.Mailing:NewPackage("Groups")
|
||||
local L = TSM.Include("Locale").GetTable()
|
||||
local Log = TSM.Include("Util.Log")
|
||||
local Threading = TSM.Include("Service.Threading")
|
||||
local Inventory = TSM.Include("Service.Inventory")
|
||||
local PlayerInfo = TSM.Include("Service.PlayerInfo")
|
||||
local BagTracking = TSM.Include("Service.BagTracking")
|
||||
local private = {
|
||||
thread = nil,
|
||||
sendDone = false,
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Module Functions
|
||||
-- ============================================================================
|
||||
|
||||
function Groups.OnInitialize()
|
||||
private.thread = Threading.New("MAIL_GROUPS", private.GroupsMailThread)
|
||||
end
|
||||
|
||||
function Groups.KillThread()
|
||||
Threading.Kill(private.thread)
|
||||
end
|
||||
|
||||
function Groups.StartSending(callback, groupList, sendRepeat, isDryRun)
|
||||
Threading.Kill(private.thread)
|
||||
|
||||
Threading.SetCallback(private.thread, callback)
|
||||
Threading.Start(private.thread, groupList, sendRepeat, isDryRun)
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Group Sending Thread
|
||||
-- ============================================================================
|
||||
|
||||
function private.GroupsMailThread(groupList, sendRepeat, isDryRun)
|
||||
while true do
|
||||
local targets = Threading.AcquireSafeTempTable()
|
||||
local numMailable = Threading.AcquireSafeTempTable()
|
||||
for _, groupPath in ipairs(groupList) do
|
||||
if groupPath ~= TSM.CONST.ROOT_GROUP_PATH then
|
||||
local used = Threading.AcquireSafeTempTable()
|
||||
local keep = Threading.AcquireSafeTempTable()
|
||||
for _, _, operationSettings in TSM.Operations.GroupOperationIterator("Mailing", groupPath) do
|
||||
local target = operationSettings.target
|
||||
if target ~= "" then
|
||||
local targetItems = targets[target] or Threading.AcquireSafeTempTable()
|
||||
for _, itemString in TSM.Groups.ItemIterator(groupPath) do
|
||||
itemString = TSM.Groups.TranslateItemString(itemString)
|
||||
used[itemString] = used[itemString] or 0
|
||||
keep[itemString] = max(keep[itemString] or 0, operationSettings.keepQty)
|
||||
numMailable[itemString] = numMailable[itemString] or BagTracking.GetNumMailable(itemString)
|
||||
local numAvailable = numMailable[itemString] - used[itemString] - keep[itemString]
|
||||
local quantity = private.GetItemQuantity(itemString, numAvailable, operationSettings)
|
||||
assert(quantity >= 0)
|
||||
if PlayerInfo.IsPlayer(target) then
|
||||
keep[itemString] = max(keep[itemString], quantity)
|
||||
else
|
||||
used[itemString] = used[itemString] + quantity
|
||||
if quantity > 0 then
|
||||
targetItems[itemString] = quantity
|
||||
end
|
||||
end
|
||||
end
|
||||
if next(targetItems) then
|
||||
targets[target] = targetItems
|
||||
else
|
||||
Threading.ReleaseSafeTempTable(targetItems)
|
||||
end
|
||||
end
|
||||
end
|
||||
Threading.ReleaseSafeTempTable(used)
|
||||
Threading.ReleaseSafeTempTable(keep)
|
||||
end
|
||||
end
|
||||
Threading.ReleaseSafeTempTable(numMailable)
|
||||
|
||||
if not next(targets) then
|
||||
Log.PrintUser(L["Nothing to send."])
|
||||
end
|
||||
for name, items in pairs(targets) do
|
||||
private.SendItems(name, items, isDryRun)
|
||||
Threading.ReleaseSafeTempTable(items)
|
||||
Threading.Sleep(0.5)
|
||||
end
|
||||
|
||||
Threading.ReleaseSafeTempTable(targets)
|
||||
|
||||
if sendRepeat then
|
||||
Threading.Sleep(TSM.db.global.mailingOptions.resendDelay * 60)
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function private.SendItems(target, items, isDryRun)
|
||||
private.sendDone = false
|
||||
TSM.Mailing.Send.StartSending(private.SendCallback, target, "", "", 0, items, true, isDryRun)
|
||||
while not private.sendDone do
|
||||
Threading.Yield(true)
|
||||
end
|
||||
end
|
||||
|
||||
function private.SendCallback()
|
||||
private.sendDone = true
|
||||
end
|
||||
|
||||
function private.GetItemQuantity(itemString, numAvailable, operationSettings)
|
||||
if numAvailable <= 0 then
|
||||
return 0
|
||||
end
|
||||
local numToSend = 0
|
||||
local isTargetPlayer = PlayerInfo.IsPlayer(operationSettings.target)
|
||||
if operationSettings.maxQtyEnabled then
|
||||
if operationSettings.restock then
|
||||
local targetQty = private.GetTargetQuantity(operationSettings.target, itemString, operationSettings.restockSources)
|
||||
if isTargetPlayer and targetQty <= operationSettings.maxQty then
|
||||
numToSend = numAvailable
|
||||
else
|
||||
numToSend = min(numAvailable, operationSettings.maxQty - targetQty)
|
||||
end
|
||||
if isTargetPlayer then
|
||||
numToSend = numAvailable - (targetQty - operationSettings.maxQty)
|
||||
end
|
||||
else
|
||||
numToSend = min(numAvailable, operationSettings.maxQty)
|
||||
end
|
||||
elseif not isTargetPlayer then
|
||||
numToSend = numAvailable
|
||||
end
|
||||
return max(numToSend, 0)
|
||||
end
|
||||
|
||||
function private.GetTargetQuantity(player, itemString, sources)
|
||||
if player then
|
||||
player = strtrim(strmatch(player, "^[^-]+"))
|
||||
end
|
||||
local num = Inventory.GetBagQuantity(itemString, player) + Inventory.GetMailQuantity(itemString, player) + Inventory.GetAuctionQuantity(itemString, player)
|
||||
if sources then
|
||||
if sources.guild then
|
||||
num = num + Inventory.GetGuildQuantity(itemString, PlayerInfo.GetPlayerGuild(player))
|
||||
end
|
||||
if sources.bank then
|
||||
num = num + Inventory.GetBankQuantity(itemString, player) + Inventory.GetReagentBankQuantity(itemString, player)
|
||||
end
|
||||
end
|
||||
|
||||
return num
|
||||
end
|
||||
53
Core/Service/Mailing/Inbox.lua
Normal file
53
Core/Service/Mailing/Inbox.lua
Normal file
@@ -0,0 +1,53 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster --
|
||||
-- https://tradeskillmaster.com --
|
||||
-- All Rights Reserved - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
local _, TSM = ...
|
||||
local Inbox = TSM.Mailing:NewPackage("Inbox")
|
||||
local Database = TSM.Include("Util.Database")
|
||||
local TempTable = TSM.Include("Util.TempTable")
|
||||
local MailTracking = TSM.Include("Service.MailTracking")
|
||||
local private = {
|
||||
itemsQuery = nil,
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Module Functions
|
||||
-- ============================================================================
|
||||
|
||||
function Inbox.OnInitialize()
|
||||
private.itemsQuery = MailTracking.CreateMailItemQuery()
|
||||
:Equal("index", Database.BoundQueryParam())
|
||||
end
|
||||
|
||||
function Inbox.CreateQuery()
|
||||
return MailTracking.CreateMailInboxQuery()
|
||||
:VirtualField("itemList", "string", private.GetVirtualItemList)
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Private Helper Functions
|
||||
-- ============================================================================
|
||||
|
||||
function private.GetVirtualItemList(row)
|
||||
private.itemsQuery:BindParams(row:GetField("index"))
|
||||
|
||||
local items = TempTable.Acquire()
|
||||
for _, itemsRow in private.itemsQuery:Iterator() do
|
||||
local itemName = TSM.UI.GetColoredItemName(itemsRow:GetField("itemLink")) or ""
|
||||
local qty = itemsRow:GetField("quantity")
|
||||
|
||||
tinsert(items, qty > 1 and (itemName.." (x"..qty..")") or itemName)
|
||||
end
|
||||
|
||||
local result = table.concat(items, ", ")
|
||||
TempTable.Release(items)
|
||||
|
||||
return result
|
||||
end
|
||||
233
Core/Service/Mailing/Open.lua
Normal file
233
Core/Service/Mailing/Open.lua
Normal file
@@ -0,0 +1,233 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster --
|
||||
-- https://tradeskillmaster.com --
|
||||
-- All Rights Reserved - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
local _, TSM = ...
|
||||
local Open = TSM.Mailing:NewPackage("Open")
|
||||
local L = TSM.Include("Locale").GetTable()
|
||||
local Delay = TSM.Include("Util.Delay")
|
||||
local Event = TSM.Include("Util.Event")
|
||||
local String = TSM.Include("Util.String")
|
||||
local Money = TSM.Include("Util.Money")
|
||||
local Log = TSM.Include("Util.Log")
|
||||
local ItemString = TSM.Include("Util.ItemString")
|
||||
local Theme = TSM.Include("Util.Theme")
|
||||
local Threading = TSM.Include("Service.Threading")
|
||||
local ItemInfo = TSM.Include("Service.ItemInfo")
|
||||
local MailTracking = TSM.Include("Service.MailTracking")
|
||||
local private = {
|
||||
thread = nil,
|
||||
isOpening = false,
|
||||
lastCheck = nil,
|
||||
moneyCollected = 0,
|
||||
}
|
||||
local INBOX_SIZE = TSM.IsWowClassic() and 50 or 100
|
||||
local MAIL_REFRESH_TIME = TSM.IsWowClassic() and 60 or 15
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Module Functions
|
||||
-- ============================================================================
|
||||
|
||||
function Open.OnInitialize()
|
||||
private.thread = Threading.New("MAIL_OPENING", private.OpenMailThread)
|
||||
|
||||
Event.Register("MAIL_SHOW", private.ScheduleCheck)
|
||||
Event.Register("MAIL_CLOSED", private.MailClosedHandler)
|
||||
end
|
||||
|
||||
function Open.KillThread()
|
||||
Threading.Kill(private.thread)
|
||||
|
||||
private.PrintMoneyCollected()
|
||||
private.isOpening = false
|
||||
end
|
||||
|
||||
function Open.StartOpening(callback, autoRefresh, keepMoney, filterText, filterType)
|
||||
Threading.Kill(private.thread)
|
||||
|
||||
private.isOpening = true
|
||||
private.moneyCollected = 0
|
||||
|
||||
Threading.SetCallback(private.thread, callback)
|
||||
Threading.Start(private.thread, autoRefresh, keepMoney, filterText, filterType)
|
||||
end
|
||||
|
||||
function Open.GetLastCheckTime()
|
||||
return private.lastCheck
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Mail Opening Thread
|
||||
-- ============================================================================
|
||||
|
||||
function private.OpenMailThread(autoRefresh, keepMoney, filterText, filterType)
|
||||
local isLastLoop = false
|
||||
while true do
|
||||
local query = TSM.Mailing.Inbox.CreateQuery()
|
||||
query:ResetOrderBy()
|
||||
:OrderBy("index", false)
|
||||
:Or()
|
||||
:Matches("itemList", filterText)
|
||||
:Matches("subject", filterText)
|
||||
:End()
|
||||
:Select("index")
|
||||
|
||||
if filterType then
|
||||
query:Equal("icon", filterType)
|
||||
end
|
||||
|
||||
local mails = Threading.AcquireSafeTempTable()
|
||||
for _, index in query:Iterator() do
|
||||
tinsert(mails, index)
|
||||
end
|
||||
query:Release()
|
||||
|
||||
private.OpenMails(mails, keepMoney, filterType)
|
||||
Threading.ReleaseSafeTempTable(mails)
|
||||
|
||||
if not autoRefresh or isLastLoop then
|
||||
break
|
||||
end
|
||||
|
||||
local numLeftMail, totalLeftMail = GetInboxNumItems()
|
||||
if totalLeftMail == numLeftMail or numLeftMail == INBOX_SIZE then
|
||||
isLastLoop = true
|
||||
end
|
||||
|
||||
CheckInbox()
|
||||
Threading.Sleep(1)
|
||||
end
|
||||
|
||||
private.PrintMoneyCollected()
|
||||
private.isOpening = false
|
||||
end
|
||||
|
||||
function private.CanOpenMail()
|
||||
return not C_Mail.IsCommandPending()
|
||||
end
|
||||
|
||||
function private.OpenMails(mails, keepMoney, filterType)
|
||||
for i = 1, #mails do
|
||||
local index = mails[i]
|
||||
Threading.WaitForFunction(private.CanOpenMail)
|
||||
|
||||
local mailType = MailTracking.GetMailType(index)
|
||||
local matchesFilter = (not filterType and mailType) or (filterType and filterType == mailType)
|
||||
local hasBagSpace = not MailTracking.GetInboxItemLink(index) or CalculateTotalNumberOfFreeBagSlots() > TSM.db.global.mailingOptions.keepMailSpace
|
||||
if matchesFilter and hasBagSpace then
|
||||
local _, _, _, _, money = GetInboxHeaderInfo(index)
|
||||
if not keepMoney or (keepMoney and money <= 0) then
|
||||
-- marks the mail as read
|
||||
GetInboxText(index)
|
||||
AutoLootMailItem(index)
|
||||
private.moneyCollected = private.moneyCollected + money
|
||||
|
||||
if Threading.WaitForEvent("CLOSE_INBOX_ITEM", "MAIL_FAILED") ~= "MAIL_FAILED" then
|
||||
if TSM.db.global.mailingOptions.inboxMessages then
|
||||
private.PrintOpenMailMessage(index)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Private Helper Functions
|
||||
-- ============================================================================
|
||||
|
||||
function private.CheckInbox()
|
||||
if private.isOpening then
|
||||
private.ScheduleCheck()
|
||||
return
|
||||
end
|
||||
|
||||
if not TSM.UI.MailingUI.Inbox.IsMailOpened() then
|
||||
CheckInbox()
|
||||
end
|
||||
private.ScheduleCheck()
|
||||
end
|
||||
|
||||
function private.PrintMoneyCollected()
|
||||
if TSM.db.global.mailingOptions.inboxMessages and private.moneyCollected > 0 then
|
||||
Log.PrintfUser(L["Total Gold Collected: %s"], Money.ToString(private.moneyCollected))
|
||||
end
|
||||
private.moneyCollected = 0
|
||||
end
|
||||
|
||||
function private.PrintOpenMailMessage(index)
|
||||
local _, _, sender, subject, money, cod, _, hasItem = GetInboxHeaderInfo(index)
|
||||
sender = sender or "?"
|
||||
local _, _, _, _, isInvoice = GetInboxText(index)
|
||||
if isInvoice then
|
||||
-- it's an invoice
|
||||
local invoiceType, itemName, playerName, bid, _, _, ahcut, _, _, _, quantity = GetInboxInvoiceInfo(index)
|
||||
playerName = playerName or (invoiceType == "buyer" and AUCTION_HOUSE_MAIL_MULTIPLE_SELLERS or AUCTION_HOUSE_MAIL_MULTIPLE_BUYERS)
|
||||
if invoiceType == "buyer" then
|
||||
local itemLink = MailTracking.GetInboxItemLink(index) or "["..itemName.."]"
|
||||
Log.PrintfUser(L["Bought %sx%d for %s from %s"], itemLink, quantity, Money.ToString(bid, Theme.GetFeedbackColor("RED"):GetTextColorPrefix()), playerName)
|
||||
elseif invoiceType == "seller" then
|
||||
Log.PrintfUser(L["Sold [%s]x%d for %s to %s"], itemName, quantity, Money.ToString(bid - ahcut, Theme.GetFeedbackColor("GREEN"):GetTextColorPrefix()), playerName)
|
||||
end
|
||||
elseif hasItem then
|
||||
local itemLink
|
||||
local quantity = 0
|
||||
for i = 1, hasItem do
|
||||
local link = GetInboxItemLink(index, i)
|
||||
itemLink = itemLink or link
|
||||
quantity = quantity + (select(4, GetInboxItem(index, i)) or 0)
|
||||
if ItemString.Get(itemLink) ~= ItemString.Get(link) then
|
||||
itemLink = L["Multiple Items"]
|
||||
quantity = -1
|
||||
break
|
||||
end
|
||||
end
|
||||
if hasItem == 1 then
|
||||
itemLink = MailTracking.GetInboxItemLink(index) or itemLink
|
||||
end
|
||||
local itemName = ItemInfo.GetName(itemLink) or "?"
|
||||
local itemDesc = (quantity > 0 and format("%sx%d", itemLink, quantity)) or (quantity == -1 and "Multiple Items") or "?"
|
||||
if hasItem == 1 and itemLink and strfind(subject, "^" .. String.Escape(format(AUCTION_EXPIRED_MAIL_SUBJECT, itemName))) then
|
||||
Log.PrintfUser(L["Your auction of %s expired"], itemDesc)
|
||||
elseif hasItem == 1 and quantity > 0 and (subject == format(AUCTION_REMOVED_MAIL_SUBJECT.."x%d", itemName, quantity) or subject == format(AUCTION_REMOVED_MAIL_SUBJECT, itemName)) then
|
||||
Log.PrintfUser(L["Cancelled auction of %sx%d"], itemLink, quantity)
|
||||
elseif cod > 0 then
|
||||
Log.PrintfUser(L["%s sent you a COD of %s for %s"], sender, Money.ToString(cod, Theme.GetFeedbackColor("RED"):GetTextColorPrefix()), itemDesc)
|
||||
elseif money > 0 then
|
||||
Log.PrintfUser(L["%s sent you %s and %s"], sender, itemDesc, Money.ToString(money, Theme.GetFeedbackColor("GREEN"):GetTextColorPrefix()))
|
||||
else
|
||||
Log.PrintfUser(L["%s sent you %s"], sender, itemDesc)
|
||||
end
|
||||
elseif money > 0 then
|
||||
Log.PrintfUser(L["%s sent you %s"], sender, Money.ToString(money, Theme.GetFeedbackColor("GREEN"):GetTextColorPrefix()))
|
||||
elseif subject then
|
||||
Log.PrintfUser(L["%s sent you a message: %s"], sender, subject)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Event Handlers
|
||||
-- ============================================================================
|
||||
|
||||
function private.ScheduleCheck()
|
||||
if not private.lastCheck or time() - private.lastCheck > (MAIL_REFRESH_TIME - 1) then
|
||||
private.lastCheck = time()
|
||||
Delay.AfterTime("mailInboxCheck", MAIL_REFRESH_TIME, private.CheckInbox)
|
||||
else
|
||||
local nextUpdate = MAIL_REFRESH_TIME - (time() - private.lastCheck)
|
||||
Delay.AfterTime("mailInboxCheck", nextUpdate, private.CheckInbox)
|
||||
end
|
||||
end
|
||||
|
||||
function private.MailClosedHandler()
|
||||
Delay.Cancel("mailInboxCheck")
|
||||
end
|
||||
287
Core/Service/Mailing/Send.lua
Normal file
287
Core/Service/Mailing/Send.lua
Normal file
@@ -0,0 +1,287 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster --
|
||||
-- https://tradeskillmaster.com --
|
||||
-- All Rights Reserved - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
local _, TSM = ...
|
||||
local Send = TSM.Mailing:NewPackage("Send")
|
||||
local L = TSM.Include("Locale").GetTable()
|
||||
local Table = TSM.Include("Util.Table")
|
||||
local Money = TSM.Include("Util.Money")
|
||||
local SlotId = TSM.Include("Util.SlotId")
|
||||
local Log = TSM.Include("Util.Log")
|
||||
local ItemString = TSM.Include("Util.ItemString")
|
||||
local Theme = TSM.Include("Util.Theme")
|
||||
local Threading = TSM.Include("Service.Threading")
|
||||
local ItemInfo = TSM.Include("Service.ItemInfo")
|
||||
local InventoryInfo = TSM.Include("Service.InventoryInfo")
|
||||
local BagTracking = TSM.Include("Service.BagTracking")
|
||||
local private = {
|
||||
thread = nil,
|
||||
bagUpdate = nil,
|
||||
}
|
||||
|
||||
local PLAYER_NAME = UnitName("player")
|
||||
local PLAYER_NAME_REALM = string.gsub(PLAYER_NAME.."-"..GetRealmName(), "%s+", "")
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Module Functions
|
||||
-- ============================================================================
|
||||
|
||||
function Send.OnInitialize()
|
||||
private.thread = Threading.New("MAIL_SENDING", private.SendMailThread)
|
||||
BagTracking.RegisterCallback(private.BagUpdate)
|
||||
end
|
||||
|
||||
function Send.KillThread()
|
||||
Threading.Kill(private.thread)
|
||||
end
|
||||
|
||||
function Send.StartSending(callback, recipient, subject, body, money, items, isGroup, isDryRun)
|
||||
Threading.Kill(private.thread)
|
||||
|
||||
Threading.SetCallback(private.thread, callback)
|
||||
Threading.Start(private.thread, recipient, subject, body, money, items, isGroup, isDryRun)
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Mail Sending Thread
|
||||
-- ============================================================================
|
||||
|
||||
function private.SendMailThread(recipient, subject, body, money, items, isGroup, isDryRun)
|
||||
if recipient == "" or recipient == PLAYER_NAME or recipient == PLAYER_NAME_REALM then
|
||||
return
|
||||
end
|
||||
|
||||
private.PrintMailMessage(money, items, recipient, isGroup, isDryRun)
|
||||
if isDryRun then
|
||||
return
|
||||
end
|
||||
|
||||
if not items then
|
||||
private.SendMail(recipient, subject, body, money, true)
|
||||
return
|
||||
end
|
||||
|
||||
ClearSendMail()
|
||||
local itemInfo = Threading.AcquireSafeTempTable()
|
||||
|
||||
local query = BagTracking.CreateQueryBags()
|
||||
:OrderBy("slotId", true)
|
||||
:Select("bag", "slot", "itemString", "quantity")
|
||||
:Equal("isBoP", false)
|
||||
for _, bag, slot, itemString, quantity in query:Iterator() do
|
||||
if isGroup then
|
||||
itemString = TSM.Groups.TranslateItemString(itemString)
|
||||
end
|
||||
if items[itemString] and not InventoryInfo.IsBagSlotLocked(bag, slot) then
|
||||
if not itemInfo[itemString] then
|
||||
itemInfo[itemString] = { locations = {} }
|
||||
end
|
||||
tinsert(itemInfo[itemString].locations, { bag = bag, slot = slot, quantity = quantity })
|
||||
end
|
||||
end
|
||||
query:Release()
|
||||
|
||||
for itemString, quantity in pairs(items) do
|
||||
if quantity > 0 and itemInfo[itemString] and #itemInfo[itemString].locations > 0 then
|
||||
for i = 1, #itemInfo[itemString].locations do
|
||||
local info = itemInfo[itemString].locations[i]
|
||||
if info.quantity > 0 then
|
||||
if quantity == info.quantity then
|
||||
PickupContainerItem(info.bag, info.slot)
|
||||
ClickSendMailItemButton()
|
||||
|
||||
if private.GetNumPendingAttachments() == ATTACHMENTS_MAX_SEND or (isGroup and TSM.db.global.mailingOptions.sendItemsIndividually) then
|
||||
private.SendMail(recipient, subject, body, money)
|
||||
end
|
||||
|
||||
items[itemString] = 0
|
||||
info.quantity = 0
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for itemString in pairs(items) do
|
||||
if items[itemString] > 0 and itemInfo[itemString] and #itemInfo[itemString].locations > 0 then
|
||||
local emptySlotIds = private.GetEmptyBagSlotsThreaded(ItemString.IsItem(itemString) and GetItemFamily(ItemString.ToId(itemString)) or 0)
|
||||
for i = 1, #itemInfo[itemString].locations do
|
||||
local info = itemInfo[itemString].locations[i]
|
||||
if items[itemString] > 0 and info.quantity > 0 then
|
||||
if items[itemString] < info.quantity then
|
||||
if #emptySlotIds > 0 then
|
||||
local splitBag, splitSlot = SlotId.Split(tremove(emptySlotIds, 1))
|
||||
SplitContainerItem(info.bag, info.slot, items[itemString])
|
||||
PickupContainerItem(splitBag, splitSlot)
|
||||
Threading.WaitForFunction(private.BagSlotHasItem, splitBag, splitSlot)
|
||||
PickupContainerItem(splitBag, splitSlot)
|
||||
ClickSendMailItemButton()
|
||||
|
||||
if private.GetNumPendingAttachments() == ATTACHMENTS_MAX_SEND then
|
||||
private.SendMail(recipient, subject, body, money)
|
||||
end
|
||||
|
||||
items[itemString] = 0
|
||||
info.quantity = 0
|
||||
|
||||
break
|
||||
end
|
||||
else
|
||||
PickupContainerItem(info.bag, info.slot)
|
||||
ClickSendMailItemButton()
|
||||
|
||||
if private.GetNumPendingAttachments() == ATTACHMENTS_MAX_SEND then
|
||||
private.SendMail(recipient, subject, body, money)
|
||||
end
|
||||
|
||||
items[itemString] = items[itemString] - info.quantity
|
||||
info.quantity = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if isGroup and TSM.db.global.mailingOptions.sendItemsIndividually then
|
||||
private.SendMail(recipient, subject, body, money)
|
||||
end
|
||||
Threading.ReleaseSafeTempTable(emptySlotIds)
|
||||
end
|
||||
end
|
||||
|
||||
if private.HasPendingAttachments() then
|
||||
private.SendMail(recipient, subject, body, money)
|
||||
end
|
||||
|
||||
Threading.ReleaseSafeTempTable(itemInfo)
|
||||
end
|
||||
|
||||
function private.PrintMailMessage(money, items, target, isGroup, isDryRun)
|
||||
if not TSM.db.global.mailingOptions.sendMessages and not isDryRun then
|
||||
return
|
||||
end
|
||||
if money > 0 and not items then
|
||||
Log.PrintfUser(L["Sending %s to %s"], Money.ToString(money), target)
|
||||
return
|
||||
end
|
||||
|
||||
if not items then
|
||||
return
|
||||
end
|
||||
|
||||
local itemList = ""
|
||||
for k, v in pairs(items) do
|
||||
local coloredItem = ItemInfo.GetLink(k)
|
||||
itemList = itemList..coloredItem.."x"..v..", "
|
||||
end
|
||||
itemList = strtrim(itemList, ", ")
|
||||
|
||||
if next(items) and money < 0 then
|
||||
if isDryRun then
|
||||
Log.PrintfUser(L["Would send %s to %s with a COD of %s"], itemList, target, Money.ToString(money, Theme.GetFeedbackColor("RED"):GetTextColorPrefix()))
|
||||
else
|
||||
Log.PrintfUser(L["Sending %s to %s with a COD of %s"], itemList, target, Money.ToString(money, Theme.GetFeedbackColor("RED"):GetTextColorPrefix()))
|
||||
end
|
||||
elseif next(items) then
|
||||
if isDryRun then
|
||||
Log.PrintfUser(L["Would send %s to %s"], itemList, target)
|
||||
else
|
||||
Log.PrintfUser(L["Sending %s to %s"], itemList, target)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function private.SendMail(recipient, subject, body, money, noItem)
|
||||
if subject == "" then
|
||||
local text = SendMailSubjectEditBox:GetText()
|
||||
subject = text ~= "" and text or "TSM Mailing"
|
||||
end
|
||||
|
||||
if money > 0 then
|
||||
SetSendMailMoney(money)
|
||||
SetSendMailCOD(0)
|
||||
elseif money < 0 then
|
||||
SetSendMailCOD(abs(money))
|
||||
SetSendMailMoney(0)
|
||||
else
|
||||
SetSendMailMoney(0)
|
||||
SetSendMailCOD(0)
|
||||
end
|
||||
|
||||
private.bagUpdate = false
|
||||
SendMail(recipient, subject, body)
|
||||
|
||||
if Threading.WaitForEvent("MAIL_SUCCESS", "MAIL_FAILED") == "MAIL_SUCCESS" then
|
||||
if noItem then
|
||||
Threading.Sleep(0.5)
|
||||
else
|
||||
Threading.WaitForFunction(private.HasNewBagUpdate)
|
||||
end
|
||||
else
|
||||
Threading.Sleep(0.5)
|
||||
end
|
||||
end
|
||||
|
||||
function private.BagUpdate()
|
||||
private.bagUpdate = true
|
||||
end
|
||||
|
||||
function private.HasNewBagUpdate()
|
||||
return private.bagUpdate
|
||||
end
|
||||
|
||||
function private.HasPendingAttachments()
|
||||
for i = 1, ATTACHMENTS_MAX_SEND do
|
||||
if GetSendMailItem(i) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function private.GetNumPendingAttachments()
|
||||
local totalAttached = 0
|
||||
for i = 1, ATTACHMENTS_MAX_SEND do
|
||||
if GetSendMailItem(i) then
|
||||
totalAttached = totalAttached + 1
|
||||
end
|
||||
end
|
||||
|
||||
return totalAttached
|
||||
end
|
||||
|
||||
function private.BagSlotHasItem(bag, slot)
|
||||
return GetContainerItemInfo(bag, slot) and true or false
|
||||
end
|
||||
|
||||
function private.GetEmptyBagSlotsThreaded(itemFamily)
|
||||
local emptySlotIds = Threading.AcquireSafeTempTable()
|
||||
local sortvalue = Threading.AcquireSafeTempTable()
|
||||
for bag = 0, NUM_BAG_SLOTS do
|
||||
-- make sure the item can go in this bag
|
||||
local bagFamily = bag ~= 0 and GetItemFamily(GetInventoryItemLink("player", ContainerIDToInventoryID(bag))) or 0
|
||||
if bagFamily == 0 or bit.band(itemFamily, bagFamily) > 0 then
|
||||
for slot = 1, GetContainerNumSlots(bag) do
|
||||
if not GetContainerItemInfo(bag, slot) then
|
||||
local slotId = SlotId.Join(bag, slot)
|
||||
tinsert(emptySlotIds, slotId)
|
||||
-- use special bags first
|
||||
sortvalue[slotId] = slotId + (bagFamily > 0 and 0 or 100000)
|
||||
end
|
||||
end
|
||||
end
|
||||
Threading.Yield()
|
||||
end
|
||||
Table.SortWithValueLookup(emptySlotIds, sortvalue)
|
||||
Threading.ReleaseSafeTempTable(sortvalue)
|
||||
|
||||
return emptySlotIds
|
||||
end
|
||||
Reference in New Issue
Block a user