fix(mesh): filtered decode must not depend on the requested subset

models_named pruned to the wanted set BEFORE distinct assignment, so collision
resolution saw a different resource population and returned different offsets:
27 of 356 resources in Stage_S02 decoded differently when asked for alone,
including real geometry (f001_bdy_30, f106_sld_02_l/m/d, f101_wep_01_l). Both the
viewer and assemble_ship decode subsets, so both could disagree with the
container's own answer. This was a regression from distinct assignment itself.

Fixed by filtering the OUTPUT: the assignment always runs over the whole
container. One-name, three-name and full decodes now agree exactly. Cost: a
single-resource query on a 50MB container goes from near-instant to ~15s;
per-container caching is the follow-up. Ten suites green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-12 18:47:41 +00:00
parent e8434541f2
commit c79c0f6ccf
3 changed files with 85 additions and 5 deletions

View File

@@ -523,11 +523,13 @@ impl Xbg7Model {
}
let name = read_cstr(bytes, e.name_offset as usize + DIR_BASE)
.unwrap_or_else(|| "XBG7".to_string());
if let Some(w) = wanted {
if !w.contains(&name) {
continue;
}
}
// NOTE: `wanted` is NOT applied here. Distinct assignment resolves
// collisions against the whole set of resources, so pruning first
// made a filtered decode depend on *which* subset was asked for —
// measured 2026-08-12: 27 of 356 resources in `Stage_S02` came out
// at a different offset when requested alone. The filter is applied
// to the OUTPUT instead, so a subset is always a subset of the
// container's own answer.
resources.push(Res {
name,
markers,
@@ -722,6 +724,9 @@ impl Xbg7Model {
}
models.push(m);
}
if let Some(w) = wanted {
models.retain(|m| w.contains(&m.name));
}
out = models;
out
}