- 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>
117 lines
6.9 KiB
TOML
117 lines
6.9 KiB
TOML
[workspace]
|
||
resolver = "2"
|
||
members = ["crates/*"]
|
||
|
||
[workspace.package]
|
||
version = "0.1.0"
|
||
edition = "2021"
|
||
license = "MIT OR Apache-2.0"
|
||
authors = ["sam <samuv.eth@gmail.com>"]
|
||
|
||
# Shared pins live here; promote a dep the moment two crates pin the same version (the policy
|
||
# since day one, enacted at the 0530 debt sweep). Per-crate feature additions stay in the crate.
|
||
# `image` deliberately stays per-crate: its default-features/feature sets differ per consumer,
|
||
# and a workspace default-features choice can't be subtracted from downstream.
|
||
[workspace.dependencies]
|
||
anyhow = "1.0.102"
|
||
# bevy's `default` is `["2d", "3d", "ui"]`, and every one of those three pulls `audio`
|
||
# (= `bevy_audio` + `vorbis`) — so a default bevy compiles rodio, a second cpal, a second ALSA
|
||
# binding and an ogg/vorbis decoder into a client that mixes through kira and has had bevy's
|
||
# `AudioPlugin` disabled at boot since 0530. This spells the same `default` out with `audio`
|
||
# taken away: `2d`/`3d`/`ui` decomposed into the parts they are made of, which is the whole
|
||
# union of the three minus that one entry (decision 1932 has the expansion, verified against a
|
||
# before/after feature tree). Nothing else in the graph asks for it — avian3d, bevy_egui and
|
||
# bevy_transform_interpolation all take bevy with `default-features = false`.
|
||
#
|
||
# If a future bevy needs another member, add it here by name; do not reach back for `2d`/`3d`/
|
||
# `ui`, which would quietly bring the audio stack with it.
|
||
bevy = { version = "0.18.1", default-features = false, features = [
|
||
"default_app",
|
||
"default_platform",
|
||
"2d_bevy_render",
|
||
"3d_bevy_render",
|
||
"ui_api",
|
||
"ui_bevy_render",
|
||
"scene",
|
||
"picking",
|
||
] }
|
||
# The render app's raw GPU handles (the WOW_GPU_MS meter's query set): bevy 0.18 does not wrap
|
||
# wgpu's QuerySet family, so the meter reaches for the same wgpu the workspace already builds.
|
||
wgpu = "27"
|
||
clap = { version = "4.6.1", features = ["derive"] }
|
||
sha1 = "0.10.6"
|
||
|
||
# The WoW format + protocol stack is fully in-repo (decision 0021), so there are no warcraft-rs /
|
||
# wow_messages crates (or forks of them) anywhere in the tree. That is still true and is why this
|
||
# section stood empty for the project's whole life.
|
||
#
|
||
# The one entry below is not a fork of a WoW crate at all. `lua-src` compiles the Lua the client's
|
||
# addon VM runs on, and the 1.12 corpus needs one opcode that Lua 5.1 deleted — the iterator-less
|
||
# generic-for (`for k, v in someTable do`), which 183 of 218 corpus addons are reached by and which
|
||
# is the first session-start error for 60 of them. It is an OPCODE, so no layer above the VM can
|
||
# reach it: not a library function, not a global, not a metamethod.
|
||
#
|
||
# The fork is currently BYTE-IDENTICAL to upstream's 5.1.5 sources, and is landed that way on
|
||
# purpose: the pipeline is proven transparent before the behavioural payload goes into it, so that
|
||
# when the suite moves, the patch is the only thing that could have moved it. The payload waits on
|
||
# an RE answer about what the real client's own Lua does — stock Lua 5.0 is corroboration, not the
|
||
# authority. `third_party/lua-src/BENILLA.md` has the current state and the verifying command.
|
||
[patch.crates-io]
|
||
lua-src = { path = "third_party/lua-src" }
|
||
|
||
# Optimize *dependencies* even in dev builds. avian/parry collision math (and wgpu/bevy render) is
|
||
# unusably slow at opt-level 0 — a plain `cargo run` crawls to <1 fps once physics is doing real work.
|
||
# opt-level 3 on deps (the standard Bevy fix) makes debug builds playable while our own crates stay
|
||
# lightly optimized for fast incremental rebuilds. One-time cost: deps recompile optimized the first time.
|
||
[profile.dev.package."*"]
|
||
opt-level = 3
|
||
|
||
# Our own crates at opt-level 1, not 0: Bevy's generic hot paths (material specialization scans,
|
||
# query par_for_each closures) monomorphize INTO our crate, so at opt 0 they run at debug codegen
|
||
# speed over every resident entity — measured at Stormwind as the difference between ~45 fps and a
|
||
# pinned 60 (decision 0362). Warm incremental rebuild cost measured at ~zero. NB: FPS probe numbers
|
||
# in decisions ≤ 0361 were taken at opt 0 and are not comparable with post-0362 probes.
|
||
[profile.dev]
|
||
opt-level = 1
|
||
|
||
# No debuginfo trimming: `debug = "line-tables-only"` was A/B-measured (decision 0192) at zero
|
||
# recurring win on this stack (macOS unpacked split-debuginfo; sccache; fast ld) — not worth
|
||
# invalidating every warm target and the sccache cache for.
|
||
|
||
# Shipping-grade optimization, A/B-graded at the pin (decision 0736): −1.0 cpu_ms (−5 %) vs
|
||
# default release, flat at the empty-map and bare-Bevy floors. The campaign keeps grading on
|
||
# default `release` — same-day A/B is the law, and fat LTO's link time would tax every
|
||
# iteration for a constant offset. Build with `--profile ship` for actual releases (add
|
||
# `RUSTFLAGS=-Ctarget-cpu=native` for a machine-local binary; not set here — it isn't portable).
|
||
[profile.ship]
|
||
inherits = "release"
|
||
lto = "fat"
|
||
codegen-units = 1
|
||
|
||
# The director's play loop (decision 1157): `release` plus incremental compilation. `benilla-app` is one crate of
|
||
# ~243k lines, and release is non-incremental by cargo's default, so a one-line edit re-optimizes
|
||
# all of it — measured 2m47s (43s frontend, ~121s LLVM at opt-level 3) against a 1.8s stamp rebuild
|
||
# and a 2.5s no-op. Incremental caches both halves per codegen unit, so an edit pays for what it
|
||
# touched. Cargo applies `incremental` to workspace members ONLY (verified: `target/debug/incremental`
|
||
# holds our 16 crates and zero registry deps), so the ~760 dependencies stay non-incremental and
|
||
# sccache-cacheable — 0192's wrapper and the cold-slot build are untouched.
|
||
#
|
||
# Why a separate profile rather than flipping `release`: incremental raises the codegen-unit count
|
||
# and drops cross-unit inlining, which is a real codegen difference. The FPS campaign grades on
|
||
# default `release` (0736) and same-day A/B is the law, so the graded profile must not quietly
|
||
# change under it. Run it as `cargo play` (the alias in `.cargo/config.toml`).
|
||
[profile.play]
|
||
inherits = "release"
|
||
incremental = true
|
||
# ThinLTO OFF, and it is not a performance choice -- it is the fix for rustc #86049. `release`
|
||
# implies thin-LOCAL LTO (ThinLTO across a crate's own codegen units), which promotes each CGU's
|
||
# internal anonymous constants to external symbols named `anon.<hash>.N.llvm.<moduleid>`. Under
|
||
# `incremental` some CGUs come back from the cache carrying names minted in an earlier compile,
|
||
# so a promoted reference finds no definition and `cc` fails with "symbol(s) not found for
|
||
# architecture arm64" -- an intermittent link failure with no source-level cause, cleared only by
|
||
# a full rebuild. Measured on the 2026-08-29 occurrence: 7 poisoned CGUs in `benilla-formats`, 48
|
||
# unresolved symbols. `lto = "off"` disables the promotion step entirely (verified: the play rlib
|
||
# goes from 381 undefined `anon.*.llvm.*` symbols to 0). `release` and `ship` are UNTOUCHED -- they
|
||
# are non-incremental, cannot hit this, and stay the graded profiles (0736). Decision 1698.
|
||
lto = "off"
|