promotional bannermobile promotional banner

Super Swing Timer

Super Swing Timer tracks white-hit swing timers across main hand, off hand, and ranged attacks. It is tuned for Classic/TBC mechanics such as next-melee-attack abilities, dual-wield desync, parry haste, extra-attack suppression, haste rescaling, and more
Back to Files

SuperSwingTimer v0.2.7

File nameSuperSwingTimer.zip
Uploader
AcidBombAcidBomb
Uploaded
Oct 26, 2026
Downloads
474
Size
2.7 MB
Flavors
ClassicClassic TBCTitan Reforged ClassicForever
File ID
9334837
Type
R
Release
Supported game versions
  • 3.80.2
  • 2.5.6
  • 2.5.5
  • 1.60.1
  • 1.15.9
  • 1.15.8

What's new

v0.2.7 - 2026-10-25

Added

  • Enterprise Diagnostics (SuperSwingTimer_Diag.lua, /stt diag / /sst diag):
    • New early-loaded diagnostics module. It is the first file in the TOC, so /stt diag / /sst diag remains reachable even if a library or later SuperSwingTimer module fails to load.
    • /sst diag prints a compact health report: client/build/project, addon version, DB version, class, bar/hook counts, aura API path, precise-clock status, event registration, render-loop state, FPS, addon memory, addon CPU, library status, SoD module status, slash registration, and captured errors.
    • /sst diag full prints every check, including informational rows that are hidden from the compact report. /sst diag errors prints captured signatures with stacks and counts. /sst diag export opens a copyable report window. /sst diag clear resets the ring buffer. /sst diag test runs live API probes (clock, spell info, aura path, metadata, glow) and reports pass/fail.
    • Error capture chains the existing seterrorhandler instead of replacing it, so Blizzard's normal error display and logging still run. Capture also listens for LUA_WARNING, ADDON_ACTION_BLOCKED, and ADDON_ACTION_FORBIDDEN.
    • Deduplicated ring buffer (40 signatures) with repeat counts, first/last timestamps, source tags (lua, warning, taint, init, slash, diag, glow), and stack excerpts. Identical failures cannot flood the report or the SavedVariables.
    • /sst diag profile [seconds] adds an opt-in per-hook profiler using debugprofilestart / debugprofilestop; it reports total time, per-frame average, share, and max for the top hooks. Profiling is completely inactive until requested.
    • Diagnostics never write to files. Export is an in-game EditBox with the report pre-selected for Ctrl+A / Ctrl+C.
  • LibCustomGlow-1.0 Integration (Lib/LibStub, Lib/LibCustomGlow-1.0, SuperSwingTimer_Glow.lua):
    • Added LibStub and LibCustomGlow-1.0 to the TOC in dependency order (LibStub before LibCustomGlow).
    • Added ns.Glow, a lifecycle-safe adapter with SetBar / SetIcon / StopAll / Refresh. Call sites may invoke it every frame; only active↔inactive transitions touch the library. SetBar supports autocast (default, best for thin bars) and proc; SetIcon uses ButtonGlow.
    • Every library call is pcall-guarded with failure latches, so a library/client mismatch cannot break swing rendering. Errors are recorded for /sst diag.
    • No-op fallback when LibCustomGlow is absent; the addon continues to render all bars and existing border pulses.
    • Bar effects:
      • Paladin Judgement of the Crusader bar: Autocast shine while the debuff is in its final 4-second window.
      • Rogue Slice and Dice bar: Autocast shine while the buff is in its final 4 seconds.
      • Warrior Overpower: Autocast shine on the main-hand bar for the full Overpower proc window.
      • Hunter Rapid Fire bar: Autocast shine while the buff is active and in its final 4 seconds.
      • Shaman weave: Autocast shine on the main-hand bar while a weave cast is in flight, using the existing safe/clip color (class color when safe, red when clipping).
    • Icon effect:
      • All six classes' buff/cooldown icon groups: ButtonGlow only in the urgent final 2 seconds, complementing (not duplicating) the existing 4-second border pulse.
      • Glow.SetIcon installs a one-time OnHide hook per icon, so an icon that expires, is hidden by its class toggle, or is hidden by Minimal Mode stops its glow immediately without per-class cleanup bookkeeping.
    • Deliberately avoids PixelGlow: its AM_29 mask asset is not referenced by either Classic Era 1.15.9 or TBC Anniversary 2.5.6 FrameXML, and registering a global replacement mask would affect other addons sharing LibStub. AutocastGlow (UI-ItemSockets), ProcGlow (proc flipbook atlases), and ButtonGlow (IconAlert) use assets verified on both clients.
    • Added /sst glow and /sst glow on|off to toggle the effects. Added DB_DEFAULTS.showGlowEffects = true; existing SavedVariables without the key are treated as enabled (no migration required).
    • Added /stt as a fifth alias for the existing command table, so /stt diag works exactly like /sst diag.

Changed

  • Initialization hardening (SuperSwingTimer.lua):
    • OnAddonLoaded now runs under xpcall with a traceback handler instead of pcall, so initialization failures keep a usable stack for /sst diag.
    • On init failure the addon records the error, routes it through the client error handler, prints a short /sst diag hint, and skips event registration instead of leaving a half-initialized addon receiving combat events.
    • Exposed ns.eventFrame so diagnostics can verify event registration and the render-loop state without duplicating frame bookkeeping.
  • OnUpdate hook labels (SuperSwingTimer_Hooks.lua, SuperSwingTimer_UI.lua, SuperSwingTimer_ClassMods.lua):
    • Added ns.RegisterNamedOnUpdateHook(name, hook, index) and a weak ns.OnUpdateHookNames map. Existing RegisterOnUpdateHook behavior is unchanged.
    • Named the core hook and all class hooks (paladin-seal, paladin-judgement, paladin-power, warrior, shaman, druid-form, druid-dots, hunter, rogue, power-fallback) so profiler output is readable.
  • TOC load order (SuperSwingTimer.toc):
    • SuperSwingTimer_Diag.lua → LibStub → LibCustomGlow → SuperSwingTimer_Constants.lua → Media\Media.xml → SuperSwingTimer_Glow.lua → engine/UI/class modules → SuperSwingTimer_SoD.lua (unchanged last position).
    • Diagnostics is first so it can capture and report a LibStub or LibCustomGlow load failure, not just failures in later SuperSwingTimer modules.
  • Documentation (README.md, SuperSwingTimer.toc):
    • Updated the current version to v0.2.7, added the diagnostics/glow command reference and compact-report example, added the LibCustomGlow texture-source row, and corrected the class-support debuff heights to the shipped 8px standard.
    • Added a 12,000+ downloads note (as of October 2026).

Performance

  • Idle bar reset guard (SuperSwingTimer_UI.lua): ResetBarDisplay now marks the bar with _sstResetDone; UpdateMeleeBar and UpdateRangedBar skip the full reset while the bar is already idle. The flag is cleared on the first swinging frame and set by every reset path (HideBars, ShowBars, ApplyVisibility, channel rendering, expiry), so labels/values cannot go stale. This removes repeated SetMinMaxValues, SetValue, label text/style, cast-overlay, cast-threshold, and spark-position work for inactive MH/OH/enemy/ranged bars while the render loop stays alive for power bars.
  • Library calls are transition-driven. ns.Glow.SetBar / SetIcon are safe to call from existing throttled/frame update paths: they compare against weak state maps and only start/stop LibCustomGlow when the desired state changes. Icon and bar glows also stop through one-time OnHide hooks, so hidden frames never leave an animation running and the throttled icon scans never need a per-class "dropped out of the active set" pass.
  • Profiling is opt-in and makes no timing calls when off: ns.OnUpdate checks a single ns.Diag.profile.active flag and otherwise runs the original loop unchanged.
  • No per-frame xpcall: error capture uses the client's seterrorhandler chain, so normal rendering keeps its original call shape. xpcall is used only for one-time initialization; slash/config failures use pcall and are recorded in the diag buffer.
  • No new per-frame color allocations: shared GLOW_GOLD and a per-bar cached Rogue glow color table replace per-call literals.

Fixed

  • Init failure could leave the addon half-initialized: RegisterEvents() previously ran even when OnAddonLoaded threw. It now runs only after a successful initialization.
  • Init error stacks were lost: the old pcall + tostring(initErr) path discarded the traceback. The new xpcall path preserves it and records it for diagnostics.
  • Diagnostics reachability: the diagnostics module and a minimal /sst + /stt fallback are registered at file load, so /stt diag / /sst diag is available even if a later addon file errors before the full command table is built. The main dispatcher replaces the fallback once it loads.
  • Hunter Auto Shot could be missed on Classic Era / TBC Anniversary, flashing the MH bar after a ranged swing: ns.AUTO_SHOT_NAME = ns.GetSpellInfo(75) or "Auto Shot" or "Shoot" made the "Shoot" fallback unreachable ("Auto Shot" or ... always yields the first string), and the only matcher accepted spell ID 75, "75", or the single client-resolved name. The supported clients disagree on whether CLEU and UNIT_SPELLCAST_* payloads carry the numeric ID or the localized name, and spell 75 resolves under different names across builds, so an unrecognised token fell through. A miss is not cosmetic: HandleSpellcastSucceeded skips the MH/OH restart only for a recognised Auto Shot (skipMeleeReset), so the miss restarted melee and showed the MH bar right after each ranged swing. ns.IsAutoShotSpell now accepts the numeric ID, its numeric string, the client-resolved localized name, and an explicit ns.AUTO_SHOT_NAMES alias set ("Auto Shot", "Shoot").
  • Auto Shot could disappear or fail to display when a hunter cast ended before the red zone: ShouldKeepHunterRangedTimerActive anchored its hold to the moment the cast ended (a fixed 1.0s window) instead of the ranged cycle end, so a Steady Shot / Arcane Shot / Multi-Shot finishing more than a second ahead of cycle end tore the ranged timer down before the shot fired. The hold is now anchored to lastSwing + duration plus latency/grace, so Auto Shot is preserved wherever in the cycle the cast finished, including a cast landing at the very end. The anchor re-targets automatically when a new cycle starts and cannot hold an idle/reset timer.
  • Interrupted or failed casts left stale cast identity behind: HandleSpellcastInterruptedOrFailed stopped clearing currentCastSpellId, currentCastStartTime, lastResolvedHunterCastToken, and lastResolvedHunterCastAt (and only ran for hunters), so a stale token survived into HandleSpellcastSucceeded, which re-attributed it to the next successful cast and fabricated a red-zone Steady Shot that never landed. Cleanup is restored for every class.

Internal

  • Headless tests (SuperSwingTimer_Tests.lua, run_tests.lua):
    • Expanded the suite from 123 to 146 tests with a new SST-Diag group covering: API presence, live error-handler capture, LUA_WARNING event capture, error dedupe and count semantics, SST-vs-external attribution, ring-buffer cap, slash consumption, compact/full/error report construction, error text inclusion, clear semantics, glow fallback, glow start/stop transition counting, icon and bar hide-stop via the OnHide hooks, the reset-guard flag, the Glow DB default, /sst glow toggling, the /stt alias, LibStub/LCG library reporting, idempotent error-handler installation, profiler stats, self-test probes, and export construction.
    • Added harness mocks for seterrorhandler, debugstack, debugprofilestart/debugprofilestop, GetBuildInfo, GetFramerate, addon memory/CPU APIs, C_AddOns.GetAddOnMetadata, project constants, UnitAura, event registration/IsEventRegistered, SetMultiLine, SetToplevel, and Raise.
    • Added SuperSwingTimer_Diag.lua and SuperSwingTimer_Glow.lua to the headless load order and to the TOC load-order assertions (LibStub before LCG, Diag before Constants, Glow before ClassMods).
    • Expanded the suite from 146 to 150 tests with Hunter regression coverage for Auto Shot alias matching ("Auto Shot", "Shoot", numeric ID and numeric string), cast-identity cleanup on interrupt/fail, and the cycle-anchored ranged hold (including that an idle/reset timer is never held).
  • CI (.github/workflows/luac.yml):
    • Added the new files plus SuperSwingTimer_SoD.lua, SuperSwingTimer_Tests.lua, and Media/SuperSwingTimer_Media.lua to the syntax check.
    • Added a headless test step (lua5.1 run_tests.lua, falling back to lua run_tests.lua) so the suite runs on every push/PR, not just locally.

Notes

  • No DB schema migration: showGlowEffects is a new optional key; nil is treated as enabled. Existing SuperSwingTimerDB versions remain valid.
  • Pending in-game verification: this build has not yet been tested on live classic_era, classic_anniversary, or classic_titan clients. The Hunter Auto Shot and cast-window changes are covered by headless tests only; bars, glow, and CLEU-driven behaviour still need an in-game pass.
  • SoD load order is unchanged (SuperSwingTimer_SoD.lua remains last): class merges run from ns.InitClassMods() on ADDON_LOADED, after every file has loaded.
  • LibCustomGlow asset verification: AnimateTexCoords (UIParent.lua:593), Interface\SpellActivationOverlay\IconAlert, Interface\SpellActivationOverlay\IconAlertAnts, Interface\ItemSocketingFrame\UI-ItemSockets, UI-HUD-ActionBar-Proc-Start-Flipbook, UI-HUD-ActionBar-Proc-Loop-Flipbook, CreateTexturePool, CreateFramePool, CreateMaskTexture, and the flipbook animation setters were confirmed against classic_era (1.15.9.70003), classic_anniversary (2.5.6.70006), and classic_titan (3.80.2.69815) UI source.

This mod has no additional files