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; /** * ResProxy缓存 * key: bundleName:path * value: ResProxy */ private _resProxies: Map>; /** * 构造函数(私有) */ private constructor() { this._bundleProxies = new Map(); this._resProxies = new Map>(); // 默认添加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 */ async loadBundle(bundleName: string): Promise { const bundleProxy = this.getBundleProxy(bundleName); await bundleProxy.loadBundle(); return bundleProxy; } /** * 获取或创建ResProxy * @param bundleName bundle名称 * @param path 资源路径 * @param type 资源类型 * @returns ResProxy */ getResProxy( bundleName: string, path: string, type: new (...args: any[]) => T ): ResProxy { 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; } /** * 加载单个资源 * @param bundleName bundle名称 * @param path 资源路径 * @param type 资源类型 * @returns Promise<资源> */ async load( bundleName: string, path: string, type: new (...args: any[]) => T ): Promise { const resProxy = this.getResProxy(bundleName, path, type); return resProxy.load(); } /** * 预加载资源 * @param bundleName bundle名称 * @param path 资源路径 * @param type 资源类型 * @param onProgress 进度回调 * @returns Promise */ async preload( bundleName: string, path: string, type: new (...args: any[]) => T, onProgress?: (finished: number, total: number) => void ): Promise { const resProxy = this.getResProxy(bundleName, path, type); return resProxy.preload(onProgress); } /** * 加载目录 * @param bundleName bundle名称 * @param dir 目录路径 * @param type 资源类型 * @param onProgress 进度回调 * @returns Promise<资源数组> */ async loadDir( bundleName: string, dir: string, type: new (...args: any[]) => T, onProgress?: (finished: number, total: number) => void ): Promise { const bundleProxy = this.getBundleProxy(bundleName); return bundleProxy.loadDir(dir, type, onProgress); } /** * 预加载目录 * @param bundleName bundle名称 * @param dir 目录路径 * @param type 资源类型 * @param onProgress 进度回调 * @returns Promise */ async preloadDir( bundleName: string, dir: string, type: new (...args: any[]) => T, onProgress?: (finished: number, total: number) => void ): Promise { 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}`); } }