mirror of
https://codeberg.org/Duvelcorp/MetaHunt.git
synced 2026-09-22 15:46:59 +00:00
251 lines
9.1 KiB
Lua
251 lines
9.1 KiB
Lua
-- MetaHunt: one-time live trainer catalog collector.
|
|
-- Developer workflow: /mth trainerscan, then open a Hunter or Pet Trainer.
|
|
|
|
local MTH_TS_Frame
|
|
local MTH_TS_Armed = false
|
|
local MTH_TS_AutoArmed = false
|
|
|
|
local function MTH_TS_Log(text)
|
|
if MTH_DebugFrame and type(MTH_DebugFrame.AddInfo) == "function" then
|
|
MTH_DebugFrame:AddInfo("[TrainerScan] " .. tostring(text))
|
|
end
|
|
end
|
|
|
|
local function MTH_TS_Call(name, ...)
|
|
local fn = getglobal and getglobal(name) or (_G and _G[name])
|
|
if type(fn) ~= "function" then return nil, "missing" end
|
|
local ok, a, b, c, d, e, f, g = pcall(fn, unpack(arg))
|
|
if not ok then return nil, "error=" .. tostring(a) end
|
|
return { a, b, c, d, e, f, g }, nil
|
|
end
|
|
|
|
local function MTH_TS_Values(values)
|
|
if not values then return "" end
|
|
local parts = {}
|
|
local i = 1
|
|
while i <= table.getn(values) do
|
|
if values[i] ~= nil then
|
|
table.insert(parts, tostring(values[i]))
|
|
end
|
|
i = i + 1
|
|
end
|
|
return table.concat(parts, " | ")
|
|
end
|
|
|
|
local function MTH_TS_TargetName()
|
|
if type(UnitName) == "function" then
|
|
local name = UnitName("target")
|
|
if name and name ~= "" then return name end
|
|
end
|
|
local title = getglobal and getglobal("TrainerFrameTitleText") or nil
|
|
if title and title.GetText then return title:GetText() or "?" end
|
|
return "?"
|
|
end
|
|
|
|
local function MTH_TS_GetLiveStatusStore()
|
|
if type(MTH_CharSavedVariables) ~= "table" then MTH_CharSavedVariables = {} end
|
|
if type(MTH_CharSavedVariables.trainerLiveStatus) ~= "table" then
|
|
MTH_CharSavedVariables.trainerLiveStatus = {}
|
|
end
|
|
return MTH_CharSavedVariables.trainerLiveStatus
|
|
end
|
|
|
|
local function MTH_TS_GetCatalogKind(name, rank)
|
|
local catalog = MTH_DS_TrainerCatalog
|
|
if type(catalog) ~= "table" or type(catalog.byNameRank) ~= "table" then return nil end
|
|
local keySuffix = "\031" .. tostring(name or "") .. "\031" .. tostring(rank or "")
|
|
if catalog.byNameRank["hunter" .. keySuffix] then return "hunter" end
|
|
if catalog.byNameRank["pet" .. keySuffix] then return "pet" end
|
|
return nil
|
|
end
|
|
|
|
function MTH_GetTrainerLiveStatus(kind, name, rank)
|
|
local store = type(MTH_CharSavedVariables) == "table" and MTH_CharSavedVariables.trainerLiveStatus or nil
|
|
if type(store) ~= "table" then return nil end
|
|
return store[tostring(kind or "") .. "\031" .. tostring(name or "") .. "\031" .. tostring(rank or "")]
|
|
end
|
|
|
|
local function MTH_TS_CollectLiveStatuses()
|
|
local countValues = MTH_TS_Call("GetNumTrainerServices")
|
|
local total = countValues and tonumber(countValues[1]) or 0
|
|
if total <= 0 then return false end
|
|
|
|
local trainerName = MTH_TS_TargetName()
|
|
local store = MTH_TS_GetLiveStatusStore()
|
|
local observed = 0
|
|
for index = 1, total do
|
|
local info = MTH_TS_Call("GetTrainerServiceInfo", index)
|
|
local name = info and info[1] or nil
|
|
local rank = info and info[2] or ""
|
|
local status = info and info[3] or nil
|
|
local kind = MTH_TS_GetCatalogKind(name, rank)
|
|
if kind and (status == "available" or status == "unavailable" or status == "used") then
|
|
local key = kind .. "\031" .. tostring(name) .. "\031" .. tostring(rank)
|
|
store[key] = {
|
|
status = status,
|
|
observedAt = time(),
|
|
trainer = trainerName,
|
|
}
|
|
observed = observed + 1
|
|
end
|
|
end
|
|
|
|
if observed > 0 then
|
|
MTH_TS_Log("Live trainer overlay: " .. tostring(observed) .. " observed catalog row(s) from " .. tostring(trainerName) .. ".")
|
|
if MTH and MTH.Print and (not MTH.IsMessageEnabled or MTH:IsMessageEnabled("trainerScan", true)) then
|
|
MTH:Print("Trainer scan: " .. tostring(observed) .. " Hunter/Pet spell status" .. (observed == 1 and "" or "es") .. " observed.")
|
|
end
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function MTH_TS_Collect()
|
|
local countValues, countError = MTH_TS_Call("GetNumTrainerServices")
|
|
local total = countValues and tonumber(countValues[1]) or 0
|
|
if not total or total <= 0 then
|
|
MTH_TS_Log("No trainer services yet. GetNumTrainerServices=" .. tostring(MTH_TS_Values(countValues))
|
|
.. " " .. tostring(countError or ""))
|
|
return false
|
|
end
|
|
|
|
local trainerName = MTH_TS_TargetName()
|
|
local capture = {
|
|
trainer = trainerName,
|
|
capturedAt = time(),
|
|
services = {},
|
|
}
|
|
MTH_TRAINER_SCAN_LAST = capture
|
|
if type(MTH_CharSavedVariables) == "table" then
|
|
if type(MTH_CharSavedVariables.trainerCatalogScans) ~= "table" then
|
|
MTH_CharSavedVariables.trainerCatalogScans = {}
|
|
end
|
|
MTH_CharSavedVariables.trainerCatalogScans[trainerName] = capture
|
|
end
|
|
MTH_TS_Log("=== " .. tostring(capture.trainer) .. " | " .. tostring(total) .. " trainer services ===")
|
|
|
|
local index = 1
|
|
while index <= total do
|
|
local info, infoError = MTH_TS_Call("GetTrainerServiceInfo", index)
|
|
local icon, iconError = MTH_TS_Call("GetTrainerServiceIcon", index)
|
|
local cost, costError = MTH_TS_Call("GetTrainerServiceCost", index)
|
|
local level, levelError = MTH_TS_Call("GetTrainerServiceLevelReq", index)
|
|
local skill, skillError = MTH_TS_Call("GetTrainerServiceSkillReq", index)
|
|
local description, descriptionError = MTH_TS_Call("GetTrainerServiceDescription", index)
|
|
local reqCountValues = MTH_TS_Call("GetTrainerServiceNumAbilityReq", index)
|
|
local reqCount = reqCountValues and tonumber(reqCountValues[1]) or 0
|
|
local requirements = {}
|
|
local reqIndex = 1
|
|
while reqIndex <= reqCount do
|
|
local requirement, reqError = MTH_TS_Call("GetTrainerServiceAbilityReq", index, reqIndex)
|
|
table.insert(requirements, {
|
|
name = requirement and requirement[1] or nil,
|
|
flag = requirement and requirement[2] or nil,
|
|
error = reqError,
|
|
})
|
|
reqIndex = reqIndex + 1
|
|
end
|
|
|
|
local row = {
|
|
index = index,
|
|
name = info and info[1] or nil,
|
|
rank = info and info[2] or nil,
|
|
status = info and info[3] or nil,
|
|
expanded = info and info[4] or nil,
|
|
icon = icon and icon[1] or nil,
|
|
cost = cost and cost[1] or nil,
|
|
requiredLevel = level and level[1] or nil,
|
|
skillRequirement = skill,
|
|
description = description and description[1] or nil,
|
|
abilityRequirements = requirements,
|
|
}
|
|
table.insert(capture.services, row)
|
|
|
|
MTH_TS_Log(string.format("%02d name=%s | rank=%s | status=%s | expanded=%s | level=%s | cost=%s | icon=%s",
|
|
index, tostring(row.name), tostring(row.rank), tostring(row.status), tostring(row.expanded),
|
|
tostring(row.requiredLevel), tostring(row.cost), tostring(row.icon)))
|
|
if row.description and row.description ~= "" then
|
|
MTH_TS_Log(" description=" .. tostring(row.description))
|
|
end
|
|
if table.getn(requirements) > 0 then
|
|
local requirementText = {}
|
|
local requirementIndex = 1
|
|
while requirementIndex <= table.getn(requirements) do
|
|
local requirement = requirements[requirementIndex]
|
|
table.insert(requirementText, tostring(requirement.name)
|
|
.. " [flag=" .. tostring(requirement.flag) .. "]")
|
|
requirementIndex = requirementIndex + 1
|
|
end
|
|
MTH_TS_Log(" abilityRequirements=" .. table.concat(requirementText, ", "))
|
|
end
|
|
if skill and table.getn(skill) > 0 then
|
|
MTH_TS_Log(" skillRequirement=" .. MTH_TS_Values(skill))
|
|
end
|
|
if infoError or iconError or costError or levelError or skillError or descriptionError then
|
|
MTH_TS_Log(" API=" .. tostring(infoError or "ok") .. ", " .. tostring(iconError or "ok")
|
|
.. ", " .. tostring(costError or "ok") .. ", " .. tostring(levelError or "ok")
|
|
.. ", " .. tostring(skillError or "ok") .. ", " .. tostring(descriptionError or "ok"))
|
|
end
|
|
index = index + 1
|
|
end
|
|
|
|
MTH_TS_Log("=== Capture complete. " .. tostring(total)
|
|
.. " rows retained in MTH_TRAINER_SCAN_LAST and trainerCatalogScans. ===")
|
|
return true
|
|
end
|
|
|
|
local function MTH_TS_EnsureFrame()
|
|
if not MTH_TS_Frame then
|
|
MTH_TS_Frame = CreateFrame("Frame", "MTH_TrainerCatalogScanner")
|
|
MTH_TS_Frame:SetScript("OnEvent", function()
|
|
if event == "TRAINER_SHOW" then
|
|
MTH_TS_AutoArmed = true
|
|
this.elapsed = 0
|
|
this:SetScript("OnUpdate", function()
|
|
this.elapsed = (this.elapsed or 0) + (arg1 or 0)
|
|
if this.elapsed < 0.25 then return end
|
|
this:SetScript("OnUpdate", nil)
|
|
MTH_TS_CollectLiveStatuses()
|
|
end)
|
|
return
|
|
end
|
|
if event ~= "TRAINER_LIST_UPDATE" or not (MTH_TS_Armed or MTH_TS_AutoArmed) then return end
|
|
this.elapsed = 0
|
|
this:SetScript("OnUpdate", function()
|
|
this.elapsed = (this.elapsed or 0) + (arg1 or 0)
|
|
if this.elapsed < 0.25 then return end
|
|
this:SetScript("OnUpdate", nil)
|
|
local manualArmed = MTH_TS_Armed
|
|
MTH_TS_Armed = false
|
|
MTH_TS_AutoArmed = false
|
|
MTH_TS_CollectLiveStatuses()
|
|
if manualArmed and not MTH_TS_Collect() and MTH and MTH.Print then
|
|
MTH:Print("Trainer list was empty. Open the trainer again and run /mth trainerscan.")
|
|
end
|
|
end)
|
|
end)
|
|
MTH_TS_Frame:RegisterEvent("TRAINER_SHOW")
|
|
MTH_TS_Frame:RegisterEvent("TRAINER_LIST_UPDATE")
|
|
end
|
|
end
|
|
|
|
function MTH_CommandTrainerScan()
|
|
if MTH_DebugFrame and type(MTH_DebugFrame.Show) == "function" then MTH_DebugFrame:Show() end
|
|
local currentRows = MTH_TS_Call("GetNumTrainerServices")
|
|
if currentRows and (tonumber(currentRows[1]) or 0) > 0 then
|
|
MTH_TS_Collect()
|
|
if MTH and MTH.Print then
|
|
MTH:Print("Trainer catalog captured from the open trainer window.")
|
|
end
|
|
return
|
|
end
|
|
|
|
MTH_TS_EnsureFrame()
|
|
|
|
MTH_TS_Armed = true
|
|
if MTH and MTH.Print then
|
|
MTH:Print("Trainer catalog scan armed. Open a Hunter Trainer or Pet Trainer; results will appear in the debug window.")
|
|
end
|
|
end
|
|
|
|
MTH_TS_EnsureFrame() |