Files
cocos/tools/split-levels-database.js
2026-06-18 14:07:38 +08:00

95 lines
3.0 KiB
JavaScript
Raw 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.
#!/usr/bin/env node
/**
* 将 levels-database.json 拆为 index + 分片,首屏只下 index~几 KB
*
* 输出:
* <outDir>/levels-db-index.json (+ .br)
* <outDir>/StreamingAssets/aa/levels-db/<min>-<max>.json (+ .br)
*/
const fs = require('fs');
const path = require('path');
const { brotliCompressFile, formatBytes } = require('./package-optimize');
const DEFAULT_SHARD_SIZE = 100;
function mkdirp(p) { fs.mkdirSync(p, { recursive: true }); }
/**
* @param {string} srcPath assets/level-data/levels-database.json
* @param {string} outDir 运行时包根目录
* @param {{ shardSize?: number }} opts
*/
function splitLevelsDatabase(srcPath, outDir, opts = {}) {
const shardSize = opts.shardSize || DEFAULT_SHARD_SIZE;
const raw = JSON.parse(fs.readFileSync(srcPath, 'utf8'));
const levels = raw.levels || {};
const ids = Object.keys(levels)
.map((k) => parseInt(k, 10))
.filter((n) => !Number.isNaN(n))
.sort((a, b) => a - b);
if (ids.length < 1) {
throw new Error(`关卡库为空: ${srcPath}`);
}
const min = ids[0];
const max = ids[ids.length - 1];
const shardDir = path.join(outDir, 'StreamingAssets', 'aa', 'levels-db');
mkdirp(shardDir);
const shards = [];
for (let start = min; start <= max; start += shardSize) {
const end = Math.min(start + shardSize - 1, max);
const slice = {};
for (const id of ids) {
if (id >= start && id <= end) {
slice[String(id)] = levels[String(id)];
}
}
if (!Object.keys(slice).length) continue;
const fileName = `${start}-${end}.json`;
const relFile = `levels-db/${fileName}`;
const absPath = path.join(shardDir, fileName);
fs.writeFileSync(absPath, JSON.stringify({ levels: slice }), 'utf8');
const br = brotliCompressFile(absPath, absPath + '.br');
console.log(`>>> levels-db/${fileName}: ${formatBytes(br.raw)} → .br ${formatBytes(br.br)}`);
shards.push({ min: start, max: end, file: relFile, count: Object.keys(slice).length });
}
const index = {
version: 2,
mode: 'sharded',
shardSize,
levelIdBase: raw.levelIdBase,
generatedAt: raw.generatedAt || new Date().toISOString(),
source: raw.source || 'split-levels-database',
total: ids.length,
min,
max,
stats: raw.stats,
shards,
};
const indexPath = path.join(outDir, 'levels-db-index.json');
fs.writeFileSync(indexPath, JSON.stringify(index), 'utf8');
const indexBr = brotliCompressFile(indexPath, indexPath + '.br');
console.log(`>>> levels-db-index.json: ${formatBytes(indexBr.raw)} → .br ${formatBytes(indexBr.br)}`);
console.log(`>>> 关卡库分片: ${shards.length} 片, ${ids.length} 关 (${min}${max})`);
return { index, shards, total: ids.length };
}
module.exports = { splitLevelsDatabase, DEFAULT_SHARD_SIZE };
if (require.main === module) {
const src = path.resolve(process.argv[2]);
const out = path.resolve(process.argv[3]);
if (!src || !out) {
console.error('Usage: split-levels-database.js <levels-database.json> <outDir>');
process.exit(1);
}
splitLevelsDatabase(src, out);
}