diff --git a/ItemScanner.lua b/ItemScanner.lua new file mode 100644 index 0000000..465803a --- /dev/null +++ b/ItemScanner.lua @@ -0,0 +1,162 @@ +local minItem, maxItem = 1, 99999 +local CONSECUTIVE_INVALID_TO_IGNORE = 5 +local VALID_DELAY = 0.025 + +local function scanItemLink(link) + local textL, textR + + -- Populate hidden tooltip + ItemScannerHiddenTooltip:ClearLines() + ItemScannerHiddenTooltip:SetHyperlink(link) + + if ItemScannerHiddenTooltipTextLeft1:GetText():find(RETRIEVING_ITEM_INFO) then + return false + end + + IS_item_info[link] = { + itemInfo = {GetItemInfo(link)}, + itemSpell = {GetItemSpell(link)}, + statTable = GetItemStats(link), + itemUniqueness = {GetItemUniqueness(link)}, + consumableItem = IsConsumableItem(link), + equippable = IsEquippableItem(link), + helpful = IsHelpfulItem(link), + harmful = IsHarmfulItem(link), + } + for i = 1, ItemScannerHiddenTooltip:NumLines() do + IS_item_info[link][i] = { + left = _G["ItemScannerHiddenTooltipTextLeft" .. i]:GetText(), + right = _G["ItemScannerHiddenTooltipTextRight" .. i]:GetText(), + } + end + + return true +end + +local frame = CreateFrame("Frame") +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 + self.itemco = nil + end + else + frame:SetScript("OnUpdate", nil) + end +end + +local function itemParseCoroutine(start) + IS_status.items.scan_active = true + 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)) + for i = start, 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 + IS_status.items.last_scanned = i + local itemStartTime = GetTime() + if scanItemLink("item:" .. i .. ":0:0:0:0:0:0:0:85") then + IS_status.items.last_valid = i + -- Reset invalid count + IS_status.items.invalid[i] = false + valid, roundValid = valid + 1, roundValid + 1 + else + -- start with 3 if no previous value + IS_status.items.invalid[i] = (IS_status.items.invalid[i] or 2) + 1 + end + if not IS_status.items.scan_active then + break + end + numProcessed = numProcessed + 1 + roundNumProcessed = roundNumProcessed + 1 + while GetTime() - itemStartTime < VALID_DELAY do + coroutine.yield() + end + local currentTime = GetTime() + if currentTime - roundStartTime >= 120 then + local elapsedTime = currentTime - startTime + print(string.format("ItemScanner: at item %d, %d in %.1f sec. (%.2f/min.) (%d valid), %d this round (%d valid)", i, numProcessed, elapsedTime, numProcessed / elapsedTime * 60, valid, roundNumProcessed, roundValid)) + roundStartTime = roundStartTime + 120 + roundNumProcessed, roundValid = 0, 0 + end + end + end + + 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)) + IS_status.items.scan_active = false + + return true +end + +local function commandHandler(msg) + if string.match(msg, "^items") then + local start + + if msg == "items" or msg == "items start" then + start = IS_status.items.last_valid or IS_status.items.last_scanned or minItem + elseif msg == "items clear" then + IS_item_info = {} + IS_status.items.last_scanned = nil + IS_status.items.last_valid = nil + return + elseif msg == "items reset" then + commandHandler("items clear") + commandHandler("items restart") + return + elseif msg == "items restart" then + start = minItem + IS_status.items.last_scanned = nil + IS_status.items.last_valid = nil + elseif msg == "items stop" then + IS_status.items.scan_active = false + return + else + print("Usage: /is items <arg> (or /itemscanner items <arg>") + print(" clear clears item data but does not stop a running scan") + print(" reset clears item data and starts over") + print(" restart restarts the current scan but leaves existing data intact") + print(" start (default) starts where you last left off") + print(" stop stops scanning but leaves existing data intact") + return + end + + frame.itemco = coroutine.wrap(itemParseCoroutine) + frame.itemco(start) + frame:SetScript("OnUpdate", OnUpdate) + else + print("Usage: /is <arg> (or /itemscanner <arg>") + print(" items scans all items") + end +end + +if not IS_item_info then + IS_item_info = {} +end + +if not IS_status then + IS_status = {} +end + +if not IS_status.items then + IS_status.items = {} +end + +if not IS_status.items.invalid then + IS_status.items.invalid = {} +end + +SLASH_ITEMSCANNER1="/is" +SLASH_ITEMSCANNER2="/itemscanner" +SlashCmdList["ITEMSCANNER"] = commandHandler diff --git a/ItemScanner.toc b/ItemScanner.toc new file mode 100644 index 0000000..33d4f34 --- /dev/null +++ b/ItemScanner.toc @@ -0,0 +1,7 @@ +## Interface: 50001 +## Title: Item Scanner +## Notes: Collects and stores data about items +## Author: The Flying Squirrels +## SavedVariables: IS_item_info, IS_status + +ItemScanner.xml diff --git a/ItemScanner.xml b/ItemScanner.xml new file mode 100644 index 0000000..0b96ba0 --- /dev/null +++ b/ItemScanner.xml @@ -0,0 +1,11 @@ +<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"> + <Scripts> + <Onload> + self:SetOwner(WorldFrame, "ANCHOR_NONE") + </Onload> + </Scripts> + </GameTooltip> +</Ui>