Two addons another player asked for, and the Linux-only gap that killed one
AlternativeClassicActionBars and UnitPlates, both now in `other-addons/`
(untracked — third-party source, not ours to vendor). Measured with the survey
and the read-back probe on a root holding only those two, so neither borrows the
other's globals. Both already loaded clean; three things were missing, and the
first was costing an entire addon's keybinding surface.
**A binding table spelled `bindings.xml`.** `ui_script::addons` asks for
`Bindings.xml` by the reference's own fixed name — `0x51f400` reads the name,
not a `.toc` entry — and the open was case-sensitive, so on Linux ACAB's 69
`<Binding>` rows never registered. Silently: an absent binding table is the
normal case, so nothing raised and nothing warned. Hover-bind, edit-mode escape
and every bar page key were dead. The texture and font side of the same file
namespace has always resolved case-insensitively (`loose_addon_file`, which
walks the path a component at a time and enumerates a directory when the spelling
does not match); the Lua and XML side now shares one resolver with it, and both
crates' private `read_under` copies delegate to it. Measured after: 69 bindings
listed by `GetBinding`, `SetBinding("CTRL-9", "ACABBIND1")` round-trips, and the
addon's drawn-frame count went 42 -> 175, because its login sequence had been
stopping short of its own bars.
**`PixelUtil`.** Called unguarded on ACAB's bar-geometry path at four sites,
three of them the same question — one screen pixel in UI units, which is what
every pixel-perfect border in that addon is drawn from. Not in ClassicAPI's
published list, but ACAB disables itself without ClassicAPI, so on this server's
kit it is present by implication. A Lua chunk beside `math_ext`, whose `Round` it
uses. One deviation, written down where it lives: upstream reads
`region:GetEffectiveScale()`, which a 1.12 texture does not answer, so the scale
read falls back to the parent and then `UIParent` — the same number in every case
that matters.
**`UnitXP("nop", "nop")` answering the boolean.** The presence probe.
SuperCleveRoidMacros keeps only `pcall`'s `ok`, but ACAB's `HasUnitXPSP3` wants
`ok and result == true`, and the fall-through handed it the stock XP getter's
`0` — truthy, so it passed the loose reading and failed the strict one. ACAB
reported UnitXP_SP3 absent on a client that answers the whole family.
Left alone with the reason in `docs/ADDON_COMPAT.md`: `IsStackableAction`
(post-1.12, guarded, and stock 1.12's own ActionButton.lua shows a count off
`IsConsumableAction` alone), `CursorHasMacro` (post-1.12 and redundant — ACAB
tests `GetCursorInfo() == "macro"` first), and five third-party tables that are
missing because those addons are not installed.
The harness grew a `--plates [n]` step, because a nameplate addon is the one kind
it could not see working: the subject is a `WorldFrame` child `vplates.rs` mints
per frame, so with none seated the addon's scan finds nothing, does nothing, and
reports a clean load over an empty screen. It seats n live plates and counts how
many an addon hung a frame on, which doubles as the contract check on the plate's
own shape — a plate that stopped being a `Button`, or stopped putting its border
texture first, would read as an addon adopting nothing. UnitPlates adopts every
plate and reads its name, health and level off ours.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
This commit is contained in:
@@ -1274,3 +1274,75 @@ either writes the CVar or registers the event.
|
||||
**ClassicAPI's 70** are the remaining bulk and are tracked in `docs/classic-api-functions.md`
|
||||
rather than here. The same caution applies twice over: its 999 pointed-at names include a great deal
|
||||
that is not Lua surface at all, and the corpus intersection is the only part worth reading.
|
||||
|
||||
|
||||
## Two addons asked for by name: AlternativeClassicActionBars and UnitPlates
|
||||
|
||||
Not grom's own install — `other-addons/` in the working tree, both for another player on this
|
||||
fork. Measured with the survey and the read-back probe
|
||||
(`cargo run -q --release -p benilla-app --example addon_harness -- <root> --verbose`, then
|
||||
`--probe <Name>`), on a root holding only these two so neither borrows the other's globals:
|
||||
|
||||
| Addon | Loads | Session | Drew | What it does with our client |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| [AlternativeClassicActionBars](https://github.com/TrusT-Codes/AlternativeClassicActionBars) 1.4.0-rc1 | clean | clean | 175 frames | 9 bars built, buttons shown, 69 of its own bindings registered and settable |
|
||||
| [UnitPlates](https://github.com/Redbu11dev/UnitPlates) | clean | clean | overlay | adopts **every** seated nameplate and reads its name, health and level off ours |
|
||||
|
||||
**Packaging, not a client gap:** a GitHub zip unpacks as `UnitPlates-main`, and the reference
|
||||
resolves an addon's manifest as `<Folder>/<Folder>.toc` (`manifest_in`, case-insensitively, as on a
|
||||
Windows filesystem). A folder whose name does not match its `.toc` is invisible to the real client
|
||||
too, so the folder has to be renamed `UnitPlates`. Nothing to fix here; worth saying once because
|
||||
the failure is silent on both clients.
|
||||
|
||||
### What they needed that we did not have
|
||||
|
||||
- **A binding table spelled `bindings.xml`.** `ui_script::addons` asks for `Bindings.xml` by the
|
||||
reference's own fixed name (`0x51f400` reads the name, not a `.toc` entry) and the open was
|
||||
case-sensitive, so on Linux ACAB's 69 `<Binding>` rows never registered — silently, since an
|
||||
absent binding table is the normal case. Its whole keybinding surface was dead: hover-bind,
|
||||
edit-mode escape, every bar page key. Fixed by giving the Lua/XML side of the file namespace the
|
||||
same case-insensitive component walk the texture and font side has always had
|
||||
(`benilla_ui::loader::read_under`, shared by both crates' readers;
|
||||
`benilla_assets::loose_addon_file` is the asset-side original). Measured: 69 bindings listed by
|
||||
`GetBinding`, `SetBinding("CTRL-9", "ACABBIND1")` round-trips, and the addon's drawn-frame count
|
||||
went 42 → 175, because the login sequence had been stopping short of its bars.
|
||||
- **`PixelUtil`** (`script/compat/classic_api/pixel_util.rs`). Called **unguarded** on ACAB's
|
||||
bar-geometry path, four sites, three of them the same question — one screen pixel in UI units.
|
||||
Not in ClassicAPI's published list, but ACAB disables itself without ClassicAPI, so on this
|
||||
server's kit it is present by implication. `GetNearestPixelSize`, `SetPoint`, `SetSize`,
|
||||
`SetWidth`, `SetHeight`, `GetPixelToUIUnitFactor`; the scale read falls back to the parent and
|
||||
then `UIParent`, because upstream's `region:GetEffectiveScale()` does not exist on a 1.12 texture.
|
||||
- **`UnitXP("nop", "nop")` answering `true`.** The presence probe. `SuperCleveRoidMacros` keeps
|
||||
only `pcall`'s `ok`, but ACAB's `HasUnitXPSP3` wants `ok and result == true` — and the
|
||||
fall-through handed it the stock XP getter's `0`, which is truthy, so it passed the loose reading
|
||||
and failed the strict one. ACAB reported UnitXP_SP3 absent on a client that answers the whole
|
||||
family.
|
||||
|
||||
### Left alone, with the reason
|
||||
|
||||
- **`IsStackableAction(slot)`** — post-1.12 (not in `reference/1.12-globals.tsv`), not in
|
||||
ClassicAPI's list, and the stock 1.12 `ActionButton.lua` shows a slot's count off
|
||||
`IsConsumableAction` alone (`ActionButton.lua:274`, read off the chain). ACAB guards it
|
||||
(`Button.lua:1560`), so its absence costs exactly what a 1.12 client does: no count on a
|
||||
stackable non-consumable. Adding it would need a new feed column for a difference no reference
|
||||
client shows.
|
||||
- **`CursorHasMacro()`** — also post-1.12, and **redundant here**: ACAB's `ButtonHasCursor`
|
||||
(`Button.lua:2112`) tests `GetCursorInfo() == "macro"` first, which this client answers, and only
|
||||
then falls through to the three `CursorHas*` getters.
|
||||
- **`CleveRoids` / `QuestieOcto` / `ShaguTweaks.libhealth` / `pfDatabase` / `WoWTranslate_API`** —
|
||||
other addons' tables, every one behind a presence test. UnitPlates' `UPCompat.lua` is a file of
|
||||
optional integrations; those names are missing because those addons are not installed, which is
|
||||
the point of the file.
|
||||
- **69 `Unknown frame type: Binding` log lines** when a `.toc` also lists its binding table, as
|
||||
ACAB's does. The reference logs one per row the same way (`0x6ee356`), and
|
||||
`loader/tests.rs`'s `a_bindings_document_loaded_as_framexml_raises_nothing` pins the count
|
||||
deliberately. Noise, faithfully.
|
||||
|
||||
### The harness grew a `--plates` step
|
||||
|
||||
A nameplate addon is the one kind the survey could not see working: its subject is a `WorldFrame`
|
||||
child that `vplates.rs` mints per frame, so with no plates seated the addon's scan finds nothing,
|
||||
does nothing, and reports a clean load over an empty screen. `Step::Plates(n)` seats `n` live
|
||||
plates through `sync_nameplates` and counts how many an addon has hung a frame on — which doubles
|
||||
as the contract check on the plate's own shape, since a plate that stopped being a `Button`, or
|
||||
stopped putting its border texture first, would read as an addon adopting nothing.
|
||||
|
||||
Reference in New Issue
Block a user