/** * gen-preview-manifest.mjs —— 生成本地预览的静态 GamePackage manifest(含 E1 适配器 engineBundle)。 * * 为什么:本地 mock 预览(/create/preview/9001)旧走「无 manifestUrl → demo 兜底」,而 demo 兜底用的 * 自研壳正被 T1b(LittleJS+Runner v2)替换 → 本地 load_timeout 玩不了。本脚本把【已验九门的 E1 适配器产物 * bundle】(__GameBundle) 包成一份 GamePackage 静态件,宿主 GamePlayer 经 fetchAndVerifyManifest 校 sha256 后 * 走【引擎包路】真玩——本地闭合 create→预览【可玩】闭环(CDP 走查实证)。 * * 用法(在 game-studio/ 下):node scripts/gen-preview-manifest.mjs * → 写 public/mock-manifests/9001.json(gitignore,不入库,体积大) * → 打印 OUTER_CHECKSUM;若与 src/mock/runtime.ts 的 LOCAL_MANIFEST_CHECKSUM 不一致,按打印值更新它。 * * 确定性:源 bundle = 仓内已提交的 game-runtime/games/_wg1-gen/_adapter-probe/bundle.iife.js(esbuild 确定性产物), * 故同一源 bundle → 同一 manifest json → 同一 sha256 → 硬编码 checksum 稳定。换源 bundle 须重跑并同步 checksum。 */ import { readFileSync, writeFileSync, mkdirSync } from 'node:fs' import { createHash } from 'node:crypto' import { fileURLToPath } from 'node:url' import { dirname, resolve } from 'node:path' const HERE = dirname(fileURLToPath(import.meta.url)) const studioRoot = resolve(HERE, '..') // 源 = 已提交的九门探针 bundle(E1 适配器 tap-target 产物,__GameBundle.bootGameHost 入口) const BUNDLE_PATH = resolve(studioRoot, '../game-runtime/games/_wg1-gen/_adapter-probe/bundle.iife.js') const OUT_PATH = resolve(studioRoot, 'public/mock-manifests/9001.json') const bundle = readFileSync(BUNDLE_PATH, 'utf8') // GamePackage(对齐 contract.ts GamePackage / game-package.schema.json#4;assets 空走几何兜底) const pkg = { schemaVersion: '1.0', gameId: '1', versionId: '9001', templateId: 'generic', gameConfig: { title: '本地预览 · 点目标', winScore: 3 }, assets: [], manifest: { runtimeVersion: '1.0.0', entry: 'index.html', preloadPolicy: 'eager', bundleSize: Buffer.byteLength(bundle), checksum: createHash('sha256').update(bundle).digest('hex'), // 内层=bundle 自身 sha256(非校验门) }, meta: { title: '本地预览 · 点目标', summary: 'E1 适配器产物(__GameBundle)经本地 mock 预览试玩——闭合 create→预览可玩闭环。', cover: 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==', ageRating: 'all', }, engineBundle: bundle, // 宿主 inject.ts 取此作独立内联