- a size-less `<Model>` pane's rect is its file's box in layout units: the reference's geometry overrides (`0x76d080`/`0x76d0d0`) answer the bbox extent whenever no size is authored, `bboxExtent · 768·√(a²+1) · layoutScale` FrameXML units (`1280 · extent` at 4:3), written into the pane's layout input when the file's facts land, re-derived on an aspect change, and ended for good by any authored size; `SetPosition` is the same unit, which is how `0x4a7b20` centres the arrow at `½·GetWidth, ½·GetHeight` through the override — so the map arrow's sprite arm and its hand-sized 33.6 px footprint go (its rect is `0.0262 × 0.0263` layout units, 33.5 × 33.7 FrameXML units at 4:3, 41.0 × 41.2 at 16:9), and the stock `ItemAnim` pane plays the item push unadapted (`ReplaceIconTexture` on the type-14 batch, the 1000 ms clamp, the stock `OnAnimFinished`), `ContainerFrameAdapters.xml` losing 0887's Lua card and its hand-measured 42.41 × 124.72 rect — the implicit one at 16:9 — and keeping the keyring fork and the three bag verbs (2015); and the cooldown is the reference's own model: the texture-transform law `uv' = R_q((uv + t − p) ⊙ s) + p`, `p = (½, ½)`, the raw quaternion component-lerped and never normalised, is one function (`uv_transform`) with the shader's UV fold as its twin — rotation and scale tracks bake per file sequence slot beside the translation, the mat-anim table gains an affine row `[cos − 1, sin, sx − 1, sy − 1]` on `anim_slots.z` whose identity is the zero row so every static batch reads exactly what it did, and a UI tile clones the twin material per animated batch and writes both rows every frame off the pane's play head, never the world clock; the stock `Cooldown.xml` runs off the chain on 2007's two handlers, the file's four quadrant quads turned by their own rotation tracks (`0 → −90°` over each quadrant's 250 ms window, clockwise from 12 o'clock) and its alpha tracks revealing the star for the flash; retired: the native `Cooldown` widget and `SetCooldown` (an Era API 1.12 never had — `CreateFrame("Cooldown")` is the reference's unknown-type refusal now), the loader's `Model → Cooldown` substitution, the app's hand-built pie and star, and our `Cooldown.xml`; `assets/ui` is eight files (2019)
- `UpdateMapHighlight` gets its zone-level exits (B360): at zone zoom ours returned the nil tail for every cursor position, so hovering Deadwind Pass from Duskwood showed no label where 1.12 shows "Deadwind Pass"; the reference's `0x4a7fa0` runs two lookups at zone level and answers a NAME only — first the current zone's exploration-gated overlay list (the builder at `0x4a6ad9` gating on the explored byte), each row's HitRect scaled by 1/1002 and 1/668 against the normalized cursor, edges inclusive, the first hit naming its Area1, then the continent grid re-windowed through the displayed zone's own rect, naming the neighbouring zone or city and nothing for the displayed zone itself — and only the name-only tail is reachable from there, fileName nil and the six coords zero, so the stock frame hides the highlight quad, as the director's own 1.12 shot shows; and `SetVerticalScroll` stores the offset as given (B370, B363): the reference's `0x786db0` compares the new offset against the old and writes it to `[+0x328]` verbatim, `0x787100` re-anchors the scroll child off it, and the range at `[+0x320]` is never read on that path — every clamp the reference exhibits is FrameXML's, through the scroll bar's `[min, max]`; ours clamped into `[0, GetVerticalScrollRange()]`, the child's overflow past the FRAME, which is 40 px short of where `FauxScrollFrame_Update` sends the bar on the 220-tall skills list (three rows lost) and 15 px short on the 287-tall who list (one); the setter fires `OnVerticalScroll` only on a change, as the bytes do, `BenillaScroll_Step` bounds its wheel in Lua where the reference's handler does, and the ScrollFrame kind's prose stops calling its offset unpinned (2017)
- overdraw's cheap half, the sky first: since 0588 every sky element wrote `frag_depth = 0.0`, which costs a pipeline its early-Z, so on an outdoor frame every full-screen dome fragment under the ground and the buildings was shaded in full (the gradient's `asin`, `atan2` and eight table lookups at dawn and dusk) and thrown away; one shared `sky_vertex.wgsl` — bevy's mesh vertex verbatim plus `out.position.z = 0.0` — is now the vertex stage of the gradient dome, the cloud dome, the star patches and the celestial discs and glares, and the model lane's `WOW_SKY_DEPTH` branch moves from its fragment to its vertex, so no sky fragment declares `frag_depth` and the rasterizer rejects the covered screen before the shader runs; every sky `specialize` zeroes the rasterizer bias constant the `sky_order` rung had been leaking into `DepthBiasState::constant`, harmless only while the fragment overwrote its depth, and the prose beside the pin follows it; then the retained `static_gx` pass draws BEFORE bevy's opaque pass (`StartMainPass → static_gx → MainOpaquePass`) — buildings and doodads are the frame's best occluders and a terrain fragment its dearest, six samples a pixel — so walls reject the terrain behind them instead of the reverse, the pass taking the first-use clear with it and the dev depth probe ordered after it; measured on 16 capture scenarios: 14 bit-identical, `northshire-dusk` 1 px and `water-night` 11 px, attributed to exact depth ties on static/terrain silhouettes and last-bit interpolation noise; a depth prepass and near-to-far bins are declined until a journal says where the time goes (2016)
- the grass cut goes per pixel because of a quarter-mip: `0x6813d0` sets `D3DSAMP_MIPMAPLODBIAS = +0.25` on stage 0 (`0x6813f4`) once per frame before the detail-doodad pass — capture-confirmed on all 29 doodad batches, and outside the `[0x6b1000, 0x6b3200)` scan 2004 had called complete; it decides the whole look because the `clutter_cut` probe finds 6 of 31 shipped detail atlases carry a BINARY alpha pyramid (mip 0 has DXT3's 16 levels, every level below exactly two, both starting zones among them), so `a × ramp` degenerates to a global on/off and every texel of a leaf crosses at the same depth — Elwynn's survivor coverage is flat at 47.6 % across the whole 52.5–61.1 yd band, then 0.0 %, while the probe's box-filtered control erodes 47.7 → 20.9 over the same band, so the art has the gradient the shipped pyramid threw away, and `clutter_size` puts the median tuft at 0.92 yd tall, 1.03 yd deep, a full yard for the boundary plane to sweep; the escape is bilinear: full alpha needs a 2×2 all-opaque texel neighbourhood, and those run out between mip 2 and 3 (179/56/10/0/0/0 on the dominant Elwynn cell), so the reference's λ ≈ 2.9–3.3 sits past the cliff and the tuft erodes continuously — 2.2 % of a tuft's pixels leave in the last half-yard with the bias, 11.6 % without, 24.2 % one mip sharper; wgpu has no sampler LOD bias, so the clutter lane re-samples base colour at `view.mip_bias + 0.25`, keeping the sampler every other model batch shares at the reference's 0; ruled out on the way: our BLP decoder (all nine uploaded levels byte-identical against the archive's 52 793 BLP2s), mip regeneration, the `has_mipmaps` byte's value 2 (a plain boolean, an authoring marker), anisotropy and geometry; what it does not fix is resolution-dependent, and so is the reference's own look — λ with the bias is 3.22 at the capture's 648p but 2.48 at 1080p and 1.48 at 2160p, so at a modern resolution the reference itself pops leaf by leaf, and scaling the bias with the viewport is one reversible line left for a look call (2021)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
170 lines
10 KiB
XML
170 lines
10 KiB
XML
<!--
|
|
OUR adapters over the reference's own `Interface\FrameXML\ContainerFrame.xml`/`.lua`.
|
|
|
|
**This client does not transcribe those files — it EXECUTES them, off the player's own patch
|
|
chain** (decision 1751; `ui_script::reference_ui` carries the rule, and `benilla.toc` carries
|
|
the position). The bag windows on screen ARE `ContainerFrame1..12`. What is in THIS file is
|
|
only benilla's, and only where a reference body reaches for something this client genuinely
|
|
does not have.
|
|
|
|
The rule, restated in one line so it can be applied without re-reading the module: the sourced
|
|
file's globals stand unmodified; ours, loading after, win where both define a name; and where a
|
|
reference body needs a benilla answer, it is WRAPPED here — never silently stubbed.
|
|
|
|
TWO THINGS THIS FILE USED TO DO AND NO LONGER DOES, both retired by 1751's swap:
|
|
· It declared `ContainerFrameItemButtonTemplate`, transcribed from ContainerFrame.xml, because
|
|
the Lua could be sourced and the XML could not. The XML is sourced now, so the reference's
|
|
own declaration is the live one and the copy is deleted — the whole point of the migration.
|
|
· It defined `updateContainerFrameAnchors()` as a deliberate no-op, because the reference's
|
|
body walks twelve `ContainerFrame` windows this client did not build. It builds them, so the
|
|
reference's own body is correct here and the stub is deleted. Five corpus addons (Bongos,
|
|
Bongos_ActionBar, the CT_BarMod family) hook that global and call through; they now reach the
|
|
real thing.
|
|
|
|
── The adapters, and why neither is a stub ──────────────────────────────────────────────────
|
|
`ContainerFrameItemButton_OnEnter` opens with a keyring fork (ref l.615-620):
|
|
|
|
if this:GetParent():GetID() == KEYRING_CONTAINER then
|
|
GameTooltip:SetInventoryItem("player", KeyRingButtonIDToInvSlotID(this:GetID()))
|
|
CursorUpdate()
|
|
return
|
|
end
|
|
|
|
That fork exists because the REAL client's keyring items are inventory slots, not container
|
|
slots, so it has to detour out of the container API to describe one. benilla's keyring is an
|
|
ordinary container (id -2, decision 0765): its slots come through `GetContainerItemInfo` and
|
|
`GameTooltip:SetBagItem` like every other bag's — which is exactly why the reference's keyring
|
|
WINDOW, its verbs and its sounds all take our keyring unchanged, and why this one line is the
|
|
only thing in that file the swap did not simply inherit. The detour is not merely unavailable
|
|
here (`KeyRingButtonIDToInvSlotID` is not a binding here) — it is *wrong* here, and supplying
|
|
the verb would buy an empty tooltip, because our keyring items were never fed into the
|
|
inventory-slot space it reads.
|
|
|
|
So the wrapper below answers the keyring case the way benilla answers every other bag, and
|
|
hands EVERY other slot straight to the reference's own body. The path the player is actually
|
|
on — hovering an ordinary bag slot — runs the real client's code, unedited.
|
|
|
|
── Named, not hidden: what still does not work through the sourced files ────────────────────
|
|
· `MerchantItemButton_OnClick`. The reference's `ContainerFrameItemButton_OnClick` closes its
|
|
shift-right-click-at-a-vendor arm with a `SplitStack` closure that calls that global, and
|
|
benilla's merchant window publishes `BenillaMerchantItem_OnClick` instead. Confirming a stack
|
|
split with a vendor open therefore raises. That is the same "a Benilla name shadows the
|
|
reference's" class this whole seam exists to close, one window over, and it is left loud
|
|
rather than guarded (1203): the fix is to publish the merchant global, not to hide the call.
|
|
· `REPAIR_COST` is read by the reference's repair-mode arm. It is a `GlobalStrings.lua` key and
|
|
this client sources that file too, so it resolves at runtime — and the arm is unreachable
|
|
today regardless, since `GameTooltip:SetBagItem`'s repairCost is an INTERIM 0.
|
|
· `NO_EMPTY_KEYRING_SLOTS` is read by the reference's `PutKeyInKeyRing` when the ring is full,
|
|
and no such GlobalString exists — 1.12 ships only `NO_EMPTY_KEYRING_SLOTS_ERROR`. That is a
|
|
REFERENCE BUG, and this client used to un-quirk it. It does not any more: the reference's own
|
|
file runs, so a full keyring prints the reference's own empty error line. Faithful, and
|
|
deliberately so (1751: a divergence becomes faithful or becomes a record, never silent).
|
|
-->
|
|
<Ui xmlns="http://www.blizzard.com/wow/ui/">
|
|
<Script><![CDATA[
|
|
-- The reference's own body, captured before we shadow the name. Nil on a machine with no
|
|
-- client data (nothing was sourced) — which must be LOUD at the call, not a quiet no-op:
|
|
-- a bag hover that silently does nothing is precisely the failure mode that let Bagnon
|
|
-- ship "working" through four green survey columns.
|
|
local refItemButtonOnEnter = ContainerFrameItemButton_OnEnter
|
|
|
|
function ContainerFrameItemButton_OnEnter(button)
|
|
if not button then
|
|
button = this
|
|
end
|
|
if not button then return end
|
|
|
|
-- benilla's keyring is a CONTAINER (0765), so the reference's inventory-slot detour is
|
|
-- both unavailable and wrong here; this is the same pair of calls its general path
|
|
-- makes for every other bag, which is all a keyring slot ever needed.
|
|
if button:GetParent():GetID() == KEYRING_CONTAINER then
|
|
if (button:GetRight() or 0) >= (GetScreenWidth() / 2) then
|
|
GameTooltip:SetOwner(button, "ANCHOR_LEFT")
|
|
else
|
|
GameTooltip:SetOwner(button, "ANCHOR_RIGHT")
|
|
end
|
|
GameTooltip:SetBagItem(KEYRING_CONTAINER, button:GetID())
|
|
ResetCursor()
|
|
return
|
|
end
|
|
|
|
if not refItemButtonOnEnter then
|
|
message("benilla: Interface\\FrameXML\\ContainerFrame.lua was not sourced from the "
|
|
.. "game data, so bag-slot tooltips cannot work. Check the client data path.")
|
|
return
|
|
end
|
|
refItemButtonOnEnter(button)
|
|
end
|
|
|
|
-- ══ The three bag verbs benilla answers differently (decisions 0561 + 1751) ═════════
|
|
--
|
|
-- `CloseAllBags`, `OpenBackpack` and `CloseBackpack` all exist in the sourced
|
|
-- `ContainerFrame.lua` too, and benilla's differ for one reason, not three: **0561, the
|
|
-- director's call that a window which opens your bags opens EVERY equipped bag**, not just
|
|
-- the backpack. The vendor/bank/mail/trade windows call `OpenBackpack` from their OnShow so
|
|
-- your bags come up with them and you can sell or deposit from one; the reference's own
|
|
-- body touches bag 0 alone. `CloseBackpack` is its inverse and has to match it, and
|
|
-- `CloseAllBags` is the same family's unconditional form.
|
|
--
|
|
-- **The `Benilla*` names, and the publish under them, are load ORDER** (1751). Order
|
|
-- decides every collision and the manifest is the order: this file loads after the
|
|
-- reference's `ContainerFrame.xml`, so the three publishes at the foot are the ones that
|
|
-- stand. The bodies lived in our UIParent.lua counterpart until 1988 retired it — a
|
|
-- harness with no bag stack now meets the loader's stand-ins for the three names
|
|
-- (`test_ui::UIPARENT_STAND_INS`), not a nil.
|
|
--
|
|
-- What CHANGED with the swap is only the plumbing: these used to walk five benilla windows
|
|
-- by name and stash `wasOpen` on each frame. The windows are the reference's recycled
|
|
-- `ContainerFrame1..12` now — frame N is a different bag every time it opens — so the
|
|
-- was-open memory is keyed by BAG ID, and every open and close goes through the
|
|
-- reference's own `OpenBag`/`CloseBag`/`IsBagOpen` rather than a raw Show/Hide. That buys
|
|
-- the reference's own guards for free (OpenBag's CanOpenPanels + NotWhileDeadError,
|
|
-- ToggleBag's `size > 0`) and means an addon replacing those verbs is honoured here too.
|
|
BENILLA_BAG_WAS_OPEN = {}
|
|
|
|
-- The UNCONDITIONAL close, called by ShowUIPanel's native-center branch above: a centre
|
|
-- frame takes the whole screen, so nothing is being "restored afterwards" the way a vendor
|
|
-- window restores the bags it opened, and the was-open memory is deliberately ignored.
|
|
-- Range 0..NUM_CONTAINER_FRAMES rather than the old five names — the reference's own
|
|
-- CloseAllBags covers the bank bags too (l.702-707), and now so does this.
|
|
function BenillaCloseAllBags()
|
|
for bagId = 0, (NUM_CONTAINER_FRAMES or -1) do
|
|
CloseBag(bagId)
|
|
end
|
|
end
|
|
|
|
-- OpenBackpack — 0561's all-bags form. A bag already open is REMEMBERED and left alone, so
|
|
-- the paired CloseBackpack does not close a window the player opened themselves; that
|
|
-- memory is the reference's own `backpackWasOpen`, one entry per bag instead of one flag.
|
|
function BenillaOpenBackpack()
|
|
for bagId = 0, (NUM_BAG_FRAMES or -1) do
|
|
-- The backpack always exists; an equipped-bag window only when a bag is in the
|
|
-- slot — `OpenBag` makes the same test itself, but the memory has to agree with it.
|
|
if bagId == 0 or GetContainerNumSlots(bagId) > 0 then
|
|
if IsBagOpen(bagId) then
|
|
BENILLA_BAG_WAS_OPEN[bagId] = 1
|
|
else
|
|
BENILLA_BAG_WAS_OPEN[bagId] = nil
|
|
OpenBag(bagId)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function BenillaCloseBackpack()
|
|
for bagId = 0, (NUM_BAG_FRAMES or -1) do
|
|
if not BENILLA_BAG_WAS_OPEN[bagId] then
|
|
CloseBag(bagId)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- The publish — after the reference's container file, so these are the definitions that
|
|
-- stand (the stock `ShowUIPanel` calls `CloseAllBags` and the vendor's OnShow
|
|
-- `OpenBackpack`, and they reach 0561's bodies).
|
|
OpenBackpack = BenillaOpenBackpack
|
|
CloseBackpack = BenillaCloseBackpack
|
|
CloseAllBags = BenillaCloseAllBags
|
|
]]></Script>
|
|
</Ui>
|