Quantcast

Enabled 4 parallel tooltips for item scanning

Kevin Lyles [09-17-11 - 21:33]
Enabled 4 parallel tooltips for item scanning
Filename
ItemScanner.lua
ItemScanner.xml
diff --git a/ItemScanner.lua b/ItemScanner.lua
index ddee57b..72ffa1e 100644
--- a/ItemScanner.lua
+++ b/ItemScanner.lua
@@ -1,7 +1,8 @@
 local minItem, maxItem, chunkSize = 1, 99999, 20000
 local CONSECUTIVE_INVALID_TO_IGNORE = 5
 local VALID_DELAY = 0.025
-local INVALID_DELAY = 5
+local INVALID_DELAY = 10
+local NUM_THREADS = 4

 local patterns = {
 	"^Design:",
@@ -22,21 +23,22 @@ local skippedLines = {
 	"^Collected %(%d/%d%)$",
 }

-local function scanItemLink(link)
+local function scanItemLink(link, tooltip, threadNumber)
 	local textL, textR
+	local tooltipName = tooltip:GetName()

 	-- Populate hidden tooltip
-	ItemScannerHiddenTooltip:ClearLines()
-	ItemScannerHiddenTooltip:SetHyperlink(link)
+	tooltip:ClearLines()
+	tooltip:SetHyperlink(link)

 	local startTime = GetTime()
 	local isPattern, hasReq = false, false
 	while true do
-		local numLines = ItemScannerHiddenTooltip:NumLines()
+		local numLines = tooltip:NumLines()
 		local done = numLines > 1
 		if done then
 			if not isPattern then
-				local text = _G["ItemScannerHiddenTooltipTextLeft1"]:GetText()
+				local text = _G[tooltipName .. "TextLeft1"]:GetText()
 				for _, pattern in ipairs(patterns) do
 					if text:find(pattern) then
 						isPattern = true
@@ -46,7 +48,7 @@ local function scanItemLink(link)
 			end
 			-- We can skip the first line because it will only be RETRIEVING_ITEM_INFO if we only have one line
 			for i = 2, numLines do
-				local text = _G["ItemScannerHiddenTooltipTextLeft" .. i]:GetText()
+				local text = _G[tooltipName .. "TextLeft" .. i]:GetText()
 				if text:find(RETRIEVING_ITEM_INFO) then
 					done = false
 					break
@@ -74,7 +76,7 @@ local function scanItemLink(link)
 		end
 	end

-	if IS_item_info[link] and #(IS_item_info[link]) >= ItemScannerHiddenTooltip:NumLines() then
+	if IS_item_info[link] and #(IS_item_info[link]) >= tooltip:NumLines() then
 		return true
 	end

@@ -89,9 +91,9 @@ local function scanItemLink(link)
 		harmful = IsHarmfulItem(link),
 	}
 	local numSkipped = 0
-	for i = 1, ItemScannerHiddenTooltip:NumLines() do
-		textL = _G["ItemScannerHiddenTooltipTextLeft" .. i]:GetText()
-		textR = _G["ItemScannerHiddenTooltipTextRight" .. i]:GetText()
+	for i = 1, tooltip:NumLines() do
+		textL = _G[tooltipName .. "TextLeft" .. i]:GetText()
+		textR = _G[tooltipName .. "TextRight" .. i]:GetText()
 		local skip = false
 		for _, pattern in ipairs(skippedLines) do
 			if textL:find(pattern) then
@@ -100,7 +102,7 @@ local function scanItemLink(link)
 				break
 			end
 		end
-		if not skip and (i ~= ItemScannerHiddenTooltip:NumLines() or (textL ~= " " and textL ~= "" and textR ~= " " and textR ~= "")) then
+		if not skip and (i ~= tooltip:NumLines() or (textL ~= " " and textL ~= "" and textR ~= " " and textR ~= "")) then
 			IS_item_info[link][i - numSkipped] = {
 				left = textL,
 				right = textR,
@@ -112,17 +114,33 @@ local function scanItemLink(link)
 end

 local frame = CreateFrame("Frame")
+local nextSlot = 1
 local function OnUpdate(self)
 	local status, err
 	if self.itemco then
-		status, err = pcall(self.itemco)
-		if status == false then
-			print("ItemScanner: item scan error, aborting.")
-			self.itemco = nil
-			IS_status.items.scan_active = false
-			error(err)
-			return
-		elseif err == true then
+		if nextSlot > #(self.itemco) then
+			nextSlot = 1
+		end
+		if self.itemco[nextSlot] then
+			status, err = pcall(self.itemco[nextSlot])
+			if status == false then
+				print("ItemScanner: item scan error, aborting thread " .. nextSlot .. ".")
+				table.remove(self.itemco, nextSlot)
+				if #(self.itemco) == 0 then
+					IS_status.items.scan_active = false
+					self.itemco = nil
+				end
+				error(err)
+				return
+			elseif err == true then
+				table.remove(self.itemco, nextSlot)
+				if #(self.itemco) == 0 then
+					self.itemco = nil
+				end
+				return
+			end
+			nextSlot = nextSlot + 1
+		else
 			self.itemco = nil
 		end
 	else
@@ -130,20 +148,26 @@ local function OnUpdate(self)
 	end
 end

-local function itemParseCoroutine(start)
-	local chunkStart, chunkEnd = chunkSize * math.floor(start / chunkSize), chunkSize * math.floor((start + chunkSize) / chunkSize) - 1
-	IS_status.items.scan_active = true
-	IS_status.items.finished = false
-	coroutine.yield()
-	local startTime = GetTime()
-	local roundStartTime = startTime
-	local numProcessed, roundNumProcessed, valid, roundValid = 0, 0, 0, 0
-	print(string.format("ItemScanner: starting scan at item %d", start))
+local startTime, roundStartTime, numProcessed, roundNumProcessed, valid, roundValid, chunkStart, chunkEnd
+local function itemParseCoroutine(start, tooltip, threadNumber)
+	if threadNumber == 1 then
+		chunkStart, chunkEnd = chunkSize * math.floor(start / chunkSize), chunkSize * math.floor((start + chunkSize) / chunkSize) - 1
+		IS_status.items.scan_active = true
+		IS_status.items.finished = false
+		coroutine.yield()
+		startTime = GetTime()
+		roundStartTime = startTime
+		IS_status.items.last_scanned = start - 1
+		numProcessed, roundNumProcessed, valid, roundValid = 0, 0, 0, 0
+		print(string.format("ItemScanner: starting scan at item %d", start))
+	else
+		coroutine.yield()
+	end

 	local function scan(i, scanningAll)
 		IS_status.items.last_scanned = i
 		local itemStartTime = GetTime()
-		if scanItemLink("item:" .. i .. ":0:0:0:0:0:0:0:85") then
+		if scanItemLink("item:" .. i .. ":0:0:0:0:0:0:0:85", tooltip, threadNumber) then
 			if scanningAll then
 				if IS_status.items.invalid[i] ~= false then
 					valid, roundValid = valid + 1, roundValid + 1
@@ -175,15 +199,24 @@ local function itemParseCoroutine(start)
 		end
 	end

-	for i = start, math.min(chunkEnd, maxItem) do
-		if not IS_status.items.invalid[i] or (type(IS_status.items.invalid[i]) == "number" and IS_status.items.invalid[i] < CONSECUTIVE_INVALID_TO_IGNORE) then
-			scan(i, false)
-			if not IS_status.items.scan_active then
+	while IS_status.items.scan_active and not IS_status.items.finished do
+		local i = IS_status.items.last_scanned
+		if i == nil then
+			break
+		end
+		repeat
+			i = i + 1
+			if i > chunkEnd or i > maxItem then
+				IS_status.items.finished = true
 				break
 			end
+		until not IS_status.items.invalid[i] or (type(IS_status.items.invalid[i]) == "number" and IS_status.items.invalid[i] < CONSECUTIVE_INVALID_TO_IGNORE)
+		if IS_status.items.finished then
+			break
 		end
+		scan(i, false)
 	end
-	IS_status.items.finished = true
+
 	local chunkName = chunkStart .. "-" .. chunkEnd
 	while IS_status.items.scan_active do
 		local i = (IS_status.items.last_invalid[chunkName] or chunkStart - 1)
@@ -197,11 +230,13 @@ local function itemParseCoroutine(start)
 		scan(i, true)
 	end

-	local elapsedTime = GetTime() - startTime
-	if elapsedTime == 0 then
-		elapsedTime = 0.001
+	if threadNumber == 1 then
+		local elapsedTime = GetTime() - startTime
+		if elapsedTime == 0 then
+			elapsedTime = 0.001
+		end
+		print(string.format("ItemScanner: scan stopped at item %d, %d in %.1f sec. (%.2f/min.) (%d valid)", IS_status.items.last_scanned, numProcessed, elapsedTime, numProcessed / elapsedTime * 60, valid))
 	end
-	print(string.format("ItemScanner: scan stopped at item %d, %d in %.1f sec. (%.2f/min.) (%d valid)", IS_status.items.last_scanned, numProcessed, elapsedTime, numProcessed / elapsedTime * 60, valid))

 	return true
 end
@@ -249,8 +284,15 @@ local function commandHandler(msg)
 			return
 		end

-		frame.itemco = coroutine.wrap(itemParseCoroutine)
-		frame.itemco(start)
+		frame.itemco = {}
+		for i = 1, NUM_THREADS do
+			local tooltip = _G["ItemScannerHiddenTooltip" .. i]
+			if not tooltip then
+				tooltip = CreateFrame("GameTooltip", "ItemScannerHiddenTooltip" .. i, nil, "ItemScannerHiddenTooltip")
+			end
+			table.insert(frame.itemco, coroutine.wrap(itemParseCoroutine))
+			frame.itemco[i](start + i - 1, tooltip, i)
+		end
 		frame:SetScript("OnUpdate", OnUpdate)
 	else
 		print("Usage: /is <arg> (or /itemscanner <arg>")
diff --git a/ItemScanner.xml b/ItemScanner.xml
index 0b96ba0..7771c7e 100644
--- a/ItemScanner.xml
+++ b/ItemScanner.xml
@@ -1,7 +1,7 @@
 <Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 		xsi:schemaLocation="http://www.blizzard.com/wow/ui/ ..\FrameXML\UI.xsd">
 	<Script file="ItemScanner.lua"/>
-	<GameTooltip name="ItemScannerHiddenTooltip" inherits="GameTooltipTemplate">
+	<GameTooltip name="ItemScannerHiddenTooltip" inherits="GameTooltipTemplate" virtual="true">
 		<Scripts>
 			<Onload>
 				self:SetOwner(WorldFrame, "ANCHOR_NONE")