Commit Graph
98 Commits
Author SHA1 Message Date
SamandClaude Fable 5.1 6af2bfcb73 plates take the mouse, Auctioneer loads, and the damage font is yours
- hovering a nameplate lights its unit and clicking one selects it, pfUI's click-through works, a drag that starts on a plate still turns the camera, and turning plates off with V clears them (2159)
- Auctioneer's XML documents open (the reference has no XML namespaces), a .toc line reaching Blizzard_AuctionUI's templates resolves for Auctioneer, BeanCounter and SpecialTalentUI, and a missing include logs rather than raising the red error dialog (2155)
- a .lua reached through <Script file=> carries the same Interface\AddOns\ chunk name as a .toc-listed one, so Ace2's debugstack split works and AtlasLoot keys its database; 26 more corpus addons load, 176 of 219 (2155)
- the floating combat numbers draw in whatever DAMAGE_TEXT_FONT holds at world entry, so MikScrollingBattleText and pfUI pick the font (2156); a dodged swing prints no line and floats no word, and happiness leech lines print (2157)
- an unknown frameStrata in XML logs and keeps the default instead of raising, so EQL3's log window loads; FrameXML_Debug is a real switch, so ImprovedErrorFrame loads (2160)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 20:56:00 +07:00
SamandClaude Fable 5.1 38e45badb9 nameplates are frames, guild names go overhead, and the camera pivots
- a nameplate is a real frame under WorldFrame, six regions and a health bar in the reference's order, so pfUI, ShaguTweaks and _Nameplates find and restyle plates instead of seeing none; the plate stays out of the mouse's way in this cut (2148)
- a player's guild shows under their overhead name in angle brackets, the line an NPC's subname already used, gated by the UnitNamePlayerGuild option at its stock on (2149)
- smart camera pivot is on, as 1.12 ships it: a mostly vertical drag with the camera pressed against something tilts the view instead of swinging the arm, easing home on release; in water the pivot rises for a swimmer (2149)
- Follow Terrain and head bob are built and ship off, as in 1.12: Follow Terrain leans the camera up or down the slope you are walking onto, and head bob sways the first-person eye in a figure of eight while you move (2149)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 20:55:15 +07:00
SamandClaude Fable 5.1 fed2c96ec8 the mailbox takes typing again, and events carry their real arguments
- the mail window's send tab takes typing again: the subject, body and money boxes were taking no input while the recipient box swallowed every key, and a sent letter clears its subject and item icon instead of putting them straight back (2145)
- seven events fire the way the reference does: UNIT_DYNAMIC_FLAGS fires at all, swapping two identical stacks between bank slots fires PLAYERBANKSLOTS_CHANGED twice, the pet sheet's training points repaint, and ITEM_LOCK_CHANGED loses its invented arguments (2140)
- nine widget methods 1.12 addons probe for are in: ShaguTweaks stops recolouring textures the reference leaves alone, pfUI and _Nameplates stop raising on a tooltip's GetAnchorType, and 63 AceEvent addons get RegisterAllEvents (2142)
- six post-1.12 methods leave the widget surface (SetSize, SetShown, HasFocus, SetFormattedText and two tooltip verbs), so an addon reaching for a later client's API finds what a real 1.12 client gives it (2142, 2146)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 20:52:50 +07:00
SamandClaude Fable 5.1 3f3cf21afa a slider snaps to its step, a pushed button releases, and warnings show
- a slider with a value step snaps to it: a stepped drag fires once per row instead of once per pixel, a scrollbar cannot rest between two rows, and one wheel notch on the trainer list reaches the bottom (2133)
- setting a step on a live slider moves its value onto the new lattice and runs its handler, which an addon on the real client can count on (2143)
- a button pushed from script releases on the next mouse-up, so Tablet-2.0's rows stop staying pressed forever; a release off the button's rect un-presses it, and a locked state holds (2134)
- the mail body and the GM ticket box scroll as you type past their bottom, and the Use UI Scale checkbox reads a registered setting (2141)
- an engine warning, a call that was accepted and did nothing, reaches the /errors window in grey instead of one terminal line; a text row trimmed mid-character no longer kills the window's repaint (2135, 2138)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 20:52:20 +07:00
SamandClaude Fable 5.1 d8de29bd9b idle sits you down and camps you, and the addons anchor, parse and draw
- five idle minutes sit you down and flag you AFK, thirty log you out through the ordinary countdown; holding a key is idle, moving the mouse is not, and a swimmer stays afloat (2092)
- a knockdown no longer wedges: the landing froze the clip that held the base-animation lock, leaving a knocked-down player on their back for the session (2098); the perf cost pill starts hidden (2099)
- Lua is exactly 1.12's 5.0 — no vararg expression, no #, no %, the remembered table size — so Cartographer loads without errors and Mik's Scrolling Battle Text shows its text, in its own shipped font now that addon TTFs load (2101, 2102, 2103)
- a widget name is a Lua global for SetPoint and its kin, so Bartender2's bars spread out; a button's NormalText disowns its justify, the raise renumbers hidden frames too, and a missing toc file warns instead of erroring (2105, 2100, 2104, 2107, 2106)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 16:35:03 +07:00
SamandClaude Fable 5.1 4040166138 the model pane takes the file's camera, and the who list sorts
- the `<Model>` widget's perspective leg: a pane whose file supplies the camera it selected renders through a camera of its own whose viewport is its own cell of the same tile atlas — the reference's structure, one target, a viewport per widget, depth cleared per widget — with the composite, packer and reaper untouched; the selection is RAW (`0x76cec0` reads the count off `MD20+0x124` and the record at `[model+0x3c4] + idx·0x84 + 0x80`, `cameraLookup` never consulted), so `M2Model::cameras` is the whole table in file order and `benilla-extract m2cam` prints it, reproducing wow-re's numbers to the digit; the camera is two fields because the reference has two — `+0x320` a PENDING index and `+0x31c` the installed one — and while a request is pending the pane paints nothing (`76d5f0`'s draw gate, now the paint list's own filter); an index past the count installs the NULL camera, which IS the orthographic leg every shipped in-game pane takes; the projection is the booths' byte-derived diagonal-FOV matrix at the pane's aspect, and the eye and target ride the model's root transform as `0x718960`'s publish does — so `SetFacing` cancels along with `SetPosition` and `SetModelScale`, a contradiction with a wow-re note that went out as a §5 round and came back agreeing: the up vector `0x7ac640` builds is model-space +Z at roll 0, the very axis the facing turns about, and the note's sentence is scoped to `<PlayerModel>`'s frozen camera; each perspective camera takes a render layer of its own from a pool of eight, the orthographic camera clears the atlas and every perspective one clears only depth; `SetLight` is a typed `CGLight` that folds each intensity into its colour, normalises a direction on write, quantizes to 8 bits, returns before the copy on `SetLight(0, …)` and reads the second intensity at index 8 on a short ambient block; the five fog verbs are built (`ClearFog` is `76f5c5 and [edi+0x3a4],-2`, bit 0 alone), so the `Model` UNBUILT list is empty for the first time since 1134; a pane that arms a light or fog takes a rig from a lazily-grown pool, and the tiles' material twins — never reaped since the cache was written — are; `WOW_PROBE_MODEL_CAMERA=1` reads the renderer's own camera back for the three cancellations, `pass=5 fail=0` (2027)
- the layout cache writes in the shutdown tail: an unlocked chat window's size and position did not survive `/logout` or `/reload` and `benilla-config/layout/` was never created (B353) — the lane was right (1.12.1 persists a chat window through `StartMoving`/`StartSizing` and the engine's userPlaced bit; no `SetChatWindowSaved*` verb exists in the 5875 FrameXML), but `UiLayoutPlugin` hung its flush on `OnExit(InWorld)`, which a `/reload` never leaves, its debounced writer was never registered in `Update` at all, and on the roots where the edge did fire the VM-reading saver raced `end_ui_session`'s VM replacement on the same unordered edge (measured: the placement moves with nothing but registration positions); the reference's UI shutdown `0x490bd0` has an ordered tail — `PLAYER_LOGOUT` (`0x490c2a`) → `layout-cache.txt` (`0x490c79`) → the flat saved file (`0x490c7e`) → the per-addon files → `AddOns.txt` — on the same five roots as SavedVariables, `/reload` included, so `save_now` joins `shutdown_ui_state` in that slot, one call site reached from every root, and its own edges are deleted; the debounce stays as the crash writer and only that, a deliberate divergence, and the chat-look flush next door is pinned `.before(end_ui_session)` (2029); the VM gets its font engine at the LOAD edge: the measurer was seated only from an `Update` system on the first frame the glyph atlas exists, but `ReloadUI()` mints a fresh VM and runs the in-game load in the same exclusive slot, so every `<OnLoad>` and every addon's file scope measured 0 through the whole reload (`LOAD MEASURE ZERO` live, 33.185 after) — `seat_text_measurer` is one construction site called from both edges; the options tabs fit once from `<OnShow>`, the `OptionsTab_FitWidth` OnUpdate poll and its `fitted` latch gone, because `GetStringWidth` answers in the region's own units and this window's 0.78 scale is applied in the window's own `<OnShow>` after every `<OnLoad>` — an OnLoad fit read 73.19 where the settled value is 76.47; the settled widths are unchanged to the last digit (76.467232 / 91.661896) and the one-frame 72/87 flash at every open goes; four comments that still called the text measure a frame late, and seven gossip-suite comments that put `UIPanelScrollFrameTemplate` in our `ScrollTemplates.xml` when it lives in the reference's `UIPanelTemplates.xml`, are corrected (2028)
- the `/who` sort is a seven-key chain, not "order by the clicked column" (B365): the reference keeps seven `{key, dir}` slots at `0xc2817c`, seeded zone → level → class → group → name → race → guild; `SortWho` (`0x5ad890`) promotes the clicked key to the front and flips its direction ONLY when it was already there — Name, Name reverses, Name, Level, Name restores what the first click left — and the comparator `0x5ada00` walks the chain as tie-breakers, most-recently-used first, through an ASCII fold (`A`–`Z` by `+0x20`, not a Unicode one), the three DBC arms comparing the localized name out of `ChrClasses`/`ChrRaces`/`AreaTable` where ours had sorted by raw id, and an unresolved row TIES (its miss jumps to `0x5adbb2`, the chain loop's own `inc esi`); the click fires `WHO_LIST_UPDATE` synchronously through `SignalEvent` at `0x5ad9ed`, so the binding promotes and sorts the snapshot and the handler repaints before the OnClick returns, where ours redrew a tick later — a redraw one click stale reads exactly like a header that does nothing; the chain is process state (initialised once from `0x401666`), so it survives a logout; the rider from the same carve: `SMSG_WHO` has two exits, and with `SetWhoToUI` clear more than three rows go to the frame with nothing printed and three or fewer to chat (`0x5adfcc jl`, `eax = 3`) where we printed every unclaimed answer; and wow-re's §11 round corrected the first build before it landed — the chat lines come out in WIRE order with the total line LAST, because `0x5ae0a1` composes each line inside the parse loop and the `qsort` at `0x5ae0e2` sits past its back-edge (2030)
- two lighting reports, one frame and one bit each: the surfacing hitch (B354) is a one-frame stale atmosphere — `update_time_lighting` is late by construction, waiting on the wire drain, the weather tick and the submersion verdict, and five `Update` systems that read the `WowLighting` it resolves declared no ordering, so the executor handed each of them last frame's value, deterministically and invisibly while the atmosphere drifts a minute at a time; at a submersion crossing it jumps, on the very frame the sky and cloud domes un-hide, so the first dry frame painted `LightParams` 27's underwater sky over a dry world (the clip's blue frame, (58, 137, 173) against the settled (53, 58, 34)) and `tick_clouds`' surfacing full-rebuild ran at the underwater cloud density, 0.0, rebuilding an empty field that crept back over 0.4 s — the fix for the pop-in handing the symptom straight back; `LightingConsumeSet` names the read side of `LightingResolveSet`, tied in one place, and four consumers join it, the FFX haze and warp are ordered after the verdict they had the same hole against, and two tests enforce it — zero ambiguities between the two sets, and a source scan over `benilla-world` that fails any `WowLighting` reader not in the set; `emit_minimap` is left stale knowingly because joining cost a 178th item through the world API wall; `WOW_FORCE_SUB=<frames>` holds the eye verdict submerged and releases it, so the crossing reproduces server-less (2032); the black furniture below a boat's deck (B373): `MeshTag` bits 6..=13 are the exterior payload's ground-shade byte and bits 6..=18 the interior payload's SH-probe slot, and `entity_shade` guarded the overlap by asking whether a part was on the interior classifier's Bake law — one of the TWO populations holding a probe slot; the other is a lit interior MODD prop, which a WMO-display GameObject parents under the net entity so it sails with the deck, putting it inside the light node's descendant walk — so every frame the boat's shade byte was written over each prop's slot, `(slot & 0x1f00) | byte`: a neighbouring prop's light where that row was live, a zeroed row — solid black — where it was not; the guard now asks the payload question (`probe_payload`) at both write sites, the tag's bits and the marker derived from one binding; measured live at Ratchet, 749 of 749 resident interior prop parts renamed before, 0 of 640 after, and both ledger leads refuted at the bytes — the MODD colours are healthy (`floor112` raises even `#010101` to diffuse 112) and the fold is rigid-motion invariant since every 1.12 transport authors zero MOLR lights; a prop's mouseover identity now names its lane, words and probe slot, and `WOW_PICK` prints `model_flags.z` (2031); the sea-crossing probe can now measure the seam a report names — an explicit `WOW_PROBE_DOCK` goes first, boards only once the body stands at the dock, carries a map id, takes only a candidate within boarding distance, and drops onto the deck rather than into the hull, because a taxi node's `z` is the WATERLINE for the sea ferries while their decks stand ~16 yd above it — and the seam re-anchor returns the cycle it moved to or `None`, so a healthy crossing no longer logs the server's 9.7 h uptime as a skew inside a 350 s cycle

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-06 19:37:40 +07:00
SamandClaude Fable 5.1 5c26c233c3 the cooldown goes stock, early-Z comes back, and lists reach the end
- 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>
2026-09-06 19:35:31 +07:00
SamandClaude Fable 5.1 b7cb2668e9 the autocast shine goes stock, and a disabled button keeps its art
- the autocast shine is the reference's own Model: `UI-AutoCastButton.mdx` has no batch at all — four bones walking the corners of a 0.02-unit square on a 2 s loop, each with a spline emitter pouring 300 `GlowStar` sparks a second — and the tile renderer plays exactly that off the file's own tracks, so the hand-transcribed lane retires whole: `autocast_shine.rs` (the token texture, the extract's parked shine sites, the append-lane producer and its motion goldens), the extract's shine side channel, and `PetActionBarAdapters.xml`, since the pet button's numbers are the reference's (`setAllPoints` at `scale="1.2"`) and nothing was left to adapt; what stays is the director's two look calls, re-seated onto the reference's own objects — `SpellBookAdapters.xml` puts the stock `$parentAutoCast` Model at 37×37 CENTER (0,0) with `SetModelScale(1.48)` and the overlay at 71.53, the two tests that pin them reading the live panes, and deleting that file is the exact reference (36×36 at CENTER (1,1), 1.22, overlay 60); `assets/ui` is nine files (2014)
- a button's shown state texture is latched on the transition, not resolved at paint (B369): `ReputationDetailAtWarCheckBox` has a `<NormalTexture>` and no `<DisabledTexture>`, and once `ReputationFrame_Update` `Disable()`d it ours drew nothing — `ButtonState` resolved the shown texture as a pure function of (enabled, pushed, held+hovered); the client's `SetState` `0x779790` gates both its hide-old and show-new steps on the NEW state's slot being non-null, with no Normal fallback anywhere in the function, and the ctor `0x7786a0` ends in `SetState(NORMAL)`, so every button reaches its first `Disable()` (`0x77ffd0`) already wearing its normal art and keeps it; `ButtonState` now carries the client's two words, `shown` (`+0x4c4`) and `state` (`+0x328`), written only by `set_state` and the `0x778fd0` setter family's conditional push, with transitions applied where the client applies them — `Enable`/`Disable`/`SetButtonState` and the four mouse edges — and the old `pushed.or(normal)` special case was this rule seen from one side; the stock corpus has 70 such declarations, so empty spellbook slots wear their `UI-Quickslot2` ring again, which 0227 had removed on a premise the shipped Lua falsifies in one line (`SpellButton_UpdateButton` calls `Disable()` at runtime); and `Disable()` switches off the whole HIGHLIGHT draw layer — `0x779160` follows `SetState` with `push 4; call 0x76a730`, the per-layer enable on the same `[frame+0x198]` array `Enable/DisableDrawLayer` writes — so a `<Layer level="HIGHLIGHT">` region no longer draws over a disabled button and the `enabled &&` term on the HighlightTexture alone is gone; the reputation tests' header stops claiming the page and the watch bar were ours (2011)
- the world's mouse buttons are latched, not read raw (B364): right-clicking a Who-list row swung the camera round to behind the character — ~180° over nine seconds on a body that never turned — because the click was the UI's but the camera's input command word (`[InputControl+0x4]`) built its two mouse bits straight off `ButtonInput` with no pointer-over-UI term, `RIGHT_MOUSE` alone classifies as `Turn`, and Smart's Turn row is `(0.0, 1.0)`, so the return armed on the press edge and ran to completion; 1.12 never reads the mouse for any of this — it reads two bindings, `TurnOrAction` and `CameraOrSelectOrMove`, and a press a UI frame captured dispatches neither — so `camera::WorldMouse` latches each primary at the press and holds it to that button's own release, written in its own system ordered ahead of every reader (latched rather than re-tested, because a level test would hand a button back to the UI mid-drag the moment a frame appeared under the locked cursor, and an edge is what arms a return); five readers move onto it — the follow word's mouse bits, the both-button run, `/follow`'s both-button cancel, the look session's engage, chord cancel and other-primary tests, and the both-button → single-button handoff — and `control` drops its `PointerOverUi` and `&Camera`, the viewport-vs-UI question no longer being its to ask
- the clutter onset is the cutout, and it gets the reference's own dial: the ramp runs 52.64 → 69.86 yd but the draw alpha-tests `texel.a × ramp` against `detailDoodadAlpha` = 128/255 with the ramp capped at 252/255, so nothing survives past 61.11 yd — grass appears there already at 50.2 % opacity with 8.5 yd left to reach full, and the last third of the ramp is spent where nothing is drawn, which is exactly the "started before it became visible from another gate" the director saw; `detailDoodadAlpha` is a console command in the reference (`0x6739a0`, registered through the command table `0x63f9e0`, not `CVar::Register` `0x63db90`, so it never persists), and we had it only as the boot-time `WOW_CLUTTER_ALPHA`, which cannot be A/B'd against a running client — `/console detailDoodadAlpha <0-255>` now sets it live, bare reports, and out of range is rejected rather than clamped (`0x6739b9: cmp eax,0xff; jbe`), classified in the console drain of 2008's `ConsoleExec` seam so it never reaches the CVar store, the bubble re-cut on a change because the ref is baked into the material; at 128 grass appears at 61.11 yd at half opacity, at 8 the onset walks out to ~69.8 yd and fades in from nothing; a late-build tripwire in the streamer — a warning whenever a chunk is built whose box is already inside the fade horizon, naming whether the distance gate or the per-frame cap was the cause — fired at once on the second: the build budget was spent in query order, so a chunk 90 yd out where the ramp is already zero took a slot ahead of one at 48 yd in plain view; candidates are sorted by distance now, and a 30 s Elwynn run reports one late-build frame, the cold first, then silence (2012)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-06 19:34:43 +07:00
SamandClaude Fable 5.1 c957f98d84 grass fades on a plane, model panes render, and the FPS journal ships
- the grass fade is a plane across the view, not a ring around the player: `0x6b2b80` texgens the camera-space position through `T(0,0,−52.5)·Ry(π/2)·S(1/17.5)`, so the fade coordinate is view-space depth, `u = (z_eye − 52.5)/17.5` — we measured `distance(eye, fragment)`, a sphere, which meets the ground as a circle centred on the player that slides as they walk and bites a piece out of every tuft it crosses, and that was the hard border; the ramp is `0x6b2320`'s quantised 64×8 table, `alpha = 4·(63 − col)`, read bilinearly as `(254 − 256·u)/255` and capped at `252/255` — plateau to 52.64 yd, zero at 69.86 yd, near grass 98.8 % opaque and never 100 — where we had a clean 1 → 0 line; the product `tex0.a × ramp` is what the 128/255 `detailDoodadAlpha` cutout tests (both stages MODULATE, `[0xc7b2fc]`, confirmed verbatim in all four apitrace captures), so the tuft eroding out at 61.11 yd is the reference's own behaviour and the "fix" that would have removed it never landed; the pass owns its render state — blend mode 2, ALPHAREF 128, cull off, depth-write on, the per-slot draw `0x6b2d60` binding nothing but the texture — where we passed the batch's authored blend and cull through, and the `clutter_state` probe counted the cost: of 322 detail batches, 2 author Opaque (no cutout, their margin drawn as a solid card) and 5 single-sided; the build gate measures the chunk's box against the frustum corner ray derived from the live projection (≈1.31× at 16:9, ≈1.45× at 21:9), not its centre plus a 24 yd margin that popped whole chunks in on relief (2004)
- a `<Model>` widget's animation state is Lua-observable and lives in the engine: a private scene clock its own `OnUpdate` advances by `trunc(elapsed·1000)` ms on visible frames only (`0x76d7f0`), an arm with an anchor the sampler re-reads every frame (`0x7121a0`), `OnUpdateModel` at the top of every paint (`0x76d1a0`) and `OnAnimFinished` from the completion callback (`0x76cdc0`); the file's sequences and bounds are facts the host hands over, `SetModel` seeds Stand now or when they land (`0x70ebd0`) with a queued arm replaying after the seed, and the XML `scale=` on a model pane is the model's scale (`CSimpleModel::LoadXML` `0x76cac0`), which the loader had never read (2007); and the pane renders its M2 — every visible pane with a file gets a cell of one render-target atlas at its device size through one orthographic camera, the root at `1280·modelScale·layoutScale` FrameXML units per model unit, the tile's `AnimationPlayer` paused and seeked to the engine's play head, the light black, particles in their own unit (`768·√(a²+1)` per model unit, neither scale), composited as one premultiplied quad at the callback rank; two corrections off the bytes: `OnUpdateModel` fires only with a model installed (`[widget+0x318] ≠ 0`) and `OnAnimFinished` fires once per arm for a looping sequence too (`0x719370`); the loader now applies a `<Model>`'s `file=` at all, which every XML-declared pane had lacked; retired: the minimap ping's byte-measured sprite, since `MiniMapPing` and `WorldMapPing` draw their own file on the pane's clock (2013)
- the stance feed fires `UPDATE_SHAPESHIFT_FORMS` only for a list change: the reference fires it at `0x4b28ff`/`0x4b2e43` from learn, unlearn and rank-replace alone, while ours fired on any change of the pushed view, and every fire runs the stock `ShapeshiftBar_Update`, which shows `ShapeshiftBarMiddle` unconditionally past two forms and `Show()`s an already-shown frame — no `OnShow`, no manage pass — so a stance switch or the category-47 cooldown arming and expiring left the middle strip drawn alone over a raised bottom-left bar; castability now rides `SPELL_UPDATE_USABLE` (`0x4b31c0`), active/texture/cooldown are pushed silently and repainted on `PLAYER_AURAS_CHANGED` and `SPELL_UPDATE_COOLDOWN`, the feed ordered before both handler sets so they read the fresh list (2009); and the loot-roll frame waits for its item template (B371): `GroupLootFrame_OnShow` paints once and nothing repaints it, and we fired `START_LOOT_ROLL` on the frame the packet arrived, against a snapshot whose name, texture and quality were still `None` — the reference's `0x61b310` ends in the item-template cache lookup `0x55ba30`, a hit firing the event there and a miss firing it from the arrival callback `0x61b460`, so the feed holds a fresh roll's event until the template answers, with two releases that are ours: a negative answer (a frame that never opens cannot even be passed on) and a 2 s deadline paid out of the roll's minute; `arg2` stays the wire's countdown, as `0x61b430` pushes it (2010)
- the FPS journal ships to players: it had registered inside the dev-only `DevToolsPlugin` and been armed by an environment variable, so nothing we shipped could have written a row on the one GPU-bound frame in the corpus, a Steam Deck's at 94 % busy; `/console fpsJournal 1` — a CVar of our own, persisted like every CVar — opens `benilla-config/Diagnostics/fps-journal.csv` and appends one row a second, `0` closes it mid-run, and `WOW_FPS_JOURNAL=<path>` stays as the harness lever; eight GPU columns appended, `gpu_ms` then `gpu_opaque, gpu_static, gpu_transp, gpu_glow, gpu_post, gpu_ui, gpu_other`, read off bevy's `RenderDiagnosticsPlugin`, which times passes where the device offers `TIMESTAMP_QUERY_INSIDE_PASSES` (Vulkan and DX12) and leaves the cells empty on an Apple GPU, empty being the honest value; `static_gx`, the four `ffx_glow_*` passes and `ui_gamma_decode` open diagnostic spans so a city's own draw is named in the split; a fresh file opens with the adapter, backend, driver and `gpu_spans yes|no` line; and a probe's `/console` line, which skips the stock `ChatEdit_ParseText` and had landed in a parser arm that knew only `reloadUI`, now forwards to `ConsoleExec` and writes a CVar the way the typed line does (2008)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-06 19:33:58 +07:00
SamandClaude Fable 5.1 ed92f71af8 the gossip window stops flashing, and the chat plate fades in again
- the gossip window stops flashing on a first-visit sub-menu: a guard's "Where is …" option answers `CMSG_GOSSIP_SELECT_OPTION` with a new `SMSG_GOSSIP_MESSAGE` on the same NPC whose text id is a first visit, and 1508's hold made the snapshot `None` while the greeting query was in flight, which the feed read as `Some → None` — `GOSSIP_CLOSED` (`HideUIPanel`) at the select, `GOSSIP_SHOW` (`ShowUIPanel`) when the text landed, the window gone for a server round trip, once per text id because the record cache serves every later visit; the reference's `0x4e2010` on a cache miss sets its select latch (`[0xbbb670] = 1`) and returns with no greeting write and no event, `0x4e1fa0` closes only on a zero guid, and `SelectGossipOption` (`0x4e2320`) is refused while the latch holds — so `GossipState::text_pending` names that latch, `feed_gossip` returns before touching the VM while it holds, both drains refuse on it, the NPC name query is asked ahead of the gate so a first visit's name rides beside its text query, and the landing repaints in place (1994); and the ready check is read off the bytes: `0x4ba40e` stores the constant 0 for any guid-matched answer, the wire byte only gates the `RAID_MEMBER_NOT_READY` print ("%s is not ready") on a 0, `ConfirmReadyCheck` sends one byte, 1 or 0, only while the deadline is armed and unexpired, `DoReadyCheck` sends an empty body, the summary lists only members who never answered, and the early close fires iff no member is both pending AND online (`[entry+0x18]` bit 0) — an offline member who never answered no longer holds the check open and is still listed as AFK when it closes; the `SMSG_GROUP_LIST` leg's close predicate (`0x4ba5f0`) keeps 1989's reading, with no online term (1997)
- the chat menu's rows hug their left edge: a `UIMenuButtonTemplate` row has no `<ButtonText>` — `UIMenu_AddButton` labels it with `SetText` — and the only thing placing the label is `<NormalFont inherits="GameFontNormal" justifyH="LEFT"/>`; the reference's lazy creator (`SetText 0x778dc0`) hands the fresh string to the adopter `0x778d20`, which anchors an unanchored label by the BUTTON's normal embedded font's justify word (`[button+0x390]`: LEFT→LEFT / RIGHT→RIGHT / else CENTER) and links it to that font, where ours anchored by the string's own ctor-default word (CENTER) and the loader wrote the justify onto a force-created label after the anchor was already decided — so every row sat centred in its fixed 104-wide slot and "Macro" ran into "/macro" (1.12's `UIMenu` does not auto-size; `UIMenu_AutoSize` is a later client's); `ButtonState` now carries each state font's own justify, one adopter (`button::adopt_label`) is the tail of both `SetText`'s lazy creation and `SetFontString`, the loader never touches the label, and paint follows the current instance's justify behind the severance mask like every other axis (1996); and the chat plate's hover fade survives a quick exit and re-entry: the stock `FCF_OnUpdate` queues the tabs' fade-out with `FCF_ChatTabFadeFinished` as its finished callback, which nils `chatFrame.oldAlpha` unconditionally 0.15 s later — re-enter inside `CHAT_FRAME_FADE_TIME` and it lands under a live hover, the plate arm's gate never passes again, no later leave clears `hover`, the hover-start re-read never runs, and only `FCF_SetWindowAlpha` (the tab menu's opacity slider) reseats it, which was every clue in the report; the flick from the text to a scroll button and back is the gesture, so an existing window looked broken from a session's first hover; the repair is the smallest guard at the one line — the finished callback leaves `oldAlpha` alone while `hover` is set — installed from Rust after the manifest loads (`manifest::install_chat_plate_guard`), never written into the stock file, and named as a deviation from the reference's own Lua (1998)
- a layer drains its quads, then its text, then its model scenes: `ZKey`'s one font-string bit becomes a two-bit batch rank (Quad, Text, Callback) — the client's layer batch (ctor `0x772e80`) carries its quads at `+0x10`, its `CGxStringBatch` at `+0x18` and a `RENDERCALLBACKNODE` list at `+0x1c`, `0x76fb00` drains them in that order, and `0x76d160` registers a `Model` frame's scene for the ARTWORK batch only — so a `ModelPane` quad takes `ZKey::callback(Artwork)`, after every texture AND every font string of its (strata, level, layer) whatever their link stamps and before anything in the next layer, closing the residual 1992 named on the world map (the arrow is linked first under `WorldMapFrame`, the area label and the overlays later); two scenes in one bucket keep registration order, and the link stamp gives up one bit (19 → 18), which the arena's renumbering at the cap makes unobservable (1995); and the two full-screen vignettes are dead code in 5875: the string `PlayerStatus_OnUpdate` occurs zero times in `WoW.exe`, the per-frame pump runs a frame's OnUpdate by registry reference (`0x70518c lua_rawgeti`, `0x705199 lua_pcall`), the whole `lua_pcall` census has exactly two by-name calls from C, and the only `UIFrameFlash` sites for `LowHealthFrame` and `OutOfControlFrame` in the chain are inside that uncalled function, while the `PLAYER_CONTROL_LOST` arm only sets `UIParent.isOutOfControl` — so 1988's "losing control flashes the vignette" is withdrawn, the two `.blp`s ship and are never loaded, nothing in code changes, and the manifest's note on the two frames says why no driver exists (1999)
- a tiled UI sprite wraps only the axis whose mapping runs past the texture: at four forms `ShapeshiftBar_Update` maps the stance shelf's middle strip `SetTexCoord(0, numForms-2, 0, 1)` — tiling along u, spanning exactly `[0, 1]` in v — and the repeat-sampled image it was served from wrapped BOTH axes, so bilinear at the strip's top pixel row reached `v < 0` and wrapped to the texture's last row, opaque grey on the 32×32 `ShapeshiftBarMiddle.blp` whose rows 0–7 are transparent: a one-device-px hairline along the strip's top edge over the world, reading 0.81–0.84× its neighbours' luma against 1.00 over the clamp-sampled caps (predicted 75 over a world of 100, measured 74–77); 1608's `uv_clamp_window` skipped an axis spanning the whole texture because "the sampler's own clamp already is this", true for the plain sprite and false for the tiled one; `tiling_axes` now decides the wrap per axis with the same tolerance, `WorldAssets::sprite_texture_wrapped` bakes `Repeat` where asked and `ClampToEdge` elsewhere, cached by (path, u, v), and the backdrop pieces and the chat bubble's edge keep both axes on; `WOW_DEMO_BOTTOM_BARS=0` leaves the action-bar demo's bottom bars down, the only state the shelf draws in (2000); the duplicate-placement census rides the probe line (`orphan_parts=`, `tiles=`) and the inspector card (parts alive, parts drawn this frame, each glow card's live world scale): a placed doodad or WMO part is spawned by exactly one placement, so a part alive outside every placement's entity list outlived a respawn, with the retained pass's fader exiles named as the one population legitimately outside the registry

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-06 19:31:38 +07:00
SamandClaude Fable 5.1 a5382d7b37 still frames skip settled work, and a guild can design its tabard
- on a still frame the world stops redoing settled work — each cut an exact gate, measured with the process pinned to the efficiency cores, where the main thread IS the frame: point lookups go through the water index, a terrain column tests its cell's four fan triangles, not the chunk's 256 (−1.3 ms), the flare march resolves its tile once, the static-world publish and light blob write only on change, billboards, emitter gates (off the new-portal edge), doodad-anim verdicts, the visibility walk, the unit publisher (its filter a named type), a rampless unit's alpha and the stable feed skip when nothing moved, the rig evaluator reuses its scratch, dormant emitters skip their step, child wiring visits pending emitters only, the shade map persists, and the terrain streamer skips its walk once settled; alone parked 25.4 → 21.6–22.8 ms of main thread, 32 → 36–38 fps there with nothing on screen (1979, 1982)
- the UI tick got the same treatment: a solo run's colour rides the material, not the mesh — the glow pulse's one `Assets<Mesh>` write a frame had armed bevy's asset-changed probes over ~44 k `Mesh3d` rows (−1.0 ms); script object ids index a dense map instead of a hash, where every scripted method call starts (−0.7 ms); the draw list is fingerprint-cached, walked every frame and sorted only when it changed (the list a named type); and the instrument that made the gates count at all: the first battery read flat until the probe printed how many frames each gate input had read as changed — `noisy=[cam:0,dbg:299,view:0,win:0,claim:0]` — one dev system took `&mut` on `DebugState` every frame to test a flag, so bevy marked it changed on 299 of 300 frames and silently disarmed every gate reading `debug.is_changed()`; it reads the flag first now, and the counters stay on the probe line (1982)
- two of the new gates were wrong the day they landed and are fixed in the same snapshot: the streamer's settled skip engaged the frame `complete` flipped, with the retained pass still baking the new cells, and froze the undrawn count `presentable()` reads above zero — the loading screen stayed up for good after a `.tele`; it now waits for a paced, presentable, complete world and keeps that count fresh; and the still-frame gates read the camera's `GlobalTransform`, which moves only after propagation — which runs after them — so a teleport frame carried every host's pre-snap verdict across the snap (a lamppost glow due to park kept its clock, over-bright after the `.tele`); the gates read the seat's own `Transform` write too (1982)
- a guild master can design the guild's tabard: the reference's own `TabardFrame.xml` joins the manifest (benilla never had the window), opened only from the wire — the click ladder's TabardDesigner arm now sends `MSG_TABARDVENDOR_ACTIVATE` and the Battlemaster arm its own hello (1861's two deviations retire); the `TabardModel` method table runs over five ints bounded by the `.rdata` table `{170, 17, 6, 17, 51}`, the design previews on the player's own body so the pane and the world show one look, and `Save` runs the fourteen pre-flight checks in the reference's order; the world frame is the reference's own `WorldFrame.xml` too — the framerate readout is live on CTRL-R — and the carve settled its kind: a `Frame` to Lua, a one-shot type, the sole tenant of stratum WORLD, and not "over the UI" when hovered, so world clicks and camera look stay live while its scripts fire (1977, 1983, 1984)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 21:00:42 +07:00
SamandClaude Fable 5.1 9bf64e1a6b the minimap and world map go stock, and the chat loses its white plate
- the minimap cluster and the battleground list are the reference's own `Minimap.xml` and `BattlefieldFrame.xml`, ours deleted, and the sixteen engine names the static probe found unbound are built, not stubbed: the battleground list and queue family (the as-group join refused client-side with no packet when the map's `MaxPlayers` is below the group), the bodyless `CMSG_BATTLEFIELD_STATUS` on world enter — benilla never sent it, so a queue joined before a reconnect was invisible — the 5.5556 yd `BATTLEFIELDS_CLOSED` leash, and the meeting-stone pair over the `0x295` five-way table with both asymmetries; the ping's lifetime is the stock Lua's now (held 5 s, faded 0.5 s), `GetPingPosition` answers two numbers always — our nil was a Lua error on every frame of the stock `Minimap_OnUpdate` — and the map-change drop the reference never had is gone (1974)
- the world map is the reference's own `WorldMapFrame.xml`, our transcription deleted; built for it: the arrow-frame family (an anonymous `Model` child at its 33.6 px footprint, drawn app-side as the minimap's own arrow sprite through one shared constant), the battleground position family over `MSG_BATTLEGROUND_PLAYER_POSITIONS` both ways (the reference's 5000 ms request throttle), and `GetPlayerMapPosition` resolving `raid1..raid40` where it knew only the party (B320); `SetupFullscreenScale` — the engine binding `0x48c270` the map's and the cinematic frame's OnShow call, which our map had stood in for with Lua — is bound to the carved law `min(0.75 · aspect, 1)` off the configured aspect, written through the frame's own `SetScale` (1.0 at 4:3 and wider, 0.9375 at 5:4); a hovered POI writes the map's own area label, not the tooltip; named gap: `WorldMapPing` draws nothing yet (1980, 1981)
- the tutorial frame is the reference's own `TutorialFrame.xml`, over a tutorial system benilla never had: two bit banks filled from `SMSG_TUTORIAL_FLAGS` — the fire-once bank `TriggerTutorial` reads and sets (never a send) and the acknowledged bank `FlagTutorial` writes and sends; there is no tutorial CVar in the binary (210 `CVar::Register` sites censused), so "disable tutorials" is every bit acknowledged; the sites this app can produce are wired (the world-enter Welcome cascade, the level-up arm, item pushes, the loot sparkle, the meeting-stone and battleground arms), the rest named; the loader learned `<TitleRegion>` — the stock frame's drag handle, a region that emits no quad; and the `TabardModel` widget kind arrives ahead of its window, five ints bounded by the `.rdata` table `{170, 17, 6, 17, 51}` and the constant 100 000 tabard cost (1976, 1977)
- the chat window drew as an opaque white plate: the chat-cache loader, gated on `InWorld` alone, restored into the boot VM 130 ms before the deferred entry load filled it, and its per-VM memo then blocked the restore that would have reached the real frames — the plate the stock Lua tints black stayed the XML's white; between the entry edge and the load there is now no VM in the world (the edge parks the boot VM, the load takes it back), so no in-world feed pushes into a VM with no interface; the perf pill reads `59 fps  7.0 ms  17.3 cpu` — the MAIN thread's milliseconds in full text and the process-wide sum dim, because the sum of every thread's CPU time had been read as a frame time (a raid read 17 on it at a solid 60 with the main thread at 7); and `WOW_PROBE_UI_ONE_TEX=1` is a pricing lever, never a look, for the draw-count ceiling a UI atlas would reach before one is built (1978, 1954)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 20:59:53 +07:00
SamandClaude Fable 5.1 edd6628329 the tooltip and five windows go stock, and the battleground keeps score
- the tooltip is the reference's own file: `GameTooltip.xml` loads off the chain, ours is deleted, and every verb it calls was already bound, so this is a plain swap; retired with it: the `$parentThicken` plate fill that thickened the plate from the art's ~73% to ~84% opacity — the reference's plate is the raw `UI-Tooltip-Background` tint, and that is what ships; the one engine fact the transcription had been hiding: the reference's instance declares no size, and a frame with one anchor and no size resolves to NO rect under the reference's own layout law — our declared size had been a harness crutch (1968); and the dressing room goes stock with `<DressUpModel>` as a widget kind (factory `0x495c00`): a `PlayerModel` plus its own `Undress`/`Dress`/`TryOn`, where `Undress` strips the body and not the hands, and Close is read off the window since the stock OnHide queues nothing (1969)
- the mail window and the auction house are the reference's own: `MailFrame.xml` loads off the chain and brings the stationery picker, invoice pane and autocomplete ours had left out; the stationery family is built off wow-re's carve over a list computed off `Stationery.dbc` rows × the player's bags (`0x622270`, not the bank); the selection rides `CMSG_SEND_MAIL` field 6 and a send with none silently aborts; its two events fire where the client fires them (1970); `Blizzard_AuctionUI` loads on demand from the `AUCTION_HOUSE_SHOW` arm, and three root fixes its Lua surfaced: `GetAuctionItemClasses()` is static — read at the addon's load, before any session, so the class tree is a login-scoped push; `SetAuctionCompareItem` (`0x535d70`) on the vendor compare's one body; `NEW_AUCTION_UPDATE` resets the create form; its dressing-room pane shares the app's one room (1971)
- the battleground keeps score: `WorldStateFrame.xml` loads off the chain and ours is deleted; the stock file is three things where ours was one: the readout, the capture bars, and the battleground scoreboard this client never had, built off wow-re's round — `MSG_PVP_LOG_DATA` both ways (throttled to 5000 ms client-side, `0x4aa170`) and `CMSG_LEAVE_BATTLEFIELD`; eleven score verbs over a board the app pushes, where the filter is a SORT, not a compaction — team first, killing blows descending, deaths ascending, honor descending, name — so the filtered count shrinks while `GetBattlefieldScore` still reaches every wire row; `HIDE_OUTDOOR_WORLD_STATE` joins the options uvar block, a capture point is a bar, and the scoreboard and battlefield-minimap toggles become bound specs at the install's own `SHIFT-SPACE`/`SHIFT-M` (1972)
- the trade skill and craft windows go stock as `Blizzard_TradeSkillUI`/`Blizzard_CraftUI` on demand, from the reference's own UIParent arms; our two transcriptions are deleted; the four item-link verbs are built off wow-re's carve on the client's link builder (`0x52adb0`) — zero values on any miss, `GetTradeSkillReagentItemLink` raising Blizzard's own typo'd Usage, kept, and `GetCraftItemLink` the `|Henchant:` link in fixed white; `SetTextColor`'s channels coerce nil to 0 on FontString, Font and Button where ours had raised (1973); and the Inspect, Talent, Macro and Raid addons load on demand — `benilla.toc` lists no `Interface\AddOns` row, and below level 10 the talent addon is never even loaded; the gates walk every reached addon and found `Blizzard_GMSurveyUI`'s four engine verbs nothing answers, reachable only through `GMSURVEY_DISPLAY`, which nothing fires (1889; 1967)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 20:59:04 +07:00
SamandClaude Fable 5.1 fb57052242 coins ride the cursor, and the trade window and combat text go stock
- coins ride the cursor: `MoneyFrame.lua`/`.xml` load off the player's chain, and the stock kit reads the cursor's coins at load, so the money cursor — payload mode 2, the copper at `[0xb4e2f0]` — is the engine's: `PickupPlayerMoney` puts coins on the cursor and the purse is never debited, and `CoinPickupFrame.xml`, the shift-click coin dialog nothing of ours had ever answered, joins; wow-re's round then set the law: the pickup raises on a non-number and refuses silently on zero, lost control and more than the purse; `AddTradeMoney` folds the coins into the offer as an absolute `CMSG_SET_TRADE_GOLD` gated on the purse; the send-mail setters and `GetCoinIcon` answer as the bytes do; the coinage-change reflex trims an offer the purse no longer covers; and the four send-mail pickup/drop verbs the stock table names do not exist in 5875, so they are not built (1962, 1965)
- the trade window is the reference's own file: `TradeFrame.xml` + `TradeFrame.lua` off the chain, ours deleted; `GameTooltip:SetTradePlayerItem`/`SetTradeTargetItem` (`0x5341e0`/`0x534410`) render the slot's item the way the loot slot's is, and `TRADE_PLAYER_ITEM_CHANGED`/`TRADE_TARGET_ITEM_CHANGED` — which the stock file repaints one slot on, and nothing had fired — fire per changed slot beside `TRADE_UPDATE`; the stock file brings the chain's own `MoneyInputFrame`, a TARGET_TRADE `SmallMoneyFrame`, `ItemButtonTemplate` slots and the enchant slot's own wording — "Item not yet modified" where ours had read "Will Not Be Traded"; the wire's enchant id is not carried into the slot yet, so the tooltip shows the item without its enchant (1966)
- the dialogs' verbs, as the bytes define them: nine of the ten stock `StaticPopup.lua` bindings 1960 had left named are built off wow-re's round with their packets, events and UIParent arms — the bare trade pair, `ForceLogout`, the instance-boot timer (whole seconds), the area spirit healer's accept/cancel/time, `AcceptBattlefieldPort` out of a three-slot queue `SMSG_BATTLEFIELD_STATUS` fills, `CancelMeetingStoneRequest`, and the pet trainer's pair as the talent wipe's twin, latch for latch — `SMSG_PET_UNLEARN_CONFIRM` latches and asks, `ConfirmPetUnlearn` sends behind the money gate, `CheckPetUntrainerDist` reads the leash; not built, named: the healer's proximity scan (`0x4923b0`: 20 yd to acquire, 22 to retain), so no healer is cached yet, and `ReplaceTradeEnchant`, which rides trade-slot enchant targeting this engine does not build (1963)
- the scrolling combat text is the reference's own `Blizzard_CombatText`, LoadOnDemand off the chain: our transcription is deleted, and the addon loads through `UIParentLoadAddOn` at the reference's own sites; the family's fourteen defaults move to the options file where the reference keeps them, because a LoadOnDemand addon cannot define the options that decide whether it loads (1964); and the Looking-for-Group pair is what the bytes define, correcting 1959's flag: `SetLookingForGroup` takes three (type, entry) pairs and a comment, packs each slot as `(type << 24) & entry` — an AND (`0x4e9713`), so every admissible input stores zero — and sends `CMSG_SET_LOOKING_FOR_GROUP` only when the commit changed something; `GetLookingForGroup` answers three nilable slot names then the comment, never 1|nil; and the stock 1.12.1 UI never calls either — both call sites sit in an XML comment (1961)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 20:58:15 +07:00
SamandClaude Fable 5.1 2ec92beeed the chat and spellbook go stock, and hidden props park their meshes
- the chat window is the reference's own `ChatFrame.xml` and `FloatingChatFrame.xml`, run off the player's chain; our 2216-line transcription is deleted, the feed fires `CHAT_MSG_*` and the reference's `ChatFrame_OnEvent` prints — no app-side composition into the windows, no routing table, no whisper chime or flash of ours, and the transcribed edit-box machine (sticky type, tell ring, Tab cycle) retires with it; the verbs the two files call are built to the bytes — the whole `0x98` chat-window record and its eight verbs, the 94-entry chat-type colour registry, the language walk, the channel verbs as a command queue, the slash handlers' emote/roll/assist/uninvite/console/logging verbs; `chat-cache.txt` is written and read in the reference's whole grammar, the 68-entry message-group table in flag order and the no-file boot included, and the chat bindings and macro lines run through the reference's own arms (1948)
- the spellbook is the reference's own `SpellBookFrame.xml`; our 965-line transcription is deleted, and two quirks it reproduced by hand (the pet page ignores its page number, its arrows write the spell book's counter) now come from the reference's lines; one adapter remains because the reference's autocast shine is a `<Model>` that draws no pixels in this engine — the script puts the token-texture shine beside each button's model and carries it with the model's shown state; the nine spell-slot bindings (`GetSpellName`, `CastSpell`, `PickupSpell` and their kin) now parse their arguments the way the reference's shared marshaller `0x4b3ec0` does — a numeric arg 1, a mandatory arg 2, the index gated to [0, 0x400) with "Invalid spell slot in <Verb>" on a miss, "pet" matched without case — where ours raised mlua's own message on a negative id, answered nil for 0 and above 1024, and read the wrong book for "PET" (1952)
- a long-hidden world model part parks its `Mesh3d`: the entity path keeps the batches the retained pass declines resident — 5.3k hidden submeshes at any instant at the Stormwind auction house — and Bevy's sweeps walk every `Mesh3d` whether it draws or not, so a part parks after 30 consecutive hidden frames and unparks the frame its verdict turns visible; every world model part takes part, units' bodies included, while a booth's mirror parts stay out; interleaved pairs read an alone Stormwind 0.1–0.4 ms lighter, and `WOW_NO_MESH_PARK=1` is the A/B; the audio thread's realtime class was the standing suspect for the raid's `cpu_p99` spikes with sound on, and `WOW_AUDIO_NO_RT=1` across two interleaved Blackrock pairs read no difference, so the lever stays as an instrument (1949); and a no-merge prop batch now says which rule declined it — animated (1551 at the auction house) or transparent, not order-free (340) (1951)
- the probe reads CPU per thread across its window (user and system split, because a user-mode sampler never sees kernel time) and the main thread's CPU inside the app's frame beside its whole-frame CPU; together they place the vsync tax every player pays by default — cpu_ms 10.7 uncapped against 12.5 under vsync, alone in Stormwind, with no system growing and no thread spinning: it lands on the main thread, in user time, inside the schedules, the same systems each running slower, and a low-priority spinner holding one core busy erases it to the last decimal (vsync + spinner 10.18 against uncapped 10.17), which is frequency scaling — under vsync the cores idle deeper between frames and the next burst starts at a lower clock; nothing in the client is the cause and nothing in the client changes for it (1950)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 20:55:55 +07:00
SamandClaude Fable 5.1 b1294ce9a1 the quest windows go stock, and the 20 ms frames were mis-split pairs
- the quest giver's dialog and the quest log are the reference's own `QuestFrame.xml` and `QuestLogFrame.xml`, run off the player's chain at the reference's own toc seats; our 1366-line and 1999-line copies are deleted, and the verbs the stock files call are built — the four `GameTooltip` quest-item and reward-spell setters, the reward spell itself (parsed on all three packets and dropped by the model until now), and two verbs; the detail pane could never scroll because `UpdateScrollChildRect` measured a frame late where the reference's measure is synchronous, so it measures through the installed font engine now; and ten things the reference does that ours did not, each found by a test that had enshrined ours — a shift-click never selects, an empty log hides the whole detail pane and says "No Active Quests", the abandon confirm lives in the popup registry (1944)
- the quest bindings' law, read off the binary and folded back: no 1.12 packet carries a quest background material — `GetQuestBackgroundMaterial` (`0x502230`) forks on the dialog's SOURCE object, an item answering its template's PageMaterial, a GameObject its template data, a creature nil (FrameXML's "Parchment"), the id naming a `PageTextMaterial.dbc` row whose six words are nowhere in the binary; its twin `ItemTextGetMaterial` has the same body, so the reader window already held every piece and the giver's feed runs the same resolve; `QuestChooseRewardError` is game-error row `0x98`, and the row plays `igQuestFailed` first, which the verb now queues; the reward-spell getters' third return is `Spell.dbc` Attributes bit 5 (1161 of 22357 rows set — craft-cast spells set, `Pattern:` teaching spells clear), read off the catalog now (1946)
- the "20 ms frames" of a raid, chased to their number: the probe's worst frames now carry their churn (entities, assets, first-play sound decodes, live particles, the GPU reading) and in a Blackrock raid with sound on every one of those read flat; then the same window on the PACED clock — under vsync with pipelined rendering the raw delta is mis-split into long/short pairs that sum to exact refresh multiples, so an alone Stormwind leg read 115 of 300 frames over budget with cpu and gpu both at their means, while the paced clock read 0 skipped frames in every leg; what remains real in the raid is `cpu_p99` at 22–23 ms with sound on; and every submesh the streamer spawns now carries why it is an entity, counted per reason — 5.8k resident ADT-doodad submeshes at the Stormwind auction house, 5.3k of them hidden, three prop families the retained pass declines by rule, each riding every per-`Mesh3d` sweep for ~0.4 ms of the alone frame (1947)
- a raid's dozen voices cost the mixer ~1.5 ms of every 60 Hz frame: upstream kira spatializes every frame — normalizes, the attenuation curve and a dB→amplitude `powf` per frame per spatial track, two more `powf`s for the volume tween, ~1.7 M `powf`s a second at 48 kHz × 12 tracks for gains that change imperceptibly across a chunk — so kira 0.12.1 is vendored with one patch: the spatial gains and the volume × fade amplitude are evaluated at the chunk's two ends and interpolated across its ~10.7 ms, the granularity FMOD 3, the reference's own mixer, updates them at; nothing a listener can name changes (1945); and rig poses are evaluated in parallel over rigs — each reads its shared clips and writes only its own pose, and a raid's ~400 live rigs were 0.4 ms of one thread walked serially on the main thread's critical path (1947)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 20:55:12 +07:00
SamandClaude Fable 5.1 4c61e6b7c6 the action bars are the reference's own, and a gift can be wrapped
- the action-bar cluster is the reference's own: `MainMenuBar.xml`, `ActionBarFrame.xml`, `MultiActionBars.xml` and `BonusActionBarFrame.xml` run off the player's own chain, and our `ActionBar.xml` (2047 lines), `MultiBars.xml` and `StanceBar.xml` are deleted — three, since the stock bonus-bar file declares the shapeshift bar too; one engine verb, `ChangeActionBarPage`, fires `ACTIONBAR_PAGE_CHANGED` and nothing else; one load blocker: stock `MultiActionBars.lua` writes the options window's table from its OnLoad, the reference's own load-order hack, so our options window moves to the reference's toc slot; and ten things the reference does that ours did not: an empty button is HIDDEN while showgrid is 0, the bonus overlay sits one pixel right of the main buttons, every slide takes one frame more than its time, and `ActionButton_ShowGrid` ghosts EVERY ring, occupied included (1938)
- a gift can be wrapped: right-clicking wrapping paper fell through to plain use and sent `CMSG_USE_ITEM`, so nothing happened — you could receive a gift and never give one; the wrap is a displayed-cursor MODE plus a stashed slot, never a payload, so `CursorHasItem()` stays false and every stock gate on it stays shut: right-click arms it, a left-click on a bag slot sends `CMSG_WRAP_ITEM`, and the client applies no eligibility test — the server's `ERR_CANT_WRAP_*` reasons are the error line (1934); a duration-limited item counts down: `SMSG_ITEM_TIME_UPDATE` parks a deadline and the tooltip's `ITEM_DURATION` line runs the enchant countdown's bucket ladder, so "Duration: 1 days" is what the reference renders; an update for an item we do not hold is DROPPED, no queue (1933); and a renamed crowd-control refusal names its mechanic — "Can't do that while stunned" — off `SpellMechanic.dbc` (1943)
- a creature paths on a boat: `SMSG_MONSTER_MOVE_TRANSPORT` carries the transport's guid and deck-local coordinates, and is the attach/detach edge; a deck sample lands on the rider or nowhere, never as a world write a few yards from the map origin; and "there is no terrain under a boat" turned out wrong: the ground probe admits GameObject meshes — a boat's `.wmo` is a GameObject, so the probe hits the deck (1936); `MSG_MOVE_TIME_SKIPPED` is read, not dropped — the reference adds the lag to the observed unit's last-wire stamp, so dropping it scheduled their next packet `lag` ms late, a hitch for every player who stalled zoning in near us; and our own settle hold reports once (1935); and the tradeskill tool order was backwards — focus FIRST, so every two-tool recipe had read "Blacksmith Hammer, Anvil" for the reference's "Anvil, Blacksmith Hammer"; the focus's `hasTool` is 1.0 in the reference too (1942)
- the crowd's second sitting, instruments first: the probe line carries the tail — cpu p95/p99 and the six worst frames — because a mean under budget hides the one frame in twenty over it (raid legs railed at 16.67 with p95 at 18–20 ms) and whether that frame was work or a wait is the first question about a stutter, and the visible meshes are counted by lane; then two cuts — a terrain tile furnishes as 4×4 cells of 4×4 chunks, one mesh, one entity, one draw per 133-yd cell instead of per 33-yd chunk (a city horizon is over a thousand chunks a frame, and a cell changes nothing a pixel can see; Stormwind 10.55 → 10.32 `cpu_ms`), and an authored point light is our own `WorldPointLight`, not Bevy's `PointLight`, which was only a data carrier while Bevy ran its whole light lane over every lamp, ~2 % of the alone frame; the sitting's record is 1945, and the code says so (1945)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 20:54:27 +07:00
SamandClaude Fable 5.1 b14dd42cf1 the unit frames are the reference's own, and the water has motes in it
- the player, party, target and pet frames are the reference's own files (`BuffFrame`, `UnitFrame`, `CombatFeedback`, `PlayerFrame`, `PartyFrame`, `TargetFrame`, `PetFrame`, in the reference's toc order) — our 2741-line `UnitFrames.xml` and our `PartyFrame.xml` are deleted; four engine verbs built for them (`PartialPlayTime`, `NoPlayTime`, `UnitPlayerControlled`, `UnitIsCivilian`, each answering 1/nil), the whole-UI load bracketed in the counted sound-suppression scope `0x48fbf0` self-brackets (the reference fires a `PlaySound` during load and throws it away), and `GetBillingTimeRested` read off `SMSG_AUTH_RESPONSE`'s third billing field rather than hardcoded; the differences the stock files bring are pinned rather than papered — `PlayerFrame` never hides, an unresolved name is BLANK not "Unknown", the target frame has no numerals at all (a bar hover pops the unit tooltip instead)
- what the swap surfaced, each a hard break under the stock files: `UnitBuff`/`UnitDebuff` returned the Classic Era ten-value tuple, name first, where 1.12 returns two and three values TEXTURE first (`0x519500`/`0x5198f0`) — a raise twice per `UNIT_AURA` on any debuffed target, and all 184 corpus call sites bind the 1.12 shape; the power events are named per resource (`UNIT_MANA`/`RAGE`/`FOCUS`/`ENERGY`/`HAPPINESS` and their MAX twins) and we fired the Era pair, so no mana, rage or energy bar could live-update; `SetRaidTarget` is the engine verb and `SetRaidTargetIcon` the FrameXML toggle wrapper — we had registered the wrapper's name on the engine's body, so every raid mark in the unit popup raised
- the underwater drift cloud: the reference draws a fixed 4000-mote field whenever the camera eye is inside a liquid — not a particle system, nothing spawns, ages or dies; a population scattered once into a 30 yd camera-relative cube, advected by the camera's own motion plus a gust and wrapped, so the field stands still in the world; benilla had the murk and nothing in it; a dry frame commits no draw, and the submerged one is bounded by the reference's own 666-quad cap (633–644 of 4000 measured live, which is the expected survivor count of a uniform cube through the 90° cone — an independent check on population, distribution and cone at once)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 17:04:32 +07:00
SamandClaude Fable 5.1 4abe2a0397 the numerals kit goes stock, and a chat link is its own mouse target
- the status-bar numerals kit (`TextStatusBar.xml` + `.lua`) is the reference's own, and the attempt found a class of silent failure: `TextStatusBar_Initialize()` takes no argument in 1.12 and acts on `this`; ours took an optional bar, our unit frames passed one, and the reference's version ignores it — so the numerals would simply never appear, no error, nothing missing; seventeen of our signatures differ from the reference's that way (Lua drops a surplus argument in silence), written down before their files migrate, and the three "ours narrower" ones — `StaticPopup_Hide(which, data)`, `StaticPopup_FindVisible`, `WorldMapButton_OnClick(button, frame)` — closed now, because that direction bites when a STOCK file arrives and calls our version
- a chat link needs no mouse on its frame: wow-re read the client's ctors as mouse-enabling Button, CheckButton, Slider, ColorSelect and EditBox and NOT the scroll frames; the objection ("something makes a 1.12 chat link clickable") resolved as the engine synthesising one mouse-enabled `CSimpleHyperlinkButton` per link span (`0x7a3240`) — so a link span is a hit-test candidate on its own, the chat window is inert everywhere else, and the wheel is its own predicate rather than a borrowed mouse bit; seven `*ScrollFrame` known divergences retire
- the relic fit rule: `IsValidForSlot`'s slot-17 leg is an EQUALITY — `(InventoryType == RELIC) == hasRelicSlot` — so a relic lights the ranged slot for a druid and a bow does not, on the bag bar and the paper doll alike; closing it half-right would have lit the highlight for a druid dragging a bow
- a chain `.xml` whose `.lua` never loaded: `MoneyInputFrame.xml` had been on the chain without its `.lua`, so the template loaded and all ten `MoneyInputFrame_*` verbs read nil, silently — a gate now fails any chain `.xml` whose `.lua` sibling is neither sourced nor listed; the gap report's LOAD column carries the probe's collision caveat, its fx column stops crying wolf (it follows `<Script file=>`, stops reading `.Field(` as a global, subtracts a file's own locals), and a window is its xml PLUS the lua it sources

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 17:01:18 +07:00
SamandClaude Fable 5.1 ed524ab184 druids get their relic slot, and the loot window is the reference's own
- `UnitHasRelicSlot` is real in 1.12 and benilla had no binding for it: `0x519e50` reads `ChrClasses.dbc` field 16 — set for Paladin, Shaman and Druid in `patch.MPQ`'s 17-column copy (the base `dbc.MPQ` copy has 16 columns and no such field, which is how the "always false in vanilla" belief survived twice in decisions and seven times in code) — and stock `PaperDollFrame.lua` calls it unconditionally, so the character sheet would have raised for EVERY class; a druid, paladin or shaman's sheet now hides the ammo slot, shows the relic plate where the bow was, tooltips "Relic", and reports ranged Attack/Damage/Power as N/A, all four branches transcribed from the reference
- the loot window is the reference's own `LootFrame.xml`: `LootButton` is built as a real widget type rather than aliased (a Button plus one slot dword and one overridden OnClick — right-click loots exactly like left, no shift/ctrl/alt takes, a row whose Lua handler errored still loots, a fast double-click takes two slots), `LOOT_SLOT_CLEARED` fires per row again because the stock file hangs hide-in-place AND the emptied-page auto-advance off it, `EditBox:Insert(nil)` is a no-op as `lua_tostring` makes it, and an alias `GameTooltip.xml` had quietly become a reader of would have turned every item tooltip white, silently, had it just gone nil
- the vendor cursor: `PickupMerchantItem` is two verbs behind one name, decided by what the cursor holds and never by the caller — a held bag item SELLS (index ignored, no merchant-open gate), otherwise the vendor row is grabbed as cursor mode 5, which is invisible to `CursorHasItem` (modes 1 and 9 only) so all thirteen stock gates stay closed while it is held; the drop is the buy, `CMSG_BUY_ITEM_IN_SLOT`, count 1, into a bag or an equipment slot, and every refusal is silent and clears the cursor; the four `Model_*` rotation handlers land in UIParent where the reference keeps them
- the gap report reads `:Method(` sites now — it found `SetMerchantCompareItem`, which would have raised on the first vendor-row hover with every check green, and `LootButton:SetSlot`, and 28 "free" windows became 25; the shared coin kit moved out of the merchant window into `MoneyFrame.xml` so the eight windows that draw coins through it can reach it without loading a vendor

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 17:00:40 +07:00
SamandClaude Fable 5 14bd5ea1a4 the bank is the reference's own window, and far sight freezes your body
- the bank window is the reference's own `BankFrame.xml` run off the player's chain — our 890-line copy is deleted whole; putting bags into the bank's bag slots works (the two verbs its buttons are wired to now exist), the purse is a real `SmallMoneyFrameTemplate` splitting 987654321 copper into three coin buttons instead of one string, `BANKFRAME_OPENED` loses the argument the real client never fires, and the bank stops auto-opening your bags while the vendor and mailbox keep doing it; the empty-slot click still plays the bag sound, because the reference's own line plays it on every click the cursor did not consume — named as faithful rather than quietly fixed
- underneath it, the bank's inventory band is a VIEW over the container feed, not a second copy — inventory ids 40..69 had answered nil because the doll array stops at 24, so the stock file swapped in would have drawn an empty bank; the six bank bag slots become real inventory slots (64..=69) fed off the player descriptor, the three bag verbs are carved from the binary (`PutItemInBackpack` IS `PutItemInBag(0xFF)` through a ten-byte thunk, the occupied-by-an-ordinary-item leg auto-stores with no destination slot at all, and the return is the Lua number 1 or nil — the nil being the whole reason a plain left-click opens a bag), and the swap caught `BankButtonIDToInvSlotID`'s bag arm six slots wrong: it took a bag number 1..6 where the reference passes the button's own id, which is the container id
- far sight freezes your own body while the view is out — the fifth conjunct of the movement predicates' shared precondition, joining the health term so the walk, the turn and the follow teardown go down together; both halves are load-bearing: the `IsActivePlayer` half is what keeps a Mind Control victim walking (possession rides the same PLAYER_FARSIGHT field), and the latch half is the RESOLVED engage rather than the raw field — and the camera is untouched, you still look around freely, which is the whole point of the spell
- the reset offer no longer outlives the character that earned it — log out after walking out of the Deadmines and your next character was offered a reset the first one had earned — and the one lockout leg no probe can ever reach (vmangos writes a last-instance map only from raid binds, which the client's handler discards as not-a-party-dungeon) is now covered end to end through the real system, its module doc saying plainly: tested and never observed

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 20:18:51 +07:00
SamandClaude Fable 5 67315143f9 the bag windows are the real 1.12 files, and /walk actually walks
- the bag windows are the reference's own `ContainerFrame.xml` running off the player's patch chain — decision 1751 makes the stock 1.12 UI off the install the end state and `assets/ui` scaffolding that retires file-by-file (86 files against the 99-file stock corpus, 72% of the 1128-function global surface already built) — via one ordered manifest, `benilla.toc`, where a bare name is a file we ship and an `Interface\FrameXML\` path is the player's own file; the windows on screen are `ContainerFrame1..12`, the bank's six copy-pasted popouts fold into them at ids 5..10, net −750 lines, and the swap forced real engine verbs into being rather than stubs (`SetBagPortaitTexture` with its id-0 no-texture arm, `GameTooltip:AppendText`, `SetButtonPulse`, and a `<Model>` whose file is the cooldown indicator materializing as the native sweep, which three corpus addons inherit)
- the 1.12 walk toggle lands: `TOGGLERUN` latches one bit with `ToggleRun`'s own silent refusal chain (dead, rooted, on a live server spline), and the walk animation was never missing at all — the flag reaches it through exactly one channel, the speed (`0x5fd100` picks Walk over Run on `speed > 2 × walkSpeed`); pinning it caught our remote extrapolator with the two min rungs backwards — `min(walk, run)` runs BEFORE the backward min, so a walking backpedaller moves at 2.5 yd/s where we would have played them the Run clip at 4.5 — and one shared `current_speed` now keeps the local controller and the extrapolator from ever disagreeing about it
- the instance and raid lockout messages exist — six packets that were dropped as unknown opcodes now land, four of them as the CHAT_MSG_SYSTEM lines the client composes itself, which is why no Lua handler ever surfaced them — plus `IsInInstance`, `ResetInstances`, and the unit popup's "Reset all instances" row behind the reference's own predicate; where the binary contradicts vmangos: the ownership flag means "any instance bind" but vmangos only ever names raid binds, so the row was dead for every character without a raid lockout — term 1 is now also satisfied by our own eyes, walking out of a party dungeon the server itself bound us to
- opening the world map showed 3D world at the sheet's margins: `BlackoutWorld` was parented to the very `UIParent` a fullscreen panel hides, and three more frames had crossed the same boundary — the shared dropdown lists (so the map's continent and zone pickers answered a click with nothing at all), the master-looter menu, and the screenshot confirmation, which could never appear during a cinematic; `frame_flag_gate` now checks the parent seat against the reference both ways a frame acquires one (the attribute, template-inherited included, and `<Frames>` nesting), and its first harvest took 30 divergences down to three accepted ones

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 20:17:25 +07:00
SamandClaude Fable 5 8ae42cc7ab 71 more key commands, and the quest windows wear the reference's names
- the binding registry goes 130 → 201 of the client's 228 live commands: a coverage gate makes registered ∪ recorded-absent exactly the 1.12 surface, each absence naming the Lua globals whose arrival refutes it — which is how 37 rows whose mechanism had already landed came home (the keyring, the pet book, the raid tab, the six action-bar pages, both vertical multibars) — and then four mechanisms bring 71 more: the five camera views with the reference's default table and its sixteen camera CVars read out of the binary (NextView/PrevView do NOT wrap), self-cast riding UseAction's third argument with autoSelfCast a real CVar at last, the friendly target cone / assist / last-hostile as one cycler with a side (the two sides use different deadness tests on purpose, and assist neither requires an assistable target nor swings), and REPLY2 — reply to the last person you told; the friendly cone also stops borrowing the enemy side's in-combat score bonus, which would have shoved a healer targeting you to the head of every cycle
- the key names close their gaps: NUMPADEQUALS, F13-F24 and BUTTON6+ were keys the binding window listed and the file saved that the dispatcher could never press — named both ways now, with the namer and the codec structurally unable to disagree again; platform= becomes the OS gate it really is (off a Mac build the iTunes-remote category never even exists), and the Mac 1.12 slice settles that its F13 IS print-screen while F14/F15 map to UNKNOWN on purpose and stay unbindable; and the last-enemy stamp gains the four conjuncts it shipped without — you resolve, are not dead, not a ghost, not mounted, and the new target is alive-or-feigning — so TargetLastEnemy can no longer land somewhere the real client's never would
- the quest windows wear the reference's names: ~40 of the quest window's globals were ours (the reference's name usually sitting in the comment beside them), its two six-item reward pools merge into the reference's single ten-item run with the update function ported line-for-line, the four panels and the quest log take REAL scroll frames (the thumb drags now), the gossip window gets its greeting panel, the two mail panes' inert painted-at-rest scrollbars become real ones, the Skills detail pane nests as the reference has it, and nine private constants take their real names; the one that broke a feature detect: our QuestLogCount — a name 1.12 doesn't publish — made pfUI conclude it was running on TBC and die in that branch
- an EditBox is born with its constructor's five regions (the text, three selection quads and the caret), so GetRegions answers the reference's own count and authored regions start at index 6 — and a bare <NormalTexture/> now builds a live blank texture, since the element is what creates the region, not its file=; OpacityFrame lands, its first customer having arrived; and the equip / auto-equip / use bind confirms complete the soulbind arc — three different predicates with no quality leg (borrowing the loot arm's would have silenced the confirm on every white bind-on-equip item), Accept re-issuing the original action with the reference's suppress flag because 1.12 ships no confirm packet, and the soulstone use going through the same gate

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 20:16:49 +07:00
SamandClaude Fable 5 542c2ac04b being summoned is a dialog, and a soulstone raises you where you fell
- being summoned becomes the dialog it should have been: the summon request was a name-table entry and nothing else, so a warlock's ritual, a meeting stone and a GM's summon all ended with the summoned player seeing nothing — now the three-field question raises CONFIRM_SUMMON and Accept sends the one guid back; the bytes settled three things a reasonable guess gets wrong: the refusal gate is dead OR ghost and lives in the handler (a ghost's wire health is 1, so the health leg alone lets one through — and refusing before the latch means an ill-timed summon can't silently overwrite a live question), the event carries no arguments because the popup re-reads all three getters every frame (the only way the summoner's name can appear after a cache miss), and there is no decline — Cancel, ESC and the clock running out are all silence plus the server's own two-minute timer; exercised end to end by a two-client live probe, the only thing that can, whose final assertion is that you land in the zone the dialog named
- self-resurrect is one private field and one bodyless opcode: PLAYER_SELF_RES_SPELL carries the stored spell and CMSG_SELF_RES spends it; HasSoulstone answers the Spell.dbc NAME of that spell, because that is where Blizzard put the button text — "Use Soulstone", "Reincarnation" and "Twisting Nether" are the spells' own names — and UseSoulstone sends on the death dialog's second button; a --self-res probe runs the whole arc on the live wire and measured the thing that matters: the field arrives BEFORE the health-zero flush, which is what makes the dialog's OnShow read safe
- the decode's fold-in corrected three claims we were resting on: HasSoulstone has a dead gate that runs FIRST, so a released ghost (wire health 1) loses the button at release rather than the dialog merely hiding; a zero field is not the empty answer — the client walks your carried inventory (gear, bags, backpack, keyring; no bank, no buyback) for an item whose on-use spell self-resurrects, labels the button with the ITEM's name and uses the item instead of sending, the two legs exclusive; and an unresolvable spell id labels the button "UNKNOWN" rather than hiding a self-res the server is holding for you

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 20:16:13 +07:00
SamandClaude Fable 5 20f38e1f7e deleting a good item asks in the reference's words
- deleting a rare-or-better item forks to the reference's typed confirm — "Type \"DELETE\" into the field to confirm": Yes starts disabled, the box takes focus, the button enables only while the field spells DELETE, and a reflexive Enter over a half-typed word is inert; the missing engine piece was one hook, the edit box's on-text-changed; beside it, the loot bind-on-pickup confirm — bind-on-pickup AND uncommon-or-better, two conjuncts and no others, so a white BoP drop is taken with no dialog and a bind-on-equip blue never asks here — with the reference's one-pending-slot latch, and the take split into two verbs the way 1.12 actually has it: the row click stays C-side, and LootSlot is only the confirmation's continuation
- the message frames get their justify quartet, read out of the binary's method tables (with the Button table re-derived as the control that lacks it); Frame:EnableDrawLayer/DisableDrawLayer and Region:GetDrawLayer land — the disabled layers are a five-bit mask on the frame, so re-enabling a layer restores exactly what was showing underneath; and the Skills tab's children take the reference's names, with SKILLS_TO_DISPLAY published — pfUI loops over it and got "'for' limit must be a number"
- the README's roadmap line now names what is genuinely big — battlegrounds and meeting stones, both verified still missing — plus the long tail, because the old line named four features that have since landed and small features go stale on a roadmap within a week

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 20:15:38 +07:00
SamandClaude Fable 5 a0d2fc383b the world map blips are the reference's, and particles go untinted
- the world map speaks the reference's names: WorldMapTooltip is declared (six corpus addons index it; pfUI dies on it at file scope), the blackout frame takes the reference's spelling BlackoutWorld, and the four hand-written party blips become the reference's own unit-blip templates — all 44 blips as instances, each with its published $parentIcon, the name pfUI recolours group blips by class through; the 40 raid ones are declared but not positioned yet, named in the OUT list rather than faked
- the templates addons build their own buttons from are published: ItemButtonTemplate, ContainerFrameItemButtonTemplate and the bag-slot chain — most of the handler scripts were live the whole time (this client executes the reference's own container and paper-doll code off the player's patch chain), so what was missing was mostly declarations, not behaviour — the bank arm stays out and is named as the omission it is; OptionsFrameSliders becomes real, with the three Graphics rows reading it and re-reading on show, so an addon's write to a slider's bounds actually moves the slider; and the template census that had ranked these at "zero demand" learns to see a local bound to a literal — its table went from 3 rows to 7
- the bindings answer in 1.12's own shapes: Button:IsEnabled() answers the NUMBER 1 or 0 (0 is truthy in Lua, so the reference's own == 0 tests got false forever, and three of our files had hand-worked around the divergence rather than fixed it); the constructors' string arguments are four shapes, not one rule — pfUI passes a Button where a template name goes and the reference constructs the FontString and ignores it; SetInventoryItem returns THREE values, the reference's own paper doll destructuring repairCost; UnitIsVisible is object presence and nothing else (57 bytes, one branch, no distance — an out-of-range party member is exists-yes, visible-nil); the tapped pair reads the two dynamic-flags bits, and its repaint wire fires UNIT_FACTION on the tap bit — the half a passing predicate test never sees; UnitIsPartyLeader is two ORed legs covering disjoint failures (a held stranger leading their own party, and an out-of-range member with no object to read a flag from); and the four nameplate verbs take no argument and return zero values
- the ghost's wisps compose onto its body instead of over it — the four emitters drew at full strength over a body at alpha 0.5, and now inherit the instance alpha down the attachment chain the way the reference recomposes it per frame; the residual we had parked ("the wisps should inherit the tint too") is REFUTED at the bytes: a particle batch commits hardcoded white RGB, and even that never reaches the fragment — particles are never tinted, only the alpha crosses, applied to the alpha byte alone — so the shipped shader split was already right and no code changes

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 20:15:16 +07:00
SamandClaude Fable 5 961d7e46a0 the select-screen ghost is four mechanisms, and a click raises windows
- the select screen's ghost is four mechanisms off one roster-row bit, and the rest of them land: the FFX pass swap — the reference builds TWO pass pairs, world and glue, and a ghost row installs the glue DEATH pass over the whole diorama while the character list and buttons composite clean above it; the ghost-gated sun — the scene's light gather is wiped and one hardcoded overhead directional injected, its colours turning out to be Light.dbc's death preset (diffuse (94,153,198), ambient (26,56,85)) rather than the live capture we had parked them as, with the sign settled at the bytes (an authored light already carries one negation, so reusing that convention lights the ghost from underneath); and three glow weights corrected — the glue screens pin 0.30 login / 0.40 living select / 0.15 ghost where we rendered a flat 0.5 everywhere, so login and create get slightly less glow too, a fidelity correction to a value we had never verified
- a press brings its window to the front: the mouse-DOWN handler raises the capture-or-hover frame unguarded, the toplevel gate living inside the worker — which is what makes a click on a child raise the window that owns it — and the release never raises; behind it, a frame-by-frame diff against the reference put back what the transcription dropped: toplevel on 47 frames (without it every raise trigger was a silent no-op across the whole interface), the mouse on 16 window bodies (a click on the bank's or merchant's own background was turning the camera or dropping your target), and id= on 81 frames — the slot index a 1.12 addon reads, where GetID() answered 0; a new gate reads our flags off the LOADED engine against the reference's, both directions with a reason each, so the next drift can't hide behind renamed templates
- the jump stops being frame-rate dependent: the fall step becomes the reference's closed form (the mean of the endpoint velocities is the exact displacement rate, and both our movers had the error in opposite directions), taking the apex from 1.668 yd at 144 fps and 1.844 at 20 to a flat 1.640 against the analytic 1.640 — a live run apexed at 1.6410; and the knockback's freeze is its PLANTED direction bit, not a velocity test — air control opens exactly while the direction nibble is clear, the launch plants forward whatever its speed, and the bit now rides the wire, which we had never sent at all
- the walk-away leash belongs to the OBJECT: the reference's watchdog overwrites the opener's stored range on the player typemask bit alone with (10+4)², so a player-shared quest panel is leashed at 14 yards — not at the 5.56-yard NPC reach, and not never, as two earlier readings had it — while a census of all 14 arming sites confirms every other NPC window already closed at the right distance; the walk-away also sends strictly LESS than the button: an NPC panel closes silently while a share still owes its decline

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 20:14:48 +07:00
SamandClaude Fable 5 31706821cd the combat log's wire completes, and PlayerModel is its own class
- the combat log's last eight wire bodies decode — PARTYKILLLOG, SPELLINSTAKILLLOG, PROCRESIST, SPELLORDAMAGE_IMMUNE, SPELLDISPELLOG, DISPEL_FAILED, ENCHANTMENTLOG, SPELLLOGEXECUTE — each layout read off vmangos's own writer and pinned by a byte-exact golden (DISPEL_FAILED carries no count, the list runs to the end of the body; SPELLLOGEXECUTE's POWER_DRAIN row is (amount, power, multiplier), verified at the client's bytes as well as the server's); with the eleven chat types that were waiting on them, 44 chat types become 55 — 29 sentence families, the death pair and the aura rows riding descriptor diffs because 1.12 has no "unit died" opcode, plus the six trailers ((glancing), (30 blocked), (12 absorbed) and kin) that had been missing from every family; also corrected: the durability-death line was going to the red error frame with hard-coded English, and SMSG_SPELLNONMELEEDAMAGELOG lacked its split-damage branch and its blocked wording
- PlayerModel is its own frame kind: SetUnit, RefreshUnit and SetRotation were published on Model, but they belong to the <PlayerModel> method table (0x84f1fc), and the client's lookup chains derived → base only, so a plain <Model> can never reach them — they got there from a strings scan read as ownership, and a strings hit answers whether a name EXISTS, not who owns it (SetUnit's one pooled string is referenced by the PlayerModel and GameTooltip tables and by no Model entry); the new PlayerModel → Model → Frame → Region chain unblocks CreateFrame("PlayerModel"), which is how pfUI builds every unit-frame portrait — and through pfUI, pfQuest and ShaguDPS
- a nil where a number goes is four shapes, not one law: a census of all 408 widget-registrar entries found 62 numeric positions that validate-or-raise, 43 that gate then stage an alternate, 64 that silently coerce to 0.0 and 5 that gate then store nothing — so SetMaxLetters(nil) completes and stores 0, "no limit" (the argument COUNT is checked exactly, the type is not), and the backdrop colour setters are asymmetric on purpose: a nil r/g/b channel is 0.0 but a nil alpha is OPAQUE, and reading every nil as 0.0 would have turned those borders transparent; both setters now also quantize ×255 into the packed 0xAARRGGBB byte quad the client actually stores, so 0.09 reads back as 23/255
- two more addon-killers: LIGHTYELLOW_FONT_COLOR_CODE was the one missing line of Fonts.xml's seven-line colour block (aux-addon concatenates it at file scope and died on its own first line), and the guard now enumerates the whole block l.4-20 instead of the names an earlier round had noticed absent; and the unit frames publish the reference's names — 1.12 has no *PowerBar anywhere, every bar is ManaBar and the colour table is ManaBarColor (8 of the top-20 addons read it by name), so ManaBarColor is the published table our own bars index into, with 22 more regions renamed to the reference's own

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 19:54:58 +07:00
SamandClaude Fable 5 850f7df3b0 the chat dock exists, and alt-arrow keys are declined not swallowed
- the chat dock is a list, not a hardcoded pair: DOCKED_CHAT_FRAMES, SELECTED_DOCK_FRAME and the FCF verbs — DockFrame, UnDockFrame, DockUpdate, SelectDockFrame, SaveDock, SetTabPosition, Close and the button-side trio — are transcribed from FloatingChatFrame.lua, and every "for i = 1, 2" moved to what it meant, the dock or every window; the dock seeds at load from the window record's own docked byte handed to FCF_DockFrame, whose first line IS the reference's early return — transcribing the function that answers the way the reference answers, where an empty stub "because we have no dock" would have been the bandaid; its unconditional re-lock cannot clobber an unlock you saved, because the stored look is applied last; pfUI's RefreshChat now runs end to end
- ignoreArrows is alt-arrow mode, and the arrow is DECLINED, not swallowed: the reference's edit-box handler returns unconsumed on an arrow key, so the walk carries it past the box and it runs TURNLEFT — the whole feature is steering while the chat box holds focus, where the old reading left the arrows dead; holding Alt resumes the caret; SetAltArrowKeyMode and its getter land with the reference's own quirk that a missing argument enables while nil disables (the getter answers 1 or nil, never a boolean), SetIgnoreArrows turns out not to exist in 1.12 and is unpublished, and the binding pass gets a named four-key exemption rather than a hole, because the handler consumes every other path
- pfUI's square minimap is actually square: Minimap:SetMaskTexture makes the disc's mask state instead of a load-time constant — write-only from Lua, as shipped, no invented getter — where an empty path restores the round default and a failed load keeps the current mask and warns, because either mistake would otherwise hand a mistyped path a silently square map that looks like a feature; and MiniMapBattlefieldFrame grows the Border and Shine regions beside its icon, on the reference's own layers — icon on BACKGROUND, ring on ARTWORK above it, the only order a ring around an icon can draw in — which pfUI hides unguarded to sit the icon flush

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 19:51:11 +07:00
SamandClaude Fable 5 d4690cc67c a cinematic holds your body, and all seven chat windows exist
- a cinematic holds the body while the camera flies: the streaming focus follows the eye — a Tauren's intro opens 1741 yards from the body — so the body's own ground unloaded under it and it fell (z=59.4 to −62 in four seconds, the server yanking it back); it now takes the same hold a teleport takes, released when the focus comes home to a resident tile, and the loading screen stops covering the fly-by, because "the player's ground is missing" is not a load while the eye is deliberately elsewhere; the letterbox measurement prints as an ordinary info line, and scripts/cine.sh plays any one cinematic and prints what the client did to the world while the camera was away
- a cinematic cuts the zone music: the reference asserts exactly what /console EnableMusic 0 asserts, through the same setter — a cut, not a fade, the music pump dead for the duration, resume at +3.000 s — and benilla asserts the runtime flag, never the CVar, or quitting during a 102-second intro would save your music off for good; ambience is deliberately untouched (it has the analogous flag and the cinematic never writes it); the narration has no category at all — its flags route it around every volume slider but not around the Enable Sound Effects gate, so unchecking that silences it — and the listener follows the cinematic camera for the duration
- addons can walk a UI they did not build: GetChildren/GetNumChildren/GetRegions/GetNumRegions land — the basis of the whole reskin genre, and the wall four of the twenty most-installed 1.12 addons died on: pfUI drew nothing before and now paints 495 quads, ShaguDPS 71 → 566, pfQuest 3 → 498 — with the reference's own quirks: the title region is NOT in the list (its creation path never reaches the region linker), hidden regions are returned and counted, oldest first; the Model widget gets its Lua surface (SetModel, SetSequence and siblings, read out of the shipped image, where SetRotation and SetFacing are two names for one slot); and the Minimap carries the nine engine-created Model children no XML declares, built before the frame descent, the ninth being the player arrow Questie indexes as ({Minimap:GetChildren()})[9]
- all seven chat windows come from one template, tabs and scroll buttons included — whether a window is shown has nothing to do with whether its globals resolve, and pfUI reads every piece of that furniture for all seven, unguarded; isDocked only on windows 1 and 2 (the chat-cache's own DOCKED byte), SELECTED_CHAT_FRAME seated beside DEFAULT_CHAT_FRAME (the window you last picked vs the one FrameXML prints to), and the four per-window fields ChatFrame_OnLoad seats; two more one-name walls fell — a Button's label answers to its second spelling NormalText, which KLHThreatMeter's column headers die without, and ABANDON_QUEST_WITH_ITEMS is declared because a dialog table is read at load whatever the client later shows, leaving Questie with zero errors of ours — and the addon harness gains --probe/--eval, one addon's VM answering a question in ~5 s instead of a 90 s corpus run

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 19:50:08 +07:00
SamandClaude Fable 5 6a8df87219 edit boxes take focus the way 1.12 does, and the stable shows its pets
- the caret was a wedge in the line: it sat in flow, four units wide, so focusing a login box shoved its text right by one caret and a caret parked mid-word opened a gap; it is a zero-width seam now with the bar drawn as an overlay (a 0×26 seam and a 5×26 bar at the same x, off a node probe), the way the reference anchors its caret quad over the FontString; a blurred box collapses its selection so only the box holding the keyboard shows one; and a dialog answers only keys pressed while it was already on screen — ENTER on an empty form used to open the error dialog and close it in the same frame
- `autoFocus` defaults ON in the reference (the ctor leaves flags = 1, and every one of the ten `autoFocus` attributes in the shipped chain is an opt-out), showing an autoFocus box focuses it after its `OnShow`, and hiding the focused box releases the keyboard — the "never focuses on show" note we had transcribed came from a `call`-only census that missed a tail `jmp`; the loader's flag loop could only ever turn a flag on, so `autoFocus="false"` was a no-op, fixed before the default flipped or it would have grabbed exactly the ten boxes the reference exempts; and the EditBox does fire generic `OnChar` with the spliced string, on every typed or pasted character and never on `SetText`
- the stable master's portrait was a black disc (its session was missing from the `"npc"` token chain — the third window to ship that way, so the test is now exhaustive over every `impl NpcSession` and names the one you forgot) and its model pane draws the selected pet: a stabled pet is a database row with no world entity, so a `PortraitStandIn(display_id)` — an entity that exists only to be mirrored — feeds the existing booth code unchanged; plus the registrar's two service rows were hidden by an inherited attribute, a charter's tooltip carries the guild name and master on line 3, and the Help window drops three strings pointing at a company that stopped answering

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:22:27 +07:00
SamandClaude Fable 5 77ca6915bc a full realm is a queue to wait in, and the login dialog is centred
- a full realm answers with `AUTH_WAIT_QUEUE`, and it used to be read as a refusal; the grammar is length-branching exactly as the reference's handler has it, so both mangos body shapes parse; the estimate is the reference's own 8-sample ring — divide before multiply, signed, no timer — whose displayed figure climbs while the queue is silent, pinned by a test so nobody "fixes" it; the dialog is the ordinary status dialog relabelled `CHANGE_REALM` (which cancels back to the login screen: no realm list exists yet), and cancelling actually leaves the queue — the IO thread used to keep its place and walk on into character select on admission
- the stable master, corrected against the binary: a stabled-pet drag rides the shared cursor at payload mode 10 (the mode census had that row's label wrong), a plain click always returns 1 and a drop always nil, the summoned pet dropped on an occupied stable slot swaps (STABLE was refused whenever both bought slots were full, silently), an unpurchased slot takes nothing, the stabled→summoned fork reads the live pet guid not the row, the client itself sends `MSG_LIST_STABLED_PETS` on the interact leg, `PET_STABLE_SHOW` fires on every list, the selection is a petNumber and every list clears it, and result codes 2–7 do nothing at all
- the login dialog's text is centred (a FontString with no `justifyH` is CENTER, and `GlueDialogText` has none), the fifteen-year-dead "see www.worldofwarcraft.com" clauses are cut at the clause, the Login click sound is unconditional (the reference plays `gsLogin` before it checks the boxes), dialog buttons play `gsTitleOptionOK`, the realmlist button's `gsClick` never existed and is `gsLoginNewAccount`, and focusing a login box selects it — a stated divergence

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:21:50 +07:00
SamandClaude Fable 5 a5cb3cf746 guild charters: the registrar, the charter, and the twelve verbs
- founding a guild: fourteen opcodes, eight goldens (four mutation-checked), twelve engine globals, `GuildRegistrarFrame` and `PetitionFrame` — `CMSG_PETITION_BUY` is a 72-byte frame the server reads two fields of and drops in silence if short, `allowedGender` is the family's one u16, a signature is a 12-byte stride not 8, and `MSG_PETITION_DECLINE` writes the charter guid and reads the decliner's — same width, opposite meaning
- two sessions, not one: the registrar is an NPC session (closed by walking away — its show event is one of the fourteen callers of the interact latch, so the registrar turns to face you) and the charter is bound to an item guid you carry across the city; right-clicking a charter in your bags opens it, keyed on template flag `0x2000` (item 5863 has no on-use spell and no quest, so every existing item-use arm declined it)
- the byte carve came back and rescored six named guesses — three confirmed, two corrected, one refuted: `PETITION_SHOW` is deferred until every signer name has resolved (the window never paints blank rows), `ClosePetition` on somebody else's charter sends `MSG_PETITION_DECLINE` ("sends nothing" had been chosen on principle and was wrong half the time), and founding a guild is silent — no `ERR_GUILD_FOUNDER_S`, the reference emits no text at all; the four success ids go to chat and the five refusals to the red error frame, three paraphrased strings are now the shipped ones (a sweep asserts all fifteen), and the `npc` unit token had never been fed — the registrar's name banner was blank; `WOW_PROBE_CHARTER=1` drives gossip → buy → open → rename → destroy live, 10/10

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:21:00 +07:00
SamandClaude Fable 5 1c4cc147f5 GM tickets are in, and a login failure shows the string 1.12 shows
- GM tickets, end to end: five request/answer pairs, the seven Help-window bindings, three events and `GMTicketCategory.dbc` — the ten categories `HelpFrame.lua` keys 1..10 live in a DBC nothing here had ever opened (the four `TICKET_TYPE` strings feed a dropdown 1.12 never gave a frame); the category is one byte on the wire (a u32 would shift the map id and position and file every ticket at a garbage spot), and `UPDATETEXT` carries it too, which vmangos stores and cmangos swallows as the first character of the text — faithful to the client, the divergence recorded
- the engine re-asks for the ticket after a create or update succeeds and on a status push (the ask opcode has three callers in the reference, two of them engine legs with no idempotence guard) — which is why the shipped FrameXML registers no handler for the three response opcodes and still repaints; without that leg the form stays a form for ten minutes; `UPDATE_GM_STATUS` is a signed passthrough (`0xFFFFFFFF` → −1), the five ticket verbs drain through one ordered queue because call order is wire order, and the Help micro button — drawn, hovering and a no-op since the micro menu landed — is live
- a typed wrong password reads the reference's long "check the spelling of the account name and password" (0x04 and 0x05 share one jump-table arm — the client cannot say "wrong password", and the lockout cmangos's header describes does not exist in the binary), unknown codes read "Disconnected from server" rather than "Authentication failed", and every realmd row of the old map was in the wrong one: the two login-status enums have two key tables and two dialog paths, and a server source can only ever verify the codes, never which string the client draws for them

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:20:24 +07:00
SamandClaude Fable 5 78e958ef4f the stable master is in, and master loot hands drops to the raid
- the stable master: `MSG_LIST_STABLED_PETS` both ways, the four mutations answered by one result byte, two slots priced from `StableSlotPrices.dbc` (500 and 50000 copper — the cap falls out of the data, corroborated by vmangos's `MAX_PET_STABLES` and the reference's `NUM_PET_STABLE_SLOTS`), rows seated by slot never by position (a petless hunter's list starts at a stabled row), slot 0 read from the wire because a dismissed pet has a row and no live unit, a re-list after every success because no result carries one, and `GetPetIcon` reading `CreatureFamily.dbc`'s icon column — which ships `Ability_Druid_CatForm` for both warlock families, asserted as shipped
- master loot: `CMSG_LOOT_MASTER_GIVE` (the slot is a byte here where the roll family's is a u32) and `SMSG_LOOT_MASTER_LIST`; the click gate is the wire's slot-type byte and nothing else — the reference never asks who the master looter is — so a MASTER row fires `OPEN_MASTER_LOOT_LIST` instead of a take and auto-loot skips every non-ALLOW row; the candidate array is bucketed by raid subgroup into blocks of five (a dense list would have filed every candidate under the wrong "Group N"), an unresolved name is nil so `UPDATE_MASTER_LOOT_LIST` has something to repaint, and a give re-checks the row is still MASTER before sending; found on the way: a master looter in another raid subgroup lit the crown on your own portrait
- `SetLootMethod` takes its third (threshold) argument; the reference's silent reset to Uncommon when it is absent is flagged and not adopted; the stable's model pane draws nothing yet — a stabled pet is a database row with no world entity, and a booth that renders from a bare display id is the next arc

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:19:45 +07:00
SamandClaude Fable 5 18858046f9 held weapons pick, book images size to their art, the panel opens again
- a unit's pick geometry is every model chained to it — body, held items, mount — one candidate per root resolving to the same unit, which is how the reference registers its pick (it walks the attachment tree and registers each model); Naxxramas' floating weapons could only be selected by their name plate before (no body, no candidate), and every armed unit gains its gear as clickable surface (our own body 12 → 21 tested parts); the broad phase stays the body's sphere, so a very long polearm on a small body is the named residual
- the selection ring's writer has two branches and we had transcribed one: a model whose stand box is degenerate (zero extent in x and y) rings at the literal 1.2 × scale — 2.7 yd under a trigger creature — instead of `sqrt(0.5·sqrt(dx²+dy²))` = 0 clamped to an invented 0.05 floor; both invented fallbacks are gone
- an HTML book image with no width/height is its art's texel square (one texel = one FrameXML unit, bit-for-bit the `<AbsDimension>` converter), not the rest of the page — *A Treatise on Military Ranks* drew its crest twice too big and stretched to the page's aspect; a texture-size oracle answers off the same decoder the renderer draws with, and an unfloated height-less `<IMG>` reserves its art's height in the flow; 797 shipped textures swept, exactly two zero-size axes move and neither is visible
- the dev debug panel killed the client on open with "Attachments have differing sample counts": Bevy's 2-D depth texture is keyed on the render target alone, so two Camera2ds on one window at different MSAA counts cannot both be valid, and the egui overlay camera had silently kept the default 4× after the player-UI camera went to Off; it now says `Msaa::Off`, and a preflight check reports any two 2-D cameras that disagree on a shared target, every run

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:16:04 +07:00
SamandClaude Fable 5 bf7201f4d3 action-bar hover stops re-deriving, and multisampling asks the GPU
- hovering the action bars re-derived the whole layout graph and hovering bags did not: `GameTooltip:SetOwner(owner, "ANCHOR_NONE")` dropped the tooltip's anchors through the conservative whole-graph derive, and with `UberTooltips` at its shipped default every action-bar button routes through that arm while a bag slot anchors `ANCHOR_RIGHT` and never does — the arm now retargets to the empty target set, and derive frames fall from 15.9 % of hovered frames to 0.2 %
- `gxMultisample` clamps to what the GPU actually offers: Apple GPUs stop at 4x, so a typed 8 was a wgpu validation panic on frame one — the clamp intersects the supported counts of every format the client multisamples into and steps the request down the way the reference's device-init retry loop does, with a warning that says so
- the Multisampling dropdown lands on the Graphics page with the device's own stops, built from the same enumeration that clamps a typed value on the reference's three bindings (`GetMultisampleFormats`, `GetCurrentMultisampleFormat`, `SetMultisampleFormat`) — a fixed Off/2x/4x/8x ladder would put a crash on the menu of every GPU that stops at 4
- capture hardening: a run whose `$WOW_WIN` the display clamped is refused in ~2 s instead of producing a wrong-sized shot to diff, a capture never reads the OS pointer (a cursor resting over the window arms a hover and a tooltip that a cursor an inch to the left does not), and the stall sampler writes into `benilla-config` instead of a hand-built `~/Library/Logs` path

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 15:13:27 +07:00
SamandClaude Fable 5 26fb25a3f8 the colour wheel draws, chat windows move, and the minimap ping returns
- the colour picker can pick a colour: the hue disc and the value strip are engine-generated pixels (no BLP in the chain is a wheel), reproduced from the reference's own lattice — a hard-cut circle at a literal V = 1.0, the brightness marker moving over a disc that never dims
- chat windows move and resize once unlocked (Lock/Unlock Window on the tab menu; the reference's own 296×75 to 608×400 bounds), the border textures doubling as the grips, and the placement is remembered per character in benilla-config/layout; both windows ship locked, as 1.12's reset leaves them
- the minimap ping is back and pinned: one world point the engine draws, the click converted in the right unit (the old path was ~27% off at 1080p), and no 10-yard auto-clear — that was the gossip marker's rule, and walking to your own ping was deleting it
- the Lightwell can be clicked: a billboard card is a world root with no parent hop, so the hit resolved to nothing and the whole shaft published a null mouseover; casting a hunter shot chains Auto Shot through `Spell.dbc`'s modalNextSpell column (the mechanism nobody had read — the next snapshot carries the seam that makes it fire in play); tradeskill list rows stop tooltipping (that hover was ours, not Blizzard's), and OnMouseUp goes to the frame that took the press

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:49:16 +07:00
SamandClaude Fable 5 fd928d9cb3 the chat tab's right-click menu, and Options gets its Chat page
- right-click a chat tab for its menu: background colour and alpha through the colour picker, font size — three of GetChatWindowInfo's nine values are real state now, persisted per character in benilla-config/chat, and the hover fade interpolates from the window's own stored alpha as the reference's guard does (the default look is unchanged, pinned)
- the Social page becomes the Chat page 1.12 has, in the reference's anchor order: Remove Chat Hover Delay and Detailed Loot Information join, and `showLootSpam` off collapses the roll chatter to the winner line with its number; Guild Member Alert is registered at the reference's default, off
- two guild-line defects found while settling that CVar: the sign-on line's fourth conjunct is a friends-list test (an ignored guildmate was silenced, a guildmate who is also a friend announced twice), and vmangos broadcasts your own sign-on, which benilla announced to you at every login

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:45:45 +07:00
SamandClaude Fable 5 4eeed067a1 landmarks and the Plaguelands towers on the map, no ultrawide crop
- the world map's landmarks: city icons and the Eastern Plaguelands towers, from AreaPOI.dbc through the reference's own three gates (level flags, exploration, world state) — the tower rows are one per (tower, owner, state), so the server flipping a world state swaps which icon exists; and the always-up PvP readout ("Towers Controlled: n") over a new WorldStateUI.dbc loader, the init clearing the table on a zone change as the client does
- the character-select scene holds its authored 4:3 view box: the diagonal-FOV relation was fed the display's aspect, so every extra pixel of width came out of height (1.55× zoom at 21:9, head and feet gone) — now width grows and height never shrinks; the reference does the same and is wrong on the same panel
- a trail particle is stored in world space and drawn raw: Sprint's trail was welded to the chest bone (turn and it swings, run and it wobbles) because the trail was faked by subtracting translation inside a bone-local store; the correction machinery deleted itself, gravity is plain world down, and the emitters' live attach frame is retired
- the spellbook can shrink: `SMSG_REMOVED_SPELL` had no handler, so a talent wipe took the points back and left every rank drawn; and the chat dock's hover driver rides a frame the dock cannot hide, so selecting the Combat Log no longer freezes the tab alphas

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:43:04 +07:00
SamandClaude Fable 5 11a0b68da6 party members show on the world map, and the leader wears the crown
- party members appear on the world map at their position and hovering names them — the party wire has carried each member's zone and coordinates since the group arc; the blip and the minimap dot read one shared position so they can never disagree, and the member's zone picks which continent the position belongs to
- the player's own frame wears the leader crown and the master-looter icon, with the reference's own asymmetry (the crown asks IsPartyLeader, the member frames compare a leader index)
- a party member outside your local area gets the generic race/sex portrait instead of an empty circle — their race and sex ride the name query, and nothing had asked for a member we never see; the roster now warms that cache, which also fills the raid grid's class column
- right-clicking a member who is nowhere near grays Trade, Inspect, Duel and Follow: the reference's bindings answer nil for a unit the object manager does not hold (carved this session), where ours defaulted "absent = in range" for exactly the farthest member; and the group-invite popup's background is measured faithful — the plate draws at the BLP's own 60% alpha

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:30:24 +07:00
SamandClaude Fable 5 034c48f2cb raid tab art is back, set bonuses fit, and 12 voices bound the mix
- the mix is bounded the way the reference's is: FMOD gave 1.12 exactly twelve software channels and nothing else limits a priest buffing five people — ported as a 12-voice ceiling (a probe capture read 42 live voices at +13 dBFS, the limiter pumping 13 dB to hold it), plus same-kit copies started in one frame capped at two, since five sample-aligned Fortitudes are one sound +14 dB; `$WOW_SOUND_PROBE` records the mix before and after the limiter with a timeline, F9 stamps the moment
- the raid tab draws its window art again — its four corner textures were written with single backslashes, which Lua drops silently, and a sweep now reads every archive path a shipped Lua chunk names; a drag whose release never arrives (pointer left the window, a second press) ends instead of gluing the frame to the cursor for the rest of the session, and `WOW_PROBE_DRAG` drives any UI drag headlessly in a live client
- the item tooltip fits its set bonuses again: an emptied line kept its last measured height forever (a pooled cell with no way to say "empty"), and the two blank rows above the set block are the reference's own literal (a space and a newline) — a whole row each, not the empty string
- an equipped BoE or BoP piece reads Soulbound: the bind line reads the item's own flags through the client's bound predicate instead of the template's bonding, one predicate shared with the enchant cursor's bind confirm

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:25:07 +07:00
SamandClaude Fable 5 0d7563b581 the raid tab lands, and sounds take the reference's voice buses
- the social window's fourth tab, Raid: the eight-subgroup grid over the roster, drag a member between subgroups, Convert To Raid, promote / demote assistant, uninvite, Ready Check with its popup, and the Raid Info flyout on the new `CMSG_REQUEST_RAID_INFO` / `SMSG_RAID_INSTANCE_INFO` wire (byte-golden against vmangos, an empty answer decoding as an empty list); `raid1`..`raid40` unit tokens, and `/partytest raid` stages a roster for a solo look
- an imbue pressed with an empty weapon hand says "Your weapon hand is empty" instead of raising a cursor — the attribute bit has two readers in the reference and the second is the error (corrects the day's first cut)
- sounds route onto the reference's own voice buses with its per-bus caps (the 0x87ce60 table, pinned as bytes): weapon impacts and clangs share four voices, footsteps six, the attacker's grunt one, the victim's injury two — so a pack swinging together makes about a dozen voices where it made dozens

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:22:17 +07:00
SamandClaude Fable 5 dddf16e963 the auction house opens, the Honor tab lands, and a day of fixes
- the auction house end to end: right-clicking an auctioneer opens Browse/Bids/Auctions on the server's reply — search, the category tree from your own DBCs, the reference's 50-a-page pager, multi-key sorting (directions corrected at the bytes), bid/buyout, the sell slot with deposit and duration, cancel with its fee popup; prices sit on the reference's own money-frame kit in lined-up columns, the twenty auction messages split refusals-red / outcomes-to-chat, and a won or sold auction reads as a proper mail receipt — the window's Lua re-worded in our own terms after the overlap ratchet caught the first cut leaning on the reference's text
- the PvP honor system whole: the Honor tab and the inspect page over a real wire model, with current rank and highest-ever rank correctly two different fields
- a day of reported fixes: WASD survives a /logout re-entry, addon settings save on a window close and Cmd+Q (exactly once — a mac close could fire the tail twice), clams open again, random-enchant items name themselves on every surface, the loot window's rows hold their seats with legible counts, idle players stop sinking through building floors, the shooter re-pulls between Auto Shots, portraits loosen ~19% to the client's own aspect-1.0 matrix, and big creatures thump the camera off the CameraShakes table
- character select clicks like 1.12 — captions whiten on hover, buttons fire on release, Humans face straight ahead off the stage bone's real yaw, the facing is per-character, and hunter/warlock pets stand beside you at their family-ramp size with their own emitters (the imp's flames), the Voidwalker's sequence-hidden shackles culled
- the smaller player-facing set: nameplate on/off rows in Options with the CanAttack category gate (emissaries stop plating), the bonus bar slides up with igBonusBarOpen, the camera's framing height glides on a shapeshift, the open letter evicts the centre seat, the far-band fog hull stops printing a pale horizon stripe at low view distance, the guide arrow is gold with per-source rim art, error text fades through its shadow too, and /convertraid converts the party
- README: the auction house and PvP honor move out of "not built yet"

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 19:04:27 +07:00
SamandClaude Fable 5 0e37c3c6ed the shapeshift cloud both ways, and the Honor tab
- druids get the shift cloud back in both directions, by the reference's own mechanism: every shapeshift aura add *or* remove arms a one-slot pending-morph latch that the model-swap rebuild drains and replays — which is why shifting out (a client-side cancel the server sends no visual for) puffs at all, and why a GM morph or a revive correctly shows nothing; the first fix that merely let one-shot effects survive the swap's teardown produced the right pixels for the wrong reason and is superseded
- the honor system lands whole: the Honor tab on the character window, the honor page on inspect, and thirteen missing Lua bindings over a real wire model — session/yesterday/this-week/last-week kills, lifetime HKs and DKs, rank progress and badge art
- the load-bearing find: your current rank and your highest-ever rank are two separately-streamed fields, and the one we already had was the wrong one for anyone who ever de-ranked; a binary cross-check corrected five display details after the build, down to the rank title never being gendered

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 18:22:13 +07:00
SamandClaude Fable 5 da786b9e59 Terrain Distance returns to Graphics, and guards flag your map
- the Terrain Distance slider is back on Options → Graphics, in its 1.12 seat and range (177–777, live, no Apply) — and it now drives how much world is resident, not just how far you see: the streamer derives its resident and prefetch windows from farclip in the reference's own chunk units, pulling the ring in as you drag left and streaming it back one tile per frame as you drag right; the `WOW_TILE_RADIUS` env var, the debug panel's farclip slider and a dressed-up fog constant all retire into it
- ask a city guard for directions and the destination lands on your maps: `SMSG_GOSSIP_POI` becomes a red flag drawn through the same landmark path as towns and inns — an icon in place when near, competing for a rim arrow when off the edge — and the world map's landmark enumeration answers now, so the flag renders there too and names itself on hover
- the flag is one slot (new directions replace the last), drops itself within 10 yards of the destination, expires after the reference's own 480 seconds, and clears on any world entry; the rim-arrow rank rides the packet's own field, not a guessed constant

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 18:18:30 +07:00
SamandClaude Fable 5 312e123fb7 windows take turns, the gossip page waits, the shot bar counts down
- the UIPanel registry is re-derived from the reference's bytes: the readable-item page finally registers, so a note or letter closes when a gossip window opens instead of interleaving with it line for line; the character sheet takes its real pushable-2 seat (an NPC window slides it over instead of replacing it), and the spellbook, quest log, talents and character sheet open for dead players again — a refused open now says "You can't do that when you're dead." instead of doing nothing
- the gossip window waits for its greeting: the first packet carries only the options and a text id, and we used to show the frame with a blank page for the round trip the text needed — the menu now exists only once the text has answered, a mid-flight click is refused, and a revisit is instant off the cache
- a bag slot whose stack count changes on the server now fires `ITEM_LOCK_CHANGED` just ahead of its `BAG_UPDATE` — the one signal 1.12 hunter addons use to detect a spent arrow — so Quiver's auto-shot bar drains per shot instead of pinning at 100%; a swap or create deliberately does not fire it, so rearranging bags can't read as a shot
- the outdoor minimap tiles' gamma byte reaches the screen exactly once — the ordinary decode arm learns the same skip the fast path already had

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 18:17:03 +07:00
SamandClaude Fable 5 80d8bd48db four extra action bars as options, and the bottom band gets one owner
- the four extra action bars become per-character options, off by default, on a new Action Bars options page — the toggles ride the server's own byte (`CMSG_SET_ACTIONBAR_TOGGLES` into `PLAYER_FIELD_BYTES`), so a fresh character's zero is the default for free; turning the bottom-left bar off gives the stance bar its previously unbuilt unraised look, end-caps and 64×64 rings
- bag windows stop drawing straight through a raised bottom bar: the bottom band has ONE owner — the manage pass — the bag stack joins it through a listener seam, and a guard test walks all eight raisable-bar combinations across 24 bar/tenant pairs and refuses overlap
- the item-push card takes the reference's real geometry, closing the gap 0887 measured
- resizable addon windows stop at their bounds instead of pinning and walking across the screen: four per-frame f32s with 0.0 the disable sentinel, the clamp on the interactive drag only with the residual rebated out of the drag delta, `<ResizeBounds>` in XML honoured — and `SetFontString`'s three raises land exactly as the bytes have them

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 18:12:19 +07:00
SamandClaude Fable 5 ad2a1fb2d1 Quiver loads, teleports stop losing the city, the camera eases right
- Quiver works end to end (the reported nil-field error): 1.12's widget method tables are flat, so the 19 Region methods are ONE function per name — a frame's `GetHeight` IS the texture's — where we had two implementations behind two disjoint registries; `Button:SetFontString` and the Set/GetMin/MaxResize quad land with it, and the 219-addon survey moves loads-without-error 150 → 151 with every other addon byte-identical
- a teleport stops dropping you into a bare city: the reveal gate now waits on geometry that can actually draw (14 regions had sat undrawn for 630 ms with the cover already down), a relocating snap ≥100 yd raises the cover, and the pipeline warm pass runs once per process — a far same-map teleport's cover drops 3.8 s → 0.8 s
- the empty-world flash on a fully-resident teleport dies with it: the camera's world pose publishes before anything in Update reads it, so the visibility verdict stops being computed up to 644 yd from the eye — the lag reads 0 yd on every snap frame of every arm
- the camera follow becomes the engine's own curve — an edge-armed cosine smoothstep clamped to 0.1–2 s behind a 7-state input classifier, the enum 0/1/2 with Smart staying the default — and overlapping chat bubbles stack as whole cards, one frame level per bubble, nearest to the camera on top

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 18:10:46 +07:00
SamandClaude Fable 5 532240f6e7 the camera follows again, /errors opens the log, cmangos lets you in
- the camera auto-follow returns, as a setting: Camera Following Style on the Controls options page — Smart (the default), Always, Never — so after an orbit drag the camera swings back behind you while you run; far sight still forces the chase off
- broken addons announce themselves: world entry prints "3 addon load failures — type /errors to see them", and the `/errors` window lists every script error this session with its traceback — 256 deduplicated rows, repeats collapsing onto a count — while the five load-failure classes that only ever hit the terminal (missing .toc, unparseable FrameXML, dependency cycles…) finally get a channel
- B opens the backpack alone, SHIFT-B opens all bags, F8–F11 toggle the individual slots — the reference's six bag commands instead of one command wearing every chord; and the Skills page gets its CLOSE button, with the ALL fold in the row font
- cmangos-classic logons work: `CMSG_AUTH_SESSION` now carries the real client's twelve secure-addon records (342 bytes, compressing to 130) — an empty addon block is a shape no client can send, and cmangos kicks for it where vmangos shrugs; Warden-enabled anticheat remains a separate wall

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 18:10:06 +07:00