Files
ascension-char-exporter/AscensionExporter/Core.lua
T
2025-12-08 13:45:59 +01:00

251 lines
9.1 KiB
Lua

-- AscensionExporter - Core
local ADDON_NAME = ...
local AE = {}
AscensionExporter = AE
-- SavedVariables defaults
AscensionExporterConfig = AscensionExporterConfig or {}
AscensionExporterConfig.enableSavedVariables = AscensionExporterConfig.enableSavedVariables == true and true or false
AscensionExporterSaved = AscensionExporterSaved or {}
-- Utils
local function IsArray(t)
if type(t) ~= "table" then return false end
local n = 0
for k, _ in pairs(t) do
if type(k) ~= "number" then return false end
n = n + 1
end
for i = 1, n do
if t[i] == nil then return false end
end
return true
end
-- Shims for safety
local function SafeCall(fn, ...)
local ok, r = pcall(fn, ...)
if ok then return r end
return nil
end
-- Export assembly
function AE:AssembleExport(which)
local nowIso = date("!%Y-%m-%dT%H:%M:%SZ")
local version, build, buildDate, toc = GetBuildInfo()
local name = UnitName("player") or ""
local level = UnitLevel("player") or 0
local _, class = UnitClass("player")
local _, race = UnitRace("player")
local faction = UnitFactionGroup("player") or ""
local realm = GetRealmName and GetRealmName() or (GetCVar and GetCVar("realmName")) or ""
local out = {
schemaVersion = 1,
exportedAt = nowIso,
client = { interface = toc or 30300, version = version, build = build, buildDate = buildDate },
character = { name = name or "", realm = realm or "", level = level or 0, class = class or "", race = race or "", faction = faction or "" },
}
local wantAll = (which == nil) or (which == "all")
if wantAll or which == "talents" then
if AE.CollectTalents then
out.talents = SafeCall(AE.CollectTalents) or {}
end
end
if wantAll or which == "gear" then
if AE.CollectGear then
out.gear = SafeCall(AE.CollectGear) or {}
end
end
if wantAll or which == "enchants" then
if AE.CollectMysticEnchants then
out.mysticEnchants = SafeCall(AE.CollectMysticEnchants) or {}
end
end
return out
end
function AE:Export(which)
local data = self:AssembleExport(which)
-- Prefer global encoder from Util/Json.lua; fallback to a tiny local encoder if missing
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
-- detect array-like
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.AscensionExporter_Json_Encode or tiny_json_encode
local json = encoder(data)
local title = "Ascension Export"
if which and which ~= "all" then title = title .. " - " .. which end
AscensionExporter_ShowExportFrame(json, title .. " - Copy All (Ctrl+C)")
if AscensionExporterConfig.enableSavedVariables then
local key = (data.character.realm or "") .. ":" .. (data.character.name or "")
AscensionExporterSaved[key] = data
DEFAULT_CHAT_FRAME:AddMessage("AscensionExporter: export saved to SavedVariables for " .. key)
end
end
-- Markdown gear table generator (for guide tables like mage-guide.md)
function AE:GenerateMarkdownGear()
local gear = self.CollectGear and self.CollectGear() or { slots = {} }
local ench = self.CollectMysticEnchants and self.CollectMysticEnchants() or { perSlot = {}, active = {} }
-- Map gear by slot and mystic enchant per slot
local bySlot = {}
for _, s in ipairs(gear.slots or {}) do
bySlot[s.slot] = s
end
local mystPer = {}
for _, e in ipairs(ench.perSlot or {}) do
mystPer[e.slot] = e.name
end
-- Desired order and pretty slot names matching the mage guide
local ORDER = {
{1, "Head"},
{2, "Neck"},
{3, "Shoulders"},
{15, "Back"},
{5, "Chest"},
{9, "Wrist"},
{16, "Mainhand"},
{17, "Offhand"},
{18, "Wand"},
{10, "Gloves"},
{6, "Belt"},
{7, "Legs"},
{8, "Boots"},
{11, "Ring 1"},
{12, "Ring 2"},
{13, "Trinket 1"},
{14, "Trinket 2"},
}
local function md_link(name, itemId)
if (itemId or 0) > 0 and name and name ~= "" then
return string.format("[%s](https://db.ascension.gg/?item=%d)", name, itemId)
elseif name and name ~= "" then
return name
else
return "-"
end
end
local lines = {}
table.insert(lines, "| Slot | Item | Location | Enchant | Alternative |")
table.insert(lines, "|------|------|----------|---------|-------------|")
for _, ent in ipairs(ORDER) do
local slotId, label = ent[1], ent[2]
local s = bySlot[slotId]
local itemCell = "-"
local enchantCell = "-"
if s then
itemCell = md_link(s.name, s.itemId)
local base = s.enchant and s.enchant.name or nil
local myst = mystPer[slotId]
if base and base ~= "" then
enchantCell = base
end
if myst and myst ~= "" then
enchantCell = (enchantCell ~= "-" and enchantCell ~= nil and enchantCell ~= "")
and (enchantCell .. " / Mystic: " .. myst)
or ("Mystic: " .. myst)
end
if not enchantCell or enchantCell == "" then enchantCell = "-" end
end
local row = string.format("| **%s** | %s | - | %s | - |", label, itemCell, enchantCell)
table.insert(lines, row)
end
return table.concat(lines, "\n") .. "\n"
end
-- Slash command handling
SLASH_ASCX1 = "/ascx"
SLASH_ASCX2 = "/asxc" -- alias: both map to the same handler key "ASCX"
SlashCmdList["ASCX"] = function(msg)
msg = msg or ""
msg = msg:lower()
if msg == "" or msg == "help" then
-- Open the export window with helpful text and let buttons drive actions
if AscensionExporter_ShowExportFrame then
local help = "Use the buttons above or type:\n/ascx export all|talents|gear|enchants|mdgear\n/ascx sv on|off (SavedVariables is currently " .. (AscensionExporterConfig.enableSavedVariables and "ON" or "OFF") .. ")\n"
AscensionExporter_ShowExportFrame(help, "Ascension Export - Tools & Help")
return
else
DEFAULT_CHAT_FRAME:AddMessage("AscensionExporter usage:")
DEFAULT_CHAT_FRAME:AddMessage(" /ascx export all|talents|gear|enchants|mdgear")
DEFAULT_CHAT_FRAME:AddMessage(" /ascx sv on|off - toggle SavedVariables export (currently " .. (AscensionExporterConfig.enableSavedVariables and "ON" or "OFF") .. ")")
return
end
end
local cmd, rest = msg:match("^(%S+)%s*(.*)$")
if cmd == "export" then
rest = rest ~= "" and rest or "all"
if rest == "mdgear" or rest == "md" then
local md = AE:GenerateMarkdownGear()
AscensionExporter_ShowExportFrame(md, "Ascension Export - Markdown Gear - Copy All (Ctrl+C)")
elseif rest == "all" or rest == "talents" or rest == "gear" or rest == "enchants" then
AE:Export(rest)
else
DEFAULT_CHAT_FRAME:AddMessage("AscensionExporter: unknown export target '" .. tostring(rest) .. "'")
end
return
elseif cmd == "sv" then
if rest == "on" then
AscensionExporterConfig.enableSavedVariables = true
DEFAULT_CHAT_FRAME:AddMessage("AscensionExporter: SavedVariables export ENABLED")
elseif rest == "off" then
AscensionExporterConfig.enableSavedVariables = false
DEFAULT_CHAT_FRAME:AddMessage("AscensionExporter: SavedVariables export DISABLED")
else
DEFAULT_CHAT_FRAME:AddMessage("AscensionExporter: sv on|off")
end
return
else
DEFAULT_CHAT_FRAME:AddMessage("AscensionExporter: unknown command. Type /ascx help")
end
end
-- Basic event binding (not strictly necessary for slash-only usage)
local f = CreateFrame("Frame")
f:RegisterEvent("ADDON_LOADED")
f:SetScript("OnEvent", function(_, event, addon)
if event == "ADDON_LOADED" and addon == ADDON_NAME then
-- init defaults if needed
AscensionExporterConfig.enableSavedVariables = AscensionExporterConfig.enableSavedVariables and true or false
end
end)