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). -->