feedback5 WU: 焰狐龙梓兰 (MH05) leaves data/assets.json; a voice slot with no line on disk is dropped, not []

She left the 自选 pool in 0.2.0 (data/backups.json diy.excluded, a collab operator) but her art stayed in the
manifest because fetch-assets refuses to shrink it. Regenerated offline in this worktree, whose public/assets and
public/fonts are the shared ones: node tools/fetch-assets.mjs --offline --add-only --allow-shrink (--add-only so no
file on disk is rewritten and the fonts entry is kept). The run dropped exactly her 163 entries.

JSON diff against the previous manifest: removed chars.char_1048_orchd2, skills.skchr_orchd2_1..3,
skillsById.skchr_orchd2_1..3, audio.sfx.units.char_1048_orchd2; changed hash and stats (files 6994 -> 6979,
bytes 462620448 -> 458334505, chars 210 -> 209, charsWithBack 207 -> 206, spineModels 673 -> 671,
skills 525 -> 522, sfxUnits 484 -> 483); nothing added, nothing else changed.

The first regeneration also added 71 entries like audio.voice.char_134_ifrit = {select: [], place: []}: the 自选
operators' voice lines are planned but not downloaded on this machine, and resolveTemplate kept an array whose lines
were all missing as []. tools/assets/manifest.mjs now drops such an array like a missing leaf (and the entry it
empties); an array that is empty in the template stays.

Tests: test/assets.test.js (the array rule), test/assets-diy.test.js (no diy.excluded operator keeps art in the
manifest). docs/ASSETS.md: 71 自选 picks, 209 operators (206 with Back), 522 skill icons, the empty-slot rule.
This commit is contained in:
sganggs committed 2026-10-06 17:51:41 +08:00
1 parent e2bb090f44
commit 9bfac54c8f
5 files changed
+42 -5

No files matched your search

+6 -1
View File
@@ -112,7 +112,12 @@ export function resolveTemplate(template, { root, spine, sourceOf = () => undefi
for (const u of [e.skel, e.atlas, ...e.textures]) files.add(u.replace(/^\/assets\//, ''));
return e;
}
if (Array.isArray(node)) return node.map((x, i) => walk(x, `${path}[${i}]`)).filter((x) => x !== undefined);
if (Array.isArray(node)) {
const lines = node.map((x, i) => walk(x, `${path}[${i}]`)).filter((x) => x !== undefined);
// An array whose every line is missing on disk is a missing entry, like a missing leaf (e.g. a voice slot whose
// lines were never downloaded here): dropped, never an empty [] that reads as a slot with no lines.
return lines.length || !node.length ? lines : undefined;
}
if (typeof node !== 'object') return node;
const out = {};
for (const [k, v] of Object.entries(node)) {