feedback2 WE: README, DEPLOY.md (new §6), setup and doctor say what falls back without the local-client art instead of 不影响游戏, and that a server without the client can copy public/assets/local + data/local-assets.json from the same version's bundle; DESIGN §22.5 (#42)

This commit is contained in:
sganggs committed 2026-10-03 23:13:23 +08:00
1 parent db7b2b1404
commit 2f0a980b2e
10 files changed
+87 -25

No files matched your search

+15 -5
View File
@@ -8,7 +8,7 @@
// 2. Dependencies: `npm ci` (falls back to `npm install`) when node_modules is missing or incomplete.
// 3. Client libraries in public/vendor (tools/vendor.mjs) when any is missing.
// 4. Game data (data/*.json, committed) present and parseable.
// 5. Art/audio (tools/fetch-assets.mjs, ~250 MB into public/assets, resumable, mirror fallback) when public/assets
// 5. Art/audio (tools/fetch-assets.mjs, ~270 MB into public/assets, resumable, mirror fallback) when public/assets
// is missing or data/assets.json lists files that are not on disk. A failure is a warning: the game still runs
// with fallback visuals and the next run resumes.
// 6. Optional: official board/UI art from a locally installed Arknights client (Windows native install, CrossOver
@@ -189,6 +189,15 @@ export function checkAssets() {
return { ok: present && missing.length === 0 && urls.length > 0, present, manifest: true, total: urls.length, missing: missing.length, sample: missing.slice(0, 5), bytes: Number(m.stats?.bytes) || 0 };
}
/**
* What the game draws instead when the local-client art is absent (DESIGN §13, docs/DEPLOY.md §6). The battle emotes and
* the 玩法说明 pages are not in the list: step 5 downloads them from the public mirror with the other assets (GitHub
* issue #42). Shown by setup and doctor.
*/
export const LOCAL_ART_FALLBACK = '3D 棋盘改用 2D,部分官方界面图标和灼热/炽焰源石虫模型用替代样式';
/** Where a machine without the client gets the local art (docs/DEPLOY.md §6「本地客户端素材」). */
export const LOCAL_ART_COPY_HINT = '没有客户端的服务器可以从同一版本的整合包复制 public/assets/local 和 data/local-assets.json';
/**
* Local-client art (optional): manifest entry count, whether the 3D board atlas is on disk and whether the extraction
* has the enemy models only the client has (`spine/enemy/*` groups, extract.py ENEMY_SPINES — added after 0.1.0).
@@ -400,7 +409,7 @@ async function main() {
let assets = checkAssets();
if (!opts.assets) add(assets.ok ? 'ok' : 'skip', '美术/音频 public/assets', assets.ok ? `${assets.total} 个文件` : '已跳过(--no-assets)');
else if (!assets.ok && deps.ok && !opts.check) {
const what = !assets.present ? `首次下载约 ${assets.bytes ? mb(assets.bytes) : '250 MB'},可随时中断,重新运行会续传`
const what = !assets.present ? `首次下载约 ${assets.bytes ? mb(assets.bytes) : '270 MB'},可随时中断,重新运行会续传`
: `补全缺失的 ${assets.missing} 个文件`;
log(`\n${c.cyan('▶')} 下载美术与音频素材(${what})…`);
const r = run(process.execPath, [path.join(ROOT, 'tools', 'fetch-assets.mjs')]);
@@ -422,7 +431,8 @@ async function main() {
const already = local.manifest && local.dirPresent;
if (!client) {
if (already && local.board3d && !local.tiles && !opts.check) cropBoardTiles(log);
add(already ? 'ok' : 'skip', '本地客户端美术(可选)', already ? `已提取 ${local.count} 项` : (opts.game ? `找不到 ${opts.game}` : '未检测到本机明日方舟客户端(不影响游戏)'));
add(already ? 'ok' : 'skip', '本地客户端美术(可选)', already ? `已提取 ${local.count} 项`
: `${opts.game ? `找不到 ${opts.game}` : '未检测到本机明日方舟客户端'}:${LOCAL_ART_FALLBACK}(${LOCAL_ART_COPY_HINT},见 docs/DEPLOY.md 第 6 节)`);
} else if (!client.autochess) {
add(already ? 'ok' : 'warn', '本地客户端美术(可选)', `${client.kind} 客户端缺少卫戍协议资源(请在游戏内下载全部资源):${client.path}`);
} else if (already && opts.local !== 'force') {
@@ -438,7 +448,7 @@ async function main() {
let go = opts.local === 'force' || opts.yes;
if (go || !state.localDeclined) {
log(`\n${c.cyan('▶')} 检测到本机明日方舟客户端(${client.kind}):\n ${c.dim(client.path)}`);
log(' 可以从中提取官方棋盘贴图、UI 图标、表情等(仅本机使用;通常 1–5 分钟,Python 依赖约 40 MB,装在项目内的 .venv-extract)。');
log(' 可以从中提取官方 3D 棋盘贴图、界面图标等(仅本机使用;通常 1–5 分钟,Python 依赖约 40 MB,装在项目内的 .venv-extract)。');
}
let unattended = false;
if (!go && !state.localDeclined) {
@@ -457,7 +467,7 @@ async function main() {
if (r.ok) cropBoardTiles(log);
const after = checkLocal();
if (r.ok && after.manifest) { add('ok', '本地客户端美术(可选)', `提取 ${after.count} 项${after.board3d ? ',3D 棋盘可用' : ''}`); saveState({ localDeclined: false, localExtractedFrom: client.path }); }
else add('warn', '本地客户端美术(可选)', `提取未成功(退出码 ${r.code}),游戏不受影响;可稍后重试 node tools/setup.mjs --local`);
else add('warn', '本地客户端美术(可选)', `提取未成功(退出码 ${r.code}):游戏照常运行,${LOCAL_ART_FALLBACK};可稍后重试 node tools/setup.mjs --local`);
}
}
}