2b97a68317
Folds three previously-separate Lua addons into one for guild-member use:
- ascension-char-exporter (per-character JSON/Wiki.js Markdown via /ascx)
- CoA_SkillExporter (skills/dispels/passives catalog via /skilldump)
- CoA_TalentExporter (talent-tree catalog via /talentdumpall)
The two CoA catalog dumpers were ~90% identical entry-walkers. Pulled the
shared C_CharacterAdvancement.GetAllEntries() loop into Catalogs/Common.lua
and have Skills.lua / Talents.lua register collectors that share a single
scan pass (so /coae catalog all walks the entry list once, not twice).
Per-character collectors (Talents, Gear, Enchants, MysticScrolls,
MysticScrollProbe) and the AtlasLootAscension-derived ScrollCatalog data
are kept verbatim, just rebranded.
Slash interface:
/coae export {all|talents|gear|enchants|mdgear|mdenchants|md}
/coae catalog {all|skills|talents|dispels [class]|passives [class]|status}
/coae scrolls {scan|export|reset|status}
/coae sv on|off | debug | help
Aliases: /coaexp, /ascx, /asxc, plus legacy /skilldump /talentdumpall
/dispels /passives that map to the catalog subcommands.
SavedVariables: CoaExporterSaved, CoaExporterConfig, CoaExporterScrollCache,
CoaExporterCatalog (skills/dispels/levelPassives/talents/_meta).
181 lines
5.4 KiB
Lua
181 lines
5.4 KiB
Lua
-- CoaExporter / Collectors / MysticScrolls.lua
|
|
--
|
|
-- Async tooltip scraper for all known mystic enchant scrolls.
|
|
-- Iterates AE.ScrollCatalog (generated from AtlasLootAscension) and dumps
|
|
-- tooltip text + the spell taught by each scroll.
|
|
--
|
|
-- Usage: /coae scrolls scan → start scan (one-time; dumps progress to chat)
|
|
-- /coae scrolls export → print accumulated JSON of everything scanned
|
|
-- /coae scrolls reset → clear cache
|
|
--
|
|
-- Design notes:
|
|
-- - WoW lazy-loads item data. First GetItemInfo() for an unseen item
|
|
-- returns nil and triggers a server query. We retry with delay.
|
|
-- - Results accumulate in CoaExporterScrollCache SavedVariable so a
|
|
-- single run across sessions builds up the full DB.
|
|
-- - A "scan" pass fires a batch of GetItemInfo requests, then waits,
|
|
-- then re-scans and records whatever resolved. Unresolved entries are
|
|
-- retried on the next scan.
|
|
|
|
CoaExporter = _G.CoaExporter or {}
|
|
_G.CoaExporter = CoaExporter
|
|
local AE = CoaExporter
|
|
|
|
CoaExporterScrollCache = CoaExporterScrollCache or {
|
|
entries = {},
|
|
meta = {
|
|
lastScanAt = nil,
|
|
totalCatalog = 0,
|
|
resolved = 0,
|
|
unresolved = {},
|
|
},
|
|
}
|
|
|
|
local function EnsureScanner()
|
|
if not AE._scrollScanner then
|
|
AE._scrollScanner = CreateFrame("GameTooltip", "CoaExpScrollsTT", nil, "GameTooltipTemplate")
|
|
AE._scrollScanner:SetOwner(WorldFrame, "ANCHOR_NONE")
|
|
end
|
|
return AE._scrollScanner
|
|
end
|
|
|
|
local function TipLines(tt)
|
|
local out = {}
|
|
for i = 1, tt:NumLines() do
|
|
local left = _G[tt:GetName() .. "TextLeft" .. i]
|
|
if left then
|
|
local t = left:GetText()
|
|
if t and t ~= "" then out[#out+1] = t end
|
|
end
|
|
end
|
|
return out
|
|
end
|
|
|
|
local function ScanItemTooltip(itemID)
|
|
local tt = EnsureScanner()
|
|
tt:ClearLines()
|
|
tt:SetHyperlink("item:" .. itemID)
|
|
return TipLines(tt)
|
|
end
|
|
|
|
local function FlatCatalog()
|
|
local out = {}
|
|
if not AE.ScrollCatalog then return out end
|
|
for class, list in pairs(AE.ScrollCatalog) do
|
|
for _, e in ipairs(list) do
|
|
out[#out+1] = { itemID = e.itemID, name = e.name, class = class }
|
|
end
|
|
end
|
|
return out
|
|
end
|
|
|
|
local function TryResolve(entry)
|
|
local cache = CoaExporterScrollCache.entries
|
|
if cache[entry.itemID] and cache[entry.itemID].itemTooltip then
|
|
return true
|
|
end
|
|
local name, _, quality = GetItemInfo(entry.itemID)
|
|
if not name then
|
|
GameTooltip:SetOwner(WorldFrame, "ANCHOR_NONE")
|
|
GameTooltip:SetHyperlink("item:" .. entry.itemID)
|
|
GameTooltip:Hide()
|
|
return false
|
|
end
|
|
local itemLines = ScanItemTooltip(entry.itemID)
|
|
local spellName, spellRank
|
|
if GetItemSpell then
|
|
spellName, spellRank = GetItemSpell(entry.itemID)
|
|
end
|
|
cache[entry.itemID] = {
|
|
itemID = entry.itemID,
|
|
class = entry.class,
|
|
scrollName = entry.name,
|
|
itemName = name,
|
|
quality = quality,
|
|
spellName = spellName,
|
|
spellRank = spellRank,
|
|
itemTooltip = table.concat(itemLines, "\n"),
|
|
fetchedAt = time(),
|
|
}
|
|
return #itemLines > 0
|
|
end
|
|
|
|
function AE.ScrollsScanPass()
|
|
local catalog = FlatCatalog()
|
|
local total = #catalog
|
|
CoaExporterScrollCache.meta.totalCatalog = total
|
|
local newlyResolved = 0
|
|
local unresolved = {}
|
|
for _, entry in ipairs(catalog) do
|
|
if TryResolve(entry) then
|
|
newlyResolved = newlyResolved + 1
|
|
else
|
|
unresolved[#unresolved+1] = entry.itemID
|
|
end
|
|
end
|
|
CoaExporterScrollCache.meta.lastScanAt = time()
|
|
CoaExporterScrollCache.meta.resolved = newlyResolved
|
|
CoaExporterScrollCache.meta.unresolved = unresolved
|
|
return { total = total, resolved = newlyResolved, unresolved = #unresolved }
|
|
end
|
|
|
|
function AE.ScrollsStartScan(callback)
|
|
local attempts = 0
|
|
local maxAttempts = 4
|
|
local function step()
|
|
attempts = attempts + 1
|
|
local stats = AE.ScrollsScanPass()
|
|
DEFAULT_CHAT_FRAME:AddMessage(string.format(
|
|
"CoaExporter scrolls: pass %d/%d - resolved %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
|
|
t:SetScript("OnUpdate", function(self, dt)
|
|
elapsed = elapsed + dt
|
|
if elapsed > 5 then
|
|
self:SetScript("OnUpdate", nil)
|
|
step()
|
|
end
|
|
end)
|
|
else
|
|
if callback then callback(stats) end
|
|
end
|
|
end
|
|
step()
|
|
end
|
|
|
|
function AE.ScrollsExport()
|
|
local out = {
|
|
schemaVersion = 1,
|
|
exportedAt = date("!%Y-%m-%dT%H:%M:%SZ"),
|
|
catalogTotal = AE.ScrollCatalogTotal or 0,
|
|
cacheMeta = CoaExporterScrollCache.meta,
|
|
entries = {},
|
|
}
|
|
for _, rec in pairs(CoaExporterScrollCache.entries) do
|
|
table.insert(out.entries, rec)
|
|
end
|
|
return out
|
|
end
|
|
|
|
function AE.ScrollsReset()
|
|
CoaExporterScrollCache = {
|
|
entries = {},
|
|
meta = { lastScanAt = nil, totalCatalog = 0, resolved = 0, unresolved = {} },
|
|
}
|
|
end
|
|
|
|
-- Compute total once on load (used in /coae catalog status etc.)
|
|
do
|
|
local total = 0
|
|
if AE.ScrollCatalog then
|
|
for _, list in pairs(AE.ScrollCatalog) do
|
|
total = total + #list
|
|
end
|
|
end
|
|
AE.ScrollCatalogTotal = total
|
|
end
|
|
|
|
AE._loadedMysticScrolls = true
|