Initial commit
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
setfenv(1, Gromissingcrafts)
|
||||
|
||||
--[[
|
||||
Turtle WoW's own trade skill / craft / trainer windows don't expose a
|
||||
recipe's spell id or required skill level through the client API - the only
|
||||
reliably scriptable facts are a recipe's exact name, and (trade skill/craft
|
||||
only) its resulting item id. "/gmc dump" walks whichever of those three
|
||||
windows is open and prints what it can, so gaps in lib/LibCrafts-1.0
|
||||
(Survival's especially) can be filled in with precise lookups instead of
|
||||
fuzzy name searches. The trainer window is the most complete source - it
|
||||
lists every recipe the trainer offers whether you've learned it or not -
|
||||
but only the trade skill/craft windows expose item ids, and only for
|
||||
recipes you already know.
|
||||
]]
|
||||
|
||||
---@class DevTools
|
||||
DevTools = {}
|
||||
|
||||
---@param itemLink string|nil
|
||||
---@return number|nil
|
||||
local function extractItemId(itemLink)
|
||||
if itemLink == nil then
|
||||
return nil
|
||||
end
|
||||
local _, _, id = strfind(itemLink, "item:(%d+)")
|
||||
return id and tonumber(id) or nil
|
||||
end
|
||||
|
||||
---@param text string
|
||||
local function printLine(text)
|
||||
DEFAULT_CHAT_FRAME:AddMessage(text)
|
||||
end
|
||||
|
||||
---@return boolean
|
||||
local function dumpTradeSkillFrame()
|
||||
local name, curRank, maxRank = GetTradeSkillLine()
|
||||
if name == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
printLine(format("|cff40bf40Gromissingcrafts|r: dumping '%s' (rank %d/%d)", name, curRank or 0, maxRank or 0))
|
||||
|
||||
for i = 1, GetNumTradeSkills() do
|
||||
local skillName, skillType = GetTradeSkillInfo(i)
|
||||
if skillType ~= "header" then
|
||||
local itemId = extractItemId(GetTradeSkillItemLink(i))
|
||||
printLine(format(" [%d] %s -> item %s (%s)", i, skillName or "?", itemId and tostring(itemId) or "?", skillType or "?"))
|
||||
end
|
||||
end
|
||||
|
||||
printLine("Look each item id up on your realm's database to get the exact spell id and skill level, then add:")
|
||||
printLine(" module:NewCraft(spellId, \"Recipe Name\", skillLevel, {SpellSource.Trainer}):SetResult(itemId):Save()")
|
||||
return true
|
||||
end
|
||||
|
||||
---@return boolean
|
||||
local function dumpCraftFrame()
|
||||
local name, curRank, maxRank = GetCraftDisplaySkillLine()
|
||||
if name == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
printLine(format("|cff40bf40Gromissingcrafts|r: dumping '%s' (rank %d/%d)", name, curRank or 0, maxRank or 0))
|
||||
|
||||
for i = 1, GetNumCrafts() do
|
||||
local skillName, _, skillType = GetCraftInfo(i)
|
||||
if skillType ~= "header" then
|
||||
local itemId = extractItemId(GetCraftItemLink(i))
|
||||
printLine(format(" [%d] %s -> item %s (%s)", i, skillName or "?", itemId and tostring(itemId) or "?", skillType or "?"))
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--[[
|
||||
The trainer window lists every service the trainer offers, known or not -
|
||||
unlike the trade skill window (which only ever shows recipes you've already
|
||||
learned). No item link exists for a trainer entry though (you're learning a
|
||||
spell, not previewing a crafted item), so this only gets names, not ids.
|
||||
GetTrainerServiceInfo's exact return order isn't confirmed for this client,
|
||||
so both candidate "type" slots are printed and checked for the header filter.
|
||||
]]
|
||||
---@return boolean
|
||||
local function dumpTrainerFrame()
|
||||
local count = GetNumTrainerServices()
|
||||
if count == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
printLine(format("|cff40bf40Gromissingcrafts|r: dumping trainer list (%d services)", count))
|
||||
|
||||
for i = 1, count do
|
||||
local serviceName, b, c = GetTrainerServiceInfo(i)
|
||||
if b ~= "header" and c ~= "header" then
|
||||
printLine(format(" [%d] %s (%s / %s)", i, serviceName or "?", tostring(b), tostring(c)))
|
||||
end
|
||||
end
|
||||
|
||||
printLine("No item ids here - cross-reference these names against your realm's database, or check the trade skill window (item ids) after learning each one.")
|
||||
return true
|
||||
end
|
||||
|
||||
---@param frameName string
|
||||
local function reportFrame(frameName)
|
||||
local frame = getglobal(frameName)
|
||||
if frame == nil then
|
||||
printLine(format(" %s: does not exist on this client", frameName))
|
||||
return
|
||||
end
|
||||
local ok, visible = pcall(function() return frame:IsVisible() end)
|
||||
printLine(format(" %s: exists, IsVisible()=%s", frameName, ok and tostring(visible) or "error calling IsVisible"))
|
||||
end
|
||||
|
||||
--[[
|
||||
Nothing matched. Rather than guess again blind, report exactly what does and
|
||||
doesn't exist on this client so the real cause (wrong frame name? visibility
|
||||
check failing? something else entirely?) can be fixed instead of guessed at.
|
||||
]]
|
||||
local function diagnose()
|
||||
printLine("|cffff8040Gromissingcrafts|r: no supported window detected. Diagnostics:")
|
||||
reportFrame("TradeSkillFrame")
|
||||
reportFrame("CraftFrame")
|
||||
reportFrame("TrainerFrame")
|
||||
reportFrame("ClassTrainerFrame")
|
||||
local ok, numServices = pcall(GetNumTrainerServices)
|
||||
if not ok then
|
||||
printLine(" GetNumTrainerServices() = error calling it")
|
||||
else
|
||||
printLine(format(" GetNumTrainerServices() = %s", numServices == nil and "nil" or tostring(numServices)))
|
||||
end
|
||||
end
|
||||
|
||||
local function dump()
|
||||
if getglobal("TradeSkillFrame") ~= nil and TradeSkillFrame:IsVisible() and dumpTradeSkillFrame() then
|
||||
return
|
||||
end
|
||||
if getglobal("CraftFrame") ~= nil and CraftFrame:IsVisible() and dumpCraftFrame() then
|
||||
return
|
||||
end
|
||||
if getglobal("TrainerFrame") ~= nil and TrainerFrame:IsVisible() and dumpTrainerFrame() then
|
||||
return
|
||||
end
|
||||
-- This client names the trainer window ClassTrainerFrame (used for both
|
||||
-- class and profession trainers), not the vanilla-standard TrainerFrame -
|
||||
-- confirmed via /gmc dump's own diagnostics.
|
||||
if getglobal("ClassTrainerFrame") ~= nil and ClassTrainerFrame:IsVisible() and dumpTrainerFrame() then
|
||||
return
|
||||
end
|
||||
diagnose()
|
||||
end
|
||||
|
||||
function DevTools:Create()
|
||||
-- Must land in the REAL global table, not this addon's isolated
|
||||
-- environment - the client's slash-command dispatcher scans real _G for
|
||||
-- SLASH_* variables, and a bare assignment here would only ever set
|
||||
-- Gromissingcrafts.SLASH_GROMISSINGCRAFTS1 (writes don't fall through
|
||||
-- the environment's __index like reads do).
|
||||
setglobal("SLASH_GROMISSINGCRAFTS1", "/gromissingcrafts")
|
||||
setglobal("SLASH_GROMISSINGCRAFTS2", "/gmc")
|
||||
SlashCmdList["GROMISSINGCRAFTS"] = function(msg)
|
||||
local command = strlower(msg or "")
|
||||
if command == "dump" then
|
||||
dump()
|
||||
else
|
||||
printLine("|cff40bf40Gromissingcrafts|r: /gmc dump - print recipe names (+ item ids where available) from the open trade skill, craft, or trainer window")
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user