From 4f61a4956ee5018e22b8492b3d3f88f27c9e718a Mon Sep 17 00:00:00 2001 From: Jon Crenshaw Date: Sat, 13 Feb 2016 21:12:33 -0800 Subject: [PATCH] Adds plugin files --- changelog.txt | 62 ++++++++++++++ kRestack.lua | 264 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ kRestack.toc | 7 ++ 3 files changed, 333 insertions(+) create mode 100644 changelog.txt create mode 100644 kRestack.lua create mode 100644 kRestack.toc diff --git a/changelog.txt b/changelog.txt new file mode 100644 index 0000000..240ce01 --- /dev/null +++ b/changelog.txt @@ -0,0 +1,62 @@ +40000.1 -- 2010-10-13 +- 4.0 toc update. +- "arg1" bug fix. + +1.1.1 -- 2009-12-08 +- 3.3 toc update. + +1.1 -- 2009-08-14 +- Fixed a bug with multiple "special" bags conflicting with each other. +- Version bump. + +1.0.9 -- 2009-08-04 +- TOC updated to 3.2 + +1.0.8 -- 2009-07-08 +- Some memory optimizations. +- Extended bag hooking to cover all of the bag open/close events. + +1.0.7 -- 2009-06-16 +- Code optimizations. +- In addition to restacking the player's bags, left-clicking the LDB plugin will now restack bank or guild vault when viewing them. + +1.0.6 -- 2009-06-11 +- Item looping now resets properly after finding and moving a matching partial stack. The entire process should now be much more stable and orderly. +- Special bags with partial stacks and no free bag slots should now be correctly filled with partial stacks from other bags. +- Set the LDB plugin to load when an addon with LDB embedded is loaded. +- Changed LDB data object type to "launcher". + +1.0.5a -- 2009-06-06 +- LDB conditionals in place. +- File structure and toc changes. Removed LDB libs that should be loaded anyway if there's a display. + +1.0.5 -- 2009-06-06 +- Fixed a bug in class/profession item sorting. A check wasn't in place to see if the item of the same type was a container, the result was bags in the inventory being equipped over the one already there. + +1.0.4 -- 2009-06-02 +- Throttled "OnUpdate" yield script. +- Minor backpack hook change. +- SavedVariables now account wide; settings still per-character. + +1.0.3 -- 2009-05-23 +- Removed auto-stacking from the TRADE_SHOW event. + +1.0.2a -- 2009-05-22 +- Added missing label text for LDB plugin. + +1.0.2 -- 2009-05-22 +- Added support for Data Broker. Left-click stacks bags, right-click opens menu. + +1.0.1 -- 2009-05-19 +- Fixed the handling of initializing saved variables when updating from 0.9 +- Fixed a bug that disabled guild tab switching when guild bank auto-stacking is turned off. + +1.0 -- 2009-05-18 +- Added support for restacking guild vault tabs. +- Hooked bag auto-stack to LOOT_OPEN and TRADE_SHOW, and guild bank auto-stack to GUILDBANKFRAME_OPENED and SetCurrentGuildBankTab(i). +- Extended auto-stack toggle to enable or disable bags, bank, or guild bank individually. +- Will now move items that can go into special class/profession bags into those bags if possible (soul shards, herbs, arrows, etc). +- Cleaned up and commented code. + +0.9 -- 2009-05-13 +- Added option to auto-stack when opening bags or bank, off by default. Toggle with '/restack auto' \ No newline at end of file diff --git a/kRestack.lua b/kRestack.lua new file mode 100644 index 0000000..6d90288 --- /dev/null +++ b/kRestack.lua @@ -0,0 +1,264 @@ +--[[ kRestack 1.1 : Katae @ Anvilmar US + + Usage: /restack [bags, bank, guild] - manual run + /restack auto [bags, bank, guild] - toggles auto mode ]] + +local AS, atBank, atVault, isViewable, canDeposit, restacker, tabswap + +SLASH_RESTACK1 = "/restack" +function SlashCmdList.RESTACK(s) kRestack(s) end + +-- pretty chat colors! +local white, green, red = "|cffffffff", "|cff55ff55", "|cffff5555" +local kR = "|cff44ccffk|cffffffaaRestack"..white + +-- set user's container identifers +local container = { bags = { 0 }, bank = { -1 }, guild = { 42 } } +for i = 1, NUM_BAG_SLOTS do table.insert(container.bags, i) end +for i = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + NUM_BANKBAGSLOTS do table.insert(container.bank, i) end + +-- ldb plugin +local function ldb() + local drop = CreateFrame("Frame", "kRestack", nil, "UIDropDownMenuTemplate") + LibStub:GetLibrary("LibDataBroker-1.1"):NewDataObject("kRestack", { + type = "launcher", + label = "kRestack", + icon = "Interface\\Icons\\INV_Crate_09", + OnClick = function(self, button) + if button == "RightButton" then + GameTooltip:Hide() + UIDropDownMenu_Initialize(drop, function() for _, opt in ipairs{ + { text = "= Restack =", isTitle = true }, + { text = "Backpack", func = function() kRestack("bags") end }, + { text = "Bank", disabled = not atBank, func = function() kRestack("bank") end }, + { text = "Guild Vault", disabled = not atVault, func = function() kRestack("guild", false, GetCurrentGuildBankTab()) end }, + { disabled = true }, + { text = "= Set Auto =", isTitle = true }, + { text = "Backpack", checked = AS.bags, func = function() kRestack("auto bags") end }, + { text = "Bank", checked = AS.bank, func = function() kRestack("auto bank") end }, + { text = "Guild Vault", checked = AS.guild, func = function() kRestack("auto guild") end }, + } do UIDropDownMenu_AddButton(opt, 1) end end, "MENU") + return ToggleDropDownMenu(1, nil, drop, self, 0, 0) + elseif button == "LeftButton" then + kRestack(atBank and "bank" or atVault and "guild" or "bags") + end + end, + }) +end + +-- watching some events +local f = CreateFrame("Frame") +f:RegisterEvent'ADDON_LOADED' +f:RegisterEvent'BANKFRAME_OPENED' +f:RegisterEvent'BANKFRAME_CLOSED' +f:RegisterEvent'LOOT_OPENED' +f:RegisterEvent'GUILDBANKFRAME_OPENED' +f:RegisterEvent'GUILDBANKFRAME_CLOSED' +f:SetScript("OnEvent", function(_, e, addon) + -- more ldb stuff + if e == "BANKFRAME_OPENED" then + atBank = true + elseif e == "BANKFRAME_CLOSED" then + atBank = false + elseif e == "GUILDBANKFRAME_OPENED" then + isViewable, canDeposit = select(3,GetGuildBankTabInfo(GetCurrentGuildBankTab())) + atVault = (IsGuildLeader() or (isViewable and canDeposit)) + elseif e == "GUILDBANKFRAME_CLOSED" then + atVault = false + end + if e == "ADDON_LOADED" then + -- initialize SavedVariables + if addon == "kRestack" then + if type(AutoStack) ~= "table" then AutoStack = {} end + local c = UnitName("player").." - "..GetRealmName() + if type(AutoStack[c]) ~= "table" then AutoStack[c] = {} end + AS = AutoStack[c] + if AS.bags == nil then AS.bags = true end + if AS.bank == nil then AS.bank = true end + if AS.guild == nil then AS.guild = false end + -- loading ldb plugin + elseif LibStub and ldb then + if LibStub:GetLibrary("LibDataBroker-1.1", true) then ldb(); ldb = nil end + end + elseif AS.bank and e == "BANKFRAME_OPENED" then + kRestack("bank", true) + elseif AS.bags and e == "LOOT_OPENED" then + kRestack("bags", true) + elseif AS.guild and e == "GUILDBANKFRAME_OPENED" then + isViewable, canDeposit = select(3,GetGuildBankTabInfo(GetCurrentGuildBankTab())) + if (IsGuildLeader() or (isViewable and canDeposit)) then kRestack("guild", true, GetCurrentGuildBankTab()) end + end +end) + +-- hooking auto-stacking +for _, func in ipairs{"CloseAllBags","ToggleBackpack","ToggleBag","OpenBackpack","OpenAllBags","OpenBackpack","CloseBackpack"} do + hooksecurefunc(func, function() if AS.bags then kRestack("bags", true) end end) +end + +local oSetCurrentGuildBankTab = SetCurrentGuildBankTab +SetCurrentGuildBankTab = function(tab) + if type(restacker) == "thread" then + tabswap = tabswap + 1 + if tabswap > 1 then restacker = nil end + end + -- going to lock tab switching while stacking is in progress + if type(restacker) ~= "thread" or coroutine.status(restacker) == "dead" then + oSetCurrentGuildBankTab(tab) + isViewable, canDeposit = select(3,GetGuildBankTabInfo(tab)) + if AS.guild and (IsGuildLeader() or (isViewable and canDeposit)) then kRestack("guild", false, tab) end + end +end + +-- yielding function; items will get locked and we have to wait +local function coYield(loc, bag, slot, count) + local elapsed = 0 + f:SetScript("OnUpdate", function(_, update) + elapsed = elapsed + update + if type(restacker) == "thread" and coroutine.status(restacker) == "suspended" and elapsed > 0.1 then + local locked = true + locked = loc == "guild" and (select(2, GetGuildBankItemInfo(bag, slot)) == count and true or false) or select(3, GetContainerItemInfo(bag, slot)) + if not locked then coroutine.resume(restacker) end + elapsed = 0 + end + end) + coroutine.yield() +end + +-- main function +function kRestack(loc, silent, tab) + if loc ~= "bags" and loc ~= "bank" and loc ~= "guild" then + if loc == "resume" then + -- manual resume if stuck + if coroutine.status(restacker) == "suspended" then + print(kR, "Resuming suspended thread.") + coroutine.resume(restacker) + else + print(kR, "No suspended threads to resume.") + end + else + loc = loc:match("auto (%a+)") + if loc == "bags" or loc == "bank" or loc == "guild" then + -- toggle auto-stack + AS[loc] = not AS[loc] + print(kR, "Auto-stacking for", loc:gsub("bags","your backpack"):gsub("bank","your bank"):gsub("guild","the guild vault"), "toggled", AS[loc] and green.."ON" or red.."OFF") + else + -- usage message + local bags = (AS.bags and green or red).."bags"..white + local bank = (AS.bank and green or red).."bank"..white + local guild = (AS.guild and green or red).."guild"..white + + print(kR, "Usage:") + print(white.."- /restack [bags, bank, guild] - Run restacker manually") + print(white.."- /restack auto ["..bags..",", bank..",", guild.."] - Toggle auto-stacking") + end + end + return + end + + if type(restacker) ~= "thread" or coroutine.status(restacker) == "dead" then + restacker = coroutine.create(function() + tabswap = 0 + local changed = true + while changed do + changed = false + local vault = loc == "guild" + for _, bag in ipairs(container[loc]) do + if changed then break end + bag = vault and tab or bag + for slot = 1, (vault and MAX_GUILDBANK_SLOTS_PER_TAB or GetContainerNumSlots(bag)) do + while true and not vault do + local locked = select(3, GetContainerItemInfo(bag, slot)) + if locked then coYield(loc, bag, slot) else break end + end + local item = vault and GetGuildBankItemLink(bag, slot) or GetContainerItemLink(bag, slot) + if item then + local itemid = tonumber(item:match("item:(%d+)")) + local stack = select(8, GetItemInfo(itemid)) + local count = vault and select(2, GetGuildBankItemInfo(bag, slot)) or select(2, GetContainerItemInfo(bag, slot)) + + -- do "special" things with "special" items by moving them into "special" bags + if not vault and select(9, GetItemInfo(itemid)) ~= "INVTYPE_BAG" then + local bagType = (bag ~= 0 and bag ~= -1) and GetItemFamily(GetInventoryItemLink("player", ContainerIDToInventoryID(bag))) or 0 + for _, sbag in ipairs(container[loc]) do + if sbag > 0 and GetContainerNumFreeSlots(sbag) > 0 then + local sbagID = ContainerIDToInventoryID(sbag) + local sbagType = GetItemFamily(GetInventoryItemLink("player", sbagID)) + local itemType = GetItemFamily(item) + + if sbagType > 0 and sbagType == itemType and bagType == 0 then + PickupContainerItem(bag, slot) + PutItemInBag(sbagID) + coYield(loc, bag, slot) + break + end + end + end + end + if count < stack then + -- found a partial stack + local locked, found, done, pbag, pslot + while true do + -- search through bags backwards for another partial stack with a matching itemid + for i = #container[loc], 1, -1 do + local _bag = container[loc][i] + if found or done then break end + local _slots = vault and MAX_GUILDBANK_SLOTS_PER_TAB or GetContainerNumSlots(_bag) + for _slot = _slots, 1, -1 do + if vault then _bag = bag end + if not (_bag == bag and _slot == slot) then + local _item = vault and GetGuildBankItemLink(_bag, _slot) or GetContainerItemLink(_bag, _slot) + if _item then + local _itemid = tonumber(_item:match("item:(%d+):")) + if _itemid == itemid then + local _stack = select(8, GetItemInfo(_itemid)) + local _count = vault and select(2, GetGuildBankItemInfo(_bag, _slot)) or select(2, GetContainerItemInfo(_bag, _slot)) + if _count < _stack then found, pbag, pslot = true, _bag, _slot; break end + end + end + else done = true; break end + end + end + if vault then break end + locked = found and select(3, GetContainerItemInfo(pbag, pslot)) or false + if locked then coYield(loc, pbag, pslot) else break end + end + + if found then + ClearCursor() + if vault then + PickupGuildBankItem(pbag, pslot) + PickupGuildBankItem(bag, slot) + ClearCursor() + coYield(loc, bag, slot, count) + else + -- if second partial stack is inside a special bag, move the original stack into it + local bagType = (bag ~= 0 and bag ~= -1) and GetItemFamily(GetInventoryItemLink("player", ContainerIDToInventoryID(bag))) or 0 + local pbagType = (pbag ~= 0 and pbag ~= -1) and GetItemFamily(GetInventoryItemLink("player", ContainerIDToInventoryID(pbag))) or 0 + if pbagType > 0 and bagType == 0 then + PickupContainerItem(bag, slot) + PickupContainerItem(pbag, pslot) + else + PickupContainerItem(pbag, pslot) + PickupContainerItem(bag, slot) + end + ClearCursor() + end + changed = true + break + end + end + end + end + end + end + -- turn off yielding function + f:SetScript("OnUpdate", nil) + end) + coroutine.resume(restacker) + else + if not silent then + -- user is impatient or there is a stall, tell them so + print(kR..red, "Restacking in progress. (use '/restack resume' if stuck)") + end + end +end \ No newline at end of file diff --git a/kRestack.toc b/kRestack.toc new file mode 100644 index 0000000..c2efec2 --- /dev/null +++ b/kRestack.toc @@ -0,0 +1,7 @@ +## Interface: 40000 +## Title: |cff44ccffk|rRestack +## Version: 40000.1 +## Author: Katae of Anvilmar +## Notes: For all of your item stacking needs. +## SavedVariables: AutoStack +kRestack.lua \ No newline at end of file -- 1.7.9.5