annotate Modules/Scanner.lua @ 109:3bbad0429d87

Now only giving the ?bags are full? message once per item rather then for every queued move. Neater coding for the container functions and prepared mailbox support (although this is not currently planned to be further developed for the moment). Updated todo list to include mailbox support.
author Zerotorescue
date Wed, 12 Jan 2011 22:48:25 +0100
parents d3fbb5676a5e
children 67bd5057ecb7
rev   line source
Zerotorescue@80 1 local addon = select(2, ...);
Zerotorescue@84 2 local mod = addon:NewModule("Scanner", "AceEvent-3.0", "AceTimer-3.0");
Zerotorescue@80 3
Zerotorescue@80 4 addon.Locations = {
Zerotorescue@80 5 Bag = 0,
Zerotorescue@80 6 Bank = 1,
Zerotorescue@80 7 Guild = 2,
Zerotorescue@109 8 Mailbox = 3,
Zerotorescue@80 9 };
Zerotorescue@80 10
Zerotorescue@101 11 local Mover, paused, currentLocation;
Zerotorescue@80 12 local itemCache = {};
Zerotorescue@80 13
Zerotorescue@101 14 local function OnMoveAccept(this)
Zerotorescue@101 15 mod:Pause();
Zerotorescue@101 16 Mover:BeginMove(currentLocation, mod.Unpause);
Zerotorescue@101 17
Zerotorescue@101 18 InventoriumItemMover:Hide();
Zerotorescue@101 19 end
Zerotorescue@101 20
Zerotorescue@101 21 local function OnMoveCancel(this)
Zerotorescue@101 22 Mover:ResetQueue();
Zerotorescue@101 23 currentLocation = nil;
Zerotorescue@101 24
Zerotorescue@101 25 InventoriumItemMover:Hide();
Zerotorescue@101 26 end
Zerotorescue@101 27
Zerotorescue@80 28 function mod:ClearCache()
Zerotorescue@80 29 table.wipe(itemCache);
Zerotorescue@80 30 end
Zerotorescue@80 31
Zerotorescue@80 32 function mod:CacheLocation(location, remember)
Zerotorescue@89 33 -- Reset cache just in case it was filled
Zerotorescue@89 34 self:ClearCache();
Zerotorescue@89 35
Zerotorescue@80 36 if location == addon.Locations.Bag or location == addon.Locations.Bank then
Zerotorescue@80 37 local start, stop;
Zerotorescue@80 38 if location == addon.Locations.Bag then
Zerotorescue@80 39 start = 0;
Zerotorescue@80 40 stop = NUM_BAG_SLOTS;
Zerotorescue@80 41 else
Zerotorescue@80 42 -- If we requested the bank then we don't want the bag info
Zerotorescue@80 43 start = ( NUM_BAG_SLOTS + 1 );
Zerotorescue@80 44 stop = ( NUM_BAG_SLOTS + NUM_BANKBAGSLOTS );
Zerotorescue@80 45 end
Zerotorescue@80 46
Zerotorescue@80 47 -- Go through all our bags, including the backpack
Zerotorescue@81 48 for i = start, ((location == addon.Locations.Bag and stop) or (location == addon.Locations.Bank and (stop + 1))) do -- if scanning bags stop at normal bag slot, if scanning bank, stop one later to allow BANK_CONTAINER to be scanned too
Zerotorescue@80 49 -- Scan the default 100 slots whenever we're at a non-existing index
Zerotorescue@80 50 local bagId = (i == (stop + 1) and BANK_CONTAINER) or i;
Zerotorescue@80 51 local slotId = GetContainerNumSlots(bagId);
Zerotorescue@80 52
Zerotorescue@80 53 while slotId ~= 0 do
Zerotorescue@80 54 -- A not equal-comparison should be quicker than a larger than-comparison
Zerotorescue@80 55
Zerotorescue@80 56 local itemId = GetContainerItemID(bagId, slotId);
Zerotorescue@80 57 local itemCount = itemId and select(2, GetContainerItemInfo(bagId, slotId));
Zerotorescue@80 58
Zerotorescue@80 59 if itemId and itemCount and itemCount > 0 then
Zerotorescue@80 60 local itemMove;
Zerotorescue@80 61 if not itemCache[itemId] then
Zerotorescue@80 62 -- If this is the first time we see this item, make a new object
Zerotorescue@81 63 itemMove = addon.ContainerItem:New();
Zerotorescue@81 64 itemCache[itemId] = itemMove;
Zerotorescue@80 65 else
Zerotorescue@80 66 -- If we had this item in another slot too
Zerotorescue@80 67 itemMove = itemCache[itemId];
Zerotorescue@80 68 end
Zerotorescue@80 69
Zerotorescue@81 70 itemMove:AddLocation(bagId, slotId, itemCount);
Zerotorescue@80 71 end
Zerotorescue@80 72
Zerotorescue@80 73 -- Continue scanning a different slot
Zerotorescue@80 74 slotId = (slotId - 1);
Zerotorescue@80 75 end
Zerotorescue@80 76 end
Zerotorescue@80 77 elseif location == addon.Locations.Guild then
Zerotorescue@84 78 for tabId = 1, GetNumGuildBankTabs() do
Zerotorescue@84 79 local isViewable = select(3, GetGuildBankTabInfo(tabId));
Zerotorescue@80 80
Zerotorescue@84 81 if isViewable == 1 then
Zerotorescue@84 82 local slotId = (MAX_GUILDBANK_SLOTS_PER_TAB or 98); -- start by scanning the last slot
Zerotorescue@80 83
Zerotorescue@84 84 while slotId ~= 0 do
Zerotorescue@84 85 -- A not equal-comparison should be quicker than a larger than-comparison
Zerotorescue@84 86
Zerotorescue@84 87 local itemLink = GetGuildBankItemLink(tabId, slotId);
Zerotorescue@95 88 local itemId = itemLink and addon:GetItemId(itemLink);
Zerotorescue@84 89 local itemCount = itemLink and select(2, GetGuildBankItemInfo(tabId, slotId));
Zerotorescue@84 90
Zerotorescue@84 91 if itemLink and itemId and itemCount and itemCount > 0 then
Zerotorescue@84 92 -- If there is actually an item in this slot
Zerotorescue@84 93 local itemMove;
Zerotorescue@84 94 if not itemCache[itemId] then
Zerotorescue@84 95 -- If this is the first time we see this item, make a new object
Zerotorescue@84 96 itemMove = addon.ContainerItem:New();
Zerotorescue@84 97 itemCache[itemId] = itemMove;
Zerotorescue@84 98 else
Zerotorescue@84 99 -- If we had this item in another slot too
Zerotorescue@84 100 itemMove = itemCache[itemId];
Zerotorescue@84 101 end
Zerotorescue@84 102
Zerotorescue@84 103 itemMove:AddLocation(tabId, slotId, itemCount);
Zerotorescue@84 104 end
Zerotorescue@84 105
Zerotorescue@84 106 -- Continue scanning a different slot
Zerotorescue@84 107 slotId = (slotId - 1);
Zerotorescue@80 108 end
Zerotorescue@80 109 end
Zerotorescue@80 110 end
Zerotorescue@80 111 else
Zerotorescue@82 112 error("Invalid location provided for CacheLocation. Must be Bank or Guild.");
Zerotorescue@80 113 end
Zerotorescue@80 114
Zerotorescue@80 115 if not remember then
Zerotorescue@80 116 -- Copy the table as clearing the cache wipes it empty (and tables are passed by reference)
Zerotorescue@80 117 local cacheCopy = CopyTable(itemCache);
Zerotorescue@80 118
Zerotorescue@80 119 self:ClearCache();
Zerotorescue@80 120
Zerotorescue@80 121 return cacheCopy;
Zerotorescue@80 122 end
Zerotorescue@80 123 end
Zerotorescue@80 124
Zerotorescue@80 125 function mod:Scan(location)
Zerotorescue@80 126 -- We might pause the scanning when we invoke moves ourself
Zerotorescue@80 127 if paused then
Zerotorescue@80 128 return;
Zerotorescue@80 129 end
Zerotorescue@80 130
Zerotorescue@80 131 local playerName = UnitName("player");
Zerotorescue@80 132
Zerotorescue@101 133 currentLocation = location;
Zerotorescue@80 134 self:CacheLocation(location, true);
Zerotorescue@80 135
Zerotorescue@80 136 -- Go through all groups
Zerotorescue@80 137 for groupName, values in pairs(addon.db.profile.groups) do
Zerotorescue@80 138 local trackAt = addon:GetOptionByKey(groupName, "trackAtCharacters");
Zerotorescue@84 139 local localItemData = addon:GetOptionByKey(groupName, "localItemData");
Zerotorescue@80 140
Zerotorescue@82 141 if values.items and trackAt[playerName] and addon:GetOptionByKey(groupName, "autoRefill") and (location ~= addon.Locations.Bank or not localItemData or not localItemData["Bank"]) then
Zerotorescue@80 142 -- Is this character interested in this data?
Zerotorescue@80 143
Zerotorescue@80 144 local minLocalStock = addon:GetOptionByKey(groupName, "minLocalStock");
Zerotorescue@80 145
Zerotorescue@80 146 -- Go through all items
Zerotorescue@80 147 for itemId, _ in pairs(values.items) do
Zerotorescue@80 148
Zerotorescue@81 149 -- Check if we have enough items local (but only do so if this location also has enough available)
Zerotorescue@81 150 local missingItems = itemCache[itemId] and (minLocalStock - addon:GetLocalItemCount(itemId, groupName));
Zerotorescue@80 151
Zerotorescue@81 152 if itemCache[itemId] and missingItems > 0 then
Zerotorescue@80 153 -- Check how many are available
Zerotorescue@81 154 local availableItems = ((itemCache[itemId] and itemCache[itemId].totalCount) or 0);
Zerotorescue@101 155 -- Calculate how many we'll be moving (less missing than available? use missing, otherwise use available)
Zerotorescue@101 156 local moving = (((missingItems <= availableItems) and missingItems) or availableItems);
Zerotorescue@80 157
Zerotorescue@80 158 if availableItems > 0 then
Zerotorescue@101 159 --addon:Print("Insufficient " .. IdToItemLink(itemId) .. " but this location has " .. availableItems .. " (moving " .. moving .. ")");
Zerotorescue@80 160
Zerotorescue@101 161 Mover:AddMove(itemId, moving, missingItems, availableItems);
Zerotorescue@80 162 else
Zerotorescue@101 163 --addon:Print("Insufficient " .. IdToItemLink(itemId));
Zerotorescue@80 164 end
Zerotorescue@80 165 end
Zerotorescue@80 166 end
Zerotorescue@80 167 end
Zerotorescue@80 168 end
Zerotorescue@80 169
Zerotorescue@80 170 self:ClearCache();
Zerotorescue@80 171
Zerotorescue@81 172 if Mover:HasMoves() then
Zerotorescue@101 173 if addon.db.profile.defaults.autoRefillSkipConfirm then
Zerotorescue@101 174 OnMoveAccept(true);
Zerotorescue@101 175 else
Zerotorescue@106 176 -- This table is never copied, just referenced. It is the same for every row.
Zerotorescue@101 177 local columns = {
Zerotorescue@101 178 {
Zerotorescue@106 179 value = function(data, cols, realrow, column, table)
Zerotorescue@106 180 return IdToItemLink(data[realrow].rowData.id);
Zerotorescue@101 181 end,
Zerotorescue@101 182 }, -- item
Zerotorescue@101 183 {
Zerotorescue@106 184 value = function(data, cols, realrow, column, table)
Zerotorescue@106 185 return data[realrow].rowData.num;
Zerotorescue@101 186 end,
Zerotorescue@101 187 }, -- moving
Zerotorescue@101 188 {
Zerotorescue@106 189 value = function(data, cols, realrow, column, table)
Zerotorescue@106 190 return addon:DisplayItemCount(data[realrow].rowData.available, data[realrow].rowData.missing); -- available / missing
Zerotorescue@101 191 end,
Zerotorescue@106 192 color = function(data, cols, realrow, column, table)
Zerotorescue@106 193 return ((data[realrow].rowData.available < data[realrow].rowData.missing) and { r = 1, g = 0, b = 0, a = 1 }) or { r = 1, g = 1, b = 1, a = 1 };
Zerotorescue@101 194 end,
Zerotorescue@106 195 }, -- missing / available
Zerotorescue@101 196 };
Zerotorescue@101 197
Zerotorescue@106 198 -- Store the list with rows in this
Zerotorescue@106 199 local data = {};
Zerotorescue@101 200
Zerotorescue@101 201 for i, move in pairs(Mover:GetMoves()) do
Zerotorescue@106 202 table.insert(data, {
Zerotorescue@106 203 ["rowData"] = move, -- this is not a key usually found in a row item and ignored by the library
Zerotorescue@101 204 ["cols"] = columns,
Zerotorescue@106 205 });
Zerotorescue@101 206 end
Zerotorescue@101 207
Zerotorescue@101 208 addon:SetMoverFrameData(data);
Zerotorescue@101 209 end
Zerotorescue@81 210 end
Zerotorescue@81 211 end
Zerotorescue@81 212
Zerotorescue@84 213
Zerotorescue@84 214
Zerotorescue@84 215 -- Events
Zerotorescue@84 216
Zerotorescue@84 217 -- Player bank
Zerotorescue@84 218
Zerotorescue@84 219 function mod:BANKFRAME_OPENED()
Zerotorescue@84 220 addon:Debug("Scanner:BANKFRAME_OPENED");
Zerotorescue@84 221
Zerotorescue@84 222 mod:RegisterEvent("BANKFRAME_CLOSED");
Zerotorescue@84 223
Zerotorescue@84 224 -- Scan once when the bank is opened, but no need to scan after
Zerotorescue@84 225 mod:Scan(addon.Locations.Bank);
Zerotorescue@84 226 end
Zerotorescue@84 227
Zerotorescue@84 228 function mod:BANKFRAME_CLOSED()
Zerotorescue@81 229 addon:Debug("Scanner:BANKFRAME_CLOSED");
Zerotorescue@81 230
Zerotorescue@89 231 self:ClearCache();
Zerotorescue@89 232
Zerotorescue@81 233 mod:UnregisterEvent("BANKFRAME_CLOSED");
Zerotorescue@81 234
Zerotorescue@101 235 InventoriumItemMover:Hide();
Zerotorescue@101 236 Mover:ResetQueue();
Zerotorescue@80 237 end
Zerotorescue@80 238
Zerotorescue@84 239 -- Guild bank
Zerotorescue@84 240
Zerotorescue@84 241 local tmrScanGuild, scanned;
Zerotorescue@84 242 function mod:GUILDBANKBAGSLOTS_CHANGED()
Zerotorescue@84 243 -- This event is spammed the first time the guild bank is opened
Zerotorescue@84 244 if not scanned then
Zerotorescue@84 245 self:CancelTimer(tmrScanGuild, true); -- silent
Zerotorescue@84 246 tmrScanGuild = self:ScheduleTimer("DoScanGuild", 1);
Zerotorescue@84 247 end
Zerotorescue@80 248 end
Zerotorescue@80 249
Zerotorescue@84 250 function mod:DoScanGuild()
Zerotorescue@84 251 if not scanned then
Zerotorescue@89 252 addon:Debug("Scanner:DoScanGuild");
Zerotorescue@84 253
Zerotorescue@84 254 scanned = true;
Zerotorescue@84 255
Zerotorescue@84 256 self:Scan(addon.Locations.Guild);
Zerotorescue@84 257 end
Zerotorescue@84 258 end
Zerotorescue@80 259
Zerotorescue@84 260 function mod:GUILDBANKFRAME_CLOSED()
Zerotorescue@81 261 addon:Debug("Scanner:GUILDBANKFRAME_CLOSED");
Zerotorescue@81 262
Zerotorescue@84 263 scanned = nil;
Zerotorescue@89 264 self:ClearCache();
Zerotorescue@81 265
Zerotorescue@84 266 self:UnregisterEvent("GUILDBANKFRAME_CLOSED");
Zerotorescue@84 267 self:UnregisterEvent("GUILDBANKBAGSLOTS_CHANGED");
Zerotorescue@84 268
Zerotorescue@84 269 self:CancelTimer(tmrScanGuild, true); -- silent
Zerotorescue@80 270
Zerotorescue@101 271 InventoriumItemMover:Hide();
Zerotorescue@101 272 Mover:ResetQueue();
Zerotorescue@80 273 end
Zerotorescue@80 274
Zerotorescue@84 275 function mod:GUILDBANKFRAME_OPENED()
Zerotorescue@81 276 addon:Debug("Scanner:GUILDBANKFRAME_OPENED");
Zerotorescue@81 277
Zerotorescue@84 278 scanned = nil;
Zerotorescue@80 279
Zerotorescue@84 280 -- Get the contents for every tab into our cache
Zerotorescue@84 281 for tabId = 1, GetNumGuildBankTabs() do
Zerotorescue@84 282 local isViewable = select(3, GetGuildBankTabInfo(tabId));
Zerotorescue@84 283 if isViewable == 1 then
Zerotorescue@84 284 QueryGuildBankTab(tabId);
Zerotorescue@84 285 end
Zerotorescue@84 286 end
Zerotorescue@84 287
Zerotorescue@84 288 self:RegisterEvent("GUILDBANKFRAME_CLOSED");
Zerotorescue@84 289 self:RegisterEvent("GUILDBANKBAGSLOTS_CHANGED");
Zerotorescue@80 290 end
Zerotorescue@80 291
Zerotorescue@80 292 function mod:OnEnable()
Zerotorescue@80 293 -- Scan once when the bankframe is opened
Zerotorescue@84 294 self:RegisterEvent("BANKFRAME_OPENED");
Zerotorescue@84 295 self:RegisterEvent("GUILDBANKFRAME_OPENED");
Zerotorescue@80 296
Zerotorescue@80 297 Mover = addon:GetModule("Mover");
Zerotorescue@101 298
Zerotorescue@101 299 if not InventoriumItemMover then
Zerotorescue@101 300 addon:CreateMoverFrame(OnMoveAccept, OnMoveCancel);
Zerotorescue@101 301 end
Zerotorescue@80 302 end
Zerotorescue@80 303
Zerotorescue@80 304 function mod:OnDisable()
Zerotorescue@80 305 Mover = nil;
Zerotorescue@101 306 currentLocation = nil;
Zerotorescue@101 307 paused = nil;
Zerotorescue@80 308
Zerotorescue@80 309 -- Bank
Zerotorescue@84 310 self:UnregisterEvent("BANKFRAME_OPENED");
Zerotorescue@80 311
Zerotorescue@80 312 -- Guild
Zerotorescue@84 313 self:GUILDBANKFRAME_CLOSED();
Zerotorescue@84 314 self:UnregisterEvent("GUILDBANKFRAME_OPENED");
Zerotorescue@80 315 end
Zerotorescue@80 316
Zerotorescue@80 317 function mod:Pause()
Zerotorescue@80 318 paused = true;
Zerotorescue@80 319 end
Zerotorescue@80 320
Zerotorescue@80 321 function mod:Unpause()
Zerotorescue@80 322 paused = nil;
Zerotorescue@80 323 end