Thread Tools Display Modes
Prev Previous Post   Next Post Next
07-18-19, 01:08 PM   #1
Malakahh
An Aku'mai Servant
AddOn Author - Click to view addons
Join Date: Jun 2009
Posts: 30
Inventory sorting

Hi!

I have an issue that I have been scratching my head about for a couple of days, and I was wondering if you good folks could assist me.

I'm making a bag addon that allows the user to separate slots from the main bag into separate bags. However, after a custom bag has been deleted, I need to reorder the slots, such that custom bags always use the "last" slots, I refer to this as "defragging".

I can rearrange the slots easily enough, but part of defragging involves moving items around in the inventory, such that to the user, they would appear to remain in place, and this is where my issue lies.

My approach so far has been to treat it as a problem of sorting. I impose a virtual order before I do any defragging. After I have reordered the slots, and thus shuffled the virtual order, I use a selection sort to swap the items around in the inventory.

The below image is before defragging. The numbers on the slots is bag number concatinated with a three digit slot number. Notice that the numbers in the bag called "Title - 1" (i.e. the Main bag) to the bottom is higher than those in the custom bag.



This is my desired result. Notice that the actual slots have shifted, but the items remain in place within the bags.


This is what actually happens. Notice that the slots are indeed in the correct place, but the items are misplaced.



Here are some relevant code sections:

Defragging
Lua Code:
  1. local function DefragBags()
  2.     ClearCursor()
  3.  
  4.     -- Reorder createdBags, so that we can get proper Ids
  5.     createdBags = ns.Util.Table.Arrange(createdBags)
  6.  
  7.     -- Gather old bag data
  8.     local oldBagData = {}
  9.     local oldSlots = {}
  10.     local cnt = 1
  11.     for i = 1, #createdBags do
  12.         local gridView = createdBags[i].GridView
  13.  
  14.         for k = 1, #gridView.items do
  15.             oldSlots[#oldSlots + 1] = {
  16.                 phys = gridView.items[k]:GetPhysicalIdentifier(),
  17.                 --virt = gridView.items[k]:GetVirtualIdentifier()
  18.                 virt = cnt
  19.             }
  20.             cnt = cnt + 1
  21.         end
  22.  
  23.         if not createdBags[i].IsMasterBag then
  24.             oldBagData[i] = {
  25.                 numColumns = gridView:GetNumColumns(),
  26.                 numSlots = gridView:ItemCount(),
  27.             }
  28.         end
  29.     end
  30.  
  31.     -- Delete old bags
  32.     for i = #createdBags, 1, -1 do
  33.         if not createdBags[i].IsMasterBag then
  34.             createdBags[i]:DeleteBag()
  35.         end
  36.     end
  37.  
  38.     -- Spawn new bags
  39.     for _,v in pairs(oldBagData) do
  40.         local bagConfig = ns.Util.Table.Copy(ns.BagFrame.DefaultConfigTable)
  41.         bagConfig.NumColumns = v.numColumns
  42.         bagConfig.Slots = v.numSlots
  43.         ns.BagFrame:New(bagConfig)
  44.     end
  45.  
  46.     -- Create new list with shuffled virtual order
  47.     local newSlots = {}
  48.     for i = 1, #createdBags do
  49.         local gridView = createdBags[i].GridView
  50.  
  51.         for n = 1, #gridView.items do
  52.             local nPhys = gridView.items[n]:GetPhysicalIdentifier()
  53.             local idx = ns.Util.Table.IndexWhere(oldSlots, function(k,v,...)
  54.                 return v.phys == nPhys
  55.             end)
  56.  
  57.             newSlots[#newSlots + 1] = oldSlots[idx]
  58.         end
  59.     end
  60.  
  61.     -- This actually calls a selection sort for now, for simplicity. I was worried my cyclesort implementation was wrong
  62.     CycleSort.Sort(newSlots, cycleSortFuncs)
  63. end

The utility functions passed to the sort function
Lua Code:
  1. local cycleSortFuncs = {
  2.     Compare = function(arr, val1, val2)
  3.         if arr[val1].virt < arr[val2].virt then
  4.             return -1
  5.         elseif arr[val1].virt > arr[val2].virt then
  6.             return 1
  7.         else
  8.             return 0
  9.         end
  10.     end,
  11.     Swap = function(arr, val1, val2)
  12.  
  13.  
  14.         print("Swap: val1: " .. val1 .. "->" .. arr[val1].phys .. " val2: " .. val2 .. "->" .. arr[val2].phys)
  15.         local temp = arr[val1].virt
  16.         arr[val1].virt = arr[val2].virt
  17.         arr[val2].virt = temp
  18.  
  19.         -- temp = arr[val1].phys
  20.         -- arr[val1].phys = arr[val2].phys
  21.         -- arr[val2].phys = temp
  22.  
  23.  
  24.         local bagId1, slotId1 = ns.BagSlot.DecodeSlotIdentifier(arr[val1].phys)
  25.         local bagId2, slotId2 = ns.BagSlot.DecodeSlotIdentifier(arr[val2].phys)
  26.  
  27.        
  28.         local attempts = 0
  29.  
  30.         -- Wait for server...
  31.         repeat
  32.             local _, _, locked1 = GetContainerItemInfo(bagId1, slotId1)
  33.             local _, _, locked2 = GetContainerItemInfo(bagId2, slotId2)
  34.  
  35.             if locked1 or locked2 then
  36.                 coroutine.yield()
  37.             end
  38.  
  39.             attempts = attempts + 1
  40.         until not (locked1 or locked2)
  41.  
  42.         print("Swapping: attempts: " .. attempts)
  43.  
  44.         PickupContainerItem(bagId1, slotId1)
  45.         PickupContainerItem(bagId2, slotId2)
  46.     end
  47. }

The sorting function itself (It says cyclesort, but it is a selection sort. For now anyway ). The coroutine is resumed OnUpdate.
Lua Code:
  1. function CycleSort.Process()
  2.     for i = 1, #CycleSort.array - 1 do
  3.         local jMin = i
  4.         for j = i + 1, #CycleSort.array do
  5.             if CycleSort.funcTable.Compare(CycleSort.array, j, jMin) == -1 then
  6.                 jMin = j
  7.             end
  8.         end
  9.  
  10.         if jMin ~= i then
  11.             CycleSort.funcTable.Swap(CycleSort.array, i, jMin)
  12.             coroutine.yield()
  13.         end
  14.     end
  15. end

The entire thing is available here, if you wish to play around with it:
https://github.com/Malakahh/ObeliskBags/tree/WoWIBug

To recreate the issue:
1) Create a 10 slot bag
2) Create a 16 slot bag
3) Delete the 10 slot bag
4) Defrag

I don't know if it matters, but I have been using a 16slot backpack and 4x 10slot bags for testing.

Hopefully it's not so simple as me doing sorting wrong, but I can't really think of anything else it could be. Please help

Edit:
I seem to have circumvented my issue by taking a different approach. Instead of sorting based on a virtual slot number, I now record which items are supposed to be in which virtual slots. I scan my bags to find an item with matching Id (and quantity, if stackable) and place it in that virtual slot. I then "lock" the slot to make sure the item isn't moved again, and repeat for the remainder of the inventory.


I still don't understand why my original approach doesn't seem to do the trick, but I guess it's moot at this point

Last edited by Malakahh : 07-26-19 at 01:13 PM. Reason: Circumvented my issue
  Reply With Quote
 

WoWInterface » Developer Discussions » Lua/XML Help » Inventory sorting

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off