From 09784ec5b23b1bd1af6182926b8e3e986a5a44d5 Mon Sep 17 00:00:00 2001 From: OEVG <950+oevg@noreply.octowow.st> Date: Sun, 1 Nov 2026 00:17:37 +0000 Subject: [PATCH] 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 Claude-Session: https://claude.ai/code/session_019W3rwutyoLNHxXPycYWSMc --- .gitattributes | 1 + .gitignore | 3 ++ CHANGELOG.md | 31 +++++++++++++ README.md | 105 ++++++++++++++++++++++---------------------- TargetFrameBuff.lua | 42 +++++++++++------- TargetFrameBuff.toc | 2 +- VALIDATION.md | 9 ++-- tests/test_addon.py | 14 +++++- 8 files changed, 132 insertions(+), 75 deletions(-) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 CHANGELOG.md diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6313b56 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7c76b92 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +*.zip diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..5a2589a --- /dev/null +++ b/CHANGELOG.md @@ -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. diff --git a/README.md b/README.md index 42845d5..8df1857 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/TargetFrameBuff.lua b/TargetFrameBuff.lua index cff5421..df55661 100644 --- a/TargetFrameBuff.lua +++ b/TargetFrameBuff.lua @@ -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 diff --git a/TargetFrameBuff.toc b/TargetFrameBuff.toc index 3f31d5c..7c39eee 100644 --- a/TargetFrameBuff.toc +++ b/TargetFrameBuff.toc @@ -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 diff --git a/VALIDATION.md b/VALIDATION.md index b15c004..e3ad39f 100644 --- a/VALIDATION.md +++ b/VALIDATION.md @@ -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. diff --git a/tests/test_addon.py b/tests/test_addon.py index f8d9df7..b2b7909 100644 --- a/tests/test_addon.py +++ b/tests/test_addon.py @@ -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.")