优化Framework.ResMgr抽象代理类使逻辑更整洁
This commit is contained in:
281
client/assets/scripts/Framework/ResMgr/BundleProxy.ts
Normal file
281
client/assets/scripts/Framework/ResMgr/BundleProxy.ts
Normal file
@@ -0,0 +1,281 @@
|
||||
import { Asset, AssetManager, assetManager } from 'cc';
|
||||
import { ResProxy } from './ResProxy';
|
||||
/**
|
||||
* Bundle代理类
|
||||
* 职责:
|
||||
* - 异步加载Bundle
|
||||
* - 管理Bundle的生命周期
|
||||
* - 提供从Bundle加载资源的统一接口
|
||||
*/
|
||||
export class BundleProxy {
|
||||
private _bundleName: string;
|
||||
private _bundle: AssetManager.Bundle | null = null;
|
||||
private _loading: Promise<AssetManager.Bundle> | null = null;
|
||||
|
||||
constructor(bundleName: string, bundle?: AssetManager.Bundle) {
|
||||
this._bundleName = bundleName;
|
||||
this._bundle = bundle || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Bundle名称
|
||||
*/
|
||||
get bundleName(): string {
|
||||
return this._bundleName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Bundle实例(同步)
|
||||
*/
|
||||
get bundle(): AssetManager.Bundle | null {
|
||||
return this._bundle;
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步加载Bundle
|
||||
* @returns Promise<AssetManager.Bundle>
|
||||
*/
|
||||
async loadBundle(): Promise<AssetManager.Bundle> {
|
||||
// 如果已经加载完成,直接返回
|
||||
if (this._bundle) {
|
||||
return this._bundle;
|
||||
}
|
||||
|
||||
// 如果正在加载中,返回加载Promise
|
||||
if (this._loading) {
|
||||
return this._loading;
|
||||
}
|
||||
|
||||
// 开始加载
|
||||
this._loading = new Promise<AssetManager.Bundle>((resolve, reject) => {
|
||||
console.log(`[BundleProxy] 开始加载Bundle: ${this._bundleName}`);
|
||||
|
||||
assetManager.loadBundle(this._bundleName, (err, bundle) => {
|
||||
if (err) {
|
||||
console.error(`[BundleProxy] 加载Bundle失败: ${this._bundleName}`, err);
|
||||
this._loading = null;
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
this._bundle = bundle;
|
||||
this._loading = null;
|
||||
console.log(`[BundleProxy] Bundle加载成功: ${this._bundleName}`);
|
||||
resolve(bundle);
|
||||
});
|
||||
});
|
||||
|
||||
return this._loading;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建资源代理
|
||||
* @param path 资源路径
|
||||
* @param type 资源类型
|
||||
* @returns ResProxy
|
||||
*/
|
||||
createResProxy<T extends Asset>(
|
||||
path: string,
|
||||
type: new (...args: any[]) => T
|
||||
): ResProxy<T> {
|
||||
return new ResProxy<T>(this, path, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载资源
|
||||
* @param path 资源路径
|
||||
* @param type 资源类型
|
||||
* @returns Promise<资源>
|
||||
*/
|
||||
async loadRes<T extends Asset>(
|
||||
path: string,
|
||||
type: new (...args: any[]) => T
|
||||
): Promise<T> {
|
||||
const bundle = await this.loadBundle();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log(`[BundleProxy] 开始加载资源: ${this._bundleName}/${path}`);
|
||||
|
||||
bundle.load(path, type, (err, asset) => {
|
||||
if (err) {
|
||||
console.error(`[BundleProxy] 加载资源失败: ${this._bundleName}/${path}`, err);
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[BundleProxy] 资源加载成功: ${this._bundleName}/${path}`);
|
||||
resolve(asset as T);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 预加载资源
|
||||
* @param path 资源路径
|
||||
* @param type 资源类型
|
||||
* @param onProgress 进度回调
|
||||
* @returns Promise<void>
|
||||
*/
|
||||
async preload<T extends Asset>(
|
||||
path: string,
|
||||
type: new (...args: any[]) => T,
|
||||
onProgress?: (finished: number, total: number) => void
|
||||
): Promise<void> {
|
||||
const bundle = await this.loadBundle();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log(`[BundleProxy] 开始预加载资源: ${this._bundleName}/${path}`);
|
||||
|
||||
bundle.preload(
|
||||
path,
|
||||
type,
|
||||
(finished, total) => {
|
||||
if (onProgress) {
|
||||
onProgress(finished, total);
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
if (err) {
|
||||
console.error(`[BundleProxy] 预加载资源失败: ${this._bundleName}/${path}`, err);
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[BundleProxy] 资源预加载成功: ${this._bundleName}/${path}`);
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载目录
|
||||
* @param dir 目录路径
|
||||
* @param type 资源类型
|
||||
* @param onProgress 进度回调
|
||||
* @returns Promise<资源数组>
|
||||
*/
|
||||
async loadDir<T extends Asset>(
|
||||
dir: string,
|
||||
type: new (...args: any[]) => T,
|
||||
onProgress?: (finished: number, total: number) => void
|
||||
): Promise<T[]> {
|
||||
const bundle = await this.loadBundle();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log(`[BundleProxy] 开始加载目录: ${this._bundleName}/${dir}`);
|
||||
|
||||
bundle.loadDir(
|
||||
dir,
|
||||
type,
|
||||
(finished, total) => {
|
||||
if (onProgress) {
|
||||
onProgress(finished, total);
|
||||
}
|
||||
},
|
||||
(err, assets) => {
|
||||
if (err) {
|
||||
console.error(`[BundleProxy] 加载目录失败: ${this._bundleName}/${dir}`, err);
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[BundleProxy] 目录加载成功: ${this._bundleName}/${dir}, 共 ${assets.length} 个资源`);
|
||||
resolve(assets as T[]);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 预加载目录
|
||||
* @param dir 目录路径
|
||||
* @param type 资源类型
|
||||
* @param onProgress 进度回调
|
||||
* @returns Promise<void>
|
||||
*/
|
||||
async preloadDir<T extends Asset>(
|
||||
dir: string,
|
||||
type: new (...args: any[]) => T,
|
||||
onProgress?: (finished: number, total: number) => void
|
||||
): Promise<void> {
|
||||
const bundle = await this.loadBundle();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log(`[BundleProxy] 开始预加载目录: ${this._bundleName}/${dir}`);
|
||||
|
||||
bundle.preloadDir(
|
||||
dir,
|
||||
type,
|
||||
(finished, total) => {
|
||||
if (onProgress) {
|
||||
onProgress(finished, total);
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
if (err) {
|
||||
console.error(`[BundleProxy] 预加载目录失败: ${this._bundleName}/${dir}`, err);
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[BundleProxy] 目录预加载成功: ${this._bundleName}/${dir}`);
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放资源
|
||||
* @param path 资源路径
|
||||
*/
|
||||
release(path: string): void {
|
||||
if (!this._bundle) {
|
||||
console.warn(`[BundleProxy] Bundle未加载,无法释放资源: ${this._bundleName}/${path}`);
|
||||
return;
|
||||
}
|
||||
|
||||
this._bundle.release(path);
|
||||
console.log(`[BundleProxy] 释放资源: ${this._bundleName}/${path}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放目录资源
|
||||
* @param dir 目录路径
|
||||
*/
|
||||
releaseDir(dir: string): void {
|
||||
if (!this._bundle) {
|
||||
console.warn(`[BundleProxy] Bundle未加载,无法释放目录: ${this._bundleName}/${dir}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Cocos没有直接的releaseDir方法,需要手动释放目录下的资源
|
||||
// 这里简化处理,实际使用时可能需要追踪加载的资源
|
||||
console.log(`[BundleProxy] 释放目录资源: ${this._bundleName}/${dir}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放所有资源
|
||||
*/
|
||||
releaseAll(): void {
|
||||
if (!this._bundle) {
|
||||
console.warn(`[BundleProxy] Bundle未加载,无法释放所有资源: ${this._bundleName}`);
|
||||
return;
|
||||
}
|
||||
|
||||
this._bundle.releaseAll();
|
||||
console.log(`[BundleProxy] 释放所有资源: ${this._bundleName}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁Bundle
|
||||
*/
|
||||
destroy(): void {
|
||||
if (this._bundle) {
|
||||
this.releaseAll();
|
||||
this._bundle = null;
|
||||
}
|
||||
this._loading = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "728bdb32-e73a-4fae-b942-b66412e95c6a",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
11
client/assets/scripts/Framework/ResMgr/README.md.meta
Normal file
11
client/assets/scripts/Framework/ResMgr/README.md.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ver": "1.0.1",
|
||||
"importer": "text",
|
||||
"imported": true,
|
||||
"uuid": "3ab80465-bd0c-4023-b253-b019b2c686df",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -1,39 +1,41 @@
|
||||
import { Asset, AssetManager, assetManager, resources } from 'cc';
|
||||
import { BundleProxy } from './BundleProxy';
|
||||
import { ResProxy } from './ResProxy';
|
||||
|
||||
/**
|
||||
* 资源管理器
|
||||
* 职责:
|
||||
* - 统一管理资源加载
|
||||
* - 提供从bundle中按路径加载资源的接口
|
||||
* - 支持资源预加载
|
||||
* - 统一管理Bundle和资源
|
||||
* - 提供BundleProxy和ResProxy的创建和管理
|
||||
* - 提供便捷的资源加载接口
|
||||
* - 管理资源缓存和释放
|
||||
*/
|
||||
export class ResMgr {
|
||||
private static _instance: ResMgr | null = null;
|
||||
|
||||
/**
|
||||
* 资源缓存
|
||||
* key: bundleName:path
|
||||
* value: Asset
|
||||
* BundleProxy缓存
|
||||
* key: bundleName
|
||||
* value: BundleProxy
|
||||
*/
|
||||
private _cache: Map<string, Asset>;
|
||||
private _bundleProxies: Map<string, BundleProxy>;
|
||||
|
||||
/**
|
||||
* Bundle缓存
|
||||
* key: bundleName
|
||||
* value: AssetManager.Bundle
|
||||
* ResProxy缓存
|
||||
* key: bundleName:path
|
||||
* value: ResProxy
|
||||
*/
|
||||
private _bundles: Map<string, AssetManager.Bundle>;
|
||||
private _resProxies: Map<string, ResProxy<any>>;
|
||||
|
||||
/**
|
||||
* 构造函数(私有)
|
||||
*/
|
||||
private constructor() {
|
||||
this._cache = new Map<string, Asset>();
|
||||
this._bundles = new Map<string, AssetManager.Bundle>();
|
||||
this._bundleProxies = new Map<string, BundleProxy>();
|
||||
this._resProxies = new Map<string, ResProxy<any>>();
|
||||
|
||||
// 默认添加resources bundle
|
||||
this._bundles.set('resources', resources);
|
||||
this._bundleProxies.set('resources', new BundleProxy('resources', resources));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,27 +48,6 @@ export class ResMgr {
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Bundle
|
||||
* @param bundleName bundle名称
|
||||
*/
|
||||
private getBundle(bundleName: string): AssetManager.Bundle | null {
|
||||
// 从缓存中获取
|
||||
if (this._bundles.has(bundleName)) {
|
||||
return this._bundles.get(bundleName)!;
|
||||
}
|
||||
|
||||
// 使用 assetManager.getBundle() 方法获取已加载的 Bundle
|
||||
const bundle = assetManager.getBundle(bundleName);
|
||||
if (bundle) {
|
||||
this._bundles.set(bundleName, bundle);
|
||||
return bundle;
|
||||
}
|
||||
|
||||
console.error(`[ResMgr] Bundle "${bundleName}" 不存在`);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成缓存key
|
||||
*/
|
||||
@@ -74,6 +55,55 @@ export class ResMgr {
|
||||
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名称
|
||||
@@ -81,44 +111,13 @@ export class ResMgr {
|
||||
* @param type 资源类型
|
||||
* @returns Promise<资源>
|
||||
*/
|
||||
load<T extends Asset>(
|
||||
async load<T extends Asset>(
|
||||
bundleName: string,
|
||||
path: string,
|
||||
type: new (...args: any[]) => T
|
||||
): Promise<T> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const cacheKey = this.getCacheKey(bundleName, path);
|
||||
|
||||
// 检查缓存
|
||||
if (this._cache.has(cacheKey)) {
|
||||
const cached = this._cache.get(cacheKey) as T;
|
||||
console.log(`[ResMgr] 从缓存加载资源: ${path}`);
|
||||
resolve(cached);
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取bundle
|
||||
const bundle = this.getBundle(bundleName);
|
||||
if (!bundle) {
|
||||
reject(new Error(`Bundle "${bundleName}" 不存在`));
|
||||
return;
|
||||
}
|
||||
|
||||
// 加载资源
|
||||
console.log(`[ResMgr] 开始加载资源: ${bundleName}/${path}`);
|
||||
bundle.load(path, type, (err, asset) => {
|
||||
if (err) {
|
||||
console.error(`[ResMgr] 加载资源失败: ${bundleName}/${path}`, err);
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// 缓存资源
|
||||
this._cache.set(cacheKey, asset as Asset);
|
||||
console.log(`[ResMgr] 资源加载成功: ${bundleName}/${path}`);
|
||||
resolve(asset as T);
|
||||
});
|
||||
});
|
||||
const resProxy = this.getResProxy(bundleName, path, type);
|
||||
return resProxy.load();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,43 +128,14 @@ export class ResMgr {
|
||||
* @param onProgress 进度回调
|
||||
* @returns Promise<void>
|
||||
*/
|
||||
preload<T extends Asset>(
|
||||
async preload<T extends Asset>(
|
||||
bundleName: string,
|
||||
path: string,
|
||||
type: new (...args: any[]) => T,
|
||||
onProgress?: (finished: number, total: number) => void
|
||||
): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 获取bundle
|
||||
const bundle = this.getBundle(bundleName);
|
||||
if (!bundle) {
|
||||
reject(new Error(`Bundle "${bundleName}" 不存在`));
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[ResMgr] 开始预加载资源: ${bundleName}/${path}`);
|
||||
|
||||
// 预加载资源
|
||||
bundle.preload(
|
||||
path,
|
||||
type,
|
||||
(finished, total) => {
|
||||
if (onProgress) {
|
||||
onProgress(finished, total);
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
if (err) {
|
||||
console.error(`[ResMgr] 预加载资源失败: ${bundleName}/${path}`, err);
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[ResMgr] 资源预加载成功: ${bundleName}/${path}`);
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
const resProxy = this.getResProxy(bundleName, path, type);
|
||||
return resProxy.preload(onProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,42 +143,35 @@ export class ResMgr {
|
||||
* @param bundleName bundle名称
|
||||
* @param dir 目录路径
|
||||
* @param type 资源类型
|
||||
* @param onProgress 进度回调
|
||||
* @returns Promise<资源数组>
|
||||
*/
|
||||
loadDir<T extends Asset>(
|
||||
async loadDir<T extends Asset>(
|
||||
bundleName: string,
|
||||
dir: string,
|
||||
type: new (...args: any[]) => T
|
||||
type: new (...args: any[]) => T,
|
||||
onProgress?: (finished: number, total: number) => void
|
||||
): Promise<T[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 获取bundle
|
||||
const bundle = this.getBundle(bundleName);
|
||||
if (!bundle) {
|
||||
reject(new Error(`Bundle "${bundleName}" 不存在`));
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[ResMgr] 开始加载目录: ${bundleName}/${dir}`);
|
||||
|
||||
// 加载目录
|
||||
bundle.loadDir(dir, type, (err, assets) => {
|
||||
if (err) {
|
||||
console.error(`[ResMgr] 加载目录失败: ${bundleName}/${dir}`, err);
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// 缓存所有资源
|
||||
assets.forEach((asset) => {
|
||||
const path = `${dir}/${asset.name}`;
|
||||
const cacheKey = this.getCacheKey(bundleName, path);
|
||||
this._cache.set(cacheKey, asset);
|
||||
});
|
||||
|
||||
console.log(`[ResMgr] 目录加载成功: ${bundleName}/${dir}, 共 ${assets.length} 个资源`);
|
||||
resolve(assets as 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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -219,17 +182,16 @@ export class ResMgr {
|
||||
release(bundleName: string, path: string): void {
|
||||
const cacheKey = this.getCacheKey(bundleName, path);
|
||||
|
||||
// 从缓存中移除
|
||||
if (this._cache.has(cacheKey)) {
|
||||
const asset = this._cache.get(cacheKey)!;
|
||||
this._cache.delete(cacheKey);
|
||||
|
||||
// 释放资源
|
||||
const bundle = this.getBundle(bundleName);
|
||||
if (bundle) {
|
||||
bundle.release(path);
|
||||
console.log(`[ResMgr] 释放资源: ${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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,55 +201,136 @@ export class ResMgr {
|
||||
* @param dir 目录路径
|
||||
*/
|
||||
releaseDir(bundleName: string, dir: string): void {
|
||||
// 释放所有以dir开头的缓存资源
|
||||
// 释放所有以dir开头的ResProxy
|
||||
const prefix = `${bundleName}:${dir}`;
|
||||
const keysToDelete: string[] = [];
|
||||
|
||||
this._cache.forEach((_, key) => {
|
||||
this._resProxies.forEach((resProxy, key) => {
|
||||
if (key.startsWith(prefix)) {
|
||||
resProxy.release();
|
||||
keysToDelete.push(key);
|
||||
}
|
||||
});
|
||||
|
||||
// 可选:从缓存中移除ResProxy
|
||||
keysToDelete.forEach((key) => {
|
||||
this._cache.delete(key);
|
||||
// this._resProxies.delete(key);
|
||||
});
|
||||
|
||||
// 释放目录
|
||||
const bundle = this.getBundle(bundleName);
|
||||
if (bundle) {
|
||||
bundle.releaseAll();
|
||||
console.log(`[ResMgr] 释放目录资源: ${bundleName}/${dir}, 共 ${keysToDelete.length} 个资源`);
|
||||
}
|
||||
// 从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._cache.size} 个`);
|
||||
this._cache.clear();
|
||||
console.log(`[ResMgr] 释放所有资源, 共 ${this._resProxies.size} 个ResProxy`);
|
||||
|
||||
// 释放所有bundle的资源
|
||||
this._bundles.forEach((bundle, name) => {
|
||||
// 释放所有ResProxy
|
||||
this._resProxies.forEach((resProxy) => {
|
||||
resProxy.release();
|
||||
});
|
||||
this._resProxies.clear();
|
||||
|
||||
// 释放所有BundleProxy的资源(除了resources)
|
||||
this._bundleProxies.forEach((bundleProxy, name) => {
|
||||
if (name !== 'resources') {
|
||||
bundle.releaseAll();
|
||||
bundleProxy.releaseAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存大小
|
||||
* 获取缓存的ResProxy数量
|
||||
*/
|
||||
getCacheSize(): number {
|
||||
return this._cache.size;
|
||||
return this._resProxies.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存的BundleProxy数量
|
||||
*/
|
||||
getBundleCount(): number {
|
||||
return this._bundleProxies.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空缓存(不释放资源)
|
||||
*/
|
||||
clearCache(): void {
|
||||
console.log(`[ResMgr] 清空缓存, 共 ${this._cache.size} 个`);
|
||||
this._cache.clear();
|
||||
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}`);
|
||||
}
|
||||
}
|
||||
|
||||
171
client/assets/scripts/Framework/ResMgr/ResProxy.ts
Normal file
171
client/assets/scripts/Framework/ResMgr/ResProxy.ts
Normal file
@@ -0,0 +1,171 @@
|
||||
import { Asset } from 'cc';
|
||||
import { BundleProxy } from './BundleProxy';
|
||||
|
||||
/**
|
||||
* 资源代理类
|
||||
* 职责:
|
||||
* - 封装单个资源的异步加载逻辑
|
||||
* - 管理资源的缓存状态
|
||||
* - 提供资源的加载、预加载、释放接口
|
||||
*/
|
||||
export class ResProxy<T extends Asset> {
|
||||
private _bundleProxy: BundleProxy;
|
||||
private _path: string;
|
||||
private _type: new (...args: any[]) => T;
|
||||
private _asset: T | null = null;
|
||||
private _loading: Promise<T> | null = null;
|
||||
private _preloading: Promise<void> | null = null;
|
||||
|
||||
constructor(
|
||||
bundleProxy: BundleProxy,
|
||||
path: string,
|
||||
type: new (...args: any[]) => T
|
||||
) {
|
||||
this._bundleProxy = bundleProxy;
|
||||
this._path = path;
|
||||
this._type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取资源路径
|
||||
*/
|
||||
get path(): string {
|
||||
return this._path;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Bundle名称
|
||||
*/
|
||||
get bundleName(): string {
|
||||
return this._bundleProxy.bundleName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取资源实例(同步)
|
||||
*/
|
||||
get asset(): T | null {
|
||||
return this._asset;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否已加载
|
||||
*/
|
||||
get isLoaded(): boolean {
|
||||
return this._asset !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否正在加载中
|
||||
*/
|
||||
get isLoading(): boolean {
|
||||
return this._loading !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否正在预加载中
|
||||
*/
|
||||
get isPreloading(): boolean {
|
||||
return this._preloading !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载资源
|
||||
* @returns Promise<资源>
|
||||
*/
|
||||
async load(): Promise<T> {
|
||||
// 如果已经加载完成,直接返回
|
||||
if (this._asset) {
|
||||
console.log(`[ResProxy] 从缓存获取资源: ${this.bundleName}/${this._path}`);
|
||||
return this._asset;
|
||||
}
|
||||
|
||||
// 如果正在加载中,返回加载Promise
|
||||
if (this._loading) {
|
||||
return this._loading;
|
||||
}
|
||||
|
||||
// 开始加载
|
||||
this._loading = this._bundleProxy.loadRes(this._path, this._type);
|
||||
|
||||
try {
|
||||
this._asset = await this._loading;
|
||||
return this._asset;
|
||||
} finally {
|
||||
this._loading = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预加载资源
|
||||
* @param onProgress 进度回调
|
||||
* @returns Promise<void>
|
||||
*/
|
||||
async preload(onProgress?: (finished: number, total: number) => void): Promise<void> {
|
||||
// 如果已经加载完成,直接返回
|
||||
if (this._asset) {
|
||||
console.log(`[ResProxy] 资源已加载,无需预加载: ${this.bundleName}/${this._path}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果正在预加载中,返回预加载Promise
|
||||
if (this._preloading) {
|
||||
return this._preloading;
|
||||
}
|
||||
|
||||
// 如果正在加载中,等待加载完成
|
||||
if (this._loading) {
|
||||
await this._loading;
|
||||
return;
|
||||
}
|
||||
|
||||
// 开始预加载
|
||||
this._preloading = this._bundleProxy.preload(this._path, this._type, onProgress);
|
||||
|
||||
try {
|
||||
await this._preloading;
|
||||
} finally {
|
||||
this._preloading = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放资源
|
||||
*/
|
||||
release(): void {
|
||||
if (!this._asset) {
|
||||
console.warn(`[ResProxy] 资源未加载,无法释放: ${this.bundleName}/${this._path}`);
|
||||
return;
|
||||
}
|
||||
|
||||
this._bundleProxy.release(this._path);
|
||||
this._asset = null;
|
||||
console.log(`[ResProxy] 释放资源: ${this.bundleName}/${this._path}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存(不释放资源)
|
||||
*/
|
||||
clearCache(): void {
|
||||
this._asset = null;
|
||||
this._loading = null;
|
||||
this._preloading = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新加载资源
|
||||
* @returns Promise<资源>
|
||||
*/
|
||||
async reload(): Promise<T> {
|
||||
if (this._asset) {
|
||||
this.release();
|
||||
}
|
||||
return this.load();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取完整路径
|
||||
*/
|
||||
getFullPath(): string {
|
||||
return `${this.bundleName}/${this._path}`;
|
||||
}
|
||||
}
|
||||
9
client/assets/scripts/Framework/ResMgr/ResProxy.ts.meta
Normal file
9
client/assets/scripts/Framework/ResMgr/ResProxy.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "e33b5325-cbc7-4082-9e05-093bb8478e2d",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
Reference in New Issue
Block a user