From ba9a333aeb06f9bcb7d625dbcba69d8f8e12e719 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 7 Aug 2026 16:03:52 +0700 Subject: [PATCH] the Ironforge lava returns, and the sound crackle is cornered - the Great Forge's lava stays drawn from every angle, and the chasm catwalk reads as a connected grate again - music decoding and shader-compile bursts stop crowding the audio's lane, and the output buffer follows the device's real deadline - the audio path grows its instruments: a mix tap to WAV, a starvation meter, a hardware overload listener - trainer detail icons carry the reference's own tooltip Co-Authored-By: Claude Fable 5 --- Cargo.lock | 2 + crates/benilla-app/Cargo.toml | 10 + .../benilla-app/assets/shaders/wow_model.wgsl | 27 +- crates/benilla-app/assets/ui/CraftFrame.xml | 5 +- crates/benilla-app/assets/ui/TrainerFrame.xml | 18 +- crates/benilla-app/src/creature_anim/lod.rs | 1 + crates/benilla-app/src/debug_panel/state.rs | 4 +- .../benilla-app/src/debug_panel/visibility.rs | 17 +- crates/benilla-app/src/pipe_warm/menagerie.rs | 6 + crates/benilla-app/src/pipe_warm/mod.rs | 149 ++- crates/benilla-app/src/player.rs | 27 + crates/benilla-app/src/sound/glue.rs | 52 +- crates/benilla-app/src/sound/hal_overload.rs | 174 ++++ crates/benilla-app/src/sound/mix_tap.rs | 200 ++++ crates/benilla-app/src/sound/mixer.rs | 268 ++++- crates/benilla-app/src/sound/mod.rs | 18 +- crates/benilla-app/src/sound/zone.rs | 13 + .../src/terrain_stream/spawn/mod.rs | 1 + crates/benilla-app/src/thread_qos.rs | 52 +- crates/benilla-app/src/ui_craft.rs | 81 +- .../src/ui_script/trainer_tests.rs | 4 + crates/benilla-app/src/ui_tradeskill.rs | 8 +- crates/benilla-app/src/ui_trainer.rs | 973 ------------------ crates/benilla-app/src/ui_trainer/law.rs | 160 +++ crates/benilla-app/src/ui_trainer/mod.rs | 428 ++++++++ crates/benilla-app/src/ui_trainer/tests.rs | 643 ++++++++++++ .../benilla-app/src/wmo_portal/audit/pin.rs | 14 +- crates/benilla-app/src/wmo_portal/mod.rs | 44 +- crates/benilla-formats/src/lib.rs | 6 +- crates/benilla-formats/src/spells/display.rs | 2 +- crates/benilla-formats/src/spells/mod.rs | 8 +- crates/benilla-ui/src/script/craft.rs | 37 +- crates/benilla-ui/src/script/mod.rs | 4 +- .../src/script/tests/tooltip_spell.rs | 231 +++++ .../benilla-ui/src/script/tooltip_item/mod.rs | 41 +- crates/benilla-ui/src/script/tooltip_spell.rs | 173 +++- crates/benilla-ui/src/script/trainer.rs | 52 +- 37 files changed, 2835 insertions(+), 1118 deletions(-) create mode 100644 crates/benilla-app/src/sound/hal_overload.rs create mode 100644 crates/benilla-app/src/sound/mix_tap.rs delete mode 100644 crates/benilla-app/src/ui_trainer.rs create mode 100644 crates/benilla-app/src/ui_trainer/law.rs create mode 100644 crates/benilla-app/src/ui_trainer/mod.rs create mode 100644 crates/benilla-app/src/ui_trainer/tests.rs diff --git a/Cargo.lock b/Cargo.lock index 5981928e..d0d3a75b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -610,8 +610,10 @@ dependencies = [ "objc2-foundation 0.2.2", "rand 0.8.6", "raw-window-handle", + "rtrb", "serde", "smithay-clipboard", + "symphonia", "toml", ] diff --git a/crates/benilla-app/Cargo.toml b/crates/benilla-app/Cargo.toml index 335e99c2..a7e5b4fa 100644 --- a/crates/benilla-app/Cargo.toml +++ b/crates/benilla-app/Cargo.toml @@ -76,6 +76,16 @@ fontdb = "0.23" # cpal types, so this must stay the exact version kira resolves — one cpal in the graph. cpal = "0.17" kira = { version = "0.12", default-features = false, features = ["cpal", "mp3", "wav", "pcm", "adpcm"] } +# kira's own decoder, named directly for one trait: the mixer feeds streams through its own +# `MediaSource` so kira's per-stream decode thread runs OUR code and can promote its QoS (decision +# 1109 — a bare-spawned decode thread starves under the world-entry burst and zero-fills the mix). +# No codecs of its own (kira's features enable those); must stay the version kira resolves — one +# symphonia in the graph, or the trait impl won't line up. +symphonia = { version = "0.5", default-features = false } +# The mix tap's audio-thread → writer-thread ring (decision 1112): the tap effect must never +# block or allocate on the render path. kira's own SPSC ring crate; kept on the version kira +# resolves so the graph carries one rtrb. +rtrb = "0.3" mint = "0.5" # The gossip greeting is a weighted random DRAW per menu-open, not a fixed pick (wow-re # `gossip-npctext-law.md` — the reference re-rolls in its gossip handler), so the app needs a uniform diff --git a/crates/benilla-app/assets/shaders/wow_model.wgsl b/crates/benilla-app/assets/shaders/wow_model.wgsl index 8a7e88ec..db852a17 100644 --- a/crates/benilla-app/assets/shaders/wow_model.wgsl +++ b/crates/benilla-app/assets/shaders/wow_model.wgsl @@ -45,6 +45,7 @@ #import bevy_pbr::{ pbr_fragment::pbr_input_from_standard_material, pbr_functions::alpha_discard, + pbr_bindings, forward_io::{VertexOutput, FragmentOutput}, mesh_view_bindings::view, mesh_functions, @@ -545,14 +546,26 @@ fn fragment(in: WowVsOut, @builtin(front_facing) is_front: bool) -> FragmentOutp // horizon). Disabled (no-op) for normal models where `clutter_fade.w == 0`. This is a draw-distance // concern, not lighting, so it survives the Phase-0 strip. var base_color = pbr_input.material.base_color; - // Interior WMO batches carry LIGHTING data in the MOCV ALPHA — TRANS (tint.w == 2) the - // lit↔bake lerp factor, INT (tint.w == 1) the ×4 self-illumination mask. Bevy pre-folds - // ATTRIBUTE_COLOR (rgba) into base_color, so un-fold the alpha before any cutout test — - // coverage stays the texel alpha, exactly the reference's interior pixel shader - // (its output alpha is tex.a; MOCV.a never reaches coverage). + // WMO batches carry LIGHTING data in the MOCV ALPHA — TRANS (tint.w == 2) the lit↔bake lerp + // factor, INT (tint.w == 1) the ×4 self-illumination mask. Bevy pre-folds ATTRIBUTE_COLOR + // (rgba) into base_color, but coverage must stay the texel alpha, exactly the reference's + // WMO pixel path (its output alpha is tex.a; MOCV.a never reaches coverage — + // wow-re models.md). Re-sampling the texture here (same UV, same implicit derivatives — the + // texture cache makes it free) replaces the old divide-the-fold-back-out reconstruction, + // which was numerically annihilated where MOCV.a ≈ 0: `tex.a × ε ÷ max(ε, 1/255)` collapses + // to 0 at ε = 0 and to 4-bit rubble near it — B65's Great Forge chasm deck, whose + // self-illumination mask is authored 0, alpha-eroded into "missing floor" exactly there. #ifdef VERTEX_COLORS - if (m.model_flags.x > 0.5 && m.tint.w > 0.5) { - base_color.a = base_color.a / max(in.color.a, 1.0 / 255.0); + if (m.model_flags.x > 0.5) { +#ifdef VERTEX_UVS_A + base_color.a = textureSample( + pbr_bindings::base_color_texture, + pbr_bindings::base_color_sampler, + vo.uv, + ).a; +#else + base_color.a = 1.0; +#endif } #endif // Ground-clutter distance fade: multiply the cutout alpha by the camera-distance ramp BEFORE the diff --git a/crates/benilla-app/assets/ui/CraftFrame.xml b/crates/benilla-app/assets/ui/CraftFrame.xml index bbdd681c..9deee9d5 100644 --- a/crates/benilla-app/assets/ui/CraftFrame.xml +++ b/crates/benilla-app/assets/ui/CraftFrame.xml @@ -444,7 +444,10 @@ -- ── The detail icon (ref CraftIcon OnEnter, l.564-568 — the Ctrl/Shift dressing-room branches -- dropped, deviation 3): SetCraftSpell, NOT SetCraftItem — Craft has no product-item concept - -- (craft.rs's own module doc). ─────────────────────────────────────────────────────────────── + -- (craft.rs's own module doc). The binding behind it is a SELECTOR into the shared spell/item + -- builders (`SetCraftSpell 0x533e90`); a CREATE_ITEM recipe therefore renders the product's + -- full ITEM tooltip here even though the row's ICON is the spell's (Law D) — the two are + -- different laws on the same row, byte-verified. ───────────────────────────────────────────── function BenillaCraftIcon_OnEnter(button) if GetCraftSelectionIndex() ~= 0 then GameTooltip:SetOwner(button, "ANCHOR_RIGHT") diff --git a/crates/benilla-app/assets/ui/TrainerFrame.xml b/crates/benilla-app/assets/ui/TrainerFrame.xml index 52ded5e6..89382dcc 100644 --- a/crates/benilla-app/assets/ui/TrainerFrame.xml +++ b/crates/benilla-app/assets/ui/TrainerFrame.xml @@ -729,13 +729,29 @@ + ring, at the detail area's top-left. Icon via SetNormalTexture; Hide()n when unselected. + + The hover is the ref's own, verbatim (Blizzard_TrainerUI.xml:452-459): owner is the icon + button, anchor ANCHOR_RIGHT, subject `ClassTrainerFrame.selectedService` — the SELECTED + row, which is why the tooltip describes the selection no matter which row the mouse + passed over on its way here. GetTrainerSelectionIndex() is our engine-held equivalent of + that field; it reads 0 with nothing selected, and SetTrainerService no-ops on 0. This is + the ONLY SetTrainerService call site in the shipped client — the list rows carry no + tooltip of their own (their template's OnEnter only recolours the subtext). -->