Unbuffed - Nameplates

Do you want to buff every person you come across? Use this addon to instantly see if any player around you needs (your) buffs.
Back to Files

v1.1.0

File nameUnbuffed-v1.1.0.zip
Uploader
GarufoGarufo
Uploaded
Oct 9, 2026
Downloads
3
Size
28.2 KB
Flavors
Classic TBCForever
File ID
9110590
Type
R
Release
Supported game versions
  • 2.5.5
  • 1.60.1

What's new

Unbuffed

v1.1.0 (2026-10-09)

Full Changelog Previous Releases

  • Choose where the icons attach, and rework the settings panel
    The icon row can now sit right of the level text (the default), left of the health
    bar, centered under the health bar, or at a custom X/Y from the plate's centre. The
    three presets follow the plate's own parts, found the way FlareUI finds them on
    Forever (UnitFrame.HealthBarsContainer.healthBar and UnitFrame.PlayerLevelDiffFrame),
    and fall back level box -> health bar -> plate when a plate lacks one. The X/Y
    sliders appear only for Custom. Profiles saved with the old side setting are
    migrated: RIGHT and LEFT map to the nearest preset, and CENTER to Custom with its
    offsets unchanged.
    The settings panel is now grouped into sections inside a scroll frame, with a live
    mock-nameplate preview drawn by the same placement code the real plates use, a
    greyed-out expiry threshold when its toggle is off, an icon spacing slider, and a
    two-click Reset for position and look. Reset is not a popup, because a StaticPopup
    shown from addon code can hang the client in Gamepad mode.
    Also:
    • Fortitude is tracked on a brand-new profile, seeded once rather than through
      copyDefaults, which merges the tracked list by index.
    • SavedVariables are adopted once, at ADDON_LOADED. The VARIABLES_LOADED and login
      re-adoption was written for a beta client bug that has since been fixed.
    • /ub check prints the settings state first, without needing a target.
    • The options panel's build now sits inside the refreshing guard.
      Co-Authored-By: Claude Sonnet 5.5 noreply@anthropic.com
  • Add the logo and the CurseForge project ID
    The logo (512 and 256 px PNGs, plus the SVG it was drawn from) matches the tile
    style of the other addons. It lives under .github, which .pkgmeta already keeps
    out of the packaged zip.
    X-Curse-Project-ID points the packager's CurseForge upload at the project page.
    Co-Authored-By: Claude Sonnet 5.5 noreply@anthropic.com
  • Re-adopt SavedVariables at login, and report when they never arrive
    The instrumentation answered it, and it was neither of the things I had been
    fixing: at ADDON_LOADED UnbuffedDB is empty. The settings are not being clobbered
    after loading -- they never load. Every session starts from defaults, saves the
    session's edits on the way out, and discards them on the way back in, which is
    exactly "loses its settings on every reload".
    So ADDON_LOADED is no longer the only chance to pick them up. Adopting the global
    is now a function, and PLAYER_LOGIN calls it again if the global is no longer the
    table we adopted -- i.e. if the real saved values landed after us. This client has
    already been caught resolving things later than the Classic ones do; the key
    binding set was unavailable at login for the same reason.
    If they genuinely never arrive, that is not something the addon can fix, so /ub
    check now says which it is: it snapshots UnbuffedDB at both ADDON_LOADED and
    PLAYER_LOGIN, prints the type and key count at each, and states plainly whether
    the values turned up late or not at all.
    Co-Authored-By: Claude Opus 5 noreply@anthropic.com
  • Stop the options panel writing defaults back over loaded settings
    Settings were still being lost, though not all of them -- side and yOffset came
    back fine while iconSize and xOffset reverted to defaults. That pattern rules out
    the save path and points at something writing over individual values after they
    load.
    Two ways that could happen, both now closed:
    A widget resync is a READ, but it triggers writes. A slider's SetValue fires
    OnValueChanged, and a dropdown's GenerateMenu can re-invoke its setter; both then
    call set() with whatever the widget was showing. Refreshes now run under a flag
    that makes those setters no-ops, so resyncing can never write.
    And the panel could still be built before the real db existed. ns.db is a stand-in
    full of defaults until ADDON_LOADED, and the Settings frame may call OnRefresh
    during registration -- which would build every widget against that stand-in and
    bake defaults in. refreshPanel now refuses to do anything until ns.dbReady.
    If it somehow persists, /ub check now settles it in one line: ADDON_LOADED
    snapshots what arrived from disk before anything touches it, and check prints that
    next to the live values, flagging any that differ.
    Co-Authored-By: Claude Opus 5 noreply@anthropic.com
  • Flag buffs that are about to expire
    A tracked buff with less than the warning threshold left (5 minutes by default)
    now draws too: the same icon, tinted amber with the minutes remaining on it, so
    "running out" reads differently at a glance from "never cast".
    HasBuff returns the aura record alongside its verdict, and ns.AuraRemaining turns
    that into seconds left. It returns nil for a permanent buff (expirationTime 0) and
    for any client that won't hand the number over -- and nil is never treated as
    "about to expire", the same rule that keeps an unreadable buff from being drawn as
    missing.
    Threshold is a slider (1-30 minutes) rather than a hardcoded 5.
    Presets moved to three columns. Nine of them in five rows wasted enough height
    that the new controls would have pushed the bottom of the panel under the Close
    button again.
    /ub check now reports the remaining time per buff, and whether ns.db is actually
    the SavedVariables table -- see the next commit for why that matters.
    Co-Authored-By: Claude Opus 5 noreply@anthropic.com
  • Build the options panel on first show, not at load
    Saved settings looked lost after /reload. They were not: SavedVariables on disk
    held every tuned value (side=CENTER, iconSize=23, yOffset=-25). The panel was the
    problem, and the stand-in ns.db was the cause.
    A Settings canvas category needs a frame at registration, so the whole panel was
    built during load -- before ADDON_LOADED, so against the stand-in defaults rather
    than the loaded values. Widgets that evaluate a callback while being constructed
    therefore captured defaults, and MenuUtil's dropdown, which generates its menu at
    setup and again on GenerateMenu, can write its remembered selection back: the
    saved "CENTER" overwritten by the stand-in's "RIGHT".
    A canvas category needs a frame up front, not a populated one. The layout now
    lives in buildPanel(), run once from the panel's first show, by which point ns.db
    is the real SavedVariables table. That removes the whole class rather than the one
    widget -- the same lazy-build shape GaruCombatText's options already use, which is
    why they never had this.
    Also defines OnRefresh/OnCommit/OnDefault: the modern Settings frame drives canvas
    panels through those rather than the legacy refresh field.
    The stand-in ns.db stays as a guard against indexing nil early, but nothing
    depends on its values now.
    Co-Authored-By: Claude Opus 5 noreply@anthropic.com
  • Add a centered icon-row position
    Third option beside left and right: the row anchors CENTER-to-CENTER on the
    nameplate, so at offset 0, 0 it sits over the player's name.
    The offsets mean something slightly different per position, deliberately. Beside
    the plate, xOffset is a GAP -- "distance away from the plate" -- so its sign is
    flipped for LEFT and a negative value pulls the row back over the plate on either
    side. Centered there is no gap to describe, so xOffset is a plain nudge, positive
    right and negative left. A hint under the dropdown says so.
    The db key stays "side" even though CENTER isn't one; renaming it would orphan
    every saved setting for the sake of a word.
    Co-Authored-By: Claude Opus 5 noreply@anthropic.com
  • Tighten the options layout and allow a negative horizontal offset
    The panel reserved room for four custom-buff rows whether or not any existed,
    leaving a hole under "No custom buffs added" and pushing the bottom controls --
    the position dropdown and Run diagnostics -- down behind the Close button.
    Everything below the custom list now lives in a container frame that
    rebuildCustomList repositions to sit just under the list, however long it is. The
    widget helpers take an optional parent so they can be built into it. With an empty
    list the block starts 68px higher and the last control lands at -576 instead of
    -642, well clear of the bottom edge.
    Horizontal offset now runs -60..60 rather than 0..60. Negative pulls the icon row
    back over the nameplate instead of away from it, and since anchorRow flips the
    sign with the chosen side, it reads the same whichever side the row is on.
    Co-Authored-By: Claude Opus 5 noreply@anthropic.com
  • Don't overwrite the Settings category ID with the addon name
    Settings.OpenToCategory forwards to C_SettingsUtil.OpenSettingsPanel on 12.x,
    which takes a numeric category id and throws on a string. Overwriting category.ID
    with "Unbuffed" made category:GetID() return that string, so /unbuffed raised
    "bad argument #1 to 'OpenSettingsPanel'" and never opened the panel.
    The override is a widespread idiom (Ace3 still ships it) and exists so other
    addons can open a panel by name, which worked back when OpenToCategory accepted a
    string. It no longer does, so the line buys nothing here and costs the addon its
    own slash command.
    Co-Authored-By: Claude Opus 5 noreply@anthropic.com
  • Fix nil ns.db while the options panel is being built
    MenuUtil generates a dropdown's menu the moment SetupMenu runs, so the isSelected
    callback fired during Options.lua's main chunk -- before ADDON_LOADED, and so
    before SavedVariables (and ns.db) existed. Indexing it threw on load.
    Fixed at the root rather than at the call site: ns.db is now seeded with a copy of
    the defaults when Core.lua loads, and ADDON_LOADED swaps in the real SavedVariables
    table. A Settings canvas panel has to be built during load so it can be registered,
    so any widget that evaluates a callback at construction hits the same window --
    seeding closes the whole class instead of the one dropdown.
    The panel resyncs against the loaded values on show, so a saved non-default side
    still paints correctly the first time the panel is opened.
    GaruCombatText uses the same MenuUtil conversion but is not affected: its options
    window is built lazily in build(), reached only via /gct, long after ADDON_LOADED.
    Co-Authored-By: Claude Opus 5 noreply@anthropic.com
  • Unbuffed 1.0.0: flag friendly nameplates missing a tracked buff
    Pick the buffs you care about; any friendly player on screen who is missing one
    gets a small row of those icons beside their nameplate. A fully buffed player
    shows nothing, so every icon visible is something to cast.
    Two things shape the design.
    Buffs are matched by NAME, not spell id. On Vanilla-era content a buff is a
    family of per-rank ids -- Power Word: Fortitude alone is 1243, 1244, 1245, 2791,
    10937, 10938 -- so a single id would match one rank and report everyone else as
    unbuffed. Names also let a preset carry the group version, since somebody under
    Prayer of Fortitude is not missing Fortitude. An id may only ever prove that a
    buff is PRESENT; absence is always decided by name.
    Reading other players' auras is restricted on Midnight. Iteration throws while
    auras are secret; GetUnitAuraBySpellID survives combat but only for whitelisted
    ids (which is exactly the long-term raid buffs this addon is for); and a refusal
    looks like "returned nothing" rather than an error. C_Secrets is used to ask
    permission first, so a genuine "not buffed" can be told apart from "won't say".
    Hence a three-valued check -- has it / definitely missing / no answer -- where
    only a definite missing draws an icon. Guessing on a refusal would paint a
    "needs buff" icon on every player in sight the moment the client clamped down.
    /ub check prints, per buff, what this client actually answered.
    Co-Authored-By: Claude Opus 5 noreply@anthropic.com

This mod has no additional files