initial commit
This commit is contained in:
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