HumanBreak/script/resource.ts

237 lines
6.8 KiB
TypeScript
Raw Normal View History

2024-05-03 20:44:43 +08:00
import fs, { Stats } from 'fs-extra';
import JSZip from 'jszip';
import { formatSize, uniqueSymbol } from './utils.js';
// 资源拆分模块,可以加快在线加载速度
type ResourceType =
| 'text'
| 'buffer'
| 'image'
| 'material'
| 'audio'
| 'json'
| 'zip';
interface CompressedLoadListItem {
type: ResourceType;
name: string;
usage: string;
2023-06-20 22:35:51 +08:00
}
2024-05-03 20:44:43 +08:00
type CompressedLoadList = Record<string, CompressedLoadListItem[]>;
interface MainData {
main: {
images: string[];
tilesets: string[];
animates: string[];
sounds: string[];
fonts: string[];
};
2023-05-31 12:09:47 +08:00
}
2024-05-03 20:44:43 +08:00
/** 单包大小2M */
const SPLIT_SIZE = 2 ** 20 * 2;
export async function splitResource() {
const splitResult: CompressedLoadList = {};
let now: CompressedLoadListItem[] = [];
let totalSize: number = 0;
let nowZip: JSZip = new JSZip();
await fs.ensureDir('./dist/resource/');
await fs.emptyDir('./dist/resource');
const pushItem = async (
type: ResourceType,
name: string,
usage: string,
file: Stats,
content: any
) => {
totalSize += file.size;
if (totalSize > SPLIT_SIZE) {
if (file.size > SPLIT_SIZE) {
const symbol = uniqueSymbol() + `.h5data`;
console.warn(
`file ${type}/${name}(${formatSize(
file.size
)}) is larger than split limit (${formatSize(
SPLIT_SIZE
)}), single zip will be generated.`
);
splitResult['resource/' + symbol] = [{ type, name, usage }];
const zip = new JSZip();
addZippedFile(zip, type, name, content);
await writeZip(zip, `./dist/resource/${symbol}`, file.size);
totalSize -= file.size;
return;
2023-06-20 22:35:51 +08:00
} else {
2024-05-03 20:44:43 +08:00
const symbol = uniqueSymbol() + `.h5data`;
splitResult['resource/' + symbol] = now;
await writeZip(
nowZip,
`./dist/resource/${symbol}`,
totalSize - file.size
2023-06-20 22:35:51 +08:00
);
2024-05-03 20:44:43 +08:00
nowZip = new JSZip();
totalSize = 0;
now = [];
await pushItem(type, name, usage, file, content);
2023-06-20 22:35:51 +08:00
}
2024-05-03 20:44:43 +08:00
} else {
now.push({ type, name, usage });
addZippedFile(nowZip, type, name, content);
2023-06-20 22:35:51 +08:00
}
2024-05-03 20:44:43 +08:00
};
2023-06-20 22:35:51 +08:00
2024-05-03 20:44:43 +08:00
const writeZip = (zip: JSZip, name: string, size: number) => {
return new Promise<void>(res => {
zip.generateNodeStream({ type: 'nodebuffer', streamFiles: true })
.pipe(fs.createWriteStream(name))
.once('finish', function () {
console.log(
`Generated ${name}. Unzipped size: ${formatSize(size)}`
);
res();
2023-06-20 22:35:51 +08:00
});
2024-05-03 20:44:43 +08:00
});
};
2023-06-20 22:35:51 +08:00
2024-05-03 20:44:43 +08:00
const addZippedFile = (
zip: JSZip,
type: ResourceType,
name: string,
content: any
) => {
zip.file(`${type}/${name}`, content);
};
2023-06-05 11:18:44 +08:00
2024-05-03 20:44:43 +08:00
const file = await fs.readFile('./dist/project/data.js', 'utf-8');
const data = JSON.parse(file.split('\n').slice(1).join('')) as MainData;
2023-06-04 23:06:56 +08:00
2024-05-03 20:44:43 +08:00
// images
for (const image of data.main.images) {
const path = `./dist/project/images/${image}`;
const stat = await fs.stat(path);
await pushItem('image', image, 'image', stat, await fs.readFile(path));
}
2023-06-20 22:35:51 +08:00
2024-05-03 20:44:43 +08:00
// tileset
for (const tileset of data.main.tilesets) {
const path = `./dist/project/tilesets/${tileset}`;
const stat = await fs.stat(path);
await pushItem(
'image',
tileset,
'tileset',
stat,
await fs.readFile(path)
2023-06-04 23:06:56 +08:00
);
2024-05-03 20:44:43 +08:00
}
2023-06-04 23:06:56 +08:00
2024-05-03 20:44:43 +08:00
// animates
for (const ani of data.main.animates) {
const path = `./dist/project/animates/${ani}.animate`;
const stat = await fs.stat(path);
await pushItem(
'text',
ani + '.animate',
'animate',
stat,
await fs.readFile(path, 'utf-8')
2023-06-05 11:18:44 +08:00
);
2024-05-03 20:44:43 +08:00
}
2024-05-03 20:44:43 +08:00
// sounds
for (const sound of data.main.sounds) {
const path = `./dist/project/sounds/${sound}`;
const stat = await fs.stat(path);
await pushItem('audio', sound, 'sound', stat, await fs.readFile(path));
}
2024-05-03 20:44:43 +08:00
// fonts
for (const font of data.main.fonts) {
const path = `./dist/project/fonts/${font}.ttf`;
const stat = await fs.stat(path);
await pushItem(
'buffer',
font + '.ttf',
'font',
stat,
await fs.readFile(path)
2023-06-20 22:35:51 +08:00
);
2024-05-03 20:44:43 +08:00
}
2024-05-03 20:44:43 +08:00
// autotiles
const autotiles = await fs.readdir('./dist/project/autotiles');
for (const a of autotiles) {
const path = `./dist/project/autotiles/${a}`;
const stat = await fs.stat(path);
await pushItem('image', a, 'autotile', stat, await fs.readFile(path));
}
2024-05-03 20:44:43 +08:00
// materials
const materials = await fs.readdir('./dist/project/materials');
for (const m of materials) {
const path = `./dist/project/materials/${m}`;
const stat = await fs.stat(path);
await pushItem(
'material',
m,
'material',
stat,
await fs.readFile(path)
2023-06-20 22:35:51 +08:00
);
}
2024-05-03 20:44:43 +08:00
const symbol = uniqueSymbol() + `.h5data`;
splitResult['resource/' + symbol] = now;
await writeZip(nowZip, `./dist/resource/${symbol}`, totalSize);
// 添加资源映射
await fs.writeFile(
'./dist/loadList.json',
JSON.stringify(splitResult),
'utf-8'
);
// 删除原资源
await fs.emptyDir('./dist/project/images');
await fs.emptyDir('./dist/project/tilesets');
await fs.emptyDir('./dist/project/animates');
await fs.emptyDir('./dist/project/fonts');
await fs.emptyDir('./dist/project/materials');
await fs.emptyDir('./dist/project/sounds');
await fs.emptyDir('./dist/project/autotiles');
// 然后加入填充内容
await fs.copy(
'./script/template/.h5data',
'./dist/project/images/images.h5data'
);
await fs.copy(
'./script/template/.h5data',
'./dist/project/tilesets/tilesets.h5data'
);
await fs.copy(
'./script/template/.h5data',
'./dist/project/animates/animates.h5data'
);
await fs.copy(
'./script/template/.h5data',
'./dist/project/fonts/fonts.h5data'
);
await fs.copy(
'./script/template/.h5data',
'./dist/project/materials/materials.h5data'
);
await fs.copy(
'./script/template/.h5data',
'./dist/project/sounds/sounds.h5data'
);
await fs.copy(
'./script/template/.h5data',
'./dist/project/autotiles/autotiles.h5data'
);
}