Files
cocos/tools/runtime-pack.js
2026-06-18 14:07:38 +08:00

107 lines
3.6 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 统一运行时包定义 — 本地 static/unity 与 OSS unitycdndir 内容完全一致。
*
* 运行时包(唯一真相):
* Build/
* StreamingAssets/
* levels-database.json
* levels-database.json.br
* levels-db-index.json
* levels-db-index.json.br
* StreamingAssets/aa/levels-db/
*
* 不含 index.html / TemplateData仅 standalone-player 独立调试页使用)
*/
const fs = require('fs');
const path = require('path');
const RUNTIME_ROOT_FILES = [
'levels-database.json',
'levels-database.json.br',
'levels-db-index.json',
'levels-db-index.json.br',
];
const RUNTIME_DIRS = ['Build', 'StreamingAssets'];
function walkFiles(root, bucket, prefix = '') {
if (!fs.existsSync(root)) return;
for (const ent of fs.readdirSync(root, { withFileTypes: true })) {
if (ent.name === '.DS_Store') continue;
const rel = prefix ? `${prefix}/${ent.name}` : ent.name;
const full = path.join(root, ent.name);
if (ent.isDirectory()) walkFiles(full, bucket, rel);
else bucket.push({ rel, full, size: fs.statSync(full).size });
}
}
/** 列出运行时包内所有相对路径(用于 manifest / 校验) */
function listRuntimeFiles(packDir) {
const files = [];
for (const dir of RUNTIME_DIRS) {
walkFiles(path.join(packDir, dir), files, dir);
}
for (const name of RUNTIME_ROOT_FILES) {
const full = path.join(packDir, name);
if (fs.existsSync(full)) {
files.push({ rel: name, full, size: fs.statSync(full).size });
}
}
return files.sort((a, b) => a.rel.localeCompare(b.rel));
}
function bundleNamesFromCatalog(catalogPath) {
if (!fs.existsSync(catalogPath)) return [];
const catalog = JSON.parse(fs.readFileSync(catalogPath, 'utf8'));
return [...new Set(
(catalog.m_InternalIds || [])
.filter((id) => String(id).includes('.bundle'))
.map((id) => String(id).split('/').pop()),
)].sort();
}
function assertRuntimePack(packDir, opts) {
opts = opts || {};
const loader = path.join(packDir, 'Build/mstest5.loader.js');
const catalog = path.join(packDir, 'StreamingAssets/aa/catalog.json');
const levelsManifest = path.join(packDir, 'StreamingAssets/aa/levels-manifest.json');
if (!fs.existsSync(loader)) {
throw new Error(`缺少运行时包: ${loader}`);
}
if (!fs.existsSync(catalog)) {
throw new Error(`缺少运行时包: ${catalog}`);
}
if (!fs.existsSync(path.join(packDir, 'levels-db-index.json'))) {
throw new Error(`缺少运行时包: ${path.join(packDir, 'levels-db-index.json')}`);
}
if (!fs.existsSync(path.join(packDir, 'levels-database.json'))) {
throw new Error(`缺少运行时包: ${path.join(packDir, 'levels-database.json')}`);
}
const names = bundleNamesFromCatalog(catalog);
if (opts.requireLevelsBundle && !names.some((n) => n.includes('levels_all'))) {
throw new Error('catalog 缺少 levels_all 分包');
}
if (opts.requireLevelsManifest && !fs.existsSync(levelsManifest)) {
throw new Error(`缺少运行时包: ${levelsManifest}`);
}
if (opts.requireLevelsManifest) {
const manifest = JSON.parse(fs.readFileSync(levelsManifest, 'utf8'));
const count = Object.keys(manifest.levels || {}).length;
if (count < 1) throw new Error('levels-manifest.json 无关卡条目');
}
for (const name of names) {
const p = path.join(packDir, 'StreamingAssets/aa/WebGL', name);
if (!fs.existsSync(p) || fs.statSync(p).size < 100) {
throw new Error(`bundle 无效: ${p}`);
}
}
}
module.exports = {
RUNTIME_ROOT_FILES,
RUNTIME_DIRS,
walkFiles,
listRuntimeFiles,
bundleNamesFromCatalog,
assertRuntimePack,
};