Thread Tools Display Modes
12-14-19, 08:45 AM   #1
loff93
A Fallenroot Satyr
Join Date: Apr 2017
Posts: 25
Inventory Sorting

Hey,

would like to test the idea of sorting items in bag depending on vendor price.
Any tips?

I think I know a way to loop through inventory, but I do not know how to swap slots in bag.

I'm a total newbie to XML/LUA/WoW, but can I for example put all items in a List and sort the list depending on Vendor price, before I put item out in the correct order? Item will swap order in bag while that is being done, so I don't know how that would work either

Help or link to APIs that can be helpful is appreciated

Last edited by loff93 : 12-14-19 at 08:52 AM.
  Reply With Quote
12-14-19, 02:26 PM   #2
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,313
You might want to check out PickupContainerItem().

You'll have to apply the sort in multiple stages since the items will become "locked" once you attempt to swap them. The swapping itself doesn't actually occur until the server responds. When doing each pass, you can keep track which slots you've put into a locked state and work on the others simultaneously. This'll make the overall process quicker as waiting for the server to catch up can consume a lot of time.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)

Last edited by SDPhantom : 12-14-19 at 02:33 PM.
  Reply With Quote
12-14-19, 03:44 PM   #3
loff93
A Fallenroot Satyr
Join Date: Apr 2017
Posts: 25
Originally Posted by SDPhantom View Post
You might want to check out PickupContainerItem().

You'll have to apply the sort in multiple stages since the items will become "locked" once you attempt to swap them. The swapping itself doesn't actually occur until the server responds. When doing each pass, you can keep track which slots you've put into a locked state and work on the others simultaneously. This'll make the overall process quicker as waiting for the server to catch up can consume a lot of time.
oww I see! Awesome - Thanks for the info
  Reply With Quote
12-15-19, 05:33 AM   #4
loff93
A Fallenroot Satyr
Join Date: Apr 2017
Posts: 25
Hello again!
I tried a lot of different things. I got some help from people on discord and this is my current result.
It doesn't work 100%. I believe the issue is that slots ain't updated if they are moved, so they might try to move even if they are at the correct spot, or trade spot with a item that is at the correct spot.

Example of issue:
First Slot A updates:
Slot A <-> Slot B

Then its Slot B's turn
Slot B <-> Slot A

Any tips on how to sort this better to avoid this kind of behavior?

- Couple other issues I haven't done much about:
Currently its only for main bag.
What if a item swap with another and they merge? Will that break something

Code:
local AllItems = {}
local waitTable = {}

local function PrintAll() -- Debugging only, Ignore this
	print('------')
    for i = table.getn(AllItems), 1, -1
    do
        print(AllItems[i].itemName, AllItems[i].itemSellPrice)
	end
	print('------')
end

local function GetAllItemsFromBag(Insert)
	-- for slot=0, NUM_BAG_SLOTS do
		for index=1, GetContainerNumSlots(0) do
			local item = GetContainerItemID(0, index)
			if(item) then
				--print(item)
				local _, _, _, _, _, _, _, _, _, itemID = GetContainerItemInfo(0, index)
				if(itemID ~= nil) then
					--print(itemID)
					local itemName, _, _, _, _, _, _, _, _, _, itemSellPrice = GetItemInfo(itemID)
					table.insert(Insert, {index = index, itemID = itemID, itemSellPrice = itemSellPrice, itemName = itemName})
				end
			end
		end
	-- end
	
end

local function SaferSwapItems(bag1, bag2, slot1, slot2)
    ClearCursor()

	print(slot1, 'To',  slot2)
	local _, _, locked1 = GetContainerItemInfo(bag1, slot1)
	local _, _, locked2 = GetContainerItemInfo(bag2, slot2)

	if(locked1 or locked2) then
		print(bag1, bag2, slot1, slot2)
		table.insert(waitTable, {bag1 = bag1, bag2 = bag2, slot1 = slot1, slot2 = slot2})
	else
		--print("Swapping bag", bag1, "slot", slot1, "......for bag", bag2, "slot", slot2)
		PickupContainerItem(bag1, slot1)
		PickupContainerItem(bag2, slot2)
	end
	
end


local function SortBag()
		local bagNr = 0
		for i = table.getn(AllItems), 1, -1 do
			local currentTable = AllItems[i]
			print(currentTable.itemName , 'CurSlot', currentTable.index ,'TargetSlot', i)
			SaferSwapItems(0,0, currentTable.index, i)
		end
end


local frame = CreateFrame("FRAME", "FooAddonFrame");

local button
local ntex
local htex
local ptex


local function ADDON_LOADED()
	button = CreateFrame("Button", nil, UIParent)
	button:SetPoint("CENTER")
	button:SetWidth(100)
	button:SetHeight(25)

	button:SetText("Sort")
	button:SetNormalFontObject("GameFontNormal")

	ntex = button:CreateTexture()
	ntex:SetTexture("Interface/Buttons/UI-Panel-Button-Up")
	ntex:SetTexCoord(0, 0.625, 0, 0.6875)
	ntex:SetAllPoints()	
	button:SetNormalTexture(ntex)

	htex = button:CreateTexture()
	htex:SetTexture("Interface/Buttons/UI-Panel-Button-Highlight")
	htex:SetTexCoord(0, 0.625, 0, 0.6875)
	htex:SetAllPoints()
	button:SetHighlightTexture(htex)

	ptex = button:CreateTexture()
	ptex:SetTexture("Interface/Buttons/UI-Panel-Button-Down")
	ptex:SetTexCoord(0, 0.625, 0, 0.6875)
	ptex:SetAllPoints()
	button:SetPushedTexture(ptex)

	button:SetScript("OnClick", function()
		
		AllItems = {}
		GetAllItemsFromBag(AllItems)
		table.sort(AllItems, function(i, k)
			return i.itemSellPrice > k.itemSellPrice
		end)
		SortBag()	

	end)
end



local function ITEM_LOCK_CHANGED(self, event, ...)
	if table.getn(waitTable) > 0 then
		local currentTable = waitTable[1]
		C_Timer.After(0.5, function() SaferSwapItems(currentTable.bag1, currentTable.bag2, currentTable.slot1, currentTable.slot2) end)
		waitTable = table.remove(waitTable, 1)
	end
end


local Events = {
	["ADDON_LOADED"] = ADDON_LOADED,
	["ITEM_LOCK_CHANGED"] = ITEM_LOCK_CHANGED
}

local function eventHandler(self, event, ...)
	if(Events[event]) then
		Events[event](...)
	end
end

frame:RegisterEvent("ADDON_LOADED")
frame:RegisterEvent("ITEM_LOCK_CHANGED");
frame:SetScript("OnEvent", eventHandler);
  Reply With Quote
12-15-19, 11:31 PM   #5
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,313
ITEM_LOCK_CHANGED fires when the lock state changes. BAG_UPDATE_DELAYED is what fires when items are added/deleted/moved in the bags.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote
12-16-19, 08:47 AM   #6
loff93
A Fallenroot Satyr
Join Date: Apr 2017
Posts: 25
Originally Posted by SDPhantom View Post
ITEM_LOCK_CHANGED fires when the lock state changes. BAG_UPDATE_DELAYED is what fires when items are added/deleted/moved in the bags.
ahh, good to know, thanks

the swapping script is not working correctly thought and I'm not sure how I'm gonna fix this.
Example: I have to click multiple times for items to get to the correct spot at times, and sometime it just won't help. I know why this happens, but I don't know how to get around it yet.
Trying to think of ways to swap them around, but I'm so new to Lua/WoW it's hard to think of something
Will update if I find a solution

*UPDATE*

This work as far as I can tell. Is it pretty? Not at all
Tips to improve is appreciated.

Code:
local AllItems = {}
local waitTable = {}

local function PrintAll() -- Debugging only, Ignore this
	print('------')
    for i = table.getn(AllItems), 1, -1
    do
        print(AllItems[i].itemName, AllItems[i].itemSellPrice)
	end
	print('------')
end

local function GetAllItemsFromBag()
	for bagnr = 0, NUM_BAG_SLOTS do
		for slotnr=1, GetContainerNumSlots(bagnr) do
			local item = GetContainerItemID(bagnr, slotnr)
			if(item) then
				--print(item)
				local _, _, _, _, _, _, _, _, _, itemID = GetContainerItemInfo(bagnr, slotnr)
				--if(itemID ~= nil) then
					--print(itemID)
					local itemName, _, _, _, _, _, _, _, _, _, itemSellPrice = GetItemInfo(itemID)
					table.insert(AllItems, {index = slotnr, itemID = itemID, itemSellPrice = itemSellPrice, itemName = itemName, targetSlot = 0, targetBag = 0})
					--print(itemName, index)
				--end
			end
		end
	end
end

local function GetSlotNr(bagnr, item)
	for index=1, GetContainerNumSlots(bagnr) do
		local _, _, _, _, _, _, _, _, _, itemID = GetContainerItemInfo(bagnr, index)
			if(item.itemID == itemID) then
				return index;
		end
	end
end

local function GetBagNr(theItem)
	for bagnr = 0, NUM_BAG_SLOTS do
		for slotnr=1, GetContainerNumSlots(bagnr) do
			local item = GetContainerItemID(bagnr, slotnr)
			if(item) then
				local _, _, _, _, _, _, _, _, _, itemID = GetContainerItemInfo(bagnr, slotnr)
				if(theItem.itemID == itemID) then
					return bagnr
				end
			end
		end
	end
end

local function SaferSwapItems(item)
	ClearCursor()
	local bag1 = GetBagNr(item);
	local bag2 = item.targetBag;
	local slot1 = GetSlotNr(bag1, item)
	local slot2 = item.targetSlot
	if(item.itemID == 11584) then
		print(bag1, bag2, slot1, slot2)
		print(item.itemName,': Move From Bag',bag1,'Slot' , slot1, 'To Bag',bag2, 'Slot', slot2)
	end
	local _, _, locked1 = GetContainerItemInfo(bag1, slot1)
	local _, _, locked2 = GetContainerItemInfo(bag2, slot2)

	if(locked1 or locked2) then
		table.insert(waitTable, {itemID = item.itemID, itemName = item.itemName, targetSlot = item.targetSlot, targetBag = item.targetBag})
	else
		PickupContainerItem(bag1, slot1)
		PickupContainerItem(bag2, slot2)
	end
	
end

local function SortBag()
		local bagNr = 0
		for i = 1, table.getn(AllItems) do
			local currentItem = AllItems[i]
			SaferSwapItems(currentItem)
		end
end

local function GetSlotInBag(index)
	local currentTotalSlot = 0
	for bagnr = 0, NUM_BAG_SLOTS do
		for slotnr = 1, GetContainerNumSlots(bagnr) do
			currentTotalSlot = currentTotalSlot + 1
			if(index == currentTotalSlot) then
				return slotnr
			end
		end
	end
end

local function SetTargetSlot()
	for i = 1, table.getn(AllItems) do
		local currentItem = AllItems[i]
		currentItem.targetSlot = GetSlotInBag(i)
		print(currentItem.targetSlot)
	end
end



local function GetBag(index)
	local currentTotalSlot = 0
	for bagnr = 0, NUM_BAG_SLOTS do
		for slotnr = 1, GetContainerNumSlots(bagnr) do
			currentTotalSlot = currentTotalSlot + 1
			if(index == currentTotalSlot) then
				return bagnr
			end
		end
	end
end

local function SetTargetBag()
	for i = 1, table.getn(AllItems) do 
		AllItems[i].targetBag = GetBag(i)
		--print(AllItems[i].itemName,'bag:', AllItems[i].targetBag)
	end
end

local function BAG_UPDATE_DELAYED(self, event, ...)
	if table.getn(waitTable) > 0 then
		local currentItem = waitTable[1]
		C_Timer.After(0.2, function() SaferSwapItems(currentItem) end)
		waitTable = table.remove(waitTable, 1)
	end
end

local frame = CreateFrame("FRAME", "FooAddonFrame");

local button
local ntex
local htex
local ptex


local function ADDON_LOADED()
	button = CreateFrame("Button", nil, UIParent)
	button:SetPoint("CENTER")
	button:SetWidth(100)
	button:SetHeight(25)

	button:SetText("Sort")
	button:SetNormalFontObject("GameFontNormal")

	ntex = button:CreateTexture()
	ntex:SetTexture("Interface/Buttons/UI-Panel-Button-Up")
	ntex:SetTexCoord(0, 0.625, 0, 0.6875)
	ntex:SetAllPoints()	
	button:SetNormalTexture(ntex)

	htex = button:CreateTexture()
	htex:SetTexture("Interface/Buttons/UI-Panel-Button-Highlight")
	htex:SetTexCoord(0, 0.625, 0, 0.6875)
	htex:SetAllPoints()
	button:SetHighlightTexture(htex)

	ptex = button:CreateTexture()
	ptex:SetTexture("Interface/Buttons/UI-Panel-Button-Down")
	ptex:SetTexCoord(0, 0.625, 0, 0.6875)
	ptex:SetAllPoints()
	button:SetPushedTexture(ptex)

	button:SetScript("OnClick", function()
		
		AllItems = {}
		GetAllItemsFromBag()
		table.sort(AllItems, function(i, k)
			return i.itemSellPrice > k.itemSellPrice
		end)
		SetTargetBag()
		SetTargetSlot()
		--PrintAll()
		SortBag()	

	end)
end

local Events = {
	["ADDON_LOADED"] = ADDON_LOADED,
	["BAG_UPDATE_DELAYED"] = BAG_UPDATE_DELAYED
}

local function eventHandler(self, event, ...)
	if(Events[event]) then
		Events[event](...)
	end
end

frame:RegisterEvent("ADDON_LOADED")
frame:RegisterEvent("BAG_UPDATE_DELAYED");
frame:SetScript("OnEvent", eventHandler);
*Update*
Everything works, but 1 issue is that if I have multiple of the same items it and calculcate total price of itemcount * sellprice, it doesn't care what stack the orders are in

Last edited by loff93 : 12-16-19 at 01:15 PM.
  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