TradeSkillMaster/Core/Service/Mailing/Send.lua

288 lines
8.5 KiB
Lua

-- ------------------------------------------------------------------------------ --
-- 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