From bae75b9d3f88c9a554353fb7ea1b9ba956baa9ff Mon Sep 17 00:00:00 2001 From: grom Date: Wed, 28 Oct 2026 22:22:19 -0600 Subject: [PATCH] A WMO material with no extension lost its texture outright MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `wmo.rs` built its submesh texture URLs by hand — backslashes folded, lowercased, `mpq://` prefixed — which is exactly what `texture_url` does, minus the one thing that matters: `texture_url` appends `.blp` to a name that has no extension, as the reference's `CImageManager::CreateTexture` does. The M2 loader has gone through it all along. The realm's WMOs ship bare material names too, so that submesh drew untextured and Bevy could not even pick a loader for it. From grom's 2026-10-28 log, the only two lines in the whole session above WARN: WARN Multiple AssetLoaders found for Asset … Extension: None ERROR Path not found: textures/wetlands_grimbatol/mm_irnfg_trim_02flip Repeat/repeat is passed, which is what the hand-rolled path was: `texture_url` returns the plain `mpq://…` for that pair and marks the stem only for a clamped mode, and a WMO submesh carries no wrap flags here to ask about. That one name is now a case in `texture_url`'s own test. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn --- crates/benilla-assets/src/lib.rs | 14 ++++++++++++++ crates/benilla-assets/src/wmo.rs | 28 ++++++++++++++++++++-------- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/crates/benilla-assets/src/lib.rs b/crates/benilla-assets/src/lib.rs index 82276256..164de307 100644 --- a/crates/benilla-assets/src/lib.rs +++ b/crates/benilla-assets/src/lib.rs @@ -290,6 +290,20 @@ mod tests { ), "mpq://world/azeroth/redridge/passivedoodads/trees/redtreecanopy_base02@cc.blp" ); + + // And a **WMO** material name, which ships bare on this realm too. `wmo.rs` built this + // URL by hand until it was routed through here, so a MOMT with no extension lost its + // texture outright: Bevy had no extension to pick the BLP loader with and answered + // `Multiple AssetLoaders found … Extension: None`, then `Path not found`. The one in + // grom's 2026-10-28 log: + assert_eq!( + texture_url( + "TEXTURES\\Wetlands_Grimbatol\\mm_irnfg_trim_02flip", + (true, true) + ), + "mpq://textures/wetlands_grimbatol/mm_irnfg_trim_02flip.blp", + "a bare WMO material name gets the reference's appended .blp" + ); } #[test] diff --git a/crates/benilla-assets/src/wmo.rs b/crates/benilla-assets/src/wmo.rs index cc7ba08b..77ea067c 100644 --- a/crates/benilla-assets/src/wmo.rs +++ b/crates/benilla-assets/src/wmo.rs @@ -477,14 +477,26 @@ impl AssetLoader for WmoModelLoader { *slot = wmo_group_liquid_mesh(&gbytes); } for sub in subs { - // Lowercased: Bevy's loader lookup is case-sensitive, and an uppercase `.BLP` falls - // to type-based resolution, ambiguous with Bevy's own image loader. - let texture = sub.texture.as_deref().map(|t| { - ctx.load::(format!( - "mpq://{}", - t.replace('\\', "/").to_ascii_lowercase() - )) - }); + // Through `texture_url`, which does the same backslash fold and lowercase this + // did by hand — Bevy's loader lookup is case-sensitive, and an uppercase `.BLP` + // falls to type-based resolution, ambiguous with Bevy's own image loader — **and + // one thing more: it appends `.blp` to a name that has no extension**, as the + // reference's `CImageManager::CreateTexture` does. + // + // Doing it by hand here cost the texture outright on any MOMT whose name ships + // bare. The M2 loader has gone through `texture_url` all along (`m2.rs:323`), and + // the realm's WMOs ship bare names too: grom's 2026-10-28 log holds + // `ERROR Path not found: textures/wetlands_grimbatol/mm_irnfg_trim_02flip`, with a + // `Multiple AssetLoaders found … Extension: None` beside it — Bevy could not pick + // the BLP loader, so that submesh drew untextured. + // + // Repeat/repeat, which is what the hand-rolled path was: `texture_url` returns the + // plain `mpq://…` for that pair and marks the path only for a clamped mode, and a + // WMO submesh carries no wrap flags here to ask about. + let texture = sub + .texture + .as_deref() + .map(|t| ctx.load::(crate::texture_url(t, (true, true)))); submeshes.push(ModelSubmesh { texture, skin_slot: sub.skin_slot,