promotional bannermobile promotional banner

TOGTools

ToGTools is a convenient place to aggregate one off tools that don't make sense to have it's own addon.

File Details

TOGTools-v0.3.3

  • R
  • May 19, 2026
  • 1.93 MB
  • 16
  • 12.0.1+7
  • Retail + 3

File Name

TOGTools-TOGTools-v0.3.3.zip

Supported Versions

  • 12.0.1
  • 12.0.0
  • 11.2.7
  • 5.5.3
  • 4.4.2
  • 3.4.5
  • 2.5.5
  • 1.15.8

Changelog

[v0.3.3] (2026-05-18) - NamePrefix /say Channel + TBC /logout Taint Fix

Bug Fixes

  • NamePrefix did not fire on TBC / Anniversary 1.15.x in the v0.3.2 working tree — During pre-release work toward this version the Classic hook was experimentally rewritten twice — first to wrap the global SendChatMessage, then to wrap the global ChatEdit_SendText (Name2Chat's pattern). Both wraps installed cleanly (verified with a temporary install-time print) but neither fire-time path was ever entered for user-typed chat on TBC / Anniversary 1.15.x — confirmed empirically with a temporary fire-time print inside ModifyMessage. On those clients ChatFrameEditBoxMixin:OnEnterPressed dispatches via self:SendText() using a captured local reference, so addon-level global reassignment never intercepts user chat. On Classic Era 1.15.x the global ChatEdit_SendText path is still active and did fire during testing, which initially masked the TBC/Anniversary regression. Restored v0.3.2's per-editbox SetScript("OnEnterPressed", ...) wrap that walks ChatFrame1EditBox..ChatFrameN.EditBox via NUM_CHAT_WINDOWS — this is the only entry point that reliably fires on every Classic flavor. Verified empirically on TBC (Anniversary, Wowhead Looter interface 20505) and Classic Era (interface 11508). Location: Modules/NamePrefix/NamePrefix.lua.
  • Per-editbox OnEnterPressed wrap tripped ADDON_ACTION_FORBIDDEN on /logoutSetScript("OnEnterPressed", addonFn) leaves an addon-Lua handler on the C call stack whenever Enter is pressed in a chat editbox. When the user types /logout, the original OnEnterPressed we invoke from inside our handler runs through ChatEdit_SendTextChatEdit_ParseText → slash-command dispatcher → protected Logout(). Because addon Lua is still on the stack, taint propagates the whole way and the secure-execution layer blocks Logout() on TBC and Anniversary. Fix: invoke the captured original script via securecall(origScript, editBox, ...) instead of a direct call. securecall is the canonical taint-clearing dispatcher (see WoWWiki "Secure Execution and Tainting") — it saves and clears the current taint flag around the call so ParseText → slash-handler → Logout() runs untainted regardless of what sits on the C stack above. Belt-and-suspenders: ApplyPrefix already early-exits on a leading /, so the editbox text is never modified for slash commands and its GetText result stays untainted on the secure dispatch path. Location: Modules/NamePrefix/NamePrefix.lua.

New Features

  • NamePrefix Say (/s) channel toggle — New checkbox at the top of the NamePrefix tab's Active Channels list. When enabled, the configured nickname is prepended to outgoing /say messages alongside the existing guild / officer / party / raid / instance toggles. SAY case added to the ApplyPrefix chatType dispatch table; say = false added to DB_DEFAULTS.global.namePrefix. Location: Modules/NamePrefix/NamePrefix.lua, GUI/NamePrefixTab.lua, TOGTools.lua.
  • Account-wide debug flag + addon:Debug() helper — New Debug section in the Settings panel (ESC → Options → Addons → TOG Tools, or right-click the minimap button) with a Verbose debug output toggle. Stored at db.global.debug, default false. addon:Debug(msg) prints |cffFF8000TOGTools|r <msg> only when the flag is true; modules call it for hook-install confirmations and fire-time diagnostics that should be silent in normal play. NamePrefix uses it for two diagnostics: the install confirmation NamePrefix: hook installed (OnEnterPressed xN) (one-shot at addon load — requires /reload to re-fire after toggling the flag) and the per-send fire line NamePrefix fire: chatType=X prefixed=true/false (no message echo, takes effect on the next chat send without /reload). Location: TOGTools.lua, GUI/Settings.lua, Modules/NamePrefix/NamePrefix.lua.

Improvements

  • NamePrefix channel defaults are now all falsesay, guild, officer, party, raid, instance all default to false in DB_DEFAULTS.global.namePrefix. Previously guild and officer defaulted to true. Fresh installs now opt-in per channel; existing saved settings are unaffected because AceDB merges defaults without overwriting saved keys. Location: TOGTools.lua.
  • .luarc.json / TOGTools.code-workspace — Added securecall, rawget, rawset to diagnostics.globals for Lua LSP coverage of the new hook code and the v0.3.2 account-wide migration block.

[v0.3.2] (2026-05-17) - NamePrefix BCC / Anniversary Fix

Bug Fixes

  • NamePrefix did nothing on BCC and Anniversary (Classic Era 1.15.x) — v0.3.0 relocated the Classic hook from ChatEdit_SendText to the global ChatEdit_OnEnterPressed to avoid tainting OPie's securecall(ChatEdit_SendText, ...) macrotext dispatch. On modern Classic builds (BCC, Anniversary 1.15.x) the chat editbox's OnEnterPressed script is the ChatFrameEditBoxMixin:OnEnterPressed method, NOT the global — so the wrapped global never fired and outgoing messages went un-prefixed. Replaced the global-wrap with a per-editbox SetScript("OnEnterPressed", ...) wrap that walks ChatFrame1EditBox..ChatFrameN EditBox (NUM_CHAT_WINDOWS) and prepends ModifyMessage to each editbox's existing script. This catches both the legacy ChatEdit_OnEnterPressed script binding and the modern mixin-method binding without touching any global function reference. Verified safe for OPie: the wrap only touches user-visible ChatFrameN editboxes, not OPie's synthetic Rewire editboxes, and never replaces ChatEdit_SendText or ChatFrameEditBoxMixin.SendText. Confirmed against Name2Chat's own analysis that EventRegistry "ChatFrame.OnEditBoxPreSendText" is not fired on Classic 1.15.x despite EventRegistry being backported — the existing gv.isRetail120Plus gate stays correct. Location: Modules/NamePrefix/NamePrefix.lua.
  • .luarc.json — Added NUM_CHAT_WINDOWS to diagnostics.globals.

Improvements

  • MainWindow remembers last-selected tab — Opening the main window (minimap button, /togt, or Toggle() with no arg) now restores the tab that was active the last time the user closed the window. Stored as db.char.lastTab; per-character so different alts can have different defaults. Resolution order in MainWindow:Open(tabKey) is: explicit caller arg → db.char.lastTab (if the module still exists) → alphabetically first tab. Slash commands that pass an explicit tab (/togt np, /togt mb, etc.) still win, and clicking a different tab updates the saved value via OnGroupSelected. Location: GUI/MainWindow.lua, TOGTools.lua.
  • NamePrefix is now account-wide — Moved namePrefix from DB_DEFAULTS.char to DB_DEFAULTS.global so the nickname, format string, per-channel toggles, and hideIfCharName are configured once and shared across every alt. Toons that shouldn't self-prefix rely on hideIfCharName (now defaulting to true) to suppress the prefix when the nickname matches the character's own name. One-shot migration in Ace:OnInitialize copies any pre-upgrade db.char.namePrefix with a non-empty nickname into db.global.namePrefix the first time an upgraded character logs in (only if the global table is still at defaults); subsequent alts inherit the now-global config. Leftover per-char entries are left in place since AceDB ignores keys not in the defaults. Location: TOGTools.lua, Modules/NamePrefix/NamePrefix.lua, GUI/NamePrefixTab.lua.
  • NamePrefix defaulthideIfCharName now defaults to true in DB_DEFAULTS.global.namePrefix. New accounts no longer self-prefix on the character whose name matches the configured nickname (the common case where the nickname IS the main's name). Existing saved-variables are unaffected. Location: TOGTools.lua.

[v0.3.1] (2026-05-06) - TBC Compatibility Fix

Bug Fixes

  • Addon Load tab crashed on TBC (and Wrath/Cata/Mists/Retail)GetNumAddOns, GetAddOnInfo, IsAddOnLoaded, GetAddOnMemoryUsage, and UpdateAddOnMemoryUsage were called as bare globals, but TBC+ moved them all into C_AddOns.*. Added five compat locals at the top of the module that prefer C_AddOns.* when available and fall back to the bare globals for Classic Era, matching the pattern already used elsewhere in the addon. Location: Modules/AddonLoad/AddonLoad.lua.

[v0.3.0] (2026-05-04) - Mailbox Stale Watcher

New Features

  • Mailbox Stale Watcher — New tab (/togt mail / mb / mailbox) tracking mail expiration across every alt on the account so mail never gets auto-deleted at the 30-day mark for an unvisited character. Captures a per-alt inbox snapshot on each MAIL_INBOX_UPDATE event, stamping absolute expiresAt = GetServerTime() + (daysLeft * 86400) per item so the time-remaining math stays accurate even when the alt does not re-visit a mailbox for several days (same content-derived-timestamp pattern TOGPM uses). Login chat alert prints once when any alt has mail expiring within the configured threshold (default 2 days, slider-configurable 1–7 in the tab). Tab lists each alt with a row-per-mail breakdown of expiring items (sender, subject, time remaining), snapshot age display, and a - stale flag for snapshots older than 7 days. Live-refresh on MAIL_INBOX_UPDATE while the tab is active, so opening a mailbox in-game while the Mailbox tab is showing updates the rows in real time without forcing a manual tab-switch (addon.MainWindow:Refresh() is called from the engine's event handler when addon.MainWindow.activeTab == "mailbox"). Account-wide storage in db.global.mailbox.snapshots[Name-Realm] so every alt's data is visible from any character, full Name-Realm keys throughout to prevent collisions across connected-realm clusters. Location: Modules/Mailbox/Mailbox.lua, GUI/MailboxTab.lua.

Improvements

  • AceDB schema — Added global namespace to DB_DEFAULTS with mailbox = { thresholdDays, snapshots }. Account-wide scope so cross-alt mail data persists across every physical realm in a connected-realm cluster (per-db.realm would silo each physical realm of the cluster into a separate notes table — wrong for our use case). Location: TOGTools.lua.
  • Slash commands/togt mb / /togt mail / /togt mailbox open the Mailbox tab directly; help output updated. Location: SlashCommands.lua.
  • .luarc.json — Added GetInboxNumItems, GetInboxHeaderInfo, and ChatEdit_OnEnterPressed to diagnostics.globals so the new mail API calls and the relocated NamePrefix hook target resolve cleanly under the Lua LSP.
  • TOC files — All six TOC variants (Vanilla, BCC, Wrath, Cata, Mists, Mainline) updated to load Modules\Mailbox\Mailbox.lua and GUI\MailboxTab.lua after the AddonLoad pair.

Bug Fixes

  • NamePrefix broke OPie macrotext ring entries (custom mounts, /cast macros) — On Classic clients, NamePrefix wrapped the global ChatEdit_SendText to enable pre-send text modification. OPie's Libs/ActionBook/Rewire.lua dispatches each line of macro ring entries via securecall(ChatEdit_SendText, box, false). Replacing the global with a wrapper created in our (insecure) addon loading context tainted that function reference, so OPie's secure dispatch path picked up taint when calling it — failing for any ring slot delivered as macrotext (custom mount macros, /cast slots), while direct spell-cast slots that bypass macrotext (most tradeskills) kept working. Fix: relocated the Classic hook target from ChatEdit_SendText to ChatEdit_OnEnterPressed, which is upstream of ChatEdit_SendText in the user-typed Enter-key flow but is not on OPie's Rewire dispatch path. The user-facing prefixing behavior is unchanged. The replaced-global pattern itself stays (hooksecurefunc fires post-call, so it can't be used to modify text before send); we just no longer taint the function OPie depends on. Location: Modules/NamePrefix/NamePrefix.lua.

[v0.2.0] (2026-05-04) - Addon Load Monitor

New Features

  • Addon Load Monitor — New tab (/togt al) showing every installed addon's memory usage, load status, and load timing. Sortable by name, memory, load time, and status (failures-first when descending). Summary bar shows totals (loaded / failed / disabled / on-demand) and total memory. Requires the !TOGT companion addon for full timing coverage across all addons. Location: Modules/AddonLoad/AddonLoad.lua, GUI/AddonLoadTab.lua.
  • !TOGT companion integration!TOGT (companion addon) added as a required dependency. Loads before all other addons at the very start of the loading screen (the ! prefix sorts before all letters) and records load order and per-addon offset into the TOGToolsEarlyData global. The Addon Load Monitor reads it at display time and shows a status-bar indicator (!TOGT active / !TOGT missing).
  • Shared addon.RowList component — New file GUI/RowList.lua, ported and trimmed from FastGuildInvite's GUI/RowList.lua. Reusable sortable-row list for any tab that needs a tabular data view: brand-colored clickable header bar, click-toggle ASC/DESC sort with per-column sortKey/sortDescDefault/sortable/gapBefore opts and tie-break on entry.name, alternating row banding, virtual-scroll pool that grows with the parent's height, custom Blizzard-textured scrollbar, mouse-wheel scroll. Cells use SetWordWrap(false) + SetMaxLines(1) and anchor LEFT/RIGHT to the parent so column layouts compact elastically when the user shrinks the window — no row-wrap. Public API: :New(parent, opts), :SetData(arr), :SetSort(key, desc), :Refresh(), :Detach(). Registered to all six TOC files after Compat.lua, before MainWindow.lua.
  • Compat.lua shared GUI helpersaddon.Tooltip.Owner / AnchorFrame (smart anchor flipping based on screen half), addon.AceGUIFrameScripts (leak-safe raw frame scripts that restore prior handlers on pooled-widget release), addon.GUI.AttachTooltip, addon.GUI.MakeColumnHeader, addon.GUI.ApplyMinResize, addon.GUI.DetachPool. Used by every tab.

Bug Fixes

  • Load times reporting 0.000sGetTime() is frame-locked, so every ADDON_LOADED event fired in the same loading-screen frame returned the same timestamp. Per-addon deltas collapsed to zero. Switched the timing capture in !TOGT.lua and the fallback capture in Modules/AddonLoad/AddonLoad.lua to debugprofilestop(), which has sub-millisecond precision. Offsets are stored in seconds (ms / 1000) so downstream consumers are unchanged.
  • Load Time column sort produced random-looking order — The sort comparator in GUI/AddonLoadTab.lua was reading row.offset (cumulative seconds since the first event) instead of row.loadTime (per-addon delta). Because offset is monotonic with load order, clicking the header effectively sorted by load order regardless of direction. Comparator now reads row.loadTime.
  • Addon Load tab wrapped to multiple lines on horizontal shrink — The tab used AceGUI Flow with widget:SetWidth(...) per cell, so when the user shrunk the window narrower than the column-width sum AceGUI moved cells to a new line and the layout fell apart. Replaced the row-rendering path with addon.RowList, whose anchor-based cells truncate instead of wrapping. The window's minWidth was tightened from 640 to 520 now that compaction is graceful.
  • Tab status bar leaked between tabsMainWindow:DrawTab now resets the status text to the version string before delegating to the tab module, so a tab that overrides the status (e.g. Addon Load showing !TOGT active/missing) doesn't bleed that text into the next tab the user opens.
  • Tab content didn't reflow on tab switchMainWindow:ApplyTabSize now calls f:DoLayout() after sizing, so when switching between tabs whose WINDOW_SIZE differs, the new tab's content reflows immediately instead of inheriting stale layout.

Improvements

  • Addon Load tab column widths tightened — Status reduced from 175 → 85 px (fits "Wrong Version"); Memory reduced from 110 → 65 px (fits "999.9 MB"); Load Time reduced from 110 → 60 px. The auto-width Addon Name column reclaims the freed space. RowList's SCROLLBAR_GUTTER reduced from SCROLLBAR_WIDTH + 6 to SCROLLBAR_WIDTH + 2 so the rightmost column sits ~5 px from the scrollbar. Status column gets gapBefore = 5 to break the visual collision between right-justified Load Time text and left-justified Status text.
  • Sort indicator removed from active column headerRowList:_updateHeaderText no longer appends a glyph (v / ^) to the active sort column; WoW's default font doesn't render unicode triangles cleanly and ASCII letters look like typos. Click affordance is communicated via the column tooltip.
  • AceGUI pool-bleed protectionRowList:Detach() orphans the row pool, header, and scrollbar to UIParent on host-widget release; a _detached guard on :Refresh() makes sure a recycled host doesn't trigger a pool grow that would re-attach rows into the next addon's widget. Wired via body:SetCallback("OnRelease", ...) in GUI/AddonLoadTab.lua.
  • .luarc.json updated — Added debugprofilestop to diagnostics.globals in both TOGTools/.luarc.json and !TOGT/.luarc.json so the new timer call resolves cleanly under the Lua LSP.

[v0.1.0] (2026-05-04) - Initial Release

New Features

  • Project scaffolding — TOC files for all WoW versions (Vanilla 11508, TBC 20505, Wrath 30405, Cata 40402, Mists 50503, Retail 110207/120001/120000), .pkgmeta with BigWigs packager config, .luarc.json (Lua 5.1 LSP), .markdownlint.json, and .github/workflows/release.yml for tag-triggered CurseForge releases.
  • Core addonTOGTools.lua: AceAddon-3.0 instance with AceConsole-3.0, AceEvent-3.0, AceHook-3.0 mixins; AceDB-3.0 schema (char scope); version detection flags (gv.isVanilla, gv.isTBC, gv.isWrath, gv.isCata, gv.isMists, gv.isClassic, gv.isRetail, gv.isRetail120Plus).
  • Slash commandsSlashCommands.lua: all /togt command registration and handling in a dedicated file, separate from core addon logic. Subcommands: /togt (toggle window), /togt np (Name Prefix tab), /togt settings (open settings), /togt vc (version check).
  • Tabbed main windowGUI/MainWindow.lua: dynamic AceGUI Frame + TabGroup; tabs auto-populate from addon.modules sorted alphabetically by label; per-tab locked/unlocked window sizing via WINDOW_SIZE; ESC-to-close proxy; position persistence via AceDB.
  • Name Prefix moduleModules/NamePrefix/NamePrefix.lua + GUI/NamePrefixTab.lua: wraps ChatEdit_SendText (Classic) or hooks EventRegistry (Retail 12.0+) to prepend a configurable nickname to outgoing chat messages. Settings: enable/disable, nickname, format string with live preview, per-channel toggles (Guild, Officer, Party, Raid, Instance, custom channel), skip-exclamation option, suppress-if-char-name option. Per-character DB scope. Skips messages beginning with / (slash commands/macros) unconditionally.
  • Minimap buttonGUI/MinimapButton.lua: LibDataBroker-1.1 launcher + LibDBIcon-1.0 registration. Left-click toggles the main window; right-click opens the native addon settings panel. Icon: textures/ToGTools_PH_MMB.tga. Button show/hide state and position persisted in DB.char.
  • Addon settings panelGUI/Settings.lua: AceConfig-3.0 options table registered under ESC → Interface → Addons → TOG Tools (native Blizzard panel). addon:OpenSettings() uses Settings.OpenToCategory (Classic Era 1.15+ / Retail 10+), InterfaceOptionsFrame_OpenToCategory (older builds), or InterfaceOptionsFrame:Show() as a final fallback — detected by API presence, not version flag.
  • VersionCheck-1.0 integrationVC:Enable(Ace) called on all non-Retail versions in OnInitialize; /togt vc broadcasts a guild-wide version check and prints responses after 21 seconds.
  • Embedded libslibs/LibDataBroker-1.1.lua, libs/LibDBIcon-1.0.lua (single-file embeds, copied from TOGProfessionMaster).
  • MIT LicenseLICENSE file added; referenced in .pkgmeta via license-output.
  • CurseForge project — Project ID 1533830 set in .pkgmeta and all TOC files.
  • Governance files.github/copilot-instructions.md and CLAUDE.md with full project rules (module pattern, commit/tag process, changelog format, HTML doc rules, no-tag rule).

Bug Fixes

  • Name Prefix not reaching other playershooksecurefunc fires after SendChatMessage has already been called. Fixed by wrapping ChatEdit_SendText directly (local orig = ...; ChatEdit_SendText = function(...) ... return orig(...) end) so the prefix is applied before the message is sent. Location: Modules/NamePrefix/NamePrefix.lua.
  • Macros/slash commands being prefixed — Added an unconditional early-return in ModifyMessage when the message starts with /. Location: Modules/NamePrefix/NamePrefix.lua.