Files
rougelike-demo/client/assets/scripts/Framework/ResMgr/ResMgr.ts

337 lines
9.7 KiB
TypeScript

import { Asset, AssetManager, assetManager, resources } from 'cc';
import { BundleProxy } from './BundleProxy';
import { ResProxy } from './ResProxy';
/**
* 资源管理器
* 职责:
* - 统一管理Bundle和资源
* - 提供BundleProxy和ResProxy的创建和管理
* - 提供便捷的资源加载接口
* - 管理资源缓存和释放
*/
export class ResMgr {
private static _instance: ResMgr | null = null;
/**
* BundleProxy缓存
* key: bundleName
* value: BundleProxy
*/
private _bundleProxies: Map<string, BundleProxy>;
/**
* ResProxy缓存
* key: bundleName:path
* value: ResProxy
*/
private _resProxies: Map<string, ResProxy<any>>;
/**
* 构造函数(私有)
*/
private constructor() {
this._bundleProxies = new Map<string, BundleProxy>();
this._resProxies = new Map<string, ResProxy<any>>();
// 默认添加resources bundle
this._bundleProxies.set('resources', new BundleProxy('resources', resources));
}
/**
* 获取单例
*/
static getInstance(): ResMgr {
if (!this._instance) {
this._instance = new ResMgr();
}
return this._instance;
}
/**
* 生成缓存key
*/
private getCacheKey(bundleName: string, path: string): string {
return `${bundleName}:${path}`;
}
/**
* 获取或创建BundleProxy
* @param bundleName bundle名称
* @returns BundleProxy
*/
getBundleProxy(bundleName: string): BundleProxy {
if (!this._bundleProxies.has(bundleName)) {
// 尝试从assetManager获取已加载的bundle
const bundle = assetManager.getBundle(bundleName);
const bundleProxy = new BundleProxy(bundleName, bundle || undefined);
this._bundleProxies.set(bundleName, bundleProxy);
}
return this._bundleProxies.get(bundleName)!;
}
/**
* 加载Bundle
* @param bundleName bundle名称
* @returns Promise<BundleProxy>
*/
async loadBundle(bundleName: string): Promise<BundleProxy> {
const bundleProxy = this.getBundleProxy(bundleName);
await bundleProxy.loadBundle();
return bundleProxy;
}
/**
* 获取或创建ResProxy
* @param bundleName bundle名称
* @param path 资源路径
* @param type 资源类型
* @returns ResProxy
*/
getResProxy<T extends Asset>(
bundleName: string,
path: string,
type: new (...args: any[]) => T
): ResProxy<T> {
const cacheKey = this.getCacheKey(bundleName, path);
if (!this._resProxies.has(cacheKey)) {
const bundleProxy = this.getBundleProxy(bundleName);
const resProxy = bundleProxy.createResProxy(path, type);
this._resProxies.set(cacheKey, resProxy);
}
return this._resProxies.get(cacheKey)! as ResProxy<T>;
}
/**
* 加载单个资源
* @param bundleName bundle名称
* @param path 资源路径
* @param type 资源类型
* @returns Promise<资源>
*/
async load<T extends Asset>(
bundleName: string,
path: string,
type: new (...args: any[]) => T
): Promise<T> {
const resProxy = this.getResProxy(bundleName, path, type);
return resProxy.load();
}
/**
* 预加载资源
* @param bundleName bundle名称
* @param path 资源路径
* @param type 资源类型
* @param onProgress 进度回调
* @returns Promise<void>
*/
async preload<T extends Asset>(
bundleName: string,
path: string,
type: new (...args: any[]) => T,
onProgress?: (finished: number, total: number) => void
): Promise<void> {
const resProxy = this.getResProxy(bundleName, path, type);
return resProxy.preload(onProgress);
}
/**
* 加载目录
* @param bundleName bundle名称
* @param dir 目录路径
* @param type 资源类型
* @param onProgress 进度回调
* @returns Promise<资源数组>
*/
async loadDir<T extends Asset>(
bundleName: string,
dir: string,
type: new (...args: any[]) => T,
onProgress?: (finished: number, total: number) => void
): Promise<T[]> {
const bundleProxy = this.getBundleProxy(bundleName);
return bundleProxy.loadDir(dir, type, onProgress);
}
/**
* 预加载目录
* @param bundleName bundle名称
* @param dir 目录路径
* @param type 资源类型
* @param onProgress 进度回调
* @returns Promise<void>
*/
async preloadDir<T extends Asset>(
bundleName: string,
dir: string,
type: new (...args: any[]) => T,
onProgress?: (finished: number, total: number) => void
): Promise<void> {
const bundleProxy = this.getBundleProxy(bundleName);
return bundleProxy.preloadDir(dir, type, onProgress);
}
/**
* 释放资源
* @param bundleName bundle名称
* @param path 资源路径
*/
release(bundleName: string, path: string): void {
const cacheKey = this.getCacheKey(bundleName, path);
// 从ResProxy缓存中获取并释放
if (this._resProxies.has(cacheKey)) {
const resProxy = this._resProxies.get(cacheKey)!;
resProxy.release();
// 可选:从缓存中移除ResProxy
// this._resProxies.delete(cacheKey);
} else {
// 如果没有ResProxy,直接从BundleProxy释放
const bundleProxy = this.getBundleProxy(bundleName);
bundleProxy.release(path);
}
}
/**
* 释放目录资源
* @param bundleName bundle名称
* @param dir 目录路径
*/
releaseDir(bundleName: string, dir: string): void {
// 释放所有以dir开头的ResProxy
const prefix = `${bundleName}:${dir}`;
const keysToDelete: string[] = [];
this._resProxies.forEach((resProxy, key) => {
if (key.startsWith(prefix)) {
resProxy.release();
keysToDelete.push(key);
}
});
// 可选:从缓存中移除ResProxy
keysToDelete.forEach((key) => {
// this._resProxies.delete(key);
});
// 从BundleProxy释放目录
const bundleProxy = this.getBundleProxy(bundleName);
bundleProxy.releaseDir(dir);
console.log(`[ResMgr] 释放目录资源: ${bundleName}/${dir}, 共 ${keysToDelete.length} 个资源`);
}
/**
* 释放Bundle的所有资源
* @param bundleName bundle名称
*/
releaseBundle(bundleName: string): void {
// 释放该Bundle下所有的ResProxy
const prefix = `${bundleName}:`;
const keysToDelete: string[] = [];
this._resProxies.forEach((resProxy, key) => {
if (key.startsWith(prefix)) {
resProxy.release();
keysToDelete.push(key);
}
});
// 从缓存中移除ResProxy
keysToDelete.forEach((key) => {
this._resProxies.delete(key);
});
// 释放BundleProxy的所有资源
const bundleProxy = this.getBundleProxy(bundleName);
bundleProxy.releaseAll();
console.log(`[ResMgr] 释放Bundle所有资源: ${bundleName}, 共 ${keysToDelete.length}`);
}
/**
* 释放所有资源
*/
releaseAll(): void {
console.log(`[ResMgr] 释放所有资源, 共 ${this._resProxies.size} 个ResProxy`);
// 释放所有ResProxy
this._resProxies.forEach((resProxy) => {
resProxy.release();
});
this._resProxies.clear();
// 释放所有BundleProxy的资源(除了resources)
this._bundleProxies.forEach((bundleProxy, name) => {
if (name !== 'resources') {
bundleProxy.releaseAll();
}
});
}
/**
* 获取缓存的ResProxy数量
*/
getCacheSize(): number {
return this._resProxies.size;
}
/**
* 获取缓存的BundleProxy数量
*/
getBundleCount(): number {
return this._bundleProxies.size;
}
/**
* 清空缓存(不释放资源)
*/
clearCache(): void {
console.log(`[ResMgr] 清空缓存, 共 ${this._resProxies.size} 个ResProxy`);
// 清空所有ResProxy的缓存
this._resProxies.forEach((resProxy) => {
resProxy.clearCache();
});
this._resProxies.clear();
}
/**
* 销毁Bundle
* @param bundleName bundle名称
*/
destroyBundle(bundleName: string): void {
if (bundleName === 'resources') {
console.warn('[ResMgr] 不能销毁resources bundle');
return;
}
// 释放并移除该Bundle的所有ResProxy
const prefix = `${bundleName}:`;
const keysToDelete: string[] = [];
this._resProxies.forEach((resProxy, key) => {
if (key.startsWith(prefix)) {
resProxy.release();
keysToDelete.push(key);
}
});
keysToDelete.forEach((key) => {
this._resProxies.delete(key);
});
// 销毁BundleProxy
if (this._bundleProxies.has(bundleName)) {
const bundleProxy = this._bundleProxies.get(bundleName)!;
bundleProxy.destroy();
this._bundleProxies.delete(bundleName);
}
console.log(`[ResMgr] 销毁Bundle: ${bundleName}`);
}
}