A WMO material with no extension lost its texture outright

`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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
This commit is contained in:
2026-10-28 22:22:19 -06:00
co-authored by Claude Opus 5
parent b5259bd608
commit bae75b9d3f
2 changed files with 34 additions and 8 deletions
+14
View File
@@ -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]
+20 -8
View File
@@ -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::<Image>(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::<Image>(crate::texture_url(t, (true, true))));
submeshes.push(ModelSubmesh {
texture,
skin_slot: sub.skin_slot,