SmexyMats-v1.14.1
What's new
Changelog
[v1.14.1]
Fixed -- item tooltips errored on WoW Forever
Reported from WoW Forever: hovering an item in TOGProfessionMaster's crafting tab raised
SmexyCore.lua:364: attempt to call a nil value from inside tt:GetItem(), 56 times in one
session. On Forever GetItem is not the client's own method but GameTooltipDataMixin:GetItem,
a shim over TooltipUtil.GetDisplayedItem (Blizzard_GameTooltip/Mainline/GameTooltip.lua:1031,
Blizzard_SharedXMLGame/Tooltip/TooltipUtil.lua:9), and on that tooltip something it calls is nil.
Which one was not confirmed in game. I called it unguarded.
The item post-call now reads the item from the tooltip data it is handed (data.hyperlink, else
item:<data.id>) and passes it to ModifyItemTooltip, which uses it before asking the tooltip.
GetItem itself is now called through pcall and a missing or throwing one counts as "no link",
so the stored-link and title fallbacks still run. Tests/core_spec.lua covers all three paths.
Changed -- release docs for v1.14.1
README.md and docs/Curseforge_Description.html checked against the code. Two corrections: the
"Where to get it" key binding is under Key Bindings > AddOns > SmexyMats (Bindings.xml declares
category="ADDONS"), not Key Bindings > SmexyMats, and it is unbound by default; and on Retail and
WoW Forever the lines also show on item tooltips other addons open, since the item post-call
covers every item tooltip. The CurseForge page's VersionCheck-1.0 line now says what the README
says (a guildmate has a newer SmexyMats). v1.14.1 Recent Updates added, grouped Fixed / Changed.
[v1.14.0]
The first release of the restored SmexyMats. It follows LunixiaLIVE's v1.13.2.
Changed -- release docs for v1.14.0
README.md rewritten player-first: the tooltip lines, the heading and [SM] prefix, where the lines
show, the "Where to get it" window (columns, chance notes, faction button, the i help, remembered
position, Questbook), slash commands, every option with its default (checked against
Data/Options/Defaults.lua), per-version coverage, requirements, Discord for reports, and
credits. docs/Curseforge_Description.html gains the same detail and fuller v1.14.0 notes. The
comparison-tooltip claim is limited to Retail and WoW Forever, where the item post-call covers
every tooltip; the Classic flavours hook GameTooltip and ItemRefTooltip only.
Fixed -- everyday vendor goods read PvP on TBC and Mists
Rebuilt Data/Flavour after ItemDB fixed its TBC and Mists location data (thread 60e304d7):
ItemDB's source builder filed any item a battleground quartermaster stocks under that battleground
only, so Refreshing Spring Water (159) read Source "PvP" on TBC. It now reads Quest, Vendor, and
about 60 TBC and 70 Mists items are corrected the same way. Vanilla was unaffected. The rebuild's
drift check flagged ItemDB's Tooltip.lua; its only change was a new _GetTooltipDefault helper,
so COPIED_FROM moved to its new checksum with sourceLabels unchanged.
Changed -- the revived CurseForge project
SmexyMats now publishes to its own CurseForge project, smexymats-revived (project ID 1718084),
taken over with LunixiaLIVE's permission. Every TOC's X-Curse-Project-ID moved from 270824
(LunixiaLIVE's original project) to 1718084, pinned by Tests/toc_spec.lua. The "Missing
Data-Tables" load message, its locale key and all six translations now point at
https://www.curseforge.com/wow/addons/smexymats-revived instead of the old project's
mods.curse.com address. The CurseForge description is rewritten to the family's section layout
and credits LunixiaLIVE as the original developer; the README gains a Credits section saying the
same.
Fixed -- WoW Forever tooltips had no heading and no Source line
Found in game on WoW Forever (ItemDB disabled): Rough Stone showed Profession(s) and ItemID only.
Two causes. Header defaulted to false; it is now true, matching ItemDB's header default (a
profile saved while it was off keeps its saved value). And the per-flavour row can leave the
sources or the expansion blank -- ItemDB's Forever row for 2835 is "||Blacksmithing,Engineering, Mining", and no Mists or Forever row carries an expansion -- so SearchDatabase now fills a blank
source list or expansion from the Materials tables (the old lookup, now searchMaterials), keeping
the flavour data's used-by list. Rough Stone on Forever now reads Drop, Mining and Classic.
Changed -- the copies of ItemDB's code and word list are pinned (audit 67e323f8 item 4)
Tests/data_spec.lua now reads every word the four generated flavours carry and asserts each draws
as the Utilities.lua Profs entry of the same name (so SmexyCore.lua's WORD_PROF indices
cannot drift from Profs), as one of ItemDB's three own icons (Quest, PvP, Reputation), or as
text for the words ItemDB also leaves iconless because no icon was verified: "Crafted",
"Poisons" and Mists' six cooking Ways. A new word fails by name. tools/build-itemdb-data.lua
stamps the Adler-32 of ItemDB's Tooltip.lua and Where.lua (the files SmexyMats copies code
from) into every Data/Flavour header and warns when either differs from COPIED_FROM, so a
change in ItemDB surfaces at the next rebuild.
The Reset button's description still promised to "reset your alt database", a feature that never
existed; it now says it restores every setting and reloads the UI. The deprecated-global sweep
(audit item 1) found only GetItemInfo and GetItemIcon among SmexyMats' calls defined solely in
the live tree's Blizzard_Deprecated* files (12.1.0), and both already go through C_Item first.
Fixed -- one Alt+Click opened two Where windows with ItemDB installed
ItemDB and SmexyMats each hooksecurefunc HandleModifiedItemClick, and both default the Where
click to ALT-LeftButton, so with both installed one click opened both windows (audit
67e323f8 item 6). New SmexyMats:ItemDBOwnsWhereClick asks the loaded LibItemDB-1.0 whether
its click is on (GetTooltipOption("altClick")) and bound, canonically, to the same click as
SmexyMats' (GetTooltipOption("whereClick") through ParseClickBinding). When it is,
WhereOnModifiedClick yields and the heading drops its click hint (ItemDB's heading already
carries one), since ItemDB's window covers every item and SmexyMats' only materials and crafted
items. Give the two addons different clicks and each opens its own. An ItemDB with no
whereClick setting (older than LibItemDB MINOR 38) is never yielded to. /sm where and the key
binding are unaffected.
Fixed -- Retail read item info through a deprecation fallback
GetItemProperties and the Where window called the bare GetItemInfo. On Retail that global is
only a deprecation fallback (Blizzard_DeprecatedItemScript/Deprecated_ItemScript.lua:
GetItemInfo = C_Item.GetItemInfo), loaded only with the loadDeprecationFallbacks CVar -- without
it every item tooltip would have raised. New SmexyMats:ItemInfo resolves C_Item.GetItemInfo
first, per call. Found by the session's self-audit.
Changed -- Retail and WoW Forever annotate every item tooltip
Only the live and forever trees' TooltipInfoDocumentation.lua define C_TooltipInfo.GetBagItem,
ItemDB's test for its data-driven route -- the same two flavours HasScript("OnTooltipSetItem")
already sends to the item post-call, so the route choice already matched. The post-call now
annotates every item tooltip it is handed (the comparison tooltips beside GameTooltip included),
as ItemDB's does, instead of GameTooltip and ItemRefTooltip only; OnTooltipCleared is hooked
once per frame as each is first met, and a tooltip with no name reads no title instead of raising.
The Classic flavours still hook GameTooltip and ItemRefTooltip only -- so does ItemDB.
Changed -- icon sizes are sliders; a malformed saved colour draws white
The << / >> buttons and the number line under them became two AceConfig range sliders:
profession icons 8-64 (ItemDB's range) and the expansion logo 16-128 (SmexyMats' own, default
50), whole numbers, clamped, showing the default when the saved size is missing. The
colour-blind colours now go through SmexyMats:ColorCode, which accepts exactly six hex digits
(as ItemDB's setter does) and otherwise draws white -- a malformed escape would have swallowed the
text after it.
Added -- the "Where to get it" window, ported from ItemDB
Where.lua (loaded right after SmexyCore.lua in every TOC) is ItemDB's Where.lua on the
SmexyMats object: GetItemPlaces (the same packed format, unpacked the same way),
GetWhereSources, BuildWhereRows (bosses, then drops, vendors, gathering nodes and chests with
zone, chance and spawns, then quest / crafted / reputation / PvP), the faction filter, Questbook
tracking with the stop icon, and the click binding (ParseClickBinding, ClickBindingText,
IsWhereClick, one hooksecurefunc("HandleModifiedItemClick")). It opens on an item from the
chosen click (default Alt+Left, a modifier always required), the unbound key binding in
Bindings.xml, or /sm where [item]. The data rides in each Data/Flavour/<Flavour>.lua as a
LoadWhereData call, written by tools/build-itemdb-data.lua from ItemDB's ItemPlaces.lua
(Vanilla 395 items with places, TBC 825, Mists 1059; Forever ships sources but no places). On
Wrath, Cata and Retail there is no Where data and nothing is hooked.
SCOPE, stated because the first write-up called this parity without it: the generator writes Where data only for the items the tooltip covers (reagents and profession-produced items), not for every item ItemDB has places for, so a boss-drop sword reads "No known source (materials and crafted items only)" in SmexyMats where ItemDB lists the drop (audit 67e323f8 #3). Extending it to every item would grow the data files several times over; the scope is said in the window and on the CurseForge page instead.
Two ItemDB features are deliberately not carried: the search strip, which searches ItemDB's
item-name database that SmexyMats does not ship; and localised creature / vendor names (ItemDB's
PlaceNames files) -- the names are English, while zone names still come from the client. New
options: WhereClickEnabled, WhereClick (a select of every modifier combination with the left
or right button, validated), WhereOwnFactionOnly; the heading gains the grey "(Alt+Click: where
to get it)" hint while the click works on that flavour. LibAceGUIWidgets is an optional dependency
in every TOC and a required one in .pkgmeta; without it the window says so in chat.
The generator's first build wrote the separator byte as \31, which Lua reads together with a
following digit (\311) as one escape; escapes are now always three digits.
Added -- optional "SmexyMats" heading
New profile setting Header (default off, so the tooltip looks as it did) and its toggle in the
options. When on, ProcessTooltip draws a blank line and "SmexyMats" (the wowtoken colour, or
colour #1 in colour-blind mode) once, just above the first line it adds, and nothing when every
line is switched off -- ItemDB's heading, minus its click hint, which waits for the Where window.
Added -- per-flavour tooltip data, generated from ItemDB
Data/Materials/Materials.lua is one Wowhead-derived table covering every expansion, so a Classic
client read later-expansion answers (Deeprock Salt: Mining). ItemDB carries the same tooltip with
per-flavour data built from each client's own DB2 tables. tools/build-itemdb-data.lua loads the
installed ItemDB's LibItemDB-1.0 and one flavour's data offline, asks it what ItemDB's tooltip
asks (GetReagentUses, the expansion tables, GetSources turned into words by a copy of ItemDB's
sourceLabels), and writes Data/Flavour/<Flavour>.lua: one [id]="<exp>|<sources>|<used by>"
row per item that is a reagent or that a profession produces. Vanilla 1571 items, TBC 2557, Mists
5918, Forever 2145. SmexyMats.toc, _TBC, _Mists and _Camelot load their file after
SmexyLoadDB.xml; where one is loaded it is the whole answer, and Materials is not consulted.
Wrath, Cata and Retail, for which ItemDB ships no data, keep Materials.
SmexyMats stays standalone: the data is copied into this repo at build time, and nothing reads
ItemDB in the game. New source words Quest, PvP, Reputation and Crafted are in Locales/enUS.lua
(other locales fall back to English); Quest/PvP/Reputation draw ItemDB's icons (file ids 134327,
132486, 134156), and a word with no icon or locale entry (Mists' "Way of the Wok") prints as it
is, read with rawget so AceLocale does not report it missing. Source order is ItemDB's --
producing professions first -- so the sort moved out of FormatToolTipString into the Materials
path of SearchDatabase. Tests/toc_spec.lua now allows exactly one Data\Flavour line per TOC,
right after SmexyLoadDB.xml, and data_spec.lua checks every generated row's shape.
Added -- release and development tooling
SmexyMats had no packaging, docs or tests of any kind -- one TOC for Interface 20501 and the Lua source. This entry brings it up to the fleet's standard layout, with ItemDB as the reference.
- Per-flavour TOCs.
SmexyMats.toc(Classic Era, 11509),SmexyMats_TBC.toc(20506),SmexyMats_Wrath.toc(30405),SmexyMats_Cata.toc(40402),SmexyMats_Mists.toc(50504),SmexyMats_Camelot.toc(WoW Forever, 16001) andSmexyMats_Mainline.toc(Retail,120005, 120007, 120100, the list VersionCheck-1.0's TOC declares). The Interface numbers come from the client versions inF:\Blizzard API Docs' per-flavour trees (1.15.9, 2.5.6, 5.5.4, 1.60.1, 12.1.0); Wrath and Cata have no live client and use the numbers ItemDB ships. Every TOC loads the same files as the old one did.## Version:is nowSmexyMats-v1.14.1for the packager, and the author line credits the original author. .pkgmeta(package as SmexyMats, manual changelog, Ace3 and VersionCheck as required dependencies;docs,Tests,*.ps1,*.code-workspaceandCLAUDE.mdignored) and.github/workflows/release.yml(BigWigs packager on a pushed tag).LICENSE(MIT),README.md,CLAUDE.mdanddocs/Curseforge_Description.html.wow-version-replication.ps1and.vscode/tasks.json: the dev watcher that copies the shippable files to the other installed flavours,_retail_included. It differs from the fleet's copy in one respect: it waits on file-system change events (FileSystemWatcher+Register-ObjectEventwithout-Action+Wait-Event) instead of polling the tree every two seconds, because writ refuses new timers. The fleet's copy polled because an-Actionblock runs in another runspace where the script's functions are not in scope; without-Actionthe events queue in the script's own session, so that reason does not apply. A watcher buffer overflow raisesError, which triggers a full resync.- Test harness. WoWAPITesting as a submodule at
Tests/wowapi, the.bustedshim,.luacheckrc,.luarc.json,.writ-suites.json,.markdownlint.json, and first specs:Tests/toc_spec.lua(every TOC's Interface number, file list and lockstep directives) andTests/manifest_spec.lua(every shipped.luais loaded by some manifest).
Fixed -- a clicked item link got no lines while GameTooltip was annotated
ModifyItemTooltip kept one "already annotated" flag for GameTooltip and ItemRefTooltip together,
cleared by either tooltip's OnTooltipCleared. With GameTooltip showing an annotated item, a chat
link opened in ItemRefTooltip was skipped. The flag is now per tooltip (a weak-keyed table), as
ItemDB's tooltip does it. Found while comparing the two for feature parity.
Fixed -- no item annotations on Retail and WoW Forever
HookTooltips hooked OnTooltipSetItem on both tooltips unconditionally. In the Blizzard source
that script is hooked only in the three Classic trees (Blizzard_PTRFeedback_Tooltips.lua in
classic_era, classic and classic_anniversary); the live and forever trees name it nowhere but the UI
schema and register TooltipDataProcessor.AddTooltipPostCall(Enum.TooltipDataType.Item, ...)
instead. HookTooltips now asks each tooltip HasScript("OnTooltipSetItem"), hooks the script
where it exists, and otherwise registers one item post-call that annotates GameTooltip and
ItemRefTooltip only. Not verified in a Retail or Forever client yet; the offline specs drive both
branches with a tooltip that refuses the script as the client would.
Removed -- SmexyEmbeds.xml
Every TOC loaded SmexyEmbeds.xml, which included ..\Ace3\*.xml from the Ace3 addon's own folder.
Ace3 is a hard dependency in every TOC, so the client has loaded it before SmexyMats either way:
if the client follows ..\ the file re-ran version-guarded libraries for nothing, and if it does not
it was a load error. Which of the two the client does was not verified. The file is gone from all
seven TOCs and the repo, and Tests/toc_spec.lua now fails any TOC or loaded XML that references a
path outside the addon folder.
Changed -- test harness pinned to 1665785
WoWAPITesting fixed coverage.lua to compile targets the way the client does (a leading UTF-8 BOM
skipped) and to print the compiler's error when a target will not load -- the request filed when
Materials.lua's BOM stopped the coverage run. Pinned and re-run: 110 specs, 1076/1076 lines.
Fixed -- every flavour called itself "Classic"
The options panel registered as SmexyMats(Classic) and the load message printed Classic as the
version, on Retail too. The panel is now SmexyMats, and the message prints the TOC's
## Version: (read through C_AddOns.GetAddOnMetadata or the bare global, whichever the client
has -- the same helper now feeds the VersionCheck registration).
Fixed -- ItemRefTooltip read GameTooltip's title
The title fallback in ModifyItemTooltip and the uncached-item message in ProcessTooltip read
GameTooltipTextLeft1 whichever tooltip they were processing, so a clicked item link was looked up
by whatever GameTooltip last showed. Both now read <tooltip name>TextLeft1 of the tooltip in hand.
Added -- logic specs, 100% line coverage
Tests/env_smexy.lua loads SmexyMats the way its TOC does, against the installed Ace3 on the
harness's widget layer (AceConfigDialog builds real frames when the options panel registers), with
recording stand-ins for GameTooltip and ItemRefTooltip. Four spec files cover the logic:
core_spec.lua (profile building, the hooks, /sm, the VersionCheck registration against the
installed library, link parsing, the lookup, every tooltip line and toggle, the uncached-item
message, the Classic profession-window path), utilities_spec.lua, options_spec.lua (every
toggle, both colour pickers, the size steppers, Reset, the header list) and data_spec.lua (every
Sources/Reagents cell the lookup indexes exists and holds item ids). 103 specs;
Tests/wowapi/coverage.lua reports 1065/1065 lines across SmexyCore.lua, Utilities.lua,
Options.lua, Defaults.lua, Materials.lua and Locales/enUS.lua. .writ-suites.json declares
the coverage run and a whole-repo luacheck run, both at zero.
Fixed -- /sm raised an error on every flavour
ChatCommand called InterfaceOptionsFrame_OpenToCategory, which is defined nowhere in the Classic
Era 1.15.9 or Retail FrameXML. It now calls Settings.OpenToCategory with the category ID that
AceConfigDialog:AddToBlizOptions returns (its second return in the installed Ace3).
Fixed -- the profile WAS the defaults table, so Reset reset nothing
OnInitialize and the Reset button both assigned SmexyMats.defaults.profile itself to
SmexyMatsDB.profile, so every setting a player changed was written into the defaults, and Reset
handed the changed table back. New SmexyMats:FillProfile copies (deeply) every default the saved
profile lacks, so a profile saved by an older version also gains settings added since; Reset builds
a fresh copy.
Fixed -- smaller defects found while writing the specs
FormatToolTipString(nil)passedSearchDatabase's empty answer totable.sortand raised; it now answers empty strings. Found by the language server's type check.Defaults.luasetColorBlindPickedOnetwice andColorBlindPickedTwonever.Options.luaused the keySection4for both the "Commands" and the "Author" header, so the Commands header was silently replaced. The second is nowSection6.GetIDFromLinkand the profession-window reads required a:after the item id, so a bareitem:2589string parsed as 0. The pattern is nowitem:(%d+).InstallHookreplacedGameTooltip.SetRecipeResultItem/SetRecipeReagentItemby assignment, which taints GameTooltip, and wrapped them even where the client has no such method (Classic), creating one that raises if called. It is gone.HookRecipeTooltipsuseshooksecurefunc, only on methods the client has, and only when the data tables loaded. Because a secure hook runs after the client's method -- after the tooltip already asked for its item and found none -- the hook records the recipe's link and annotates the tooltip itself;ModifyItemTooltipnow marks a tooltip done only once it found an item, so that second attempt is let through and a laterOnTooltipSetItemcannot add the lines twice.Data/Materials/Materials.luabegan with a UTF-8 byte order mark, which plainloadfilerejects (the client and the harness loader both strip it). Removed, with trailing whitespace; line count and every number verified unchanged. The coverage tool'sloadfilewas reported to WoWAPITesting.
Changed -- Options.lua and Utilities.lua built from small constructors
The eleven identical toggle definitions, the two colour pickers, the four size steppers and their
labels in Options.lua, and the 28 icon closures in Utilities.lua, are now produced by local
builder functions. Output is unchanged, which the specs pin; the colour pickers' unused alpha hex and
the dead "100" check went with it, as did Options.lua's unused locale handle.
Added -- guild version check (VersionCheck-1.0)
VersionCheck-1.0 is a hard dependency in all seven TOCs and in .pkgmeta's
required-dependencies. SmexyMats:OnEnable (AceAddon fires it at login, after every dependency
has loaded) registers the addon object with VC:RegisterCheck(self, <raw TOC Version>), falling
back to VC:Enable(self) on a VersionCheck that predates RegisterCheck. The version is passed raw
so an unsubstituted SmexyMats-v1.14.1 still marks a dev build. VersionCheck's own TOC declares
every flavour SmexyMats ships for, Retail included, so the hard dependency does not stop SmexyMats
loading anywhere. Tests/toc_spec.lua now asserts the dependency on every TOC.
Removed -- the "Report errors to chat" option and the code behind it
ProcessTooltip opened with a "cannot fetch item" chat block (with a LID de-duplication this
session first "fixed") and a Classic TradeSkillFrame / GetMouseFocus lookup. Neither could run:
the only caller, ModifyItemTooltip, calls ProcessTooltip only after ExamineObject has accepted
an item with a real id, so the option never printed anything in game. The specs that drove the
branch called ProcessTooltip directly, which is why 100% line coverage did not show it. Found in
the session self-audit (inbox 67e323f8), confirmed by Peer Review. Removed the branch, the option
and its ErrorReporting default, as ItemDB dropped chat error reporting; reversible if wanted.
Changed -- SmexyCore.lua made lint-clean
luacheck reported 138 warnings. Besides the fix above: the SetCurrencyToken hook was removed,
because its post-hook named Hook_SetCurrencyToken, which is defined nowhere, so the hook wrapped
the method and did nothing; JustTheTip and ExamineObject became file-local functions instead
of globals; the doubled ExamineObject(obj) and ExamineObject(obj) tests became single calls; and
unused locals, loop variables and trailing whitespace were dropped. C_AddOns and
GetAddOnMetadata were added to .luacheckrc and .luarc.json.
Fixed -- the locale files were pulled in with the XML-file element
SmexyLocales.xml loaded all seven Locales/*.lua files with <Include file=...>, which is the
element for an XML file; a Lua file is loaded with <Script file=...>. manifest_spec.lua caught
it on its first run (all seven reported as loaded by no manifest). Whether the client tolerated the
old form in game was not verified. The commented-out block of locales that do not exist
(itIT, ptBR, zhCN, zhTW) was removed with it.
This mod has no additional files

