Tidy up for 0.9.3: Shagu overlap warning, readme rewrite

- Warn once in chat when ShaguTweaks Debuff Timer draws on target debuffs.
- Use STANDARD_TEXT_FONT for timers and stack counts.
- Clean up comments and dead code; add .gitattributes and .gitignore.
- Rewrite README (ClassicAPI version table, ShaguTweaks compatibility);
  move history to CHANGELOG.md.
- Tests: 19 scenarios, no machine-specific paths.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019W3rwutyoLNHxXPycYWSMc
This commit is contained in:
2026-11-01 00:17:37 +00:00
co-authored by Claude Sonnet 5.5
parent b350a142e2
commit 09784ec5b2
8 changed files with 132 additions and 75 deletions
+1
View File
@@ -0,0 +1 @@
* text=auto eol=lf
+3
View File
@@ -0,0 +1,3 @@
__pycache__/
*.pyc
*.zip
+31
View File
@@ -0,0 +1,31 @@
# Changelog
## 0.9.3
- Warn once in chat when ShaguTweaks Debuff Timer is drawing on target debuffs.
- Use the client font (`STANDARD_TEXT_FONT`) for timers and stack counts.
- Tidy source comments; add `.gitattributes` (LF) and `.gitignore`.
- Rewrite the README: ClassicAPI version table (1.17.11+ recommended for the
reverse-sweep fix) and a ShaguTweaks compatibility table.
- Tests: 19 scenarios; no machine-specific paths.
## 0.9.2
- ClassicAPI 1.17.10+: use `UNIT_AURA_DELTA`; no periodic polling. The displayed
snapshot is rebuilt to keep filtered ordering and tooltip indices aligned.
- Older ClassicAPI keeps the 0.5-second fallback.
- Hide native cooldown numbers on our sweeps; disable the expiration flash and
clear removed sweeps where supported.
- Spellbook and player-pet changes refresh capability-dependent presentation.
## 0.9.1
- Refresh on target change and target aura events, with a 0.5-second fallback.
- Update only active countdowns every 0.2 s from cached expirations.
- Use `GetAuraSlots` / `UnitAuraBySlot` with reusable buffers; positional
`UnitAura` fallback for older ClassicAPI.
- Stack counts for buffs and overflow debuffs; debuff-type borders.
- Gold borders on enemy buffs you or your pet can remove.
- Optional reverse cooldown sweeps.
- Saved settings, an AddOn Options panel and `/tfb` commands.
- Guard against an aura vanishing just before its tooltip opens.
+53 -52
View File
@@ -1,71 +1,72 @@
# TargetFrameBuff v0.9.2
# TargetFrameBuff
Shows up to 32 upper-row icons and 16 lower-row debuffs on the default target frame.
The existing 5-11-11-5 buff layout and 4-4-8 debuff layout are preserved.
With ClassicAPI, harmful auras beyond the first 16 use available upper-row icons.
Shows up to **32 buffs** and **16 debuffs** on the default target frame of a
1.12 client (tested target: Turtle WoW 1.18.1). Buffs sit above the frame in
rows of 5-11-11-5, debuffs below it in rows of 4-4-8.
With the optional [ClassicAPI](https://github.com/brues-code/ClassicAPI) client
mod it also adds countdown text, stack counts, debuff-type borders, a gold
border on enemy buffs you can remove, optional cooldown sweeps, and accurate
tooltips. Without ClassicAPI it behaves like the original: more icons, no timers.
## Installation
Back up your existing TargetFrameBuff folder, then replace it with the TargetFrameBuff
folder from the ZIP under Interface/AddOns. Restart the client or reload the UI.
ClassicAPI is optional; version 1.17.3 was reviewed for this update.
For working reverse sweeps and edges, use ClassicAPI 1.17.1 or newer.
1. Copy the `TargetFrameBuff` folder into `Interface/AddOns`, replacing any older copy.
2. Restart the client (or `/reload`).
3. Optional: install ClassicAPI.
## Changes in v0.9.2
## ClassicAPI
- ClassicAPI 1.17.10+: use UNIT_AURA_DELTA for applications, removals, stack changes
and timing-only refreshes; no periodic aura polling on this path. Rebuild the
displayed snapshot to preserve filtered ordering and tooltip index alignment.
- Older ClassicAPI retains the 0.5-second fallback below.
- Hide native cooldown numbers on our sweeps to prevent duplicate text when
countdownForCooldowns is enabled; retain TargetFrameBuff's text controls.
- Disable the sweep expiration flash and clear removed/disabled sweeps where supported.
- Spellbook and player-pet changes refresh capability-dependent aura presentation.
| Version | What you get |
| --- | --- |
| none | 32 buffs and 16 debuffs, no timers, borders or sweeps |
| 1.17.x | Timers, stack counts, borders; auras are re-read every 0.5 s |
| 1.17.10+ | Event-driven updates (`UNIT_AURA_DELTA`), no polling |
| 1.17.11+ | **Recommended.** Fixes the reverse sweep briefly showing a bright icon just before an aura ends |
## Earlier changes (v0.9.1)
- Refresh auras on target changes and target aura events, with a 0.5-second fallback.
- Update only active countdowns every 0.2 seconds using cached expiration; stop
countdown work when none remain. Silent timing changes can take up to 0.5 seconds to appear.
- Use GetAuraSlots with reusable buffers and UnitAuraBySlot where available; retain
the positional UnitAura fallback for older ClassicAPI. Slot IDs never survive a scan.
- Display stack counts for upper-row buffs and overflow debuffs, with debuff-type borders.
- Gold borders identify enemy buffs ClassicAPI says you or your pet can remove.
- Optional reverse cooldown sweeps; countdown and stack text draw above the sweep.
- Saved settings, a ClassicAPI AddOn Options panel, and vanilla-compatible slash commands.
- Guard against an aura disappearing immediately before its tooltip opens.
Harmful auras beyond the first 16 use free buff-row slots. ClassicAPI decides
aura order and lists your own auras first.
## Settings
Run /tfb to open AddOn Options when available, or show command help otherwise.
`/tfb` opens the AddOn Options panel (or prints help if the client has none).
| Command | Action |
| --- | --- |
| /tfb timers on or off | Toggle countdown text (default on) |
| /tfb highlight on or off | Toggle removable-buff borders (default on) |
| /tfb sweeps on or off | Toggle cooldown sweeps (default off) |
| /tfb size 6-20 | Set countdown font size (default 9) |
| /tfb warning 0-30 | Seconds remaining at which text turns red (default 5) |
| /tfb reset | Restore defaults |
| Command | Action | Default |
| --- | --- | --- |
| `/tfb timers [on\|off]` | Countdown text | on |
| `/tfb highlight [on\|off]` | Gold border on removable enemy buffs | on |
| `/tfb sweeps [on\|off]` | Reverse cooldown sweeps | off |
| `/tfb size 6-20` | Countdown font size | 9 |
| `/tfb warning 0-30` | Seconds left at which text turns red | 5 |
| `/tfb reset` | Restore defaults | |
Without ClassicAPI the original native aura display remains available without timers,
highlighting or sweeps. Settings are retained for use when ClassicAPI is installed.
Settings are saved and kept even while ClassicAPI is absent.
## Timing limitations
## Compatibility with ShaguTweaks
ClassicAPI timings are best-effort. Unobserved applications and certain max-stack
refreshes can have unknown expiration. Unknown or expired timers hide their text
and sweep; the icon stays visible while the aura remains listed by the API.
ClassicAPI controls aura ordering and puts your own auras first.
Checked against the upstream [ShaguTweaks](https://github.com/shagu/ShaguTweaks) source.
## Validation
| ShaguTweaks option | Effect | What to do |
| --- | --- | --- |
| **Unit Frames > Debuff Timer** | Conflict. Adds its own timer text, sweep and green stack count to debuffs 1-16, on top of ours. It ignores overflow debuffs in the buff row. | Disable it. TargetFrameBuff prints a warning in chat if it detects it. Alternatively use `/tfb timers off` and `/tfb sweeps off`. |
| Cooldown Numbers | No conflict found. It only hooks `CooldownFrame_SetTimer`; our sweeps use `SetCooldown`. | Keep. |
| Dark UI Elements | Adds a dark border to every `TargetFrameBuff*` button. Ours draws above it, so the gold removable-buff border should stay visible. | Not verified in-game. |
| Target Castbar | Positions the castbar from debuff 7 and 11 being shown. With the 4-4-8 layout it can sit over the second and third debuff rows. | Disable it or move the castbar if it overlaps. |
| Move Unit Frames | Buff and debuff buttons are children of `TargetFrame`, so they follow it. | Keep. |
17 automated scenarios passed using Lua 5.1 with a simulated WoW API; XML parses.
This is not a live WoW 1.12/1.18.1 test or an exact Lua 5.0 runtime test.
See VALIDATION.md for remaining in-game checks.
## Notes
Based on https://wow.curseforge.com/projects/project-949
Original author: lua@lumpn.de (modified).
- Timings from ClassicAPI are best effort. Unobserved applications and some
max-stack refreshes have unknown expiration; their timer and sweep stay hidden
while the icon remains.
- This is not a live WoW test. See [VALIDATION.md](VALIDATION.md) for what was
simulated and what to check in-game, and [CHANGELOG.md](CHANGELOG.md) for history.
## Development
Disable ShaguTweaks Unit Frames > Debuff Timer to prevent duplicate countdown text.
Tests simulate the WoW API under Lua 5.1: `pip install lupa`, then `python3 tests/test_addon.py`.
## Credits
Based on [project-949](https://wow.curseforge.com/projects/project-949).
Original author lua@lumpn.de; modified.
+25 -17
View File
@@ -1,14 +1,14 @@
-- Title: TargetFrameBuff v0.9.2
-- Notes: Shows up to 32 Buffs & 16 Debuffs on a Target (Buffs above, Debuffs below),
-- with remaining-time countdowns when ClassicAPI is installed
-- Author: lua@lumpn.de (modified)
-- TargetFrameBuff: up to 32 buffs above and 16 debuffs below the default target
-- frame. With ClassicAPI it also adds countdowns, stack counts, removable-buff
-- highlights and optional cooldown sweeps. Version and author live in the .toc.
local lOriginal_TargetDebuffButton_Update = nil;
local TARGETFRAMEBUFF_MAX_TARGET_DEBUFFS = 16;
local TARGETFRAMEBUFF_MAX_TARGET_BUFFS = 32;
-- Follow the client font so localized clients keep readable glyphs.
local TARGETFRAMEBUFF_FONT = STANDARD_TEXT_FONT or "Fonts\\FRIZQT__.TTF";
-- How often the countdowns refresh, in seconds.
local TARGETFRAMEBUFF_TIMER_INTERVAL = 0.2;
@@ -62,13 +62,13 @@ local function TargetFrameBuff_AddTimer(button)
holder:SetFrameLevel(button:GetFrameLevel() + 2);
local timer = holder:CreateFontString(nil, "OVERLAY");
timer:SetFont("Fonts\\FRIZQT__.TTF", 9, "OUTLINE");
timer:SetFont(TARGETFRAMEBUFF_FONT, 9, "OUTLINE");
timer:SetPoint("CENTER", button, "CENTER", 0, 0);
timer:Hide();
if (not button.auraCount) then
button.auraCount = holder:CreateFontString(nil, "OVERLAY");
button.auraCount:SetFont("Fonts\\FRIZQT__.TTF", 9, "OUTLINE");
button.auraCount:SetFont(TARGETFRAMEBUFF_FONT, 9, "OUTLINE");
button.auraCount:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", 1, -1);
button.auraCount:Hide();
local stockCount = getglobal(button:GetName().."Count");
@@ -90,7 +90,7 @@ function TargetFrameBuff_OnLoad()
overlay:SetAllPoints(button);
overlay:SetFrameLevel(button:GetFrameLevel() + 2);
button.auraCount = overlay:CreateFontString(nil, "OVERLAY");
button.auraCount:SetFont("Fonts\\FRIZQT__.TTF", 9, "OUTLINE");
button.auraCount:SetFont(TARGETFRAMEBUFF_FONT, 9, "OUTLINE");
button.auraCount:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", 1, -1);
button.auraCount:Hide();
button.auraBorder = overlay:CreateTexture(nil, "OVERLAY");
@@ -148,6 +148,18 @@ function TargetFrameBuff_OnLoad()
end
-- ShaguTweaks "Debuff Timer" wraps TargetDebuffButton_Update and adds its own
-- cooldown (button.cd), timer text and stack count to every debuff button. On
-- top of ours that doubles the timers, sweeps and stack numbers. Its field is
-- named cd (ours is cooldown), so seeing it is a locale-proof way to notice.
local lWarnedShagu = false;
local function TargetFrameBuff_CheckShagu()
if (lDebuffButtons[1] and lDebuffButtons[1].cd and lDebuffButtons[1].timer) then
lWarnedShagu = true;
DEFAULT_CHAT_FRAME:AddMessage("|cffffd100TargetFrameBuff:|r ShaguTweaks Debuff Timer is also drawing timers, sweeps and stack counts on target debuffs, so they overlap. Disable it under ShaguTweaks > Unit Frames, or use /tfb timers off and /tfb sweeps off.");
end
end
-- use extended update-function (original code from FrameXML/TargetFrame.lua)
function TargetFrameBuff_Update()
if (TargetFrameBuff_HasClassicAPI() and lBuffButtons[1] and lBuffButtons[1].timer) then
@@ -156,6 +168,7 @@ function TargetFrameBuff_Update()
TargetFrameBuff_UpdateNative();
end
TargetFrameBuff_Layout();
if (not lWarnedShagu) then TargetFrameBuff_CheckShagu(); end
-- Draw countdowns right away instead of waiting for the next tick.
lTimerElapsed = TARGETFRAMEBUFF_TIMER_INTERVAL;
end
@@ -372,13 +385,8 @@ function TargetFrameBuff_Layout()
TargetFrameBuff1:ClearAllPoints();
TargetFrameBuff1:SetPoint("BOTTOMLEFT", "TargetFrame", "TOPLEFT", 5, -10);
-- Position debuffs below target frame using default positioning (no gap)
-- Layout: 4-4-8 (three rows: 4 debuffs, 4 debuffs, 8 debuffs)
-- Debuff 1 uses default WoW positioning to avoid gap with target frame
-- TargetFrameDebuff1:ClearAllPoints();
-- TargetFrameDebuff1:SetPoint("TOPLEFT", "TargetFrame", "BOTTOMLEFT", 5, 0);
-- Position remaining buttons in 4-4-8 layout
-- Debuff 1 keeps the stock anchor so it sits flush under the target frame.
-- Remaining debuffs use a 4-4-8 layout (three rows).
for i=2, TARGETFRAMEBUFF_MAX_TARGET_DEBUFFS do
button = lDebuffButtons[i];
if button then
@@ -417,7 +425,7 @@ TargetFrameBuff_UpdateTimer = function(button, now)
local size = TargetFrameBuff_Setting("timerSize");
if (button.timerSize ~= size) then
button.timer:SetFont("Fonts\\FRIZQT__.TTF", size, "OUTLINE");
button.timer:SetFont(TARGETFRAMEBUFF_FONT, size, "OUTLINE");
button.timerSize = size;
end
+1 -1
View File
@@ -1,5 +1,5 @@
## Interface: 1700
## Title: TargetFrameBuff v0.9.2
## Title: TargetFrameBuff v0.9.3
## Notes: Shows up to 32 Buffs & 16 Debuffs on a Target, with countdowns when ClassicAPI is installed
## Author: lua@lumpn.de (modified)
## SavedVariables: TargetFrameBuffDB
+5 -4
View File
@@ -1,8 +1,8 @@
# TargetFrameBuff v0.9.2 validation
# TargetFrameBuff v0.9.3 validation
17 simulated Lua 5.1 regression scenarios passed, plus XML parsing. These cover
19 simulated Lua 5.1 regression scenarios passed, plus XML parsing. These cover
old/native clients, aura reordering, overflow, settings, sweep lifecycle, delta
refreshes and full updates, target/pet/spellbook changes, reused delta payloads,
refreshes and full updates, the Debuff Timer overlap warning, target/pet/spellbook changes, reused delta payloads,
no polling in delta mode, and native-number/flash suppression.
ClassicAPI 1.17.10+ is detected through GetAuraDataByAuraInstanceID, introduced with
@@ -16,4 +16,5 @@ New Clear and SetDrawBling methods are optional, preserving older versions.
Not tested inside a running WoW client. Verify recasts, target switches, auras
expiring, and sweeps with countdownForCooldowns enabled. Keep ShaguTweaks Debuff
Timer disabled to prevent overlapping addon countdowns. No FPS gain is claimed.
Timer disabled to prevent overlapping addon countdowns (a chat warning appears
if it is detected). No FPS gain is claimed.
+13 -1
View File
@@ -1,7 +1,6 @@
import sys
from pathlib import Path
import xml.etree.ElementTree as ET
sys.path.insert(0, str(Path("work/pythonlibs").resolve()))
from lupa.lua51 import LuaRuntime
addon = Path(__file__).resolve().parents[1]
@@ -214,6 +213,19 @@ SlashCmdList.TARGETFRAMEBUFF("sweeps off"); assert(cd.cleared and not cd:IsShown
SlashCmdList.TARGETFRAMEBUFF("sweeps on"); cd.cleared=false
auras.HELPFUL={}; Tick(); assert(cd.cleared and not cd:IsShown())
''')
run("ShaguTweaks Debuff Timer overlap warns once, only with ClassicAPI", 'InstallAPI(true); auras.HELPFUL={Aura("A")}', '''
Tick(); assert(#messages==0)
TargetFrameDebuff1.cd={readable={}}
Tick(); Tick()
local n=0
for _,m in ipairs(messages) do if string.find(m,"Debuff Timer",1,true) then n=n+1 end end
assert(n==1)
''')
run("no warning on the native path", 'nativeBuffs={"Native"}; nativeDebuffs={}', '''
TargetFrameDebuff1.cd={readable={}}
Tick(); Tick()
for _,m in ipairs(messages) do assert(not string.find(m,"Debuff Timer",1,true)) end
''')
ET.parse(addon/"TargetFrameBuff.xml")
print("PASS XML parsing")
print(f"{passed} Lua regression scenarios passed; XML parsed.")