c573ecc5d0fd52c7dcefa426678658bb9624ebd9
31
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
fbeb0f02f6 |
MONKEY (gfx): separate fading foliage from downstream material markers
Move the foliage wind marker from bit 14 to bit 15 in its Rust producer and WGSL consumer so distance-fade twins cannot trigger a downstream fragment effect. Keep bit 14 reserved for those extensions. Verified on Windows: cargo build -p benilla --profile play; cargo test -p benilla-app --lib (4313 passed, 0 failed, 10 ignored; no-install run). Public-base and fixed captures at the reported Elwynn position are pixel-identical; downstream integration still needs its in-game retest. Co-Authored-By: GPT-6 Astra (Codex) |
||
|
|
2f68d4c4e6 |
MONKEY (integration): merge gfx/skybox
Zone Skyboxes row moved to the end of the Advanced Graphics page and added to OPTIONS_PAGE_ROWS (the lane had left it out of the list). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
22d75ea613 |
MONKEY (skybox): second texture stage for two-texture skybox batches
RenderSubmesh carries stage 1 (texture, UV set, transform, Mod/Mod2x) for textureCount 2 batches; M2Vertex reads UV1. WowModelExt gains a stage1 uniform + texture binding 94/95 and the WOW_STAGE1 shader def, so every one-texture batch compiles the old code. The skybox lane binds stage 1 on its own material copies and drives its transform rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
512c81f43e |
MONKEY (fix-wind): tree exile sway rides a material marker, not MeshTag bit 18
Bit 18 aliases the top lane-weight bit and bit 12 of the interior probe slot, so doorway units and probe-lit interior props swayed like trees. A classified leaf batch's fade-band exile now gets marked copies of its cutout/blend materials (clutter_fade.z bit 14, FOLIAGE_WIND_MARKER, not a key axis) and wow_model.wgsl sways only those. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
129ea35f5a |
Merge upstream main (samwhosung/benilla fd386e75) into lighting
71 upstream commits: the repo-wide comment rewrite, the hover highlight as the scene ambient, M2 Mod/Mod2x batches drawing the bare texel, test and contribution changes. Conflicts were comment-vs-code in 36 files; where upstream changed only comments our code was kept, and wow_model.wgsl carries both our lighting lanes and upstream's new unlit/Mod/Mod2x paths. Follow-ups folded in: - our nine Advanced Graphics / water / fog options tests take upstream's wow_data_or_skip! guard - PostUpdate ambiguity ceiling re-measured under upstream's new census: 466, with the per-family breakdown in the comment - LIGHTING.md: new upstream base Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
fdfd8d39ec |
Comments in benilla-world: one line of fact each, no history, no record numbers (#121)
Part of #41: the comments of `benilla-world`, Rust and WGSL, are rewritten to the rule in `docs/METHOD.md`, which is what the code does and the reference fact behind it, in a line. 24,226 comment lines become 8,863. - **The mechanical strip.** The citations that were only a private record number go first, and each edit is shown to be a pure removal. - **Wrong facts corrected.** The rewrite corrects the comments that stated wrong facts. Among them: - `0x6b62e0` is the WMO group's liquid renderer, not a doodad drawer. - The reference creates a WMO's props once, when a group enters its streaming window (`0x698720` → `0x695aa0`). It then admits them each frame the portal walk visits the group (`0x685d70` → `0x6838f0`). The old text had them created per visible group. - The liquid query's comments now state the reference's order: the map-object leg first, then the ADT (`0x69b6d0`). They no longer call the Outdoors/Inside split a match. - The interior probe runs from the character, not the camera. - The reference lights ground clutter. The old comment said it draws unlit. - The model-particle "pool order" deviation was wrong. Each instance is its own mesh, depth-sorted every frame. - The reference's vertical field of view follows the aspect ratio (44.1° at 16:9). The comment now gives it beside our fixed 45°. - The effect shader's far wall is the live `farclip`, 177 to 777 yd, not a fixed 777 yd. - Dozens more turned up on the way: renamed or deleted items, docs sitting on the wrong item, stale counts and links. - **Deviation labels.** "Deviation:" now marks only a choice with a reason. An unbuilt behaviour says so plainly. - **Verification.** Every file strips to identical code, and `cargo fmt --check` is clean. Five second readers compared every file old against new, restored the facts the rewrite had dropped, and checked each new citation against the reference. Defects the rewrite surfaced outside the comments are filed as their own issues (#106, #114, #115, #116). The comments here state what the code does. String literals are untouched; they are #92. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
8952d590e6 |
comments cite the reference by address, not by private note (#30)
Comments that pointed into the maintainer's private reverse-engineering notes (a note by name, a path, a section or finding id, the analysis's own name for a client function, a process word) now carry the fact itself, cited by the reference client's address, by vmangos file and line, or as "the reference". Nobody outside could follow those pointers. Comment text only, plus the test-assert and log strings that carried the same pointers. No claim changes: a comment the notes have since corrected keeps its wording here, and correcting it is separate work. The two reference generators, `scripts/gen-reference-globals.py` and `scripts/gen-reference-verb-events.py`, named the private notes' layout to find their inputs. They now take the input files as arguments (`--capture`, `--framexml`, `--names`, `--extents`, `--disasm`). Run on the same inputs, both write the committed tables row for row; only the two header lines that named the old environment variable change. Checked per file: - the code is identical: each file with its comments stripped compares equal before and after; a changed string literal is compared under a mask that proves only literal text moved and every literal kept its line count; - no client address the old text cited was dropped; - a second reviewer checked every added address against its derivation; - a detector for the notes' names, paths, ids, function names and process words finds none left; - `scripts/gates.sh` is green. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
74ac33098d |
Merge upstream main (samwhosung/benilla edec5b22) into lighting
Ports the lighting settings into upstream's single settings registry and the lighting plugins into game_plugins.rs. 1108 world+formats tests green; world scenes (inn, Northshire dusk, Stormwind) render clean. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
d36a2303f7 |
Merge upstream/main (samwhosung/benilla 66388278, 78 commits) into everwood-cs
Keeps both sides: upstream's settings rework, model_render rework, mesh-tag change-gating, static_gx node move + diagnostics span, WorldPointLight, brightness/weather options, weapon trails; and the MONKEY lighting stack (sun shadow lanes, dynamic interiors, cube-map torch shadows, daylight fixtures, spell lights, bake floor, K=12 exterior selection, debug panel). All MONKEY light lanes migrated from Bevy PointLight to upstream's WorldPointLight. 1091 world+formats tests green; all 8 WGSL probes OK; server-less smoke (inn, Northshire) clean. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
5f622e6fe8 |
air elementals, Ragnaros and the forge lava animate
- every unit, GameObject and held item runs its texture animation: air elementals, Ragnaros, the Ash'ari Crystal, Ironforge's forge lava, the Scourge rune circles and the Zul'Gurub forcefields were static (2295) - a GameObject whose animation slots disagree gets a material of its own: the Blood of Heroes pools bubble and the Freezing Trap's glow pulses (2295) - three sound kits with a doubled separator in their path were silent, the flight-path-discovered chime among them; the Ashbringer's lines stay silent, as they are in 1.12 (2294) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
8562fb0ef1 |
a crash leaves a report, and the wire's counts are capped
- a panic writes benilla-config/Diagnostics/crash-<time>.txt with the build id, the location, a backtrace and the last 200 log lines, and names the file as its last line, so a bug report can attach it (2266) - every wire-count allocation hint is capped and the compressed update object reads through the cursor, so a malformed packet can no longer ask for gigabytes (2266) - the 23 in-world run conditions are one set, the 45 probe variables one registry, the install-gated tests say when they skip, and every gate is timed (2266) - one workspace-level lint allowance replaces 413 per-site attributes, and the decision corpus gets a lint in the gate (2266) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
d41ebdd642 |
eighteen no-op writes gated, and the dead-gate finder
- eighteen per-frame systems now write only when their inputs moved: the equipment resolve, the skills, language and bind-location feeds, quest markers, shadows, the ambience seat and the weapon trail (2197) - a still remote mover writes no transform, so a city's idle crowd no longer re-propagates every model subtree each frame, and the WMO liquid latch no longer holds a city's visibility walk open (2197) - the bags are walked once a frame for every reagent and item slot instead of once per slot, and fourteen per-frame environment reads become one read each (2197) - the ffx blur chain is skipped where the combine multiplies it by zero, the audio pump compares before set_volume, and the QoS latch sits beside bevy's own exclusive system (2197) - WOW_RES_CENSUS counts on how many frames each resource read as changed, noisiest first — the finder that named these gates (2197) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
a8d0ee80f3 |
a body at the waterline draws on both sides, and its gear follows
- a creature spawning or coming into range in water no longer punches a body-shaped hole in the surface at the start of its fade-in: a model crossing its water plane draws on both sides, each half clipped at the waterline (2188) - the same split covers your own body on login while swimming, stealth and ghost form in the water; Crystal Lake's murlocs streaming in were the scene that showed it (2188) - helms, shoulders, weapons and hung spell kits clip at their wearer's waterline too, so the fade no longer looks wrong whenever the surface crosses the armour (2190) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
693d45ac84 |
MONKEY: dynamic WMO interiors + cube-map torch shadows (surfaces + entities)
Interior rooms light per fragment from their authored fixtures instead of the MOCV bake (direct + fill + ambient, soft rolloff; live cvars interiorLight/interiorAmbient/interiorFill/interiorExposure/interiorShadows/ interiorDebug), TRANS/EXT batches blend to the day/night reference at the portal seam, and fixtures admit camera-independently (90 yd). Torch shadows are a from-scratch depth-map renderer (Bevy point shadows are dead under ClusterConfig::None): a shared Depth32Float 512^2 x 24-layer Image + depth-only pipeline + ViewNode rendering the static caster and a per-frame entity caster into 6 cube faces for the nearest <=4 fixtures (reverse-Z, GreaterEqual compare, 4-tap PCF, far fade). WMO surfaces receive through static_gx group 3; entities receive on the wow_model path through WowModelExt bindings 91/92/93 (depth array, comparison sampler, 1616-byte torch table) with a 0.15 yd normal offset against CPU-vs-GPU skinning self-shadow. The entity lane is gated on is_interior OR the new MATTE_INDOOR tag bit (exterior payload bit 14, written by the classifier's Matte law), so a unit whose verdict flickers Bake<->Matte at one spot keeps its room lighting. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
8584b89274 |
guild lines are message ids, mail sends again, and the shadow fades in
- the guild lines are message ids: `ui_guild/lines.rs` carried 34 English constants and two hand-rolled fill helpers and pushed composed text onto the chat log — 2045's largest ratchet row and the one file its rule had no route for, because `UiError`'s doc claimed the 1.12 formats use at most one `%s` and one `%d` and the type was built to match, while `ERR_GUILD_PROMOTE_SSS` is "%s has promoted %s to %s." — a wrong sentence in a doc had become a wrong type, and the wrong type had made a file's worth of drift structurally necessary; `CGGameUI::DisplayError` (`0x496720`) is cdecl varargs — `add esp,4` bare, `add esp,8` with one string, `SMSG_GUILD_INVITE` pushing two with the stack check exact at `0x30 + 0x60 = 0x90`, and `SMSG_GUILD_EVENT`'s emitter tail `0x5e745f` passing one, two or three off `strCount` — so `UiError` carries an ordered heterogeneous `Vec<FillArg>` (`S(String) | D(i64)`, since `ERR_USE_LOCKED_WITH_SPELL_KNOWN_SI` is String-then-Integer) behind four constructors naming the reference's call shapes (`key`, `s`, `strings`, `args`), twenty sites migrated; what the catalog knew and composed text could not carry: `ERR_GUILD_NAME_INVALID`/`ERR_GUILD_NAME_EXISTS_S` are kind 2 — the red line — and went to chat, `ERR_GUILD_CREATE_S`/`ERR_INVITED_TO_GUILD_SS` carry the LEVELUP cue and `ERR_GUILD_PERMISSIONS` (type_tag `0x3e`) is one the reference speaks (1815), all three silent; the default arm was missing outright — `0x5e745a` pushes `0x69` = `ERR_GUILD_INTERNAL` for `0x09` and every id past `0x0d`, catalog row 105 the whole time, so `TABARD_CHANGE` had been silent under a comment calling the key unsettled; a short `strCount` is passed SHORT (0 and ≥ 4 pass zero strings) so a starved specifier reads "…promoted Furor to %s.", not "…to ."; `/ginfo` deliberately stays off the queue — `GUILD_NAME_TEMPLATE`/`GUILD_INFO_TEMPLATE` are not catalog rows, `0x5e6fb0` resolves each token through the VM and emits chat itself, and a non-row key through `Shown::keyed` would turn a chat line red — so it waits on the guild feed and goes out unkeyed, the enUS month-day-year swap with it; the `_S` arity is asserted from the key names, 22 of 22; the ratchet row is deleted, 208 over 31 files remain (2054) - a unit's blob shadow asks the UNIT for its alpha: the lane gathered live `RenderFade`s off a unit's part entities and read "no part is fading" as 1.0 — true of a settled unit and exactly backwards for arrival, where a streamed unit holds `PendingAppearFade` with no `RenderFade` anywhere until the world is shown, so its parts were deliberately invisible while the shadow drew fully opaque; measured on a probe login: alpha 1.000 from t 0.61 to the arm at t 3.51, then 0, then the ramp — 2.9 s of dark oval under no creature, the symptom `model_render_alpha`'s own "pending ⇒ 0" law (0827) already named for emitters and ribbons; `model_fade::UnitRenderAlpha` is the one door, composed from the ROOT where `UnitAppearFade` tells pending from settled, published as one question rather than its three inputs so a caller cannot reassemble the mistake, and `DespawnFade::armed()` retires the `-1.0` sentinel from every caller; the world API wall goes 177 → 178; and wow-re settled what the shadow's alpha IS, four questions VERIFIED: it reads `CM2Model+0x180` through `0x710ca0`, not `+0x19c`; that slot carries the appear and despawn ramps, the self fade AND the CharProc-14 aura — `0x60d180` drives the same `StartAlphaFade` the appear fade does, so a stealthed unit's shadow now dims with its body — and not the per-batch M2 colour/weight tracks; and the reference draws nothing under a not-yet-shown object either (`+0x180 = 1.0 · 0.0`, written 30 bytes before the read), so this is fidelity, not taste; three module-doc claims corrected against it: the dead `0x683ea5` gate, the registration handoff (GameObjects and DynamicObjects never cast; units, players and corpses always do), and 1277's `InheritedVisibility` gate, which the reference lacks and stays ours on purpose (2055) - the mail stationery list was empty for the whole session, and every send with it: the five `dropping command — not connected` lines at login, once named, were `ItemQuery` for all five `Stationery.dbc` rows — `feed_mail` carried no run condition and asked from the login screen before the socket existed, the asks evaporated in the io thread, and `Items::template` had already latched all five in its ask-once `pending` set, cleared on disconnect and never on connect, so they were never re-asked and the stock `SendMailFrame_Reset`'s row-1 selection left every send silently unsent; the list now waits for a self player, and `release_ask_once_latches_on_enter` clears the pending sets at world enter, the counterpart the disconnect teardown never had — a redundant re-ask costs one packet, a wrong latch costs a dead feature nobody can see is dead; and three more log lines answer for themselves: a control character is answered before the shape — a newline is a line break the markup parser consumes, not a missing glyph — so the warn stays meaningful for a glyph a face genuinely lacks; the blend-check's one-frame run is the specialization tick catching up with a material swap, a real login showing four entries clear 26 ms later, so the warn waits for a run to SURVIVE the tick and a one-frame run is recorded at debug; and the audio starve line carries the wall span it covered beside the time it counted and the position it saw advance, because a 1.0 s window still closed 0.756 s of wall after the stream started on `Time<Real>` — if they disagree the caller's clock is still wrong, if they agree the starvation is real Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
7a03f5d211 |
strings become keys, hidden tiles park, and the water stops breathing
- a reference string is a key, never a Rust literal: display text is a key into `GlobalStrings.lua` in-game or `GlueStrings.lua` on the glue screens, resolved at runtime from the player's own install, and a literal is legitimate only as a fallback beside a lookup — the reference's own `UNKNOWNOBJECT` shape — because a re-typed sentence costs the wording nobody diffed, the surface and the voice a composed string has no catalog record to read off (1770, 1815), and localization; the tripwire in `reference_strings.rs` is the check a comment could never be: it walks the workspace, normalises both sides and fails on any literal matching a shipped value — 273 re-typed literals over 34 files, after calibration threw out three false-positive classes (a path-mangling bug, the 85 fallbacks beside a real lookup, and `#[cfg(test)]` modules whose fake tables match by construction — the first run's 378 would have enshrined ~50 phantom sites); `ALLOWED` is a per-file ratchet whose counts may only go down and whose stale rows fail too, regenerated from a clean tree at 253 over 33 files — the first baseline was captured mid-edit and the land gates failed on a row claiming drift in a file that had none — then 252 over 32 as `ui_trade`'s row retired behind a neighbouring conversion to `ERR_TRADE_BLOCKED_S` (2042); stated in its own doc: it cannot find an INVENTED sentence, which matches nothing; and `benilla_ui::strings::fill` is the one template filler — ordered `%s`/`%d`, positional `%N$s`, `%%` collapsing, a starved specifier copied through visibly so a mis-modelled template looks wrong rather than plausible — replacing eight hand-rolled copies that disagreed, one of them `str::replace` filling every `%s` with the same argument, latent only because no message on that queue carried two yet (2045)
- two families convert, and both assert the identifier, not the sentence: the character-create result line resolves its key off the player's chain with the literal as fallback, and three bugs the 23-arm literal table had hidden come out — `0x36` re-typed without its second sentence ("Please try again during off peak hours."), `0x50` invented (there is no `CHAR_NAME_CONSECUTIVE_SPACES` in 1.12, so it takes the default arm), and `0x4B` naming `CHAR_CREATE_NAME_IN_USE` where the code means `CHAR_NAME_RESERVED` — both read "That name is unavailable" in enUS, so no assertion on displayed text could ever have caught it, and a sentinel test that rewrites `CHAR_NAME_RESERVED` in a copy of the real table proves `0x4B` moves while `0x31` does not; the ratchet's first row retires, 21 → 0; and `SMSG_PARTY_COMMAND_RESULT` returns the catalog message the reference's own jump table names — handler `0x5e68b0`, `dec eax; cmp eax,7; ja <silent>; jmp [4*eax+0x5e6a14]`, results 1–8 onto `ERR_BAD_PLAYER_NAME_S` … `ERR_IGNORING_YOU_S` plus `ERR_INVITE_PLAYER_S` (`0x3a`) and `ERR_LEFT_GROUP_YOU` (`0x42`) on result 0 — so text, surface and sound come off one row: `ERR_PLAYER_WRONG_FACTION` (`0xff`) is the red line where the other nine are chat, and three inputs the reference is DELIBERATELY silent on (result ≥ 9, result 0 outside op {0, 2}, an invite with an empty name) stop printing an invented "Party command failed (N)."; tests assert the message id, since no English distinguishes a right key from a wrong one here, and `ui_party` goes 22 → 12 (2045)
- a hidden `<Model>` tile is parked: every orthographic pane shares the atlas's one camera, deliberately kept active whenever any cell is packed because it is the camera that clears the sheet, so `booth_frozen` — exact for every booth ever built, one camera one scene — answered "drawn" for every pane that had left the paint list, and a hidden autocast-shine pane's four spline emitters kept integrating and pushing quads for the whole 600-frame linger at a cell the packer had since given away; `sync_tiles` gains a sixth stage that parks any live tile with no cell this frame — `AnimParked` on the root, which holds the pose evaluator, the compose, the palette write and the global-sequence bone writes, and `ParticleEmitter::set_frozen` on every emitter — with `scene_frozen` stating the freeze law in one place and the park verdict pinned to the composite by a test, so a repack or a full atlas cannot freeze a visible pane's cloud; the bone global sequences move onto the pane's clock, where the material rows have been since 2019: the kernel's Phase B cursor is `(sceneClock − attachSnapshot) % duration` off the scene that owns the instance (`[model+0x2c]`, the snapshot at `CM2Model+0x68` stored at `0x70eae1`), and a `<Model>` widget owns a private `CM2Scene` at `CSimpleModel+0x314` that only its own advance at `0x76d863` moves — so the ping's spinner holds while hidden and resumes where it stopped, with no accumulator of ours; measured with a cooldown pane holding the atlas alive: twelve hidden shine panes cost 54 effect items / 63 transparent draws before, 34 / 43 after, the pool held rather than drained by design; and the particle census's `gated=` column, which printed `fade.is_some()` and read backwards as the gate verdict, is renamed `has_fade=` (2046)
- a doodad is not an entity: `[def+0xa4]` has exactly four writers image-wide — ctor `0x6a7d73` (0.0), WMO doodad-set commit `0x695bb3` (1.0), ADT MDDF commit `0x6b01bb` (1.0), MCSH refresh `0x698cb4` (0.5) — and the 2.5-producer `0x69e280` and the ramp `0x69e770` are reachable only through the entity-attached `[obj+0xe0]` path, which contradicted the §6 both lit-ground sites cited and a capture with gains up to 2.5, so the premise was marked contested at both sites first (the shader's own note told a future session to cut `min(I, 1)` and `LIT_T` together on its strength); wow-re then settled it — two C++ classes inline the same base and share the offset: `CMapDoodadDef` (vtable `0x810a74`, `"WDOODADDEF"`, size `0x198`, serving ADT MDDF and WMO MODD) and the WENTITY light node (vtable `0x810810`, size `0x108`, off `[obj+0xe0]`) that `0x69e770` ramps at 3.3333/s; on the doodad class `+0xf8`, the field the ramp reads its target from at `0x69e894`, is `m[2][3]` of the world matrix — it has no target field — and six trace frames put 111 MDDF placements over 356 draws at gains only in {0.5, 1.0}, none changing, against an entity walking out of shadow at 0.5 / 0.81 / 1.09 / 1.3367 and rising; so ADT map doodads join the fixed-1.0 family with the exterior WMO props, `ShadeSel::Lit` is entity-only, the retained lane's Matte arm drops its prop requirement, and no pixel changes — the cap was faithful for trees all along and lifting it is now an entity-only look change for the director to call; `WORD_SHADE_LIT` is left as a documented dead bit (2050); and the far water's 1.25 s breath is flattened: the director's recording autocorrelates at lag 75 @ 60 fps = 1.250 s (r = +0.60), the 30-frame ocean flipbook at 24 fps, whose frames do not share a mean — alpha 55.985..57.628, DXT3's 4-bit alpha swinging 1.64 at mip 0, 3.72 at mip 5, 6.38 at mip 6 — so at distance the mipped sheet moves together, 0.8..1.84/255 on screen, fogged out at `farclip` 300 and visible at 777; wow-re proved the reference breathes too (`0x68abab` creates the flipbook with `applyGlobal = 1`, the upload hands the driver `Levels = 9`, LOD bias 0, the loop period `[0x8102b8]` 1.25 s over 30 frames), so ours was faithful and it is flattened anyway by the director's eye: each frame's DC equalised per level and per channel at texture-build time as an exact integer redistribution in ±1 steps on a coprime stride (1.64 / 3.72 / 6.38 / 0.555 → 0.000), water and ocean only since magma and slime take the sheet as their body colour, `WOW_LIQUID_DC=raw` restoring the authored art for the A/B (2051)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
||
|
|
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>
|
||
|
|
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> |
||
|
|
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> |
||
|
|
50771c7c05 |
Apply reference real-character-shadows patch (Bevy shadow-map approach)
Character-only realtime shadows via a DirectionalLight + a private-layer
CPU-skinned caster proxy; terrain/models/static_gx receive through Bevy's
shadows::fetch_directional_shadow. Opt-in cvar `worldShadows` (default off);
hides the blob oval when on. Branched from
|
||
|
|
9105fa72a4 |
the flight map goes stock, and vendors refuse in 1.12's own words
- the pet stable and the flight map are the reference's own files: `TaxiRouteFrame` maps to a plain Frame (factory `0x495ba0` allocates the base size, the ctor adds no field, no new virtual, no method table — and `GetObjectType` is not overridden, so its own kind would have been the divergence), and the swap found three silent behaviours — the close button did nothing (an unknown `inherits=` is a WARNING, so it loaded as a bare button), the "no paths" line drew empty, and the title is READ off `UnitName("npc")`, not received; the WMO skybox rides the interior crossfade — one weight (`[0xce9bdc]`, the same number the MFOG lerp rides), a 4 s alpha fade, so a skybox the flood publishes through a doorway draws at weight 0 instead of popping in whole
- a widget predicate answers the NUMBER 1 or nil, never a boolean: eleven of them (`IsShown`, `IsVisible`, `IsMovable`, `GetChecked`…) move to the 1.12 shape — the reference proves it in its own source (`tostring(this:GetChecked())` saved and read back `== "1"`; `tostring(true)` would never match and buff timers would never appear), 21 corpus sites compare directly (`IsVisible() == nil`, `GetChecked() == 1`), and one of our own tests had the guild rank editor sending `true` where a real client sends 1
- the vendor's refusals are the reference's table: `SMSG_BUY_FAILED`/`SMSG_SELL_ITEM` route through `0x5dcd60`/`0x5dd1f0`'s switches, six lines were wrong (code 3 printed "That vendor can't be found." — vmangos's identifier — where 1.12 prints "That merchant doesn't like you."), silence is now expressible, and keying them gives the vendor a voice (`ERR_NOT_ENOUGH_MONEY` carries error-speech line 0x28); the bank's three ids were right and its "purchase failed (n)" an invention; the logout refusal is one key, `ERR_LOGOUT_FAILED`, for every non-zero reason; the two mail codes we said had no string have one (`ERR_PLAYER_WRONG_FACTION`, `ERR_RESTRICTED_ACCOUNT`) and a sent mail says `ERR_MAIL_SENT` in yellow; a test runs the chain's own `GlobalStrings.lua` and requires non-empty text for all 193 `ERR_*` the workspace names
- a clicked quest timer no longer raises — stock `QuestTimerFrame.lua` calls `QuestLog_SetSelection`/`QuestLog_Update`, which existed nowhere in this tree; our quest log owns the reference's two names now, which also shrinks the delta when that window itself migrates
Co-Authored-By: Claude Fable 5.1 <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> |
||
|
|
d2b3492cd5 |
the walking tax banded, and the minimap stops rewriting the world
- a panning UI batch rides its Transform instead of rewriting its mesh, minimap tiles emit unclipped (the mask shader already zeroes the corners), and the blip layer's origin snaps to half a logical pixel — steady UI mesh writes while moving drop from ~183/s to 10–14/s, and three minimap quads stop arming change detection over ~40k world meshes - the classify twin GC comes off the despawn edge: a part despawn schedules the full walk behind a 2 s deadline instead of running it that frame — 12–22 full walks a second while walking, gone - the walking tax measured and banded at Goldshire: parked 10.7 → moving 14.1 ms/frame of process CPU, ~+2.5 after the two fixes above - WOW_PART_CHURN and WOW_MESH_HOLDERS count part spawn/despawn frames and name which entities hold a churning mesh; the capture rig's `at:` pin learns a facing Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
5360a44f89 |
event-driven UI feeds, and the character window's cost lets go
- the eight heaviest UI feeds — spellbook, party, character, bags, talents, units, pet, player — rebuild only when an input moved instead of every frame: 216 → 12 µs a frame parked - the character window's cost settles once it closes: enchant countdowns feed by the second instead of firing an inventory event into all 20 slots every frame, the paper-doll booth parks with its camera, and a window hidden under the cursor fires OnLeave so its tooltip goes with it — the reference's hover-hide law - the walk stops paying for finished work: the loading-screen tally's per-placement walk latches off once the world is ready, the settled placement spawner is one integer compare, and billboards stop dirtying every card's transform - never-rendering hierarchy nodes — rig anchors, joints, doodad hosts — keep the hide chain but leave the per-camera visibility sweep: 25,198 → 18,026 swept entities at Goldshire Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
8522c65937 |
the lava bubbles move again, and the bonfire keeps its wood
- Blackrock Mountain's lava bubbles animate at last: their sprite's flip-book channel was baked from a sequence they never play — UV and tint loops now bake per sequence, and a placement whose sequences disagree gets its own material - a bonfire's logs were vanishing while its flame burned on: a body planted just under its own floor now claims the room above it, and the flame card and fire sound follow the body's cull instead of outliving it - a WMO prop's animation host stops being cull-tested as an object in its own right - WOW_TILE_RADIUS's doc now states its real default, 2, and why Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
970cac46c2 |
material animation stops touching assets: one shared table
- a drawn animated material — scrolling texture, pulsing tint — is never mutated again: the animation rides delta rows in a shared region of the light buffer, folded branch-free in the shader, with zero as identity - the churn that came with mutating assets dies by construction — no per-material modified ratchet, no far-twin re-inserts — and capture parity is bit-exact - the portal flood's answer goes compare-then-write, clearing the ground for a static-visibility lane - the single-threaded PostUpdate probe answered: cheaper on mean cpu, parked on a tail-latency class, kept as a documented lever Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
49ba9d599b |
the bevy 0.19 excursion: graded 5.5 ms slower lane-for-lane, rolled back
- the full bevy 0.19 / avian 0.7 / egui 0.35 port landed and rendered at visual parity, then profiling matched the lanes honestly: +5.5 ms against 0.18 in our scenes, priced to three named buckets — so it was reverted the same day, with the pins mapped for a future release - back on 0.18 the client is faster than 0.18 ever ran here, keeping both performance days' wins - what the hunt left behind: the material-animation scan visits only rows that can be registry keys, and a capture that settles on an all-black image now says EMPTY instead of grading it Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
d1140829d7 |
the interface code is ours: the transcription debt is paid
- forty files that carried the reference's literal Lua are rewritten as our own expression of the behaviour — worst identical run 61 lines down to 7 — and the README now says exactly that - the overlap gate measures the code itself across all four reference corpora, and ratchets: the number may only go down - a lost session ends at the login screen instead of silently re-authenticating and stealing the account back - a building's skybox is a real model: Caverns of Time's white ceiling becomes its painted nebula and additive stars Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
0058888def |
birds stop blinking out, and the version check is answered
- an animated doodad is culled by its authored box, not its bind pose — the one-yard bird flying a 64-yard circuit stops vanishing with the camera angle — and the fix survives the engine's own bound recompute - the logon proof answers the server's version challenge instead of sending zeros, so a strict realmd stops rejecting benilla as a modified client - two instruments land: a frame-by-frame visibility trace for one model, and a probe that classifies whether a realmd enforces the version check Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
8eea16157c |
benilla-world: the engine becomes its own crate
- the world engine splits from the game into a benilla-world crate — 112 files, and the wall is ratcheted to zero names of the game inside the engine - the engine's public doorway is counted and gated at 32 items, and the render materials, shaders and asset cache move down to benilla-assets - the game's files leave the engine's asset root — game:// is its own space — and a spike binary boots the engine with no game attached - weather rides along: snowfall emission is denominated in the reference's frame cap, and a long teleport retires the stranded precipitation field instead of leaving it behind Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |