View Single Post
02-24-18, 11:45 AM   #6
MunkDev
A Scalebane Royal Guard
 
MunkDev's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 431
Lua Code:
  1. SellAllInBag = CreateFrame('Frame')
  2. SellAllInBag.itemsToSell = {}
  3. SellAllInBag.pendingBags = {}
  4.  
  5. function SellAllInBag:SetCurrentBag(bagID)
  6.     wipe(self.itemsToSell)
  7.     self.currentBagID = bagID
  8.     self.itemsSold = 0
  9.  
  10.     local toggleEvent = (bagID ~= nil) and self.RegisterEvent or self.UnregisterEvent
  11.  
  12.     toggleEvent(self, 'BAG_UPDATE')
  13.     toggleEvent(self, 'BAG_UPDATE_DELAYED')
  14. end
  15.  
  16. function SellAllInBag:AttemptSellItems(index)
  17.     for i=index or 1, #self.itemsToSell do
  18.         UseContainerItem(self.currentBagID, self.itemsToSell[i])
  19.     end
  20. end
  21.  
  22. function SellAllInBag:ProcessNextInQueue()
  23.     local bagInQueue = tremove(self.pendingBags, 1)
  24.     if bagInQueue then
  25.         self(bagInQueue)
  26.     end
  27. end
  28.  
  29. function SellAllInBag:OnEvent(event)
  30.     if ( event == 'BAG_UPDATE' ) then
  31.         self.itemsSold = self.itemsSold + 1
  32.     elseif ( event == 'BAG_UPDATE_DELAYED' ) then
  33.         if ( self.itemsSold == #self.itemsToSell ) then
  34.             self:SetCurrentBag(nil)
  35.             self:ProcessNextInQueue()
  36.         else
  37.             self:AttemptSellItems(self.itemsSold)
  38.         end
  39.     elseif ( event == 'MERCHANT_SHOW' ) then
  40.         self.merchantAvailable = true
  41.     elseif ( event == 'MERCHANT_CLOSED' ) then
  42.         self.merchantAvailable = false
  43.         self:SetCurrentBag(nil)
  44.         wipe(self.pendingBags)
  45.     end
  46. end
  47.  
  48. SellAllInBag:RegisterEvent('MERCHANT_SHOW')
  49. SellAllInBag:RegisterEvent('MERCHANT_CLOSED')
  50. SellAllInBag:SetScript('OnEvent', SellAllInBag.OnEvent)
  51.  
  52. setmetatable(SellAllInBag, {
  53.     __index = getmetatable(SellAllInBag).__index;
  54.     __call = function(self, bagID)
  55.     --------------------------------------------------
  56.         if self.merchantAvailable then
  57.             if not self.currentBagID then
  58.                 self:SetCurrentBag(bagID)
  59.  
  60.                 local itemsToSell = self.itemsToSell
  61.                 for slot=1, GetContainerNumSlots(bagID) do
  62.                     local link = select(7, GetContainerItemInfo(bagID, slot))
  63.                     local sellPrice = (link and select(11, GetItemInfo(link))) or 0
  64.  
  65.                     if sellPrice > 0 then
  66.                         itemsToSell[#itemsToSell + 1] = slot
  67.                     end
  68.                 end
  69.  
  70.                 if #itemsToSell > 0 then
  71.                     self:AttemptSellItems()
  72.                 else
  73.                     self:SetCurrentBag(nil)
  74.                 end
  75.             else
  76.                 tinsert(self.pendingBags, bagID)
  77.             end
  78.         end
  79.     --------------------------------------------------
  80.     end;
  81. })

Here's a robust solution for you. Using C_Timer.After is bad for multiple reasons, one of which is asynchronous execution.
Unlike the others, this takes into account if you're actually interacting with an NPC and it is safe to use even if you have massive lag.
It's a bit over-engineered, but I think this is your best bet. You can also run this for multiple bags and it'll queue them up and finish them off in order.

The way it works is it attempts to sell as many items as possible at once, counting each item that goes through, but when the server throttles your request, it'll queue a new attempt to sell as many items as possible from the items you have remaining in your bag. It will look like chunks of items are disappearing out of your bags.

Usage:
Lua Code:
  1. SellAllInBag(0)
__________________

Last edited by MunkDev : 02-24-18 at 12:17 PM.
  Reply With Quote