view Modules/Scanner.lua @ 89:a12d22ef3f39

AceSerializer has been enabled again as it?s used when exporting/importing groups. All other unused libraries are now really removed. Adjusted debug function to format only when a debug channel is available. Fixed moving from guild banks, checking if items are locked is different then with banks. Now unregistering the item locking event so it doesn?t continue to try to move every time an item is switched after the automated cycle has finished. (geeezus, this description is a total overkill) Fixed item queueing. Queue all when there?s a group without any items inside no longer crashes. Removing cached container data after closing a container.
author Zerotorescue
date Fri, 07 Jan 2011 22:19:03 +0100
parents 3bec0ea44607
children 31493364b163
line wrap: on
line source
local addon = select(2, ...);
local mod = addon:NewModule("Scanner", "AceEvent-3.0", "AceTimer-3.0");

addon.Locations = {
	Bag = 0,
	Bank = 1,
	Guild = 2,
};

local Mover, paused;
local itemCache = {};

function mod:ClearCache()
	table.wipe(itemCache);
end

function mod:CacheLocation(location, remember)
	-- Reset cache just in case it was filled
	self:ClearCache();
	
	if location == addon.Locations.Bag or location == addon.Locations.Bank then
		local start, stop;
		if location == addon.Locations.Bag then
			start = 0;
			stop = NUM_BAG_SLOTS;
		else
			-- If we requested the bank then we don't want the bag info
			start = ( NUM_BAG_SLOTS + 1 );
			stop = ( NUM_BAG_SLOTS + NUM_BANKBAGSLOTS );
		end
		
		-- Go through all our bags, including the backpack
		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
			-- Scan the default 100 slots whenever we're at a non-existing index
			local bagId = (i == (stop + 1) and BANK_CONTAINER) or i;
			local slotId = GetContainerNumSlots(bagId);
			
			while slotId ~= 0 do
				-- A not equal-comparison should be quicker than a larger than-comparison
				
				local itemId = GetContainerItemID(bagId, slotId);
				local itemCount = itemId and select(2, GetContainerItemInfo(bagId, slotId));
				
				if itemId and itemCount and itemCount > 0 then
					local itemMove;
					if not itemCache[itemId] then
						-- If this is the first time we see this item, make a new object
						itemMove = addon.ContainerItem:New();
						itemCache[itemId] = itemMove;
					else
						-- If we had this item in another slot too
						itemMove = itemCache[itemId];
					end
					
					itemMove:AddLocation(bagId, slotId, itemCount);
				end
			
				-- Continue scanning a different slot
				slotId = (slotId - 1);
			end
		end
	elseif location == addon.Locations.Guild then
		for tabId = 1, GetNumGuildBankTabs() do
			local isViewable = select(3, GetGuildBankTabInfo(tabId));
			
			if isViewable == 1 then
				local slotId = (MAX_GUILDBANK_SLOTS_PER_TAB or 98); -- start by scanning the last slot
				
				while slotId ~= 0 do
					-- A not equal-comparison should be quicker than a larger than-comparison
					
					local itemLink = GetGuildBankItemLink(tabId, slotId);
					local itemId = itemLink and addon:GetItemID(itemLink);
					local itemCount = itemLink and select(2, GetGuildBankItemInfo(tabId, slotId));
						
					if itemLink and itemId and itemCount and itemCount > 0 then
						-- If there is actually an item in this slot
						local itemMove;
						if not itemCache[itemId] then
							-- If this is the first time we see this item, make a new object
							itemMove = addon.ContainerItem:New();
							itemCache[itemId] = itemMove;
						else
							-- If we had this item in another slot too
							itemMove = itemCache[itemId];
						end
						
						itemMove:AddLocation(tabId, slotId, itemCount);
					end
					
					-- Continue scanning a different slot
					slotId = (slotId - 1);
				end
			end
		end
	else
		error("Invalid location provided for CacheLocation. Must be Bank or Guild.");
	end
	
	if not remember then
		-- Copy the table as clearing the cache wipes it empty (and tables are passed by reference)
		local cacheCopy = CopyTable(itemCache);
		
		self:ClearCache();
		
		return cacheCopy;
	end
end

function mod:Scan(location)
	-- We might pause the scanning when we invoke moves ourself
	if paused then
		return;
	end
	
	local playerName = UnitName("player");
	
	self:CacheLocation(location, true);
	
	-- Go through all groups
	for groupName, values in pairs(addon.db.profile.groups) do
		local trackAt = addon:GetOptionByKey(groupName, "trackAtCharacters");
		local localItemData = addon:GetOptionByKey(groupName, "localItemData");
		
		if values.items and trackAt[playerName] and addon:GetOptionByKey(groupName, "autoRefill") and (location ~= addon.Locations.Bank or not localItemData or not localItemData["Bank"]) then
			-- Is this character interested in this data?
			
			local minLocalStock = addon:GetOptionByKey(groupName, "minLocalStock");
			
			-- Go through all items
			for itemId, _ in pairs(values.items) do
				
				-- Check if we have enough items local (but only do so if this location also has enough available)
				local missingItems = itemCache[itemId] and (minLocalStock - addon:GetLocalItemCount(itemId, groupName));
				
				if itemCache[itemId] and missingItems > 0 then
					-- Check how many are available
					local availableItems = ((itemCache[itemId] and itemCache[itemId].totalCount) or 0);
					
					if availableItems > 0 then
						print("Insufficient " .. select(2, GetItemInfo(itemId)) .. " but this location has " .. availableItems .. " (moving " .. missingItems .. ")");
						
						Mover:AddMove(itemId, missingItems);
					else
						print("Insufficient " .. IdToItemLink(itemId));
					end
				end
			end
		end
	end
	
	self:ClearCache();
	
	if Mover:HasMoves() then
		StaticPopupDialogs["InventoriumRefill"] = {
			text = "There are items that can be refilled from this location, do you wish to proceed?",
			button1 = YES,
			button2 = NO,
			OnAccept = function()
				mod:Pause();
				Mover:BeginMove(location, self.Unpause);
			end,
			timeout = 0,
			whileDead = 1,
			hideOnEscape = 1,
			exclusive = 1,
		};
		StaticPopup_Show("InventoriumRefill");
	end
end



-- Events

-- Player bank

function mod:BANKFRAME_OPENED()
	addon:Debug("Scanner:BANKFRAME_OPENED");
	
	mod:RegisterEvent("BANKFRAME_CLOSED");
	
	-- Scan once when the bank is opened, but no need to scan after
	mod:Scan(addon.Locations.Bank);
end

function mod:BANKFRAME_CLOSED()
	addon:Debug("Scanner:BANKFRAME_CLOSED");
	
	self:ClearCache();
	
	mod:UnregisterEvent("BANKFRAME_CLOSED");
	
	StaticPopup_Hide("InventoriumRefill");
end

-- Guild bank

local tmrScanGuild, scanned;
function mod:GUILDBANKBAGSLOTS_CHANGED()
	-- This event is spammed the first time the guild bank is opened
	if not scanned then
		self:CancelTimer(tmrScanGuild, true); -- silent
		tmrScanGuild = self:ScheduleTimer("DoScanGuild", 1);
	end
end

function mod:DoScanGuild()
	if not scanned then
		addon:Debug("Scanner:DoScanGuild");
		
		scanned = true;
		
		self:Scan(addon.Locations.Guild);
	end
end

function mod:GUILDBANKFRAME_CLOSED()
	addon:Debug("Scanner:GUILDBANKFRAME_CLOSED");
	
	scanned = nil;
	self:ClearCache();
	
	self:UnregisterEvent("GUILDBANKFRAME_CLOSED");
	self:UnregisterEvent("GUILDBANKBAGSLOTS_CHANGED");
	
	self:CancelTimer(tmrScanGuild, true); -- silent
	
	StaticPopup_Hide("InventoriumRefill");
end

function mod:GUILDBANKFRAME_OPENED()
	addon:Debug("Scanner:GUILDBANKFRAME_OPENED");
	
	scanned = nil;
	
	-- Get the contents for every tab into our cache
	for tabId = 1, GetNumGuildBankTabs() do
		local isViewable = select(3, GetGuildBankTabInfo(tabId));
		if isViewable == 1 then		
			QueryGuildBankTab(tabId);
		end
	end
	
	self:RegisterEvent("GUILDBANKFRAME_CLOSED");
	self:RegisterEvent("GUILDBANKBAGSLOTS_CHANGED");
end

function mod:OnEnable()
	-- Scan once when the bankframe is opened
	self:RegisterEvent("BANKFRAME_OPENED");
	self:RegisterEvent("GUILDBANKFRAME_OPENED");
	
	Mover = addon:GetModule("Mover");
end

function mod:OnDisable()
	Mover = nil;
	
	-- Bank
	self:UnregisterEvent("BANKFRAME_OPENED");
	
	-- Guild
	self:GUILDBANKFRAME_CLOSED();
	self:UnregisterEvent("GUILDBANKFRAME_OPENED");
end

function mod:Pause()
	paused = true;
end

function mod:Unpause()
	paused = nil;
end