diff --git a/CoaExporter/Catalogs/Common.lua b/CoaExporter/Catalogs/Common.lua index de9e609..0de7efc 100644 --- a/CoaExporter/Catalogs/Common.lua +++ b/CoaExporter/Catalogs/Common.lua @@ -100,7 +100,7 @@ function C.Run(filter, callback) playerClassFile = playerClassFile or "UNKNOWN" local ctx = { - startedAt = date("!%Y-%m-%dT%H:%M:%SZ"), + startedAt = date(), filter = filter or "all", playerClass = playerLocalizedClass, playerClassFile = playerClassFile, @@ -166,17 +166,9 @@ function C.Run(filter, callback) end end - -- Only tooltip-scan entries with a backing spell. Advancement - -- IDs are NOT spell IDs - SetHyperlink("spell:" .. entry.ID) - -- would alias them into real 3.3.5 spell-ID space and capture - -- some unrelated spell's tooltip (and adopt its first line as - -- the entry name). local name, _, icon - local tooltip = "" - if spellId > 0 then - name, _, icon = GetSpellInfo(spellId) - tooltip = GetCatalogTooltip(spellId) - end + if spellId > 0 then name, _, icon = GetSpellInfo(spellId) end + local tooltip = GetCatalogTooltip(spellId > 0 and spellId or entry.ID) if not name or name == "" then name = tooltip:match("^([^\n]+)") or ("ID:" .. tostring(entry.ID)) end diff --git a/CoaExporter/Collectors/Items.lua b/CoaExporter/Collectors/Items.lua index 836b851..e549572 100644 --- a/CoaExporter/Collectors/Items.lua +++ b/CoaExporter/Collectors/Items.lua @@ -88,9 +88,11 @@ local function TryResolve(itemID) local name, link, quality, iLevel, reqLevel, class, subclass, maxStack, equipSlot, texture, sellPrice = GetItemInfo(itemID) if not name then - -- Trigger the server-side ITEM_QUERY_SINGLE via the hidden scanner - -- tooltip; this is also what writes the row into itemcache.wdb. - ScanItemTooltip(itemID) + -- Trigger the server-side ITEM_QUERY_SINGLE; this is also what writes + -- the row into itemcache.wdb. + GameTooltip:SetOwner(WorldFrame, "ANCHOR_NONE") + GameTooltip:SetHyperlink("item:" .. itemID) + GameTooltip:Hide() return false end local itemLines = ScanItemTooltip(itemID) @@ -119,28 +121,22 @@ local function TryResolve(itemID) return true end --- One synchronous pass over `ids`. Returns counts + the still-unresolved --- list. `resolved` counts everything in the cache (including hits from --- earlier passes); `new` counts only ids that resolved during this pass. +-- One synchronous pass over `ids`. Returns counts + the still-unresolved list. function AE.ItemsScanPass(ids) - local cache = CoaExporterItemCache.entries local total = #ids - local resolved = 0 local newlyResolved = 0 local unresolved = {} for _, id in ipairs(ids) do - local wasCached = cache[id] and cache[id].name ~= nil if TryResolve(id) then - resolved = resolved + 1 - if not wasCached then newlyResolved = newlyResolved + 1 end + newlyResolved = newlyResolved + 1 else unresolved[#unresolved+1] = id end end CoaExporterItemCache.meta.lastScanAt = time() - CoaExporterItemCache.meta.resolved = resolved + CoaExporterItemCache.meta.resolved = newlyResolved CoaExporterItemCache.meta.unresolved = unresolved - return { total = total, resolved = resolved, new = newlyResolved, unresolved = #unresolved } + return { total = total, resolved = newlyResolved, unresolved = #unresolved } end -- Multi-pass scan with delays so the server has time to answer queries. @@ -151,8 +147,8 @@ function AE.ItemsStartScan(ids, callback) attempts = attempts + 1 local stats = AE.ItemsScanPass(ids) DEFAULT_CHAT_FRAME:AddMessage(string.format( - "CoaExporter items: pass %d/%d - resolved %d/%d (%d new this pass, still unresolved: %d)", - attempts, maxAttempts, stats.resolved, stats.total, stats.new, stats.unresolved)) + "CoaExporter items: pass %d/%d - resolved this pass %d/%d (still unresolved: %d)", + attempts, maxAttempts, stats.resolved, stats.total, stats.unresolved)) if stats.unresolved > 0 and attempts < maxAttempts then local t = CreateFrame("Frame") local elapsed = 0 diff --git a/CoaExporter/Collectors/MysticScrolls.lua b/CoaExporter/Collectors/MysticScrolls.lua index fdcac0f..a8fbd23 100644 --- a/CoaExporter/Collectors/MysticScrolls.lua +++ b/CoaExporter/Collectors/MysticScrolls.lua @@ -71,23 +71,17 @@ end local function TryResolve(entry) local cache = CoaExporterScrollCache.entries - local hit = cache[entry.itemID] - if hit and hit.itemTooltip and hit.itemTooltip ~= "" then + if cache[entry.itemID] and cache[entry.itemID].itemTooltip then return true end local name, _, quality = GetItemInfo(entry.itemID) if not name then - -- Poke the server (ITEM_QUERY_SINGLE) via the hidden scanner so the - -- next pass can resolve - no need to touch the global GameTooltip. - ScanItemTooltip(entry.itemID) + GameTooltip:SetOwner(WorldFrame, "ANCHOR_NONE") + GameTooltip:SetHyperlink("item:" .. entry.itemID) + GameTooltip:Hide() return false end local itemLines = ScanItemTooltip(entry.itemID) - if #itemLines == 0 then - -- Tooltip not server-resolved yet; don't cache an empty entry, or - -- this scroll would never be retried on later passes. - return false - end local spellName, spellRank if GetItemSpell then spellName, spellRank = GetItemSpell(entry.itemID) @@ -103,7 +97,7 @@ local function TryResolve(entry) itemTooltip = table.concat(itemLines, "\n"), fetchedAt = time(), } - return true + return #itemLines > 0 end function AE.ScrollsScanPass() diff --git a/CoaExporter/Core.lua b/CoaExporter/Core.lua index 32248ef..af90b89 100644 --- a/CoaExporter/Core.lua +++ b/CoaExporter/Core.lua @@ -128,7 +128,31 @@ end function AE:Export(which) local normWhich = Norm(which) local data = self:AssembleExport(normWhich) - local encoder = _G.CoaExporter_Json_Encode + local function tiny_json_encode(v) + local tv = type(v) + if tv == 'nil' then return 'null' end + if tv == 'boolean' then return v and 'true' or 'false' end + if tv == 'number' then return tostring(v) end + if tv == 'string' then + local s = v:gsub('\\', '\\\\'):gsub('"', '\\"'):gsub('\n', '\\n'):gsub('\r', '\\r'):gsub('\t', '\\t') + return '"' .. s .. '"' + end + if tv == 'table' then + local n = 0 + for k,_ in pairs(v) do if type(k) ~= 'number' then n = -1 break else n = math.max(n, k) end end + if n >= 1 then + local parts = {} + for i=1,n do parts[#parts+1] = tiny_json_encode(v[i]) end + return '[' .. table.concat(parts, ',') .. ']' + else + local parts = {} + for k,val in pairs(v) do parts[#parts+1] = tiny_json_encode(tostring(k)) .. ':' .. tiny_json_encode(val) end + return '{' .. table.concat(parts, ',') .. '}' + end + end + return 'null' + end + local encoder = _G.CoaExporter_Json_Encode or tiny_json_encode local json = encoder(data) local title = "CoaExporter"