压缩文件的加载

This commit is contained in:
unanmed 2023-06-11 20:23:13 +08:00
parent 80ce3b1a31
commit 069ee0613b
6 changed files with 99 additions and 19 deletions

View File

@ -41,6 +41,7 @@
- 宝物目标设定
- 每个怪物加一个怪物说明
- 歌词展示系统
- 小地图显示框,可以选择是否显示剩余怪物数量等
### 第二章 智慧

View File

@ -1,4 +1,4 @@
export class MotaAudio {}
export class SoundEffect {}
class SoundController {
add(uri: string, data: ArrayBuffer) {}

View File

@ -3,7 +3,7 @@ export {};
declare global {
interface AncTe {}
interface Window {
ancTe: AncTe;
readonly ancTe: AncTe;
}
const ancTe: AncTe;
}

View File

@ -1,10 +1,9 @@
import resource from '../../data/resource.json';
import { Resource, ResourceType } from './resource';
import { NonZipResource, Resource, getTypeByResource } from './resource';
const info = resource as ResourceInfo[];
export interface ResourceInfo {
floor: [FloorIds, FloorIds][];
includes: string[];
zip: boolean;
zippedName?: string;
@ -13,13 +12,15 @@ export interface ResourceInfo {
export function readyAllResource() {
info.forEach(v => {
if (v.zip) {
const res = new Resource(`zip.${v.zippedName}`, 'zip');
ancTe.resource.push([[`zip.${v.zippedName}`, res]]);
const id = `zip.${v.zippedName}`;
ancTe.zipResource.push([[id, new Resource(id, 'zip')]]);
} else {
const res: [string, Resource][] = v.includes.map(v => {
const type = v.split('.')[0];
return [v, new Resource(v, type as ResourceType)];
});
const res: [string, Resource<NonZipResource>][] = v.includes.map(
v => {
const type = getTypeByResource(v);
return [v, new Resource(v, type as NonZipResource)];
}
);
ancTe.resource.push(res);
}
});

View File

@ -15,6 +15,7 @@ interface ResourceData {
}
export type ResourceType = keyof ResourceData;
export type NonZipResource = Exclude<ResourceType, 'zip'>;
export class Resource<
T extends ResourceType = ResourceType
@ -33,22 +34,46 @@ export class Resource<
/** 资源数据 */
resource?: ResourceData[T];
constructor(resource: string, type: T) {
constructor(resource: string, format: T) {
super(resource);
this.data = this.resolveUrl(resource);
this.format = type;
this.format = format;
this.resStr = resource;
this.on('active', this.load);
this.on('load', this.onload);
this.once('active', this.load);
this.once('load', this.onLoad);
this.once('loadstart', this.onLoadStart);
}
protected onload(v: ResourceData[T]) {
protected onLoadStart(v?: ResourceData[T]) {
if (this.format === 'bgm') {
// bgm 单独处理,因为它可以边播放边加载
}
}
protected onLoad(v: ResourceData[T]) {
// 资源类型处理
if (this.type === 'fonts') {
document.fonts.add(new FontFace(this.name, v as ArrayBuffer));
} else if (this.type === 'sounds') {
ancTe.sound.add(this.resStr, v as ArrayBuffer);
}
// 资源加载类型处理
if (this.format === 'zip') {
(this.resource as ZippedResource).once('ready', data => {
data.forEach((path, file) => {
const [base, name] = path.split(/(\/|\\)/);
const id = `${base}.${name}`;
const type = getTypeByResource(id) as NonZipResource;
const format = getZipFormatByType(type);
ancTe.resource.set(
id,
new Resource(id, type).setData(file.async(format))
);
});
});
}
}
/**
@ -84,6 +109,9 @@ export class Resource<
*
*/
protected load() {
if (this.loaded) {
throw new Error(`Cannot load one resource twice.`);
}
const data = this.data;
if (!data) {
throw new Error(`Unexpected null of url in loading resource.`);
@ -92,6 +120,7 @@ export class Resource<
this.request = new Promise(res => {
const img = new Image();
img.src = data;
this.emit('loadstart', img);
img.addEventListener('load', () => {
this.resource = img;
this.loaded = true;
@ -103,6 +132,7 @@ export class Resource<
this.request = new Promise(res => {
const audio = new Audio();
audio.src = data;
this.emit('loadstart', audio);
audio.addEventListener('load', () => {
this.resource = audio;
this.loaded = true;
@ -115,6 +145,7 @@ export class Resource<
this.format === 'text' ||
this.format === 'arraybuffer'
) {
this.emit('loadstart');
this.request = axios
.get(data, { responseType: this.format })
.then(v => {
@ -124,6 +155,7 @@ export class Resource<
return v;
});
} else if (this.format === 'zip') {
this.emit('loadstart');
this.request = axios
.get(data, { responseType: 'arraybuffer' })
.then(v => {
@ -147,6 +179,25 @@ export class Resource<
return this.resource ?? null;
}
}
/**
*
* @param data
*/
protected setData(data: ResourceData[T] | Promise<ResourceData[T]>) {
if (data instanceof Promise) {
data.then(v => {
this.loaded = true;
this.resource = v;
this.emit('load', v);
});
} else {
this.loaded = true;
this.resource = data;
this.emit('load', data);
}
return this;
}
}
interface ZippedEvent extends EmitableEvent {
@ -167,7 +218,7 @@ export class ZippedResource extends EventEmitter<ZippedEvent> {
}
}
class ResourceStore extends Map<string, Resource> {
class ResourceStore<T extends ResourceType> extends Map<string, Resource<T>> {
active(key: string[] | string) {
const keys = ensureArray(key);
keys.forEach(v => this.get(v)?.active());
@ -183,7 +234,7 @@ class ResourceStore extends Map<string, Resource> {
keys.forEach(v => this.get(v)?.destroy());
}
push(data: [string, Resource][] | Record<string, Resource>): void {
push(data: [string, Resource<T>][] | Record<string, Resource<T>>): void {
if (data instanceof Array) {
for (const [key, res] of data) {
if (this.has(key)) {
@ -201,13 +252,41 @@ class ResourceStore extends Map<string, Resource> {
): Promise<ResourceData[T] | null> {
return this.get(key)?.getData() ?? null;
}
getDataSync<T extends ResourceType = ResourceType>(
key: string
): ResourceData[T] | null {
return this.get(key)?.resource ?? null;
}
}
declare global {
interface AncTe {
/** 游戏资源 */
resource: ResourceStore;
resource: ResourceStore<Exclude<ResourceType, 'zip'>>;
zipResource: ResourceStore<'zip'>;
}
}
ancTe.resource = new ResourceStore();
ancTe.zipResource = new ResourceStore();
console.log(JSZip.external.Promise);
export function getTypeByResource(resource: string): ResourceType {
const type = resource.split('.')[0];
if (type === 'zip') return 'zip';
else if (type === 'bgms') return 'bgm';
else if (['images', 'autotiles', 'materials', 'tilesets'].includes(type)) {
return 'image';
} else if (['sounds', 'fonts'].includes(type)) return 'arraybuffer';
else if (type === 'animates') return 'json';
return 'arraybuffer';
}
export function getZipFormatByType(type: ResourceType): 'arraybuffer' | 'text' {
if (type === 'text' || type === 'json') return 'text';
else return 'arraybuffer';
}

View File

@ -1,6 +1,5 @@
[
{
"floor": [],
"includes": [],
"zip": false
}