How to add item set filters for ItemRack, Outfitter and Blizzards Equipment Manager
Since I spent quite some time to analyse each of those addons code to extract all the information I need and to create all the necessary callbacks, I thought I'd share my resulting code. You are of course absolutely free to use it in your own cargBags layout, however if you decide to publish it, I'd appreciate to be credited.
All three filters are also included in my own layout, you can get it here:
cargBags_Nivaya
(
Note: ClosetGnome doesn't need support anymore, since it is now only an LDB plugin for switching sets from Blizzards Equipment Manager.)
I'll first explain the code for extracting the item set info from each of those addons. The basic idea is to add some specific callbacks or hooks to each addon, which notify us when sets are added, removed or changed. Those callbacks then create a table containing all set items as a key, so the final filter can do its work efficiently.
Blizzards Equipment Manager
Code:
-- This table will hold information about all items which are part of a set:
local item2setEM = {}
-- This function will extract the item set data, so it can be
-- efficiently checked in the filter later:
local function cacheSetsEM()
for k in pairs(item2setEM) do item2setEM[k] = nil end
for k = 1, GetNumEquipmentSets() do
local sName = GetEquipmentSetInfo(k)
local set = GetEquipmentSetItemIDs(sName)
for _,item in next, set do
-- "item" is simply the item ID here:
if item then item2setEM[item] = true end
end
end
cargBags:UpdateBags()
end
-- This creates an invisible frame to hold the required event handlers:
local EQ_Event = CreateFrame("Frame")
EQ_Event:RegisterEvent("PLAYER_LOGIN")
EQ_Event:RegisterEvent("EQUIPMENT_SETS_CHANGED")
EQ_Event:SetScript("OnEvent", cacheSetsEM)
Outfitter
Code:
local OF = IsAddOnLoaded('Outfitter')
local item2setOF = {}
local pLevel = UnitLevel("player")
-- Outfitter doesn't use item strings or links to identify items by default,
-- so this is the function to create an item string:
local function createItemString(i) return "item:"..i.Code..":"..i.EnchantCode..":"..i.JewelCode1..":"..i.JewelCode2..":"..i.JewelCode3..":"..i.JewelCode4..":"..i.SubCode..":"..i.UniqueID..":"..pLevel end
local function cacheSetsOF()
for k in pairs(item2setOF) do item2setOF[k] = nil end
-- Outfitter grants access to sets via categories,
-- so there are two loops here:
for _,id in ipairs(Outfitter_GetCategoryOrder()) do
local OFsets = Outfitter_GetOutfitsByCategoryID(id)
for _,vSet in pairs(OFsets) do
for _,item in pairs(vSet.Items) do
-- "item" is a table here, and since I don't want to save
-- the whole table, I'll create an itemstring out of it:
if item then item2setOF[createItemString(item)] = true end
end
end
end
cargBags:UpdateBags()
end
if OF then
-- Outfitter supports the needed callbacks by itself:
Outfitter_RegisterOutfitEvent("ADD_OUTFIT", cacheSetsOF)
Outfitter_RegisterOutfitEvent("DELETE_OUTFIT", cacheSetsOF)
Outfitter_RegisterOutfitEvent("EDIT_OUTFIT", cacheSetsOF)
if Outfitter:IsInitialized() then
cacheSetsOF()
else
Outfitter_RegisterOutfitEvent('OUTFITTER_INIT', cacheSetsOF)
end
end
ItemRack
Code:
local IR = IsAddOnLoaded('ItemRack')
local item2setIR = {}
local function cacheSetsIR()
for k in pairs(item2setIR) do item2setIR[k] = nil end
local IRsets = ItemRackUser.Sets
for i in next, IRsets do
-- Some internal sets and queues start with one of these
-- characters, so let's exclude them:
if not string.find(i, "^~") then
for _,item in pairs(IRsets[i].equip) do
-- "item" is a custom itemstring here:
if item then item2setIR[item] = true end
end
end
end
end
if IR then
cacheSetsIR()
-- ItemRack doesn't support any callbacks by itself, so we're going to
-- hook into the functions we need manually:
local function ItemRackOpt_CreateHooks()
-- Those are the actual hooks for adding, updating and deleting sets:
local IRsaveSet = ItemRackOpt.SaveSet
function ItemRackOpt.SaveSet(...) IRsaveSet(...); cacheSetsIR(); cargBags:UpdateBags() end
local IRdeleteSet = ItemRackOpt.DeleteSet
function ItemRackOpt.DeleteSet(...) IRdeleteSet(...); cacheSetsIR(); cargBags:UpdateBags() end
end
-- Amusingly, ItemRack puts its set updating functions into a
-- load-on-demand module, so we need to hook into the LoD-function first:
local IRtoggleOpts = ItemRack.ToggleOptions
function ItemRack.ToggleOptions(...) IRtoggleOpts(...) ItemRackOpt_CreateHooks() end
end
The filter
Finally the filter itself, use this function as an argument to SetFilter() for one of your cargBags bag objects:
Code:
local fItemSets = function(item)
if not item.link then return false end
-- Check ItemRack sets:
if item2setIR[string.match(item.link,"item:(.+):%-?%d+")] then return true end
-- Check Outfitter sets:
local _,_,itemStr = string.find(item.link, "^|c%x+|H(.+)|h%[.*%]")
if item2setOF[itemStr] then return true end
-- Check Equipment Manager sets:
local _,itemID = strsplit(":", itemStr)
if item2setEM[tonumber(itemID)] then return true end
return false
end
Blizzards Equipment Manager simply uses the item ID to identify set items, ItemRack uses some custom item string and Outfitter uses a table with extracted values from the item link. I manually created an itemstring from those values in the corresponding cacheSets-function, so I don't have to match the whole table.
**edit: Updated for Blizzards Equipment Manager and removed ClosetGnome stuff, since it is not needed anymore.