95 lines
3.0 KiB
JavaScript
95 lines
3.0 KiB
JavaScript
#!/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);
|
||
}
|