annotate Modules/Mover.lua @ 84:3bec0ea44607

Cleaned the Inventorium folder; moved all classes to classes directory, modules to modules directory and support addons to plugins directory. In addition support addons are now references within XML files rather than inside the TOC. Fixed the default local item count setting, you can now exclude bag and AH data from it. Fixed some mover algorithm bugs. Mover can no longer freeze the game but instead will terminate the process after a 1000 passes. Now reversing the moves table after making it, rather than every single time it is used. Fixed guild bank support. Now displaying the amount of items moved. Scanner now scans all guild bank tabs rather than only the current. Fixed a bug with local item data not being retrieved properly. Disabled ?enterClicksFirstButton? within dialogs as this causes the dialog to consume all keypress. Events are now at the addon object rather than local.
author Zerotorescue
date Thu, 06 Jan 2011 20:05:30 +0100
parents Mover.lua@f885805da5d6
children f1c035694545
rev   line source
Zerotorescue@80 1 local addon = select(2, ...);
Zerotorescue@80 2 local mod = addon:NewModule("Mover", "AceEvent-3.0", "AceTimer-3.0");
Zerotorescue@80 3
Zerotorescue@80 4 local Scanner;
Zerotorescue@80 5 local queuedMoves = {}; -- table storing all queued moves before BeginMove is called
Zerotorescue@80 6 local combinedMoves = {}; -- table storing all combined moves (with source and target) that is to be processed by the actual mover in the order of the index (1 to #)
Zerotorescue@81 7 local movesSource;
Zerotorescue@80 8
Zerotorescue@80 9 function mod:AddMove(itemId, amount)
Zerotorescue@80 10 table.insert(queuedMoves, {
Zerotorescue@80 11 id = itemId,
Zerotorescue@80 12 num = amount,
Zerotorescue@80 13 });
Zerotorescue@80 14 end
Zerotorescue@80 15
Zerotorescue@81 16 function mod:HasMoves()
Zerotorescue@81 17 return (#queuedMoves ~= 0);
Zerotorescue@81 18 end
Zerotorescue@81 19
Zerotorescue@84 20 if not table.reverse then
Zerotorescue@84 21 table.reverse = function(orig)
Zerotorescue@84 22 local temp = {};
Zerotorescue@84 23 local origLength = #orig;
Zerotorescue@84 24 for i = 1, origLength do
Zerotorescue@84 25 temp[(origLength - i + 1)] = orig[i];
Zerotorescue@84 26 end
Zerotorescue@84 27
Zerotorescue@84 28 -- -- Update the original table (can't do orig = temp as that would change the reference-link instead of the original table)
Zerotorescue@84 29 -- for i, v in pairs(temp) do
Zerotorescue@84 30 -- orig[i] = v;
Zerotorescue@84 31 -- end
Zerotorescue@84 32 return temp; -- for speed we choose to do a return instead
Zerotorescue@84 33 end
Zerotorescue@84 34 end
Zerotorescue@84 35
Zerotorescue@80 36 function mod:BeginMove(location, onFinish)
Zerotorescue@81 37 addon:Debug("BeginMove");
Zerotorescue@80 38
Zerotorescue@80 39 -- Find the outgoing moves
Zerotorescue@80 40 -- We need the source container and slot, find all the requires sources and put them in a list which we go through later to find matching targets
Zerotorescue@80 41
Zerotorescue@80 42 -- Get a list of items in the source container
Zerotorescue@80 43 local sourceContents = Scanner:CacheLocation(location, false);
Zerotorescue@80 44
Zerotorescue@80 45 local outgoingMoves = {};
Zerotorescue@80 46
Zerotorescue@82 47 addon:Debug(#queuedMoves .. " moves were queued.");
Zerotorescue@82 48
Zerotorescue@81 49 for _, singleMove in pairs(queuedMoves) do
Zerotorescue@80 50 local sourceItem = sourceContents[singleMove.id];
Zerotorescue@80 51 if not sourceItem then
Zerotorescue@80 52 print("Can't move " .. IdToItemLink(singleMove.id) .. ", non-existant in source");
Zerotorescue@80 53 else
Zerotorescue@82 54 -- We want to move the smallest stacks first to keep stuff pretty (and minimize space usage, splitting a stack takes 2 slots, moving something only 1)
Zerotorescue@80 55 table.sort(sourceItem.locations, function(a, b)
Zerotorescue@81 56 return a.count < b.count;
Zerotorescue@80 57 end);
Zerotorescue@80 58
Zerotorescue@81 59 for _, itemLocation in pairs(sourceItem.locations) do
Zerotorescue@80 60 -- if this location has more items than we need, only move what we need, otherwise move everything in this stack
Zerotorescue@80 61 local movingNum = ((itemLocation.count > singleMove.num and singleMove.num) or itemLocation.count);
Zerotorescue@80 62
Zerotorescue@80 63 table.insert(outgoingMoves, {
Zerotorescue@80 64 itemId = singleMove.id,
Zerotorescue@82 65 num = movingNum,
Zerotorescue@80 66 container = itemLocation.container,
Zerotorescue@80 67 slot = itemLocation.slot,
Zerotorescue@80 68 });
Zerotorescue@80 69
Zerotorescue@80 70 singleMove.num = (singleMove.num - movingNum);
Zerotorescue@80 71
Zerotorescue@80 72 if singleMove.num == 0 then
Zerotorescue@80 73 -- If we have prepared everything we wanted, go to the next queued move
Zerotorescue@81 74 break; -- stop the locations-loop
Zerotorescue@80 75 end
Zerotorescue@80 76 end
Zerotorescue@80 77 end
Zerotorescue@80 78 end
Zerotorescue@82 79
Zerotorescue@82 80 addon:Debug(#outgoingMoves .. " outgoing moves are possible.");
Zerotorescue@80 81
Zerotorescue@80 82 -- No longer needed
Zerotorescue@80 83 table.wipe(queuedMoves);
Zerotorescue@80 84
Zerotorescue@80 85 -- Process every single outgoing move and find fitting targets
Zerotorescue@80 86
Zerotorescue@80 87 -- Get a list of items already in the target container
Zerotorescue@80 88 local targetContents = Scanner:CacheLocation(addon.Locations.Bag, false);
Zerotorescue@80 89
Zerotorescue@80 90 -- Find all empty slots
Zerotorescue@80 91
Zerotorescue@80 92 local emptySlots = {};
Zerotorescue@80 93
Zerotorescue@80 94 local start = 0;
Zerotorescue@80 95 local stop = NUM_BAG_SLOTS;
Zerotorescue@80 96
Zerotorescue@80 97 -- Go through all our bags, including the backpack
Zerotorescue@80 98 for bagId = start, stop do
Zerotorescue@80 99 -- Go through all our slots
Zerotorescue@80 100 for slotId = 1, GetContainerNumSlots(bagId) do
Zerotorescue@82 101 local itemId = GetContainerItemID(bagId, slotId); -- we're scanning our local bags here, so no need to get messy with guild bank support
Zerotorescue@80 102
Zerotorescue@80 103 if not itemId then
Zerotorescue@80 104 table.insert(emptySlots, {
Zerotorescue@81 105 container = bagId,
Zerotorescue@81 106 slot = slotId,
Zerotorescue@80 107 });
Zerotorescue@80 108 end
Zerotorescue@80 109 end
Zerotorescue@80 110 end
Zerotorescue@82 111
Zerotorescue@82 112 addon:Debug(#emptySlots .. " empty slots are available.");
Zerotorescue@80 113
Zerotorescue@81 114 -- Remember where we're moving from
Zerotorescue@81 115 movesSource = location;
Zerotorescue@81 116
Zerotorescue@84 117 local backup = 0;
Zerotorescue@84 118
Zerotorescue@80 119 while #outgoingMoves ~= 0 do
Zerotorescue@80 120 -- A not equal-comparison should be quicker than a larger/smaller than-comparison
Zerotorescue@80 121
Zerotorescue@81 122 for _, outgoingMove in pairs(outgoingMoves) do
Zerotorescue@80 123 -- itemId will be set to nil when this outgoing move was processed - sanity check
Zerotorescue@80 124 if outgoingMove.itemId then
Zerotorescue@80 125 local targetItem = targetContents[outgoingMove.itemId];
Zerotorescue@80 126
Zerotorescue@80 127 if not targetItem then
Zerotorescue@80 128 -- grab an empty slot
Zerotorescue@80 129 -- make new instance of ItemMove
Zerotorescue@80 130 -- populate targetContents with it so future moves of this item can be put on top of it if this isn't a full stack
Zerotorescue@80 131
Zerotorescue@80 132 local firstAvailableSlot = emptySlots[1];
Zerotorescue@80 133
Zerotorescue@80 134 if not firstAvailableSlot then
Zerotorescue@80 135 print("Bags are full. Skipping " .. IdToItemLink(outgoingMove.itemId) .. ".");
Zerotorescue@80 136
Zerotorescue@82 137 outgoingMove.itemId = nil; -- remove this record from the outgoingMoves-table
Zerotorescue@80 138 else
Zerotorescue@80 139 table.insert(combinedMoves, {
Zerotorescue@82 140 itemId = outgoingMove.itemId,
Zerotorescue@82 141 num = outgoingMove.num,
Zerotorescue@80 142 sourceContainer = outgoingMove.container,
Zerotorescue@80 143 sourceSlot = outgoingMove.slot,
Zerotorescue@80 144 targetContainer = firstAvailableSlot.container,
Zerotorescue@80 145 targetSlot = firstAvailableSlot.slot,
Zerotorescue@80 146 });
Zerotorescue@80 147
Zerotorescue@80 148 -- We filled an empty slot so the target contents now has one more item,
Zerotorescue@80 149 -- make a new instance of the ItemMove class so any additional items with this id can be stacked on top of it
Zerotorescue@81 150 local itemMove = addon.ContainerItem:New();
Zerotorescue@82 151 itemMove:AddLocation(firstAvailableSlot.container, firstAvailableSlot.slot, outgoingMove.num);
Zerotorescue@80 152 targetContents[outgoingMove.itemId] = itemMove;
Zerotorescue@80 153
Zerotorescue@81 154 table.remove(emptySlots, 1); -- no longer empty
Zerotorescue@80 155
Zerotorescue@82 156 outgoingMove.num = 0; -- nothing remaining - sanity check
Zerotorescue@80 157 outgoingMove.itemId = nil; -- remove this record from the outgoingMoves-table
Zerotorescue@80 158 end
Zerotorescue@80 159 else
Zerotorescue@80 160 -- Find the maximum stack size for this item
Zerotorescue@80 161 local itemStackCount = select(8, GetItemInfo(outgoingMove.itemId));
Zerotorescue@80 162
Zerotorescue@80 163 -- We want to move to the largest stacks first to keep stuff pretty
Zerotorescue@80 164 table.sort(targetItem.locations, function(a, b)
Zerotorescue@81 165 return a.count > b.count;
Zerotorescue@80 166 end);
Zerotorescue@80 167
Zerotorescue@81 168 for _, itemLocation in pairs(targetItem.locations) do
Zerotorescue@82 169 if itemLocation.count < itemStackCount and outgoingMove.num > 0 then
Zerotorescue@80 170 -- Check if this stack isn't already full (and we still need to move this item)
Zerotorescue@80 171
Zerotorescue@80 172 local remainingSpace = (itemStackCount - itemLocation.count);
Zerotorescue@84 173 if remainingSpace >= outgoingMove.num then
Zerotorescue@80 174 -- Enough room to move this entire stack
Zerotorescue@80 175 -- Deposit this item and then forget this outgoing move as everything in it was processed
Zerotorescue@80 176
Zerotorescue@80 177 table.insert(combinedMoves, {
Zerotorescue@82 178 itemId = outgoingMove.itemId,
Zerotorescue@82 179 num = outgoingMove.num,
Zerotorescue@80 180 sourceContainer = outgoingMove.container,
Zerotorescue@80 181 sourceSlot = outgoingMove.slot,
Zerotorescue@80 182 targetContainer = itemLocation.container,
Zerotorescue@80 183 targetSlot = itemLocation.slot,
Zerotorescue@80 184 });
Zerotorescue@80 185
Zerotorescue@82 186 itemLocation.count = (itemLocation.count + outgoingMove.num);
Zerotorescue@84 187 outgoingMove.num = 0; -- nothing remaining
Zerotorescue@80 188 outgoingMove.itemId = nil; -- remove this record from the outgoingMoves-table
Zerotorescue@80 189 break; -- stop the locations-loop
Zerotorescue@80 190 else
Zerotorescue@80 191 -- Deposit this item but don't remove the outgoing move as there are some items left to move
Zerotorescue@80 192
Zerotorescue@80 193 table.insert(combinedMoves, {
Zerotorescue@82 194 itemId = outgoingMove.itemId,
Zerotorescue@82 195 num = outgoingMove.num,
Zerotorescue@80 196 sourceContainer = outgoingMove.container,
Zerotorescue@80 197 sourceSlot = outgoingMove.slot,
Zerotorescue@80 198 targetContainer = itemLocation.container,
Zerotorescue@80 199 targetSlot = itemLocation.slot,
Zerotorescue@80 200 });
Zerotorescue@80 201
Zerotorescue@80 202 -- The target will be full when we complete, but the source will still have remaining items left to be moved
Zerotorescue@80 203 itemLocation.count = itemStackCount;
Zerotorescue@82 204 outgoingMove.num = (outgoingMove.num - remainingSpace);
Zerotorescue@80 205 end
Zerotorescue@80 206 end
Zerotorescue@80 207 end
Zerotorescue@80 208
Zerotorescue@82 209 if outgoingMove.num > 0 then
Zerotorescue@80 210 -- We went through all matching items and checked their stack sizes if we could move this there, no room available
Zerotorescue@80 211 -- So forget about the target item (even though it may just have full locations, these are useless anyway) and the next loop move it onto an empty slot
Zerotorescue@84 212 targetContents[outgoingMove.itemId] = nil;
Zerotorescue@80 213 end
Zerotorescue@80 214 end
Zerotorescue@80 215 end
Zerotorescue@80 216 end
Zerotorescue@80 217
Zerotorescue@80 218 -- Loop through the array to find items that should be removed, start with the last element or the loop would break
Zerotorescue@80 219 local numOutgoingMoves = #outgoingMoves; -- since LUA-tables start at an index of 1, this is actually an existing index (outgoingMoves[#outgoingMoves] would return a value)
Zerotorescue@80 220 while numOutgoingMoves ~= 0 do
Zerotorescue@80 221 -- A not equal-comparison should be quicker than a larger/smaller than-comparison
Zerotorescue@80 222
Zerotorescue@80 223 -- Check if the item id is nil, this is set to nil when this outgoing move has been processed
Zerotorescue@84 224 if not outgoingMoves[numOutgoingMoves].itemId or outgoingMoves[numOutgoingMoves].num == 0 then
Zerotorescue@80 225 -- Remove this element from the array
Zerotorescue@80 226 table.remove(outgoingMoves, numOutgoingMoves);
Zerotorescue@80 227 end
Zerotorescue@80 228
Zerotorescue@80 229 -- Proceed with the next element (or previous considering we're going from last to first)
Zerotorescue@80 230 numOutgoingMoves = (numOutgoingMoves - 1);
Zerotorescue@80 231 end
Zerotorescue@84 232
Zerotorescue@84 233 addon:Debug(#outgoingMoves .. " moves remaining.");
Zerotorescue@84 234
Zerotorescue@84 235 backup = (backup + 1);
Zerotorescue@84 236 if backup > 1000 then
Zerotorescue@84 237 dump(nil, outgoingMoves);
Zerotorescue@84 238 table.wipe(outgoingMoves);
Zerotorescue@84 239 self:Abort("mover crashed", "Error preparing moves, hit an endless loop");
Zerotorescue@84 240 onFinish();
Zerotorescue@84 241 return;
Zerotorescue@84 242 end
Zerotorescue@80 243 end
Zerotorescue@84 244
Zerotorescue@84 245 -- Reverse table, we need to go through it from last to first because we'll be removing elements, but we don't want the actions to be executed in a different order
Zerotorescue@84 246 combinedMoves = table.reverse(combinedMoves);
Zerotorescue@82 247
Zerotorescue@82 248 addon:Debug(#combinedMoves .. " moves should be possible.");
Zerotorescue@80 249
Zerotorescue@80 250 -- No longer needed
Zerotorescue@80 251 table.wipe(emptySlots);
Zerotorescue@80 252
Zerotorescue@81 253 self:ProcessMove();
Zerotorescue@80 254
Zerotorescue@82 255 -- Even though we aren't completely done yet, allow requeueing
Zerotorescue@81 256 onFinish();
Zerotorescue@80 257 end
Zerotorescue@80 258
Zerotorescue@81 259 function mod:ProcessMove()
Zerotorescue@81 260 addon:Debug("ProcessMove");
Zerotorescue@81 261
Zerotorescue@81 262 if #combinedMoves == 0 then
Zerotorescue@81 263 print("Nothing to move.");
Zerotorescue@81 264
Zerotorescue@81 265 self:Abort();
Zerotorescue@81 266
Zerotorescue@81 267 return;
Zerotorescue@81 268 end
Zerotorescue@81 269
Zerotorescue@82 270 self:RegisterEvent("BAG_UPDATE");
Zerotorescue@81 271 self:RegisterEvent("UI_ERROR_MESSAGE");
Zerotorescue@81 272
Zerotorescue@80 273 -- combinedMoves now has all moves in it (source -> target)
Zerotorescue@80 274 -- go through list, move everything inside it
Zerotorescue@81 275 -- add source and target to lists, if either is already in this list, skip the move
Zerotorescue@81 276 -- repeat every few seconds until we're completely done
Zerotorescue@80 277
Zerotorescue@80 278 local sourceLocationsLocked = {};
Zerotorescue@80 279 local targetLocationsLocked = {};
Zerotorescue@80 280
Zerotorescue@84 281 local _GetContainerItemId = GetContainerItemID;
Zerotorescue@82 282 if movesSource == addon.Locations.Guild then
Zerotorescue@84 283 _GetContainerItemId = function(tabId, slotId) return addon:GetItemID(GetGuildBankItemLink(tabId, slotId)); end;
Zerotorescue@82 284 end
Zerotorescue@82 285
Zerotorescue@82 286 local combinedMovesOriginalLength = #combinedMoves;
Zerotorescue@82 287 local numCurrentMove = combinedMovesOriginalLength;
Zerotorescue@80 288 while numCurrentMove ~= 0 do
Zerotorescue@80 289 local move = combinedMoves[numCurrentMove];
Zerotorescue@80 290
Zerotorescue@80 291 -- sourceContainer, sourceSlot, targetContainer, targetSlot, itemId, num
Zerotorescue@81 292 if move and (not sourceLocationsLocked[move.sourceContainer] or not sourceLocationsLocked[move.sourceContainer][move.sourceSlot]) and
Zerotorescue@80 293 (not targetLocationsLocked[move.targetContainer] or not targetLocationsLocked[move.targetContainer][move.targetSlot]) then
Zerotorescue@80 294
Zerotorescue@84 295 print(("Moving %dx%s."):format(move.num, IdToItemLink(move.itemId)));
Zerotorescue@80 296
Zerotorescue@81 297 addon:Debug(("Moving %dx%s from (%d,%d) to (%d,%d)"):format(move.num, IdToItemLink(move.itemId), move.sourceContainer, move.sourceSlot, move.targetContainer, move.targetSlot));
Zerotorescue@81 298
Zerotorescue@84 299 if _GetContainerItemId(move.sourceContainer, move.sourceSlot) ~= move.itemId then
Zerotorescue@81 300 self:Abort("source changed", "Source (" .. move.sourceContainer .. "," .. move.sourceSlot .. ") is not " .. IdToItemLink(move.itemId));
Zerotorescue@81 301 return;
Zerotorescue@81 302 end
Zerotorescue@81 303
Zerotorescue@80 304 -- Pickup stack
Zerotorescue@81 305 if movesSource == addon.Locations.Bank then
Zerotorescue@81 306 SplitContainerItem(move.sourceContainer, move.sourceSlot, move.num);
Zerotorescue@81 307 elseif movesSource == addon.Locations.Guild then
Zerotorescue@81 308 SplitGuildBankItem(move.sourceContainer, move.sourceSlot, move.num);
Zerotorescue@81 309 end
Zerotorescue@80 310
Zerotorescue@80 311 -- Remember we picked this item up and thus it is now locked
Zerotorescue@80 312 if not sourceLocationsLocked[move.sourceContainer] then
Zerotorescue@80 313 sourceLocationsLocked[move.sourceContainer] = {};
Zerotorescue@80 314 end
Zerotorescue@80 315 sourceLocationsLocked[move.sourceContainer][move.sourceSlot] = true;
Zerotorescue@80 316
Zerotorescue@81 317 if movesSource == addon.Locations.Guild or CursorHasItem() then -- CursorHasItem is always false if source is a guild tab
Zerotorescue@84 318 -- We are moving into our local bags, so the below must check normal
Zerotorescue@84 319 local targetItemId = GetContainerItemID(move.targetContainer, move.targetSlot);
Zerotorescue@84 320 if targetItemId and targetItemId ~= move.itemId then
Zerotorescue@81 321 self:Abort("target changed", "Target (" .. move.targetContainer .. "," .. move.targetSlot .. ") is not " .. IdToItemLink(move.itemId) .. " nor empty");
Zerotorescue@81 322 return;
Zerotorescue@81 323 end
Zerotorescue@81 324
Zerotorescue@82 325 -- And drop it (this is always a local bag so no need to do any guild-checks)
Zerotorescue@80 326 PickupContainerItem(move.targetContainer, move.targetSlot);
Zerotorescue@80 327
Zerotorescue@80 328 -- Remember we dropped an item here and thus this is now locked
Zerotorescue@81 329 if not targetLocationsLocked[move.targetContainer] then
Zerotorescue@81 330 targetLocationsLocked[move.targetContainer] = {};
Zerotorescue@80 331 end
Zerotorescue@81 332 targetLocationsLocked[move.targetContainer][move.targetSlot] = true;
Zerotorescue@80 333
Zerotorescue@80 334 -- This move was processed
Zerotorescue@80 335 table.remove(combinedMoves, numCurrentMove);
Zerotorescue@81 336 else
Zerotorescue@81 337 self:Abort("item disappeared from mouse", "Couldn't move " .. IdToItemLink(move.itemId) .. ", CursorHasItem() is false");
Zerotorescue@81 338 return;
Zerotorescue@80 339 end
Zerotorescue@80 340 end
Zerotorescue@80 341
Zerotorescue@80 342 -- Proceed with the next element (or previous considering we're going from last to first)
Zerotorescue@80 343 numCurrentMove = (numCurrentMove - 1);
Zerotorescue@80 344 end
Zerotorescue@81 345
Zerotorescue@82 346 addon:Debug((combinedMovesOriginalLength - #combinedMoves) .. " moves processed. " .. #combinedMoves .. " moves remaining.");
Zerotorescue@82 347
Zerotorescue@81 348 if #combinedMoves == 0 then
Zerotorescue@81 349 print("Finished.");
Zerotorescue@81 350
Zerotorescue@81 351 self:Abort();
Zerotorescue@81 352
Zerotorescue@81 353 return;
Zerotorescue@81 354 end
Zerotorescue@80 355 end
Zerotorescue@80 356
Zerotorescue@80 357 local tmrProcessNext;
Zerotorescue@81 358 function mod:BAG_UPDATE()
Zerotorescue@81 359 self:CancelTimer(tmrProcessNext, true); -- silent
Zerotorescue@81 360 tmrProcessNext = self:ScheduleTimer("ProcessMove", 1);
Zerotorescue@80 361 end
Zerotorescue@80 362
Zerotorescue@81 363 function IdToItemLink(itemId)
Zerotorescue@81 364 local itemLink = select(2, GetItemInfo(itemId));
Zerotorescue@81 365 itemLink = itemLink or "Unknown (" .. itemId .. ")";
Zerotorescue@81 366 return itemLink;
Zerotorescue@81 367 end
Zerotorescue@81 368
Zerotorescue@81 369 function mod:UI_ERROR_MESSAGE(e, errorMessage)
Zerotorescue@81 370 if errorMessage == ERR_SPLIT_FAILED then
Zerotorescue@81 371 self:Abort("splitting failed", "Splitting failed.");
Zerotorescue@80 372 end
Zerotorescue@80 373 end
Zerotorescue@80 374
Zerotorescue@81 375 function mod:Abort(simple, debugMsg)
Zerotorescue@81 376 if debugMsg then
Zerotorescue@81 377 addon:Debug("Aborting:" .. debugMsg);
Zerotorescue@81 378 end
Zerotorescue@81 379 if simple then
Zerotorescue@81 380 print("|cffff0000Aborting: " .. simple .. ".|r");
Zerotorescue@81 381 end
Zerotorescue@81 382 table.wipe(combinedMoves);
Zerotorescue@81 383 movesSource = nil;
Zerotorescue@80 384
Zerotorescue@81 385 -- Stop timer
Zerotorescue@81 386 self:UnregisterEvent("BAG_UPDATE");
Zerotorescue@81 387 self:CancelTimer(tmrProcessNext, true); -- silent
Zerotorescue@80 388
Zerotorescue@81 389 self:UnregisterEvent("UI_ERROR_MESSAGE");
Zerotorescue@80 390 end
Zerotorescue@80 391
Zerotorescue@80 392 function mod:OnEnable()
Zerotorescue@80 393 Scanner = addon:GetModule("Scanner");
Zerotorescue@80 394 end
Zerotorescue@80 395
Zerotorescue@80 396 function mod:OnDisable()
Zerotorescue@80 397 Scanner = nil;
Zerotorescue@81 398
Zerotorescue@81 399 self:Abort();
Zerotorescue@80 400 end