The Lua VM keeps no surface the 1.12.1 client lacks. - **Removed:** the nine Era-only globals: `UnitAura`, `CancelUnitBuff`, `GetCursorInfo`, `GetInventoryItemID`, `GetPlayerFacing`, `GetTradePartnerName`, `IsGossipOptionCoded`, `UnitIsAFK`, `UnitIsDND`. - **Hooks off Lua:** `GameTooltip:BenillaSetItemById` and `:BenillaGetTooltipOwner` are replaced by Rust-side calls. The uncalled `Benilla*` hooks are deleted. - **Frame strata:** `SetFrameStrata` knows the reference's eight strata and raises its message for any other (`0x774450`). - **`SetDrawLayer`** reads the layer name alone (`0x79a780`). - **`Set<State>Texture`** reads a number as a path (`0x781b23`); there is no colour form. - **`PlaySound`** names a kit and returns nothing (`0x4586d0`). `PlaySoundFile` returns one value (`0x458780`); benilla answers 1, a recorded deviation, since it plays after the call. - **`OnClick`** sets only `arg1` (`0x779540`). - **Quest getters:** `GetQuestItemInfo` and the quest-log reward and choice getters answer the reference's five values and its miss behaviour (`0x501f80`, `0x4e0b00`, `0x4e0cf0`). - **`PickupContainerItem`** returns nothing (`0x4f9b30`). - **Surface gates:** the bare VM's globals and every widget class's methods are held to `reference/1.12-globals.tsv` with one commented allowlist. A new gate on the full production load (core plus layer) allows beyond that only the layer's `Benilla`-prefixed globals. Verified: - A test per removal and per corrected form; a scripted undo of each fails its test. - Each gate fails on a re-added name. - `scripts/gates.sh` and `scripts/smoke.sh` are green. - A live run showed the same warnings and 0 script errors before and after. - In the 219-addon corpus, AckisRecipeList's bundled AceGUI-3.0 and Roid-Macros' Grid extension now behave as they do on 1.12.1. Built on macOS; no platform seam touched. Fixes #171 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
84 lines
5.0 KiB
Markdown
84 lines
5.0 KiB
Markdown
# `reference/`: verified facts about the 1.12.1 client, vendored
|
|
|
|
Generated tables describing the reference client, committed so benilla can measure itself against
|
|
them on any machine without re-deriving them. Data, not documentation: each has a generator beside
|
|
it in `scripts/`.
|
|
|
|
Nothing here is Blizzard content. A catalogue of names is not the thing named, the same way a
|
|
comment may quote a byte address and `docs/MAP.md` may name a file.
|
|
|
|
## `1.12-globals.tsv`
|
|
|
|
The 1.12.1 client's entire global namespace: 21,555 names, `name<TAB>type<TAB>origin`.
|
|
|
|
Where it comes from: a dump of `_G` inside the running reference client, which is the surface an
|
|
addon sees (FrameXML-defined globals as well as engine ones), unioned with every global the shipped
|
|
UI defines. The union matters because the twelve `Blizzard_*` addons are LoadOnDemand: a live dump
|
|
only carries their globals if their windows were opened first, so the 1,986 rows a dump cannot see
|
|
carry type `lod`. The table answers "is this a 1.12 name?", not "was this name live in one session".
|
|
|
|
The `origin` column says whose job it is to provide the name, attributed by its definition site in
|
|
the complete 1.12 shipped-UI corpus:
|
|
|
|
| origin | count | meaning |
|
|
|---|---|---|
|
|
| `engine` | 1,104 | the C client provides it; benilla implements these in Rust |
|
|
| `framexml` | 20,427 | the shipped UI defines it; the stock files run off the player's own install (`ui_script::reference_ui`) |
|
|
| `lua` | 24 | Lua 5.0's own runtime |
|
|
|
|
The `framexml` bulk is UI objects, `ContainerFrame1Item16IconTexture` and its 11,000 siblings,
|
|
which materialize from the XML and are nobody's to implement. The number that matters for the API
|
|
surface is the function split: 1,100 engine functions, 1,075 FrameXML functions. A name defined in
|
|
shipped Lua is FrameXML's, and hardcoding it in Rust is a category error even when it works.
|
|
|
|
Regenerating: `scripts/gen-reference-globals.py`, whose header carries the method and the traps. It
|
|
needs a 1.12 install, its FrameXML extracted to a folder, and the maintainer's runtime capture of
|
|
the reference client's `_G`, which is not in this repo, so it is a manual regeneration. The table is
|
|
stable: it describes a client that shipped in 2006.
|
|
|
|
Reading it: `scripts/api-coverage.sh` asks a real `UiScript::new()` what benilla exposes and reports
|
|
`have / missing / beyond-1.12`. Two gates hold the line.
|
|
`crates/benilla-ui/src/script/tests/reference_surface.rs` fails if the engine puts a global 1.12
|
|
does not have in a bare VM and nobody wrote down why, with no prefix excusing an engine name.
|
|
`crates/benilla-app/src/ui_script/surface_gate.rs` fails if the production load, the core and
|
|
benilla's layer, adds any global past 1.12 other than the layer's own `Benilla`-prefixed names, or
|
|
any widget method.
|
|
|
|
## `1.12-shapes.tsv` and `1.12-events.tsv`
|
|
|
|
The binding-shape table (what each Lua verb takes and returns, gated by `ui_script/shape_gate.rs`)
|
|
and the event table with the arguments each producer pushes (gated by
|
|
`ui_script/event_shape_gate.rs`). Each file's header carries its column contract.
|
|
|
|
Regenerating: `1.12-shapes.tsv` is vendored as the reference analysis writes it.
|
|
`scripts/gen-reference-events.py` derives `1.12-events.tsv` from two more vendored tables,
|
|
`1.12-event-catalog.tsv` (event id to name, off the client's name-pointer array) and
|
|
`1.12-event-firesites.tsv` (every fire site with the format string it pushes), so it runs from any
|
|
clone and reproduces the committed file byte for byte.
|
|
|
|
## `1.12-message-catalog.tsv`
|
|
|
|
The client's message registry (`0xb4b498`: id, key, kind, sound, chat type).
|
|
`scripts/gen-message-catalog.py` re-shapes it into `crates/benilla-ui/src/messages/catalog.rs`,
|
|
the table `CGGameUI::DisplayError` indexes.
|
|
|
|
## `1.12-verb-events.tsv`
|
|
|
|
Every event the reference fires from inside a Lua verb, keyed by the verb: the verb's own body, or
|
|
a helper that only registered verbs call (`0x4d8c90` is the trainer's). The two tables above say
|
|
what an event carries and whether something fires it; this one says who. A stock file that calls a
|
|
verb for its side effect of an event repaints nothing when the verb fires nothing.
|
|
|
|
Regenerating: `scripts/gen-reference-verb-events.py`, whose header carries the rule, the two
|
|
families it drops (glue-space verbs, the unit-field bridge) and why getters are excluded (a getter's
|
|
fire is a cache-miss re-query, a state event benilla's feeds fire off the packet). A fire site is
|
|
attributed to a function by the verified function extents plus the disassembly's padding
|
|
boundaries, and a site past its candidate's extent is left out rather than mis-filed. The fire
|
|
sites and the shapes are the vendored tables above; the function names, their extents and the
|
|
disassembly are the maintainer's, so this one is a manual regeneration.
|
|
|
|
Reading it: `crates/benilla-app/src/ui_script/verb_event_gate.rs` is the gate. For every pair whose
|
|
verb benilla registers, the module that registers the verb fires the event, or the pair is declared
|
|
there: `ELSEWHERE` (a feed fires it on the state the verb changes, and the named file is checked
|
|
too) or `GAP` (nothing does, with the reason).
|