mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-01-18 11:59:26 +08:00
资源分离
This commit is contained in:
parent
39c655d355
commit
1bdfb9be7d
3
.gitignore
vendored
3
.gitignore
vendored
@ -34,4 +34,5 @@ dist.rar
|
||||
index.cjs
|
||||
!public/swap/*.h5save
|
||||
_bundle
|
||||
out
|
||||
out
|
||||
dist-resource
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,11 +1,13 @@
|
||||
import fs from 'fs-extra';
|
||||
import { extname, resolve } from 'path';
|
||||
import { formatSize } from './utils.js';
|
||||
|
||||
(async function () {
|
||||
const dir = process.argv[2] || './src';
|
||||
const dir = process.argv.slice(2) || ['./src'];
|
||||
let totalLines = 0;
|
||||
let totalFiles = 0;
|
||||
const list: Record<string, [number, number]> = {};
|
||||
let totalSize = 0;
|
||||
const list: Record<string, [number, number, number]> = {};
|
||||
const ignoreDir = [
|
||||
'node_modules',
|
||||
'floors',
|
||||
@ -36,32 +38,38 @@ import { extname, resolve } from 'path';
|
||||
const file = await fs.readFile(resolve(dir, one), 'utf-8');
|
||||
const lines = file.split('\n').length;
|
||||
const ext = extname(one);
|
||||
list[ext] ??= [0, 0];
|
||||
list[ext] ??= [0, 0, 0];
|
||||
list[ext][0]++;
|
||||
list[ext][1] += lines;
|
||||
list[ext][2] += stat.size;
|
||||
totalLines += lines;
|
||||
totalFiles++;
|
||||
totalSize += stat.size;
|
||||
}
|
||||
} else {
|
||||
await check(resolve(dir, one));
|
||||
}
|
||||
}
|
||||
};
|
||||
await check(dir);
|
||||
await Promise.all(dir.map(v => check(v)));
|
||||
|
||||
const sorted = Object.entries(list).sort((a, b) => {
|
||||
return a[1][1] - b[1][1];
|
||||
});
|
||||
for (const [ext, [file, lines]] of sorted) {
|
||||
for (const [ext, [file, lines, size]] of sorted) {
|
||||
console.log(
|
||||
`${ext.slice(1).padEnd(7, ' ')}files: ${file
|
||||
.toString()
|
||||
.padEnd(6, ' ')}lines: ${lines}`
|
||||
.padEnd(6, ' ')}lines: ${lines
|
||||
.toString()
|
||||
.padEnd(9, ' ')}size: ${formatSize(size)}`
|
||||
);
|
||||
}
|
||||
console.log(
|
||||
`\x1b[33mtotal files: ${totalFiles
|
||||
.toString()
|
||||
.padEnd(6, ' ')}lines: ${totalLines}\x1b[0m`
|
||||
.padEnd(6, ' ')}lines: ${totalLines
|
||||
.toString()
|
||||
.padEnd(9, ' ')}size: ${formatSize(totalSize)}\x1b[0m`
|
||||
);
|
||||
})();
|
||||
|
@ -3,8 +3,8 @@ import { uniqueSymbol } from './utils.js';
|
||||
import { extname, resolve } from 'path';
|
||||
|
||||
type ResorceType =
|
||||
| 'bgm'
|
||||
| 'sound'
|
||||
| 'bgms'
|
||||
| 'sounds'
|
||||
| 'autotiles'
|
||||
| 'images'
|
||||
| 'materials'
|
||||
@ -12,9 +12,8 @@ type ResorceType =
|
||||
| 'animates'
|
||||
| 'fonts';
|
||||
|
||||
let resorceIndex = 0;
|
||||
const compress: ResorceType[] = [
|
||||
'sound',
|
||||
'sounds',
|
||||
'animates',
|
||||
'autotiles',
|
||||
'images',
|
||||
@ -24,13 +23,16 @@ const compress: ResorceType[] = [
|
||||
|
||||
const SYMBOL = uniqueSymbol();
|
||||
const MAX_SIZE = 100 * (1 << 20);
|
||||
const baseDir = './dist';
|
||||
|
||||
let totalSize = 0;
|
||||
|
||||
type Stats = fs.Stats & { name?: string };
|
||||
|
||||
export async function splitResorce(compress: boolean = false) {
|
||||
const folder = await fs.stat('./dist');
|
||||
totalSize = folder.size;
|
||||
if (totalSize < MAX_SIZE) return;
|
||||
// if (totalSize < MAX_SIZE) return;
|
||||
|
||||
await fs.ensureDir('./dist-resource');
|
||||
await doSplit(compress);
|
||||
@ -38,16 +40,112 @@ export async function splitResorce(compress: boolean = false) {
|
||||
|
||||
async function sortDir(dir: string, ext?: string[]) {
|
||||
const path = await fs.readdir(dir);
|
||||
const stats: fs.Stats[] = [];
|
||||
const stats: Stats[] = [];
|
||||
|
||||
for await (const one of path) {
|
||||
if (ext && !ext.includes(extname(one))) continue;
|
||||
const stat = await fs.stat(resolve(dir, one));
|
||||
if (!stat.isFile()) continue;
|
||||
stats.push(stat);
|
||||
const status: Stats = {
|
||||
...stat,
|
||||
name: one
|
||||
};
|
||||
stats.push(status);
|
||||
}
|
||||
|
||||
return stats.sort((a, b) => b.size - a.size);
|
||||
}
|
||||
|
||||
async function doSplit(compress: boolean) {}
|
||||
async function calResourceSize() {
|
||||
return (
|
||||
await Promise.all(
|
||||
[
|
||||
'animates',
|
||||
'autotiles',
|
||||
'bgms',
|
||||
'fonts',
|
||||
'images',
|
||||
'materials',
|
||||
'sounds',
|
||||
'tilesets'
|
||||
].map(v => fs.stat(resolve('./dist/project/', v)))
|
||||
)
|
||||
).reduce((pre, cur) => pre + cur.size, 0);
|
||||
}
|
||||
|
||||
async function doSplit(compress: boolean) {
|
||||
let size = await calResourceSize();
|
||||
await fs.emptyDir('./dist-resource');
|
||||
const priority: ResorceType[] = [
|
||||
'materials',
|
||||
'tilesets',
|
||||
'autotiles',
|
||||
'animates',
|
||||
'images',
|
||||
'sounds',
|
||||
'fonts',
|
||||
'bgms'
|
||||
];
|
||||
const dirInfo: Record<ResorceType, Stats[]> = Object.fromEntries(
|
||||
await Promise.all(
|
||||
priority.map(async v => [
|
||||
v,
|
||||
await sortDir(resolve(baseDir, 'project', v))
|
||||
])
|
||||
)
|
||||
);
|
||||
|
||||
let currSize = 0;
|
||||
const split = async (index: number): Promise<void> => {
|
||||
size -= currSize;
|
||||
currSize = 0;
|
||||
|
||||
const cut: string[] = [];
|
||||
|
||||
(() => {
|
||||
const mapped: ResorceType[] = [];
|
||||
while (1) {
|
||||
const toCut = priority.find(
|
||||
v => dirInfo[v].length > 0 && !mapped.includes(v)
|
||||
);
|
||||
if (!toCut) return;
|
||||
|
||||
mapped.push(toCut);
|
||||
|
||||
let pass = 0;
|
||||
while (1) {
|
||||
const stats = dirInfo[toCut];
|
||||
const stat = stats[pass];
|
||||
if (!stat) {
|
||||
break;
|
||||
}
|
||||
if (currSize + stat.size >= MAX_SIZE) {
|
||||
pass++;
|
||||
continue;
|
||||
}
|
||||
cut.push(`${toCut}/${stat.name}`);
|
||||
stats.splice(pass, 1);
|
||||
currSize += stat.size;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
const dir = `./dist-resource/${index}`;
|
||||
await fs.ensureDir(dir);
|
||||
await Promise.all(priority.map(v => fs.ensureDir(resolve(dir, v))));
|
||||
|
||||
await Promise.all(
|
||||
cut.map(v =>
|
||||
fs.move(
|
||||
resolve('./dist/project', v),
|
||||
resolve(dir, `${v}-${SYMBOL}`)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if (Object.values(dirInfo).every(v => v.length === 0)) return;
|
||||
else return split(index + 1);
|
||||
};
|
||||
|
||||
await split(0);
|
||||
}
|
||||
|
@ -1,3 +1,13 @@
|
||||
export function uniqueSymbol() {
|
||||
return Math.ceil(Math.random() * 0xefffffff + 0x10000000).toString(16);
|
||||
}
|
||||
|
||||
export function formatSize(size: number) {
|
||||
return size < 1 << 10
|
||||
? `${size.toFixed(2)}B`
|
||||
: size < 1 << 20
|
||||
? `${(size / (1 << 10)).toFixed(2)}KB`
|
||||
: size < 1 << 30
|
||||
? `${(size / (1 << 20)).toFixed(2)}MB`
|
||||
: `${(size / (1 << 30)).toFixed(2)}GB`;
|
||||
}
|
||||
|
36
src/core/common/disposable.ts
Normal file
36
src/core/common/disposable.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { EmitableEvent, EventEmitter } from './eventEmitter';
|
||||
|
||||
interface DisposableEvent<T> extends EmitableEvent {
|
||||
active: (value: T) => void;
|
||||
dispose: (value: T) => void;
|
||||
}
|
||||
|
||||
export class Disposable<T> extends EventEmitter<DisposableEvent<T>> {
|
||||
protected _data: T;
|
||||
set data(value: T | null) {
|
||||
if (value !== null) this._data = value;
|
||||
}
|
||||
get data(): T | null {
|
||||
if (!this.activated) {
|
||||
return null;
|
||||
}
|
||||
return this._data;
|
||||
}
|
||||
|
||||
protected activated: boolean = false;
|
||||
|
||||
constructor(data: T) {
|
||||
super();
|
||||
this._data = data;
|
||||
}
|
||||
|
||||
active() {
|
||||
this.activated = true;
|
||||
this.emit('active', this._data);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.activated = false;
|
||||
this.emit('dispose', this._data);
|
||||
}
|
||||
}
|
73
src/core/common/eventEmitter.ts
Normal file
73
src/core/common/eventEmitter.ts
Normal file
@ -0,0 +1,73 @@
|
||||
export interface EmitableEvent {
|
||||
[event: string]: (...params: any) => any;
|
||||
}
|
||||
|
||||
interface Listener<T extends (...params: any) => any> {
|
||||
fn: T;
|
||||
once?: boolean;
|
||||
}
|
||||
|
||||
interface ListenerOptions {
|
||||
once: boolean;
|
||||
}
|
||||
|
||||
export class EventEmitter<T extends EmitableEvent = {}> {
|
||||
private events: {
|
||||
[P in keyof T]?: Listener<T[P]>[];
|
||||
} = {};
|
||||
|
||||
/**
|
||||
* 监听某个事件
|
||||
* @param event 要监听的事件类型
|
||||
* @param fn 触发事件时执行的函数
|
||||
* @param options 监听选项
|
||||
*/
|
||||
on<K extends keyof T>(
|
||||
event: K,
|
||||
fn: T[K],
|
||||
options?: Partial<ListenerOptions>
|
||||
) {
|
||||
this.events[event] ??= [];
|
||||
this.events[event]?.push({
|
||||
fn,
|
||||
once: options?.once
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消监听某个事件
|
||||
* @param event 要取消监听的事件类型
|
||||
* @param fn 要取消监听的函数
|
||||
*/
|
||||
off<K extends keyof T>(event: K, fn: T[K]) {
|
||||
const index = this.events[event]?.findIndex(v => v.fn === fn);
|
||||
if (index === -1 || index === void 0) return;
|
||||
this.events[event]?.splice(index, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听事件,并只触发一次
|
||||
* @param event 要监听的事件
|
||||
* @param fn 监听函数
|
||||
*/
|
||||
once<K extends keyof T>(event: K, fn: T[K]) {
|
||||
this.on(event, fn, { once: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发某个事件
|
||||
* @param event 要触发的事件类型
|
||||
* @param params 传入的参数
|
||||
*/
|
||||
emit<K extends keyof T>(event: K, ...params: Parameters<T[K]>) {
|
||||
const events = (this.events[event] ??= []);
|
||||
for (let i = 0; i < events.length; i++) {
|
||||
const e = events[i];
|
||||
e.fn(...(params as any));
|
||||
if (e.once) {
|
||||
events.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -76,7 +76,7 @@
|
||||
"text": "优化加载",
|
||||
"desc": [
|
||||
"开启后游戏将对加载进行优化,缩短进入游戏时的加载时长,而在游戏中对资源进行部分性按需加载,从而对加载进行优化。",
|
||||
"该设置不会影响你的正常游戏。",
|
||||
"该设置不会影响你的正常游戏,但如果网络环境较差,可能会导致楼层转换时间明显变长。",
|
||||
"<br>",
|
||||
"<br>",
|
||||
"注:修改后刷新页面起效。"
|
||||
|
@ -130,7 +130,8 @@ const settings: Record<keyof Settings, Ref<boolean>> = {
|
||||
useFixed,
|
||||
autoLocate,
|
||||
antiAliasing,
|
||||
fullscreen
|
||||
fullscreen,
|
||||
betterLoad: ref(false)
|
||||
};
|
||||
|
||||
const ignore: (keyof Settings)[] = ['fullscreen'];
|
||||
|
Loading…
Reference in New Issue
Block a user