c3555b4eeaedeba182eb503f7c9f15397cd4e62e
118
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
c3555b4eea |
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>
|
||
|
|
73ead4e4d2 |
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> |
||
|
|
e800974806 |
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>
|
||
|
|
e7ac8b94f3 |
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>
|
||
|
|
c965b5425d |
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> |
||
|
|
2fed249252 |
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> |
||
|
|
fd595b7119 |
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> |
||
|
|
2f7cfcabf5 |
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> |
||
|
|
72e78ebc92 |
a 40-man raid costs less per frame, and the money frames go stock
- a 40-man raid cost +5 to +8 ms of CPU per frame — a population, not a hot function — and three cuts landed where it was measured: the rig palette upload sends one `write_buffer` per run, bridging the gaps parked bodies leave between live rigs (calls 93 → 3); a built material becomes an asset when something visible binds it, not when a spawner builds it — 9.9k material assets were alive for 36 drawn batches, so a material is realized only once bound and visible, readers that clone before binding doing it themselves through one new function in the engine's wall (172 → 173): a 17× cut in live GPU objects; and a body's batches spawn as material groups — a geared body stood as 12–27 mesh parts, its skin composite drawn as five separate batches, and two visible batches now join when nothing downstream can tell them apart: parts per body 17 → 12, the Stormwind raid leg 17.0–21.0 → 15.65–15.82 `cpu_ms` (1929, 1940) - the instruments that priced it, all on the probe line: wgpu's own resource census, because a sampled profile put roughly half of the pass encoder in usage trackers sized to the device's live buffer and texture counts — a term that scales with residency, not with what is drawn, and nothing printed the number; the active camera count, since every view is its own pass set; the UI's live texture-identity runs, one 2D draw each, which is the number a UI change moves, not the quad count; and parts and materials per dressed body on the dress census, the ceiling on merging a body's batches read off a real body instead of guessed from a model's batch table (1940) - the coin kit retires: every remaining money display — quest progress, the mail purse and postage, the trade recipient, the tooltip, the quest log, the trainer's purse and cost — moves onto the reference's `MoneyFrameTemplate`, each seat already matching ours; the progress panel's required-money flow is ported in full — `QuestFrame.lua:168-190` colours the FRAME red/white AND the LABEL black/dark-grey when the quest costs more than you hold, where ours had neither colour; the mail postage takes the reference's name and label, trade and mail issue no explicit update because the frames repaint on their own events, and the trainer's cost label is shown or hidden with its `local COSTS_LABEL` shadow deleted; with the trainer converted the hand-built coin trios have no consumer, so their templates and the `BenillaMoney_*` helpers are deleted and `MoneyFrame.xml` is the only money kit (1937) - the crowd-control ladder's aura exemption exists, and it is a join between two `Spell.dbc` records — each arm asks whether the spell being cast is itself an immunity covering the aura that blocks it (Ice Block cast while stunned), the school arm shifting because `School` is an index and `EffectMiscValue` a mask; what the scan mostly decides is WHICH message a refusal carries — a blocking aura the cast does not counter renames the reason to "Can't do that while %s" (1941); bevy_audio leaves the build — its plugin had been disabled since 0530, but disabling a plugin does not remove a crate, and rodio, a second cpal and an Ogg/Vorbis decoder were still linked into a client that mixes through kira (1932); and cpal has four stream errors, not two — a routine ALSA underrun was treated as "the device is gone", tearing the stream down on every hiccup; now only a lost or invalidated device rebuilds (1939) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
b41acbf98a |
Linux and Windows get their sound back, and emotes refuse while moving
- every build off macOS has been silent since the 09-02 snapshot (B356): the non-macOS device layer was a stub that opened nothing, and nothing had ever compiled the client for another target; that layer is now the same output stream over cpal — one seam, not two stacks: the ring, the render thread and the rebuild-on-device-change loop are one code on every platform, only the device file differs; the audio thread never allocates, a lost or changed default device is noticed at kira's own cadence, and realtime is `SCHED_FIFO` on unix and MMCSS "Pro Audio" on Windows, either refusable, the ring turning a refusal into a degradation; and the two instruments this bug says were missing exist — a Linux and Windows cross-compile under `clippy -D warnings`, and a live output test that opens the real device and asserts the ring never ran dry, because compiling is not sounding (1920) - an emote that requires standing still now refuses on the move: `CheckEmoteEligible`'s `0x4000` arm writes an out-param that `DoEmote` turns into a red "You can't do that while moving!" and aborts; 20 emotes of 78 can raise the line, read off the shipped `Emotes.dbc`; SWIMMING is not in the mask, so a swimmer holding still emotes fine, and `IsSelfControlled` is TRUE for an ordinary player, so a feared or confused player emotes away happily (1904); and the cast path gains its equipped-item rung — the button greyed and pressing it still sent: the reference short-circuits to "fits" on four gates, not one, the miss being a zero `EquippedItemSubClassMask`, which means no item required at all, and the rung sits above the crowd-control validator, so a player both stunned and missing the weapon is told about the weapon; that ladder has six arms, not three — CHARMED, FLEEING and CONFUSED join (1925) - the quest reward's money is the reference's own widget: the tail of the shared `QuestFrameItems_Update` drives `questState.."MoneyFrame"` through `MoneyFrame_Update`, and the two hand-built coin trios become one `MoneyFrameTemplate` instance each at the reference's anchors, which our coins already used; the progress panel stays on coins, being the required-money flow, not the reward one (1928); and the flight master's `!` joins the questgiver sweep, because the green `!` and the gold `!` are the SAME slot, `unit+0xb2c`, torn down once before both queries re-issue; the mouseover re-ask is refuted — the only taxi-status sender has one live caller — and the two queries are not symmetric: the questgiver's goes out on every sweep, the taxi one only when the unit's key moves or on a full sweep, as the wire shows at Dungar Longdrink: 68 questgiver status queries against 1 taxi-node one (1918) - `GetSpellTabInfo` out of range answers `nil, nil, 0, 0` — the reference returns four values on every path that returns (`0x4b3ce0`), and ours answered a single nil copied from another binding's shape; it matters because stock `SpellBookFrame_OnLoad` calls it unconditionally and then does `id > (offset + numSpells)`, which a nil raises on and (0+0) makes true, hiding every button on the page — the behaviour to match; the argument raises the reference's usage string when absent, and the index truncates toward zero THEN decrements (1931); the perf probe gains a `WOW_PROBE_UNCAP=vsync` arm, because the uncapped present mode is a request, not a schedule — measured, it taxes the number it was meant to pin (11.80 `cpu_ms` uncapped against 14.65 under it), so the default stays uncapped; and the last three test temp paths are keyed on the pid, after concurrent runs raced on one fixed shared file Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
9f204d894b |
a bot walks on the ground, and a stunned cast never leaves the client
- a bot floating a body-height above the ground in mid-stride (B357): cmangos's Playerbots moves its bots as Player objects under `SMSG_MONSTER_MOVE`, and our ground clamp skipped anything that was not a Unit, so a splined Player kept the wire Z verbatim — and a spline is a straight chord, which over a hollow leaves the body in the air; kind is not a question the reference asks (`0x616620` runs every registered mover once per frame, reading only its own flag word), so one rule grounds every Unit plus a Player from the moment a server spline first moves it, never the body we steer; and a re-sent identical wire pose no longer leaves a unit floating (1921); the body we STEER is a mover too — the reference hands a ride's spline displacement to the same vertical-zeroing step as walking, so the spline owns XY and facing and the ground owns Z, closing a +0.47 yd gap at mid-chord on an Elwynn slope, endpoint included (1927) - the client refuses a stunned, silenced or pacified cast itself, in the requirement validator `0x6094f0` whose mounted and moving legs we already model, before any packet — and the three arms are not symmetric: STUNNED refuses everything, SILENCED and PACIFIED run only where `Spell.dbc PreventionType` declares them, so a silence stops casts and leaves melee abilities alone and a pacify does the reverse; the leg sits above the mounted block and below the equipped-item requirement, so stunned and missing the weapon you are told about the weapon; `PreventionType` is column 165, Auto Shot alone telling it from its look-alike neighbour; the preflight banner splits movement blockers from ability blockers, since a disarm or a pacify touches no movement gate; and the refusal sink is an explicit parameter rather than a ladder field, because a resource reachable twice from one system panics on the first live frame (1903) - a disarm greys what needs the hidden hand: the spell equipped-item test is `0x5f0c50`, walking all 23 equipment slots, rejecting a deprecated or genuinely broken item, and taking its slot mask from `AttributesEx3` (main-hand-only, off-hand-only, else every slot) — DISARMED strips the hidden hand's bit out of that mask, so a main-hand-only ability whose one allowed hand is the one the disarm took has an empty mask and dies, Heroic Strike greyed with its tooltip line red; using a worn weapon while disarmed answers `ERR_CANT_USE_DISARMED`, the client's own refusal at rung 15 of the item-use ladder's 20, above the bind-confirm arm and never a bag click (1903); and two stale claims go — `UNIT_FLAG_STUNNED` no longer says the idle selectors bail on it (0889 had refuted that at the bytes), and the charter's `ShowPetition` arm is rung #9 of that same ladder, read rather than reasoned - `UpdateSpells()` is twelve bytes and all of them are the event: it ends in a jump into the event signal with 0x104 = `SPELLS_CHANGED` in hand, whose repaint is FrameXML's alone, so a no-op would not have been faithful and our own repainting stand-in was wrong in both directions at once; it fires synchronously as the reference's does, at the cost of a fire-path refactor rather than a next-tick queue; `PlayerHasSpells()` is a hard-coded 1, no branch, no store read, pinned to answer 1 on an empty spellbook, where a plausible implementation diverges silently (1924); and three integration harnesses loaded every document against an empty base, so a self-sourcing chain file loaded as an empty shell with every handler missing — none of their lists could fail, so the fix lands with a guard watched failing first, `FadingFrame.xml`, one relative script reference and nothing else (1923) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
ef7140c294 |
an item on the cursor is a sale, and an animation's sound has a place
- right-clicking a vendor with an item on the cursor sells it: `0x5df5d0` asks `GetCursorItem` before anything else and a non-zero answer takes the arm to `CMSG_SELL_ITEM` instead of `CMSG_LIST_INVENTORY`, where benilla sent the list unconditionally — the whole stack, to the clicked vendor, with no merchant-window gate anywhere in the arm; the clear is `SetCursorItem(0, …)` rather than `ClearCursor`, which fires `CURSOR_UPDATE` and leaves the source slot greyed until the server's inventory update (1914); and the NPC you are talking to is not clickable: `0x5f0130` refuses a right-click on the NPC whose window is already open, against a global with exactly two writers — the interaction setter, whose fourteen callers are every one a window opener, and its clear — so the first click always gets through and no double-click is eaten, where benilla re-sent the arm's opcode on every click (1866) - a Hated or Hostile questgiver's `!` now disappears, every `!` blinks off and back on when you resurrect, and the minimap no longer dots a corpse, your own pet or an untrackable unit: the sweep tears down on HOSTILITY, not on the flag — `0x5eb134` is a convergent block reached from two branches, so three incompatible readings had each seen one path — and an escort giver's `!` clearing with its flag is the field watch instead, which B257 now rests on; the dots gain `0x4eaa90`'s three preconditions (1906); the quest log's rebuild is all-or-nothing — the reference makes every rebuild a no-op until its template misses are answered, so a cold log shows empty and then lands in one step, never our `"..."` row per in-flight quest — sorted level then title, case-insensitively, with the `id == 0` group first under the reference's own "Missing header! (quest designers)"; and `GetQuestLogTitle`'s `isHeader`/`isCollapsed` answer 1/nil, not booleans - an animation event has a place, not just a time: the M2 event kernel (`0x719370`) places each fired key through its bone, and benilla carried the when and the what and never the where, so every animation-event sound played at the model root — 149 of 244 `$DSL` records sit off their model's origin, out to 67.6 yd on `Maraudon_Waterfall01.m2` — and the point belongs to the record, not the tag, since 75 models author one tag twice; doodad, GameObject and shake sounds now sound where the key is (1904); and the unit dispatcher's arms do not agree about the point they are handed — footsteps and emotes at the event point (the footstep's material foley stays at the origin), `$TRD` at the origin, `$CSD` at attachment 17 rather than its head-mounted records, `$CSS` at the event point on a hit and attachment 1 on a miss — with `0x623b90`'s attachment-else-bias resolver transcribed table and all (1915) - `GetSkillLineInfo` out of range answers the reference's thirteen-value tuple, numbers in the rank slots, not a single nil — the stock skill window adds two of those slots unguarded straight off `SetSelectedSkill(0)`, so one nil raises the moment it drives us; one shape serves every out-of-range case because the bounds test at `0x4d3675` is a single unsigned compare, and our source had asserted the opposite (1919); the outbound wire is traced by name (`out`, mirroring `in`), a line pushed only after a successful write — a 5-second visit to the Goldshire poster reads as 87 lines (1901); the binding shape gate seats a player and checks the `Unit*` verbs it had been skipping, coverage 220 → 249, all agreeing with the reference (1911); and a UI capture scenario opts the UI in itself instead of photographing a UI-less world and exiting 0, the opt-in answering `false` in a player build that has no harness Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
766395116c |
a disarmed fighter punches, and the quest log tags its elite rows
- a disarmed fighter swings bare-fisted: `UNIT_FLAG_DISARMED` was read nowhere but a dev banner, and the reference applies it inside `GetWeapon` on the `visFlag == 0` path, so the swing lands on AttackUnarmed; the RE cross-check (nine workers converging byte-for-byte) corrected the first reading twice — disarm hides exactly ONE weapon, main hand first (`5ec28d je 0x5ec2aa`), so a disarmed dual-wielder keeps swinging its dagger; and the weapon comes OFF the hand: the field-change reflex `0x5ff580` detaches a drawn main-hand weapon when the bit goes up, while a stowed one stays frozen on the back; one pure ladder feeds every unarmed-view site of the 82-site `visFlag` census — parry, the sheath machine, the melee sounds (a disarmed punch does not clang like a sword), Heroic Strike greying out, and the Attack button showing `Spell-Reset` with the weapon still equipped (1863) - a quest-log row reads `(Elite)`, `(Dungeon)`, `(Raid)` or `(PvP)`: `QuestInfo.dbc` was never parsed and `GetQuestLogTitle`'s third return was a literal nil; the table is seven rows read out of `patch-2.MPQ`, SPARSE (1 Elite · 21 Life · 41 PvP · 62 Raid · 81 Dungeon · 82 World Event · 83 Legendary — vanilla's 1 is "Elite", not TBC's "Group"), and the base `dbc.MPQ` copy has only four, so a chain stopping short would lose Dungeon, World Event and Legendary; the row gains the reference's own right-flush tag string and its precedence — a finished quest's FAILED/COMPLETE word OVERWRITES the tag — replacing the " (Complete)" we appended to the title; the RE round confirmed the tag path and found the arity bug: six values ALWAYS (`mov eax,6`), the level a NUMBER 0 even on a header, where we gave one nil; the reference's title shrink stays out: an explicit width is a WRAP width here (1873) - the death thud is silent indoors, and that is the content: BOTH the footstep and the thud lookups key on `TerrainType.SoundID`, and TerrainType 10 "None" has SoundID 0 — the footstep table has a row there for 17 classes and `DeathThudLookups` has none, so the floor that creaks underfoot swallows the body that lands on it; 10 075 of 10 299 WMO materials (97.8%) are TerrainType 10 and 694 of 815 WMO roots have no surface that can thud, every inn and tavern among them, the Kharanos inn included — the code was always right and the prose was not; the RE round also confirmed the strict `depth > 2.0` sense and the size-class column, pinned a sound id of 0 as silence, and placed `0x6005d0` as the loot sparkle, not a second sound; `thudcensus` prints all 121 buildings that do thud rather than a head, because a truncated list cannot answer "does THIS one" (1870) - a questgiver's overhead marker follows its rider on and off the mount: the reference re-runs the attach from the `UNIT_FIELD_MOUNTDISPLAYID` watch handler, and benilla picked the slot once at build, relying on a teardown the reseat rework no longer does (B199), so the seat rode at the WRONG slot; `overhead_slot` is now the one definition of the pick (`0x6074c0`) and the marker rebuilds when it moves (1871); and the chat menu's kit was ours overwriting the reference's — `UIMenu.xml` loads earlier on the chain and our `ChatFrame.xml` carried the same kit under the SAME ten names, faithful enough that deleting it changes nothing; nothing ever opened the chat menu, and now a test does; an event census holds the gap between registered and fired events at exactly eighteen, failing on a surprise AND on a quietly gained producer — features not yet built, none a split pair (1869) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
0535fe9097 |
a body lands with a thud, and twelve lists scroll again
- a dying body lands with a sound: the `$DTH` marker makes three calls in the reference (`0x624a94`) and benilla had built only the middle one, so the screen shook and nothing landed; the thud is a two-axis join — size class against terrain sound, through `DeathThudLookups.dbc` to a land or water kit — behind exactly three gates: more than 2.0 yd of liquid over the feet is complete silence, a size class outside 0..=4, and no terrain, no row or a kit of 0; it plays on bus 0, uncapped, so a battlefield's worth of bodies all land — the shake is the rare thing (49 of 430 models name a preset), the thud the universal one (329 key a `$DTH`, players included); the size axis had sat in our `CreatureDisplayInfo` schema labelled a string column 5875 does not have, and `StringLookups` stays unparsed on purpose — 9 rows benilla already resolves (1866) - twelve faux-scroll lists showed their bar, moved their thumb and never moved their list: the reference's kit writes `frame.offset` from one handler the OWNER declares, and ours were wired to a `frame.updateFunc` field the reference does not have — Skill, Craft, TradeSkill, ScriptLog, the auction and the social panes are rewired, and a gate fails any faux frame without a handler of its own, because a list only scrolls when something drives it (1868); and the macro window's "Change Name/Icon" raised on a nil offset: `MacroPopupScrollFrame` inherits a template the manifest never loaded, and a missing template is a warning, so the frame was built BARE — no scroll bar, no scripts, no `offset = 0` — and the reference's offset read has no `or 0` cushion; the line is in the manifest, and a static gate fails any `inherits=` the manifest declares nowhere (1862) - the character geoset selector's missing eighth branch is the tabard designer: B6 of `0x477520` is gated on "the guild registrar's tabard designer is open", not an ItemDisplayInfo column, and wears the tabard flap with an EMPTY tabard slot; dormant until `TabardFrame` migrates, but reading the whole function turned up three branches wrong since their first pass: B4-short never disabled [501,599], so the bare foot — a real submesh on 11 of the 18 character models — rendered inside every boot; B3 asked "is a chest equipped?" where the reference asks whether anything but the shirt paints the ArmLower tile, wrong more often than right (533 of 637 chest displays leave it empty, 566 of 570 wrist displays fill it); and B7 had no tabard guard, an ungated doublet arm, and a leg arm read off chest-or-legs where the reference reads the chest's bit alone (1864) - a GameObject's display sounds have one trigger and two lanes: `GameObjectDisplayInfo.Sound[0..9]` has one reader (`0x5f4010`), reached only from the anim-event dispatcher, so benilla's state-transition arm — 19 Open and 4 Close rows the reference leaves silent, 80 Open and 38 Close doubled against the clip's own `$GO1`/`$GO3` — is deleted; and the kit's `0x200` flag is a LANE SELECT, not a loop flag: set means the ambient pool, which every campfire, brazier, torch and fountain names (37 live slots), and which had been starting untracked forever-channels (1867); and `WOW_PROBE_SERVICE=1` reads the NPC-service ladder back off a live server — four real NPCs, reporting the arm taken, the opcode sent and the window opened — with every hop inside the reference's own service reach, after a first run parked ~29 yd from Deputy Willem and blamed the client for a dropped packet (1865) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
a8c9bc37a2 |
the audio crackle is gone, and a trainer answers a click as a trainer
- the audio crackle was our own stall sampler: `/usr/bin/sample` suspends every thread of the task for each of its snapshots, CoreAudio's realtime IO thread included, and coreaudiod times the client out — every HAL overload of the session sat inside a sample of our own process (three for three by timestamp), and the watchdog fires on exactly the stalls the crackle lands on (a desktop switch's `nextDrawable` block, a world entry's compile burst); in-frame sampling now waits for a run nobody can hear; and the output stream is ours — kira's renderer runs 256-frame chunks on a realtime render thread (time-constraint policy, joined to the device's IO workgroup) into a lock-free ring, the IOProc copies one device buffer and touches nothing else (≤ 0.01 ms), the device buffer goes 2048 → 512, a lost or changed default device rebuilds the stream (cpal's no-op error callback on macOS had paused it forever), a debug allocator aborts on any allocation inside either realtime path, and per-cycle meters name a skipped cycle's layer; `SoundBufferSize` is registered at the reference's own FMOD dial, and `audiowatch.py` puts the OS side — thread bands, coreaudiod's overload verdicts — on the same timeline - right-clicking a trainer, questgiver, innkeeper, spirit healer, petitioner, tabard designer or battlemaster sent `CMSG_GOSSIP_HELLO` — eight of the reference's fourteen service arms collapsing into one packet, because the dispatch keyed on the CURSOR kind and Speak covers eight bits; the reference runs two structurally identical ladders over `UNIT_NPC_FLAGS` (one for the cursor at `0x482336`, one for the send at `0x5f0289`), so the ladder is transcribed, first match wins low to high: questgiver → `CMSG_QUESTGIVER_HELLO`, trainer → `CMSG_TRAINER_LIST`, petitioner → `CMSG_PETITION_SHOWLIST`, and the spirit healer and innkeeper send NOTHING on the click — they cache the guid and raise the confirm, whose Lua accept sends with a zero guid — both ghost-gated at entry, so a living player clicking a menuless spirit healer now gets exactly what the reference gives: nothing; the stable-master conjunct and the banker/auctioneer fork fall out of the bit order for free - the -1 blood id is unfilled, not none, and the tests now name the creatures: -1 splits families that share a directory (QuillBoar beside QuillBoarWarrior, GnollMelee beside GnollCaster) and splits single creatures shipped under two rows (a Baby Murloc is both), so a "bloodless" reading would put non-bleeding quilboar beside bleeding quilboar warriors in one Razorfen room; `violenceLevel` 2 IS the reference's default — formatted out of a per-region cap table at `0x86c3f8`, and the one capped locale is koKR, whose green-blood row the table predicts from bytes alone; a spurt whose victim authors no attachment point is dropped, not relocated, and no creature-keyed suppression exists anywhere on the spurt path (ten stop conditions, none keyed on the creature) - twenty dead copies of ours (`PanelTemplates_*`, `TabButtonTemplate`, `FauxScrollFrame_*`, `ScrollFrame_OnLoad`, `ScrollingEdit_*`) that a later chain entry had been shadowing are deleted under a gate that fails any such shadow, and deleting them turned 141 tests red on four bugs live since the kit swap: lists populated before showing (the reference gates every scroll-bar write on `IsVisible()`, so both arrows were dead on every faux list), every faux window wired to a `frame.updateFunc` the reference does not have (the bar moved, the list did not follow), a trainer pitch declared `local` where an `<OnVerticalScroll>` chunk cannot see it, and the armed-wheel guard bypassed by the template's own `<OnMouseWheel>`; nine faux windows (Skill, Craft, TradeSkill, Auction, QuestLog, Friends, ScriptLog) are still on `updateFunc` and their lists do not scroll until each is rewired Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
1646addd6c |
a rider cannot loot from the saddle, and other swimmers tilt
- a rider does not loot: a corpse was looted from horseback, and the client-side mounted gate built for casts and attack-start had left interaction out of scope — `0x60bf98` reads the PLAYER's mount field and skips the loot leg into skin, a silent fall-through rather than a refusal; the stand-state gate (`ERR_LOOT_NOTSTANDING`), player bones, skin/insignia/key-turn (all through TryCast's 0x39 block, asked after the reagent check) and GameObjects (gated only when NO `Lock.dbc` row exists — nodes and herbs refuse loudly via their cast, signs and chairs in silence, the mailbox exempt) follow the RE; and the world right-click shows no attack-refusal text under any condition, since `0x5ecb70`'s extent holds no `DisplayError` at all — a correction to the earlier record; the cursor is untouched, so the pouch still lights from the saddle - 595 creature displays were dropping their blood spurt: the `UnitBloodLevels` row resolve has a THIRD tier — display `BloodLevel`, else model `BloodID`, else the records base (`0x60b117`'s branchless `setle/dec/and`: file row 0, RED) — and `BloodID == -1` (122 of 430 shipped models: crocolisks, quilboar, gnolls, murlocs, pigs, deer) is a tier-2 MISS, not a bloodless marker; replayed over the shipped tables here and in the wow-re round with the same numbers (36 · 9903 · 595 of 10534 displays); the ground-splat textures are read (four per row) and the RE verdict on their trigger is dead code — `"BloodSplat"` occurs nowhere in the image, though all twelve `.blp` ship - other swimmers tilt on arrival: `SMSG_UPDATE_OBJECT`'s LIVING block carried the mover's live flags and swim pitch and benilla threw both away (`let _pitch = read_f32_le(r)?;` — the director's own citation, exact), so a player who swam into view rendered LEVEL until their next relay packet, and an idle floater — who sends none while unmoving — stayed level as long as they floated; the create apply `0x619320` merges the block's flags under the same mask a relayed move uses and copies the pitch unconditionally, before the model is even built; one render law (`swim_body_rotation`) now serves both pose owners, the relay trace prints the pitch beside a guid that joins, and `WOW_PROBE_PITCH` can aim a scripted swimmer so a two-client probe of the lane can be written at last Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
46c7cf2b80 |
spells shake the camera, and the sound keeps playing in the background
- spells shake the camera: `SpellEffectCameraShakes.dbc` loads beside `CameraShakes.dbc` as the group table, `SpellVisualKit` field 14 is the shake column (58 of 1772 kits carry one — War Stomp, Thunder Clap, Kodo Stomp, the ~50 Knockdown/Slam/Charge impacts, every summon, Sapper Charge, Earthquake, Sapphiron's death), and the kit shake fires exactly once per play from the first effect node's one-time arm pass (`0x620e11`), the same leg that plays the kit sound one field over — the older "fires only if nothing else did" reading would have silenced every kit with a populated effect slot; `$SHK` markers fire from GameObject and DynamicObject hosts only (the titan chest, the bomb wagon); one deliberate deviation — the reference reads a bone-attached node's position twelve instructions before it is written, so 26 of its 58 shake kits shake at the world origin and are culled by the 80 yd cut, which is an uninitialised field, not a design; 21 of 24 presets now have a live producer, up from 6 - the sound keeps playing when the window loses focus, if you want it to: 1.12 mutes everything on `WM_ACTIVATE` and offers no way out, so benilla ships that as the default (`Sound_EnableSoundWhenGameIsInBG` "0") and puts an Audio-page checkbox on it — a gate appended LAST in the main-track chain, downstream of every tap, so an unattended capture still records; wow-re's round settled that music is not exempt and that it is a mute, not a pause - a building's far side no longer draws through its own walls: the camera-inside leg has three passes and we had one and a half — Pass 2 admits an exterior-shell group only against a frustum clipped to ONE deferred window (we marked every such group visible against the full view, under a comment calling it a benign over-draw), and Pass 3, which we had none of, draws the 24 `0x10000` groups (14 in Stormwind, 6 across Dire Maul, Razorfen's four 450–520 yd shells) from anywhere, frustum-tested on both legs by byte-identical setup; there is no antiportal branch in 5875 and no such flag in its data (815/815 roots and 5220/5220 groups censused, no bit above 18 ever set) - the macro window is the reference's own `Blizzard_MacroUI`, and `GlobalStrings.lua` — line 1 of the reference's own toc — was missing from our manifest entirely (the app loaded it out of band at startup, so the client was right and every harness that loaded the manifest was not); exactly one `<OnLoad>` runs, the most-derived, because `SetScript` releases the slot before it looks at the new body — which is why the reference re-states the template's width line in tab 1 and not tab 2 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
7308046d60 |
the screen warps underwater, and the ocean darkens with depth
- the screen warps underwater: submerged, the reference runs a second pass list whose third pass is `FFXGlowWave` (`0x6cb1f0`), binding a 128×128 two-channel sine bump map that displaces both the screen and the blur texcoords by 3.0 full-res pixels — uv rotated 10°, scaled W/128 × 0.88·H/128, two phases at 3174 and 2805 ms; wow-re had carried the swap as "GlowWave, or a duplicate Glow" and the cross-check settled it (the two arms are mutually exclusive and the plain-Glow arm is unreachable on both backends; lava and slime warp too, and a ghost's death pass replaces the glow outright); a dry frame binds the same pipeline object as before this existed, and the phases advance live at 0.313/s and 0.355/s against a predicted 0.315 and 0.357 - ocean is a fifth submersion state — 96.8% of every wet sub-tile in the shipped corpus, so essentially all open water — and it alone runs a depth ramp on the light: `t = clamp(eye.z, −30, 0)`, ambient at `(k+1)/2`, diffuse at `k/4 + 3/4`, exactly k = 0 at −30 yd, gated on the full dword `== 1` at `0x6d2821` (the ramp does NOT drive the fog colour — that store is dead, overwritten before submit); the sun and moon glare fade over a 10-yard depth ramp applied to the slew TARGET, not the drawn alpha — a read one indirection out that two notes had published a verified negative on; the MCLQ fishable bit (0x40) is deliberately unread, since `0x69b5d0` has zero callers in the image and fishability is the server's verdict - the dropdown kit is the reference's own `UIDropDownMenu.xml` (one manifest line for 1150 lines of ours, `DropDownList3` gained, and two fixtures that only worked because our copy was more forgiving); `UnitFactionGroup` returns the English name AND the localized one — ours returned the localized string twice, and the first return names a TEXTURE in every stock consumer (`UI-PVP-`..factionGroup), so on a non-English client every one of them named a file that does not exist Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
6bafea0919 |
your character speaks its refusals, and clicks land on the right frame
- your character speaks its refusals: `VocalUISounds.dbc` gets an adapter, `sound::vocal` transcribes `0x4580f0`'s per-race table and `0x458250`'s play cycle — four plays of one line arm the annoyed variations, and the bus cap of one keeps the annoyed and ordinary lines from playing at once; a displayed message now carries its catalog RECORD, so its sound comes off the same row (tag 0x44 plays the named cue, anything else speaks the line), and 36 of the keys benilla raises have a voice — cast failures, inventory refusals, the quest/auction/petition lines, taxi, bank, stable, mail, the talent wipe; `EnableErrorSpeech` joins the CVars at the registrar's own default and the Audio page grows 1.12's fourth Sound checkbox with the dependency ours was missing (the master greys Ambience AND Error Speech, not Music); seven of the twelve taxi refusals turn out to be the YELLOW info line, not the red one they all took - at equal (strata, level) the hit sweep takes the EARLIER-linked frame: `0x764aa0` inserts with a strict `ja`, so equal keys are appended, and `0x7660d0` sweeps each bucket from index 0 upward — the reverse of the reverse-draw-order walk we had, so draw order is unchanged and only the hit sweep reorders within a plane; the wheel becomes its own index, and the five full-area wheel-catcher Buttons (Craft, QuestLog, Skill, TradeSkill, Trainer) are deleted, since under the true tie law each would have swallowed its whole window's clicks — a bug the Skill window's own comment had already recorded once - one rasterizer settle for the whole ground-decal family, and it is the measured one: the shipped client constructs `CGxDeviceD3d`, so the OpenGL arm holding the −4.0 slope factor is never executed (factor 0 on 2485 of 2485 captured `glPolygonOffset` calls), and every number derived from it was 256× too small; the reference groups the blob shadow with the selection RING and the footprints on their own at 10×, the reverse of ours — but ours is reversed-Z float where the bake residual is millimetre-scale and constant with distance, so `DECAL_RASTER` collapses to one value (32768: the ring and the reticle had been under their own conflict at 8192 and simply never walked on a slope) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
feca23de3f |
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>
|
||
|
|
f01a964e6e |
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> |
||
|
|
d961d0bc06 |
Shadowfang's far rooms lose their cyan, and the street lamps hum
- Shadowfang Keep's far doorways no longer fill with flat blue-cyan at distance: it was never a hole — the room behind the arches is in the visible set at every camera distance — it was the building's own MFOG record (rgb 40,68,79 at end 106.9 yd, ~95% saturated at 70 yd) painted over a room the reference shows under the scene fog, because benilla picked the fog lane STATICALLY per batch (`flags & 0x48`) where the client's `[0xca7f00]` gate decides it per frame per group along the portal walk; the flood publishes that bit now and all three lanes (entity, retained, WMO liquid) read it, and the wow-re carve confirmed the predicate verbatim and added the conjunct we lacked — the MFOG target exists only when one of the camera's own containing groups is a true interior, so in a courtyard the interior triple decays to the scene triple, which is what a unit standing in the keep reads - every world-placed M2 was silent — the street lamp's hum, the campfire, the waterfall, the windmill: no doodad ever wrote into the anim-event stream (three producers, none a terrain placement), and the sound clock was gated on the RIG, which is rightly never built for a model whose idle is the static mesh — `KalidarStreetLamp01.m2` is one looping 3.3 s Stand keying no bone at all, carrying one `$DSL`; the census (`benilla-extract soundeventscan`) counts 273 carrier models, 108 on tiers no rig gate arms; a sound-carrying placement now gets a clock-only host, `$DSL` is a sustained emitter, and the RE foldback settled three laws: `$DSL` ALWAYS loops and consults no flag (the kit's 0x200 bit is a lane select and 0x400 is random pitch — a neat four-row correlation of ours refuted), `$DSE` is the stop token, and a doodad holds ONE registration slot, which is why `bellows.m2`'s two loops alternate rather than drone - the reference voices sound IDS, not doodads: `$DSL` registers the doodad's position as one record in a 32-entry pool keyed by SoundEntries id (`0x461d80`), each entry runs one channel at whichever of its records is nearest the listener — moved, not restarted (`0x7a5b10`), so one hum follows you down a row of lamps — the pump admits the first four entries by claim order and fades the rest over 3.0 s; the per-id duplicate suppressors turn out to be the one-shot lane's and were being applied to every lane (a three-second dropout every time a loop came back under the cap); three 76 yd hops between two Darnassus lamps now produce ONE play, and Darnassus runs 12 entitled ambiences with 8 withheld by the cap - the selection ring joins the decal band too, and it draws UNDER the shadow: the RE found the ring emitted from inside PHASE 1's own M2 node drain (`[node+0xb4] = 0x481540` → the `+0x38` tick → `0x608e00`), the same iteration that then draws that node's blob shadow — the reverse of the tie-break this ladder had asserted since both rungs existed, a rule invented here and never read anywhere; `WOW_EFFECT_TRACE` names every rung of the band and prints its index in the sorted transparent phase, which is the ladder read straight off a live frame Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
6356bc8f43 |
Enter World stops freezing character select, and bags close by the law
- Enter World stops freezing the character screen: from the click, the select image stayed on the glass ~100 ms because the loading cover could not draw until the state-flip frame — which cost 60 ms, 57 of it render+present: the world camera's first render of a 3000-entity world on cold pipelines, plus fifteen booth cameras waking on the very frame that owes the glass a cover; the glue now yields the glass on the click's own frame and the world camera (booths with it) holds off until the cover has presented — flip frame 60 → 43 ms and off the critical path — measured by the new `WOW_FRAME_PHASES` instrument, which stamps every phase of a frame and prints the render+present remainder no in-schedule stamp can see - switching to a character you haven't clicked before no longer flashes somebody else's body in their stage — the background swapped the frame the selection changed while the character waited for its whole assembly, so whichever won is what the screen showed (53 ms of the human standing in the orc's stage, and the reverse under a stage still loading); stage and character now commit as a PAIR, loads still starting on the click and an empty stage still swapping at once — on the same cold walk, eight selections make eight rebakes, every one the right body in the frame its stage lands, where before it was twelve with four of them wrong - the bank's six bag buttons repaint again — the stock UI repaints them only on `PLAYERBANKSLOTS_CHANGED`, which benilla fired for the vault's 24 slots alone, so a bag dropped in never appeared and one moved between slots stayed drawn in the one it left; the lock clear becomes its own system ordered ahead of BOTH feeds (resolve, then push, then fire), ending the stuck-grey icon — and `GetInventoryItemCount` is carved as not-the-stack-count: an EMPTY slot answers 1 (a sentinel, not a count), a container past the slot cutoff answers a literal 0 before any lookup (the whole answer to the stray digit on the bank's bag buttons), and an equipped bag answers the SUM of its contents gated on a DBC bit our class-11 guess missed twice — including the Soul Bag, so a warlock's shard count never showed - the bags close by the law: `BAG_CLOSED` is the only thing in all of FrameXML that hides an open bag window, and benilla never fired it, so a window outlived its bag in both bands (equipped and bank); the carve pins the condition — the bag changed AND the slot was occupied — so a swap fires BAG_CLOSED then BAG_UPDATE with the slot occupied throughout, an unequip fires it with the announce suppressed for exactly that transition, and two identical empty bags exchanged between slots still close both windows, because the diff is on the bag's own guid rather than the container state; `PLAYERBANKSLOTS_CHANGED` meanwhile turns out to carry NO arguments — a census of all 485 dispatcher call sites — the slot travels in how many times it fires, and every bank button repaints from its own slot id Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
023c490974 |
the server's broadcasts land, and a ghost walks through closed doors
- the four world broadcasts decode and land — a shutdown countdown, the civilian-kill alarm, a defense-tower capture and the whisper-cap refusal all reached benilla as unhandled opcodes; `SMSG_SERVER_MESSAGE` carries a row id and a fill, never a finished line, so `ServerMessages.dbc` ships (the five sentences a shutdown has, plus the client's own `[%d]: %s` row-missing fallback, which is mechanism, not an error path); the two defense broadcasts are CHANNEL lines, not system lines — delivered once per joined channel whose row carries DEFENSE, the LocalDefense copy zone-matched against the PARENT area while the text names the packet's own — so a character in neither channel sees nothing, faithfully, and since nothing auto-joins WorldDefense in 1.12 an Eastern Plaguelands tower capture reaches only players standing there unless they typed /join; the wow-re cross-check then made the length prefix load-bearing — the client borrows a pointer into the receive buffer and composes NULL on an overrun, so an overrunning length is a refusal here too: the packet drops with a log line, nothing displayed - `BankButtonIDToInvSlotID` is carved: `isBag` is a TYPE test, not truthiness — `lua_isnumber` refuses every non-number tag without ever loading the payload, so `true` takes the same arm as `nil` while `0` and `"1"` take the bag arm — the function is TOTAL (our out-of-range 0 was an invention; the only compares in all 118 bytes are on `lua_isnumber`'s return), and the +59/+39 arithmetic stands confirmed, byte-identical to `ContainerIDToInventoryID`'s second arm - a deliberate right-drag turn no longer stands you while seated — the observation was right and our attribution was wrong: the body-facing commit is refused by two independent gates and the stand arm is skipped outright while the button is held; what stands you is the RELEASE, a press under 200 ms with under 2.25 degrees of yaw dispatched as a right-CLICK whose interact reaches `SetStandState(0)` — this lands the deletion half, with the click's own stand held for one more wow-re answer - a ghost walks through closed doors — the whole mechanism is one instruction image-wide, reading bit 15 through the sign flag to answer "not a collision candidate" for a DOOR when the traced body is a player in ghost form; the bit is a property of whose trace it is, not of the door, so the exclusion rides the two mover-only casts and the set is empty on every living frame — the particle snap, the precipitation probe, the mouse pick and the creature conform keep the door's collider untouched, exactly as the binary leaves them Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
f9e75a79fc |
the ghost world gets its own sky, and a corpse cannot steer
- a dead player's sky is DeathClouds now — `lightSkyboxID` was named in the schema and read by nobody and `LightSkybox.dbc` was never loaded at all, so a ghost kept the ordinary gradient dome; the shipped data has exactly 5 of 426 LightParams rows carrying a skybox id, every one of them DeathClouds.mdx, reached from the death profile (slot 4) of all 374 Light rows and gated on the ghost bit, with a hardcoded weight of 1.0 that skips the WMO skybox outright; it resolves off the same (map, camera position) seed the atmosphere uses, so the ghost sky and the death-profile fog it hangs over switch on the same frame — and the lane sheds its `wmo_sky` name for `skybox`, no longer being WMO-only - a corpse cannot steer: the reference's two movement-input predicates share a precondition benilla never modelled — `UNIT_FIELD_HEALTH > 0` — so at zero health the keyboard turn and the right-drag close together, exactly as they do inside an Ice Block, while the ghost (health 1) keeps moving; the wow-re §5 round then corrected three byte trails (the mouse turn has its own eight-conjunct predicate, the supposed on-taxi test is the Knockdown animation lockout — set on exactly one of 208 AnimationData rows — and the "charm bit" is the far-sight latch) and added three verified health gates we lacked: the jump IS health-gated, sit and stand are refused while the body reads dead (a feigner too), and a follow tears down only when BOTH predicates drop — we had that wrong in both directions - the walk-gait cross-check folds back confirming `min(walk, run)` and the speed-only animation channel (by a 2,304-function closure census), and finds the trap we lacked: every incoming spline re-authors the gait, and the spline's RUNMODE flag is an INVERSE — a spline marked as a run clears walk mode, one not so marked SETS it — so a charge, taxi, knockback or flee hand-off leaves the body in whatever gait its path was authored with, applied once on the spline's start edge; the post-worldport zero-walk fallback is retracted on a re-run (the ctor's zero is a transient thirty instructions wide, never observable), leaving the plain minimum the bytes compute — the better failure mode too, since a fallback makes a walker silently RUN if a walk speed ever goes missing, where the transcription makes them visibly stop Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
03c70a7035 |
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> |
||
|
|
6e3a67e039 |
your corpse answers the mouse, and a cinematic's last holes close
- a corpse is a body you can hover, cursor and click: it enters the same ray pass as units with the winner switched on type at publish (the reference's own shape — one trace over every object), the cursor classifier is transcribed whole (lootable-by-me → the pickup cursor, grayed by range; else the insignia leg behind the learned-skill latch; your own body falls through to the clear), and right-click is "not mounted AND lootable" → CMSG_LOOT; CORPSE_FIELD_FLAGS bit 5 is the PvP insignia flag, not "reclaimable" as an old note had it; the widening also caught that a GameObject anywhere on screen could steal the click from a nearer corpse, and that a left-click on a body cleared your target as if you had clicked ground
- the cinematic sweep closes eleven holes: a shot plays its sequence band's WIDTH, not its end — two shipped fly-bys band away from zero and ran long with their opening frames frozen (the Night Elf intro measured 102333 → 102000 ms); CMSG_NEXT_CINEMATIC_CAMERA announces every shot, the first included — the old "between shots" reading meant it was sent NEVER, since every 1.12 sequence row carries exactly one camera; the ack invariant is stated once (one CMSG_COMPLETE_CINEMATIC per accepted trigger, over-acking tolerated, under-acking never — a dropped ack despawns the world around you until relog); the hardware cursor hides for the shot; and the music cut lands in the frame that starts it — it was one frame late, exactly long enough for a first login's zone fanfare to start under the narration and be stamped as played
- RunBinding exists, and a fly-by stops handing the world its mouse: CinematicFrame's OnKeyDown hands the SCREENSHOT chord back to its binding through RunBinding, a global we never had, so every press during a fly-by raised and took no picture; and the mouse was fully live under a shot — right-drag turned the character, clicks picked targets through the flying camera, both buttons walked the body — so the pointer now reads as over the UI while a shot plays
- AdvanceTime and ReplaceIconTexture are carved off the bytes: AdvanceTime really is a no-op in the reference (its one reachable call is mov eax,1; ret), ReplaceIconTexture is a material swap over a model's type-14 texture slots that stores nothing on the widget, and SetModel(nil) RAISES — the "documented clear" our binding claimed was invented, not read; and the addon roster now says WHOSE package is short when a .toc names files the folder doesn't hold — nine of the corpus's twenty-nine load failures are the addon's own manifest, which the real client also shrugs off ("Couldn't open %s", carry on), so they stop reading as our defects
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
ac74c98c15 |
knockback is a jump the server aims, and tabards wear their guild crest
- knockback is a jump whose seed came off the wire, not a server spline: SMSG_MOVE_KNOCK_BACK's four floats are exactly the MovementInfo jump tail in a different order (speedZ down-positive — a rising launch carries a negative value, the sign vmangos's own source marvels at), flown at the same take-off site as the keyboard jump and acked with the post-launch pose, which the server matches float-for-float within 0.01 before relaying to anyone; it is the one take-off that seeds BOTH axes, absolute in world XY, so it skips the arm that would hand the momentum back to a held key and reduce the whole knockback to a hop; root refuses it silently, a seated player stands up first, no MSG_MOVE_JUMP goes out — that packet is the keyboard's, and vmangos logs a jump at knockback speed as an overspeed cheat — and MSG_MOVE_KNOCK_BACK turns out not to be dead: an observed knockback replays as the arc it is - your guild crest reaches your tabard: the three GuildEmblems layers — background, border, emblem, on both torso tiles — belong to no equipment slot, so the body composite never wrote those cells and every guild wore the Guild Tabard's own default art; the install is gated on a display flag only seven of 29,604 rows set, of which exactly one is worn by any item — which is why every battleground and Argent Dawn tabard keeps its own art; the five wire indices are signed, because an undesigned guild carries −1 in all five and the client refuses to paint on the first −1 (unguarded, the commonest guild state on a young realm would have worn a blank tabard); the emblem keys the skin cache, so two guilds in the same tabard display cannot lend each other crests; and a guild tabard's background hides the bra where a plain tabard does not — it is a cutout, 79.5% opaque off the shipped art, and what shows at the sides is bare skin - a fly-by is framed by the world camera, not the M2 camera record's fov: a census of every reader shows the record's fov and clip planes reach only the portrait and Model-frame paths — nothing on the cinematic path reads any of the three — so fifteen of the sixteen shipped shots were rendering at HALF their intended vertical FOV, visibly over-zoomed on every race intro but the Undead; the fix is a deletion, and it dissolves a standing puzzle: the authored 0.22 and 27.8-yard "clips", which would render the dwarf intro's mountains as empty sky, are not clips at all on this path — two floats nobody consumes look exactly like that - 104 of Onyxia's lava traps stood on an interior floor classified as outdoors, taking the day/night sun inside a windowless lair: a GameObject's light node anchors at its model's AUTHORED bounding-box centre, and the trap's box reaches 98.42 yd past its bind pose — the anchor sits ~40 yd under the chamber floor, where a downward ray finds nothing above it to claim; the reference recovers with a 1000-yd upward retry at the claim itself, which benilla had only at the colour sample, so the verdict was decided before any colour was read; all 104 now classify interior, beside the 26 rocks and 119 eggs that always did — and the drowned-corpse pose came back from its cross-check confirmed at the bytes (a strict liquid-depth test at exactly two-thirds of a yard, Dead or Drowned), with the two reference-side notes it contradicted corrected over there Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
c827813351 |
cinematics play, and a lit particle stops brightening as you turn
- cinematics play: `SMSG_TRIGGER_CINEMATIC` resolves through `CinematicSequences.dbc` → `CinematicCamera.dbc` → a `Cameras\*.m2` whose camera record is an eye path, a look-at path and a roll — cubic tracks with the full step / linear / Bézier / Hermite dispatch the bone loops collapse to step-or-linear (every shipped fly-by is Bézier), planted at the row's origin and facing (`Rz(+facing)`, checked against vmangos's own waypoint table: 8.5 yd mean on the human path, 154 with the other sign); FOV is per shot (the Undead intro authors 90°, the rest 45°), roll is authored around whole turns, the flight ends at the sequence band's end, a trigger arriving before the loading cover lifts is latched and started when it does, ESC skips through `CinematicFrame`'s own `OnKeyDown` (`StopCinematic` has zero native callers), and every path acks — natural end, ESC, or an unresolvable trigger immediately, as before; `.debug play cinematic <id>` replays any of them - a cinematic hides the HUD — `UIParent:Hide()` reaches nothing here because the HUD frames are not its children, so the ALT-Z draw-level hide is used and the letterbox moves out of FrameXML onto Bevy UI nodes where that hide cannot reach it, recomputed per frame (bars only wider than 4:3, the picture cropped to 2:1) — and the restore only un-hides a UI this module hid - a lit particle's normal is world up, one constant per draw, not camera-facing: Onyxia's always-on floor haze read about four times brighter from a level camera than from above because the shader dotted a to-eye normal against a fixed light; the reference uploads row 2 of the view matrix — world +Z carried into eye space — on every vertex and carries the light into the same frame, so the rotation cancels; 400 lit emitters (the waterfalls, chimney and campfire smoke, Westfall dust, Dun Morogh snow) stop brightening and dimming as you turn - the `play` profile drops ThinLTO — rustc #86049 was intermittently poisoning the incremental link with `_anon.<hash>.llvm.<id>` symbols promoted by an earlier compile (48 unresolved across 7 codegen units; 1065 such symbols → 0 after) — and `benilla-formats` stops taking `image` with default features, which had been compiling a complete AV1 encoder into a crate that writes two PNGs: 499 → 466 workspace crates Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
6710b31a82 |
scrolling chat brings lines back, and Onyxia's lava traps spurt again
- every chat scroll re-arms the displayed lines' fade — up, down, top, bottom, page up/down, and a no-op scroll at the bottom too, which is what clicking the arrows on an already-at-bottom chat does; a line at alpha 0 was unreachable for the rest of the session (play two minutes and the chat was empty and stayed empty), because "scrolling off the bottom freezes all fade countdowns; nothing un-fades" had been read as a law about the class when it was a finding about one function's gate; the displayed set only, never the whole ring, with the frame's current defaults, as the reference's re-arm writes them; there is no hover reveal — the scroll re-arm is the whole mechanism; and the fade ramp reads the un-rounded countdown, not the stored f32 - the GameObject animation arm rolls a variation: Onyxia's 104 lava traps and 26 falling rocks author Stand twice — a 29491 : 3276 chain whose second take is the `LAVALUMP2` ember burst — and the arm is issued with `variationIdx = −1`, a weighted random walk of the alias chain, where we resolved the chain head every time (215 emitters, every one at live = 0); and a resting substate re-arms itself through the model's completion callback, so the roll is re-taken every window for ever (~867 ms for the traps) — 45 emitters firing and 1299 live particles at +25 s, a standing field rather than a one-time flurry; 72 of 1582 GameObject models author such a chain (the fish schools, the AQ fireflies, the plague cauldrons, lanterns, mugs) and every one was playing take 1 of N; `benilla-extract goanimscan` censuses it Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
55b40b5257 |
names persist, the GM notice is a toast, and the target reads Dead
- the name cache persists to `benilla-config/cache/<realm>.tsv`, because the reference's `namecache.wdb` / `petnamecache.wdb` do and that is why it never sees the races we lost every time — unstabling a pet raised `Usage: SetText("text")` off an unresolved `UnitName("pet")`; the header carries magic, format, build, locale and realm and any mismatch discards the file (no checksum, no TTL: eviction is explicit only, via `SMSG_INVALIDATE_PLAYER`, decoded now and never sent by vmangos), negatives persist too, written on a 10 s debounce and at exit; a stable list also seeds the pet-name cache from the names it already carries
- `SMSG_NOTIFICATION` is the red UIErrorsFrame toast, not a chat line — `.gm on` printed twice because vmangos sends both a system message and a notification and both were rendered as chat; the stand-in dated from before the errors frame existed; `SMSG_AREA_TRIGGER_MESSAGE` moves with it on the yellow arm (its handler ends `xor edx,edx` — flag 0 — where the notification's is flag 1)
- the target frame's dead text is the GlobalString `DEAD` = "Dead" resolved through `text=` like the target-of-target frame, not the key typed into `SetText` in caps, and it takes `UnitIsConnected` so a disconnected player does not read as dead; a shipped-script sweep now refuses any key-shaped literal handed to a text sink; and the Help window is one click deep — Home's button opens the ticket text box, Auto-Unstuck sits beside it, and a ticket files as category 0, which a GM's queue names "Unknown" (a guard added days earlier refused 0 on reasoning from the enum rather than from the function that reads it)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
57b61de04b |
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> |
||
|
|
c0b7a613a9 |
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> |
||
|
|
693c26d9c4 |
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> |
||
|
|
ee8f9ddfa0 |
the login scene frames its art, char select remembers, DXT stays DXT
- the glue scene widens only as far as its art goes: none of the seven login dioramas is drawn wider than about 3:2 — measured per texel by `benilla-extract glueextent`, which rasterises every batch into the camera's own tan-space, painting where the reference's alpha-key test passes — so the frame zooms down to the reference's own 16:9 opening (never tighter) and pillarboxes past the aspect the art cannot fill, instead of showing the clear colour past the backdrop's slanted edges; 4:3 stays byte-identical - the character screen opens on whoever you last logged in as: the reference's `lastCharacterIndex` CVar, written at Enter World and only there — clicks and arrow keys never touch it, which is what makes the value mean "last logged in" rather than "last clicked" — restored on every character-list rebuild and clamped into range - spam-hovering tooltips stops costing 2 ms: two write sites gave up naming their node and re-derived the whole layout graph (1,812 µs against the ledger's 44, on 919 of 1,262 resolves) — the wrap pin now touches the one region it wrote, and re-pointing a tooltip at the button under the cursor retargets the node's edges in place instead of throwing the cached graph away - two corrections off the project's first GPU-bound report (a Steam Deck at 94% GPU busy on 8.4 W of a 15 W budget, the memory-stall signature): `farclip` ships the reference's registered 350 instead of the clamp's 777 — the value also sizes terrain residency, so 777 streamed, held and drew 4.8× the area — and BLP textures upload WoW's own DXT blocks verbatim the way the reference does, instead of decoding to RGBA8 at 8× the bytes of DXT1; the terrain slider still reaches 777, and the lanes that read texels on the CPU (terrain arrays, the character-skin compositor) stay decoded and say why Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
d6953c936f |
the missing bra, the robe's hem, and a doll that puts its arrow down
- the missing bra: the underwear section's CharSections row spends BOTH of its texture columns and the body compositor read only the first — the pelvis — so a bare-chested female composited panties and then bare skin above them; the second column is torso art authored on all eight female race rows and no male row, which is how the male-only regression test stayed green over the missing half, and the new test is byte-exact — the composite's torso tile must equal the shipped BLP's mip 0 verbatim - underwear is the tile's FALLBACK, not an under-layer: the reference tests a prefix of a tile's equipment cells and skips the underwear blit entirely when any is occupied, while cells past the prefix stack on top of an underwear that was allowed to draw — so a shirt or chest suppresses the bra, trousers the panties, but a belt never hides the panties and a plain tabard never hides the bra; benilla blitted underwear first and equipment over it, which coincides on most gear and is still the wrong law - a robe outranks footwear on the lower-leg tile: the equipment stacking table is a DEFAULT that two of the eight layer choosers overrule, and the robe bit lifts a chest to cell 4 over a boot's 3, so sandals stop repainting a robe's hem; and `_U` outranks the gendered file — the reference probes the universal name first and patches the gender letter in only on a miss (43 of 7944 shipped basenames carry both, and on those the gendered art is dead), which closes the bare-skin ring a shorter `_F` pant file left below the knee; `benilla-extract charatlas` prints the blits in order with the file each region resolved to, reading the same `equip_blits` law the compositor walks - a model widget edits its copy the way the reference does: fifteen attach ids reset off every duplicate — blood, breath, the nameplates, the spell hands, and the nocked arrow — and the hand grips arm from attachment occupancy, where ours sat hardcoded open under a comment claiming the pane sheaths its weapons (it never did); the character doll stops drawing a hunter's arrow and closes the hand around the bow, and the booth bake log now names its attach ids (`at=[2,35] grip=[false,true]`), which is also the reset's retest readout Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
db86a9c7ad |
the zone counters line up, and the ballista shine holds still
- the world-state readout — the top-centre counters a battleground or Silithus keeps up — takes the reference's real geometry: every icon those rows name is a sprite authored into the upper-left corner of a power-of-two canvas (`AllianceTower` is 16×16 of ink at (3,2) in a 32×32 file), nothing anywhere crops it, and the reference compensates geometrically — a 42×42 slot hung 6 units off the row's left edge with the label seated 10 above its centreline, taken as one system; our snug 20×20 box stripped exactly that compensation, so the art drew at half size floating away from its own `0/200` label — and an empty icon column now reserves its rect instead of sliding the text left, which straightens the readout's left edge - the dynamic icon is a second slot, not a swap: `Icon` and `DynamicIcon` feed two different regions and shipped content never mixes them, so the flag is a 32×32 button off the row's right edge with an ADD-blend flash overlay pulsing 0.5 s in / 0.5 s out, lit only at `uiState == 2` — the flag-taken value; before, any non-zero state replaced the static art, which fires on the ordinary state 1 and hid a faction shield that should never have moved, and the pulse's alpha ramp is now pinned by a test, not just its art - the dev cost pill yields the band: the readout is the game, the pill is scaffolding, and a stock 1.12 UI has no free corner to move house to — so it steps below whatever the readout draws, reading `WorldStateAlwaysUpFrame:GetBottom()` on its own 4 Hz cadence and only while it is drawing, rather than mirroring the frame's row pitch in Rust; the probe's cost is stated at the site (an edge read settles the layout — up to one graph solve, ~47 µs, four times a second) - the Hearthglen ballista's bolt heads and shields stop flickering: a shine layer is a second batch over its base's own triangles, and ours split the pair across lanes — the base rode the retained lane's f64 CPU bake while the env-mapped, additive, no-depth-write shine stayed on the entity path's f32 GPU rotate, and a few ULPs between coplanar surfaces turns the depth test into a per-pixel coin flip re-rolled by every camera move; a batch now names the M2 skin section it draws, neither member of a shared section diverts into a consolidator (depths equal by construction), and a corpus census bounds the cost — 1,080 of 9,691 models draw a section more than once, 264 such sections across 221 `World\` doodads — with toggling pixels at the pin dropping 0.26% to 0.14%, matching the consolidators-off arm bit-for-bit Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
f8421c1545 |
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> |
||
|
|
eaabe372f7 |
the Lightwell stands up, and stealth openers start your swing
- the Lightwell has its shaft: a billboard card kept only the x of its bone's scale, so a bone animated non-uniformly (the well's 8.8 × 8.8 × 37.6 light column) collapsed into a squat blob drowning the bowl — 32 models and 49 bones in the corpus were losing their stretch the same way, mage Teleport's six bones at ×11 among them; `bbscan` grew the column that finds them - Backstab, Garrote, Ambush, Cheap Shot, Shred, Ravage, Pounce and one Judgement start your auto-attack on the spell's hit, as the reference does — the "no spell carries that bit" the deferral rested on was a proof by absence over ten rows; the census now covers the shipped file's 36 - Quiver's range rung reads right: the interact-distance map held players only, so a mob "target" answered a constant at every distance; it holds every unit now, with the inspect refusal riding the entry - the craft and tradeskill reagent slot is the reference's QuestItemTemplate (147×41, the name plate, the count on the icon) — its base template lives in the Blizzard addons, not FrameXML, which is why the first cut was hand-rolled Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
1c5db5c2c1 |
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>
|
||
|
|
ab235bad6e |
the target-of-target frame, and talents can be unlearned again
- the target-of-target frame and its option: 1.12's frame with its five display modes, fed one hop off the selected unit's own target field through the same read `/assist` runs, in four feeds (snapshot and transitions, the debuff buttons, the portrait booth, TargetUnit's click arm); ships off, as 1.12 does, on its own pair of saved globals - talents can be unlearned again: the trainer's `MSG_TALENT_WIPE_CONFIRM` had no handler since the wipe flow was deferred, so the gossip line closed the menu and did nothing — the question is an NPC session (walking away retracts it), the popup shows the cost on the StaticPopup money variant, Accept answers it behind the client's own purse check - Sprint's sparkles hang in the air behind you along the trail instead of collapsing into your torso: ride-vs-trail is the emitter's own file flag 0x10, not the host class — the finding wow-re returned eighteen days ago and nobody folded; the particle dump names the two flag bits it had been mis-reporting - `/sleep` takes both movement masks (the strictest posture), correcting the day's sit gate which let you lie down on a lake bottom while `/sit` was refused; a Lua-driven selection (TargetUnit on an attackable token) starts the swing exactly as a click does, through the one select path Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
ac2ed34735 |
the combat log speaks, and the swim line follows your native form
- the client synthesises its combat-log chat lines: 44 chat types over 34 GlobalString families from 7 packets, the reference's own four hops (classify both endpoints → chat type → string key → format), text resolved out of the player's own GlobalStrings — so damage meters and Quiver's TranqAnnouncer have something to parse; wow-re's byte round corrected six gates (owner is charmed-by then created-by, "party" is your subgroup, friend-or-foe is CanAttack, the range gate, the miss defaults, the damage-shield chat type) - the collision prism follows the NATIVE display, not the rendered one: a druid in bear form keeps the druid's swim, splash and wade lines and a morph keeps the human's — worst divergence on shipped data 0.72 yd (tauren moonkin), the sign flipping by form - the creature swim gate is on both legs: a unit that loses its flag mid-water is driven out of swim at any depth, as the reference drops a charmed creature to the seabed on the next tick Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
b3a156f090 |
plate armor rings like plate, and sea giants walk the seabed
- a plate-wearing player's incoming hits stop sounding like a punch on meat: the victim's impact column comes from the chest armor's material (plate, chain, else flesh), the clang follows the defending item's class and material (a wooden shield rings wood, an unarmed parry is silent), and Material.dbc's Flags column gets one home instead of three interim readings - a creature swims only if the server said it may: the reference tests three unit flags before starting a swim, and a Shore Strider carries none, so it wades chest-deep with its legs working instead of gliding — the collision height the triage suspected was right to the float; the height also takes the reference's max() floor over the display scale - a second nudge of the rotate arrow inside a half-run blend no longer stacks fades: the client refuses the snapshot past the halfway mark and lets the older pose finish on its own window Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
a8ab442d27 |
every melee hit makes a sound, and footsteps get their armor foley
- every connecting melee swing makes a sound: the reference splits its swing sound in two — a miss whoosh by handedness, and for a landed hit, parry, block, immune or deflect the WeaponSwingSounds2 kit picked by the swinging hand's weight class, a DBC column (ItemSubClass.WeaponSwingSize) this crate had carried unread; deflect and absorb get their real kits after three weeks as silent stubs - a footfall is two sounds: the terrain step and the armor foley of your chest piece's material — chain, plate and leather rustle, cloth is silent by data; on the real 1.12.1 files every creature model's foley material is 0, so the foley you hear in the reference is your own, and that is what ships - the paper doll's turn cross-fades at both ends instead of cutting — the reference plays every turn clip blended over the incoming clip's own authored blend time (0.25 s into a shuffle, 0.5 s back to Stand on HumanMale), and the outgoing clip keeps running under the fade rather than freezing, which corrects a "universal snapshot law" an earlier record had over-generalised; `m2seq` prints the blend column that settles such questions Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
915ebc0119 |
the login theme rides the loading screen, and the mix gets a limiter
- the login theme no longer cuts off the instant the loading screen appears: it plays through the whole load and hands over on a 3 s fade once the world is ready, as the reference does — the stop sat on the same edge that raised the cover, and the reference never calls its music-stop on the enter-world path at all
- the mix had no headroom: every WoW sound is mastered to full scale, so five party-wide Fortitudes in one frame asked for 5× and clipped hard ("dirty, like a speaker breaking") — a stereo-linked look-ahead limiter now holds the output, a meter reports the peak the mix asked for, `SoundOutputLimiter 0` A/Bs it, and the 3D voice ceiling is named at 512 instead of inherited from the backend at 128
- a shaman's Rockbiter / Flametongue / Frostbrand / Windfury Weapon casts straight onto the equipped weapon on the press — no item cursor, no click — the reference's own `Attributes & 0x200` read; stones, oils and poisons still raise the cursor
- the nameplate category's player arm is pinned to the bytes (CanCooperate is faction-group-mask equality) and `/reaction` prints the one number it turns on: a GM-mode character plates as an enemy on a test realm because faction 35's mask is zero, exactly as 1.12 does
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
cf581aa2ac |
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> |
||
|
|
f8e312d015 |
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> |
||
|
|
b3dbd5d6ab |
speech you don't know arrives scrambled, and a GPU crash dies
- opposite-faction speech garbles client-side now, the way 1.12.1 actually does it: the wire carries plaintext plus a language id, and the client substitutes per word — a word survives iff `SStrHash(word) % 300 < skill` (300 copies verbatim) — reimplemented from `0x49b560` over the LanguageWords pool, 35 golden vectors passing; a Horde character also stops seeing a spurious `[Orcish]` tag on every line of their own faction's chat, and the talk gesture reads the plaintext, not the garbled line - a mid-session wgpu validation crash is gone: `NoIndirectDrawing` rides the camera's spawn instead of a per-frame sweep — 18 cameras were being flagged after spawn, and one whose first extraction beat the sweep latched indirect buffers forever; the census now reads zero late inserts with the direct-draw optimisation fully intact - the 20-yard overhead-name cap is withdrawn: it read the V-key nameplate frame's law onto the overhead name lane, which the bytes show carries no distance term at all — a distant name just gets small; V-plates keep their 20 yd, which is correctly theirs Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
7171a4997c |
bogus form requirements, the hover jump, and mining at skill 1
- priest tooltips drop their bogus red lines ("Requires Shadowform" on Psychic Scream and Inner Fire, "Requires Spirit of Redemption" on Flash Heal): `Spell.dbc`'s Stances mask is an allow-list, not a requirement, when `AttributesEx2` bit 19 is set — 244 of the 522 masked spells carry the waiver, and the tooltip now consults the same gate the cast validator already did; Charge's "Requires Battle Stance" still asserts
- a hovering mover refuses the jump, silently — no packet, no toast — exactly as `CMovement::Jump` does: the HOVER test sits ahead of the swim select, so a levitating swimmer can't breach either; the old gate refused on ROOT only
- opening a lock gates on your skill, never your level: mining with 1 Mining no longer appears to open a 300 vein only to be bounced by the server — the client-side "Requires Mining ≥N" refusal fires with no packet sent, and the level term rides the skill block through the same clamp the reference uses
- the Mod/Mod2x fade was never a deviation — preset 5 IS the identity-lerp, byte-exact, five comment sites re-lawed with no behaviour change; and the garble word pool (`LanguageWords.dbc`) loads, the first hop of the language scramble that lands next
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
a76530ab62 |
the minimap's black lines close out, and shared water cells draw once
- the Stormwind/Orgrimmar minimap lines are gone, at the cause: a group's boundary tile is authored 1.0 yd larger on that side alone, so touching groups overlap by 2 yd — without the bleed a LINEAR-filtered silhouette loses ≈0.38 texel at every abutment and the black clear reads through as a dashed line; with it, disc black goes 4.49% → 3.69% and no lines, inside the reference's own band - the tile sampler stays LINEAR but filters in gamma space (`GL_SKIP_DECODE_EXT`, as the reference's trace has it) — a terrain underlay and a NEAREST sampler both reproduced the symptom and were both retracted as wrong once wow-re refuted them - the canal-surface line in the world was a second defect: Stormwind's canal groups genuinely overlap (14,416 lattice points claimed wet twice), so the translucent sheet composited twice — the MLIQ `0x80` shared-tile gate now resolves each shared cell to one owner at load, pixel-identical and zero double-claimed points, not one wet point lost - the interior composite is probeable headless now: `WOW_MM_PROBE` synthesises the minimap slot server-less, and an offline rebuilder reproduces the defect and the fix from the shipped art Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |