import { Asset, AssetManager, Constructor, __private, assetManager, error, js, resources } from "cc"; export type ProgressCallback = __private._cocos_asset_asset_manager_deprecated__LoadProgressCallback; export type CompleteCallback = any; // (error: Error | null, asset: T) => void; (error: Error | null, asset: T[], urls: string[]) => void; export type IRemoteOptions = { [k: string]: any; ext?: string; } | null; export type AssetType = Constructor; interface ILoadResArgs { bundle?: string; dir?: string; paths: string | string[]; type: AssetType | null; onProgress: ProgressCallback | null; onComplete: CompleteCallback | null; } /** * 游戏资管理 * 1、加载默认resources文件夹中资源 * 2、加载默认bundle远程资源 * 3、主动传递bundle名时,优先加载传递bundle名资源包中的资源 */ export class ResLoader { /** 全局默认加载的资源包名 */ defaultBundleName: string = "resources"; /** * 加载远程资源 * @param url 资源地址 * @param options 资源参数,例:{ ext: ".png" } * @param onComplete 加载完成回调 * @example var opt: IRemoteOptions = { ext: ".png" }; var onComplete = (err: Error | null, data: ImageAsset) => { const texture = new Texture2D(); texture.image = data; const spriteFrame = new SpriteFrame(); spriteFrame.texture = texture; var sprite = this.sprite.addComponent(Sprite); sprite.spriteFrame = spriteFrame; } oops.res.loadRemote(this.url, opt, onComplete); */ loadRemote(url: string, options: IRemoteOptions | null, onComplete?: CompleteCallback | null): void; loadRemote(url: string, onComplete?: CompleteCallback | null): void; loadRemote(url: string, ...args: any): void { var options: IRemoteOptions | null = null; var onComplete: CompleteCallback | null = null; if (args.length == 2) { options = args[0]; onComplete = args[1]; } else { onComplete = args[0]; } assetManager.loadRemote(url, options, onComplete); } /** * 加载资源包 * @param url 资源地址 * @param complete 完成事件 * @param v 资源MD5版本号 * @example var serverUrl = "http://192.168.1.8:8080/"; // 服务器地址 var md5 = "8e5c0"; // Cocos Creator 构建后的MD5字符 await oops.res.loadBundle(serverUrl,md5); */ loadBundle(url: string, v?: string) { return new Promise((resolve, reject) => { assetManager.loadBundle(url, { version: v }, (err, bundle: AssetManager.Bundle) => { if (err) { return error(err); } resolve(bundle); }); }); } /** * 加载一个资源 * @param bundleName 远程包名 * @param paths 资源路径 * @param type 资源类型 * @param onProgress 加载进度回调 * @param onComplete 加载完成回调 * @example oops.res.load("spine_path", sp.SkeletonData, (err: Error | null, sd: sp.SkeletonData) => { }); */ load(bundleName: string, paths: string | string[], type: AssetType | null, onProgress: ProgressCallback | null, onComplete: CompleteCallback | null): void; load(bundleName: string, paths: string | string[], onProgress: ProgressCallback | null, onComplete: CompleteCallback | null): void; load(bundleName: string, paths: string | string[], onComplete?: CompleteCallback | null): void; load(bundleName: string, paths: string | string[], type: AssetType | null, onComplete?: CompleteCallback | null): void; load(paths: string | string[], type: AssetType | null, onProgress: ProgressCallback | null, onComplete: CompleteCallback | null): void; load(paths: string | string[], onProgress: ProgressCallback | null, onComplete: CompleteCallback | null): void; load(paths: string | string[], onComplete?: CompleteCallback | null): void; load(paths: string | string[], type: AssetType | null, onComplete?: CompleteCallback | null): void; load( bundleName: string, paths?: string | string[] | AssetType | ProgressCallback | CompleteCallback | null, type?: AssetType | ProgressCallback | CompleteCallback | null, onProgress?: ProgressCallback | CompleteCallback | null, onComplete?: CompleteCallback | null, ) { let args: ILoadResArgs | null = null; if (typeof paths === "string" || paths instanceof Array) { args = this.parseLoadResArgs(paths, type, onProgress, onComplete); args.bundle = bundleName; } else { args = this.parseLoadResArgs(bundleName, paths, type, onProgress); args.bundle = this.defaultBundleName; } this.loadByArgs(args); } loadAsync(bundleName: string, paths: string | string[], type: AssetType | null): Promise; loadAsync(bundleName: string, paths: string | string[]): Promise; loadAsync(bundleName: string, paths: string | string[]): Promise; loadAsync(bundleName: string, paths: string | string[], type: AssetType | null): Promise; loadAsync(paths: string | string[], type: AssetType | null): Promise; loadAsync(paths: string | string[]): Promise; loadAsync(paths: string | string[]): Promise; loadAsync(paths: string | string[], type: AssetType | null): Promise; loadAsync(bundleName: string, paths?: string | string[] | AssetType | ProgressCallback | CompleteCallback | null, type?: AssetType | ProgressCallback | CompleteCallback | null): Promise { return new Promise((resolve, reject) => { this.load(bundleName, paths, type, (err: Error | null, asset: T) => { if (err) { error(err.message); } resolve(asset); }); }); } /** * 加载文件夹中的资源 * @param bundleName 远程包名 * @param dir 文件夹名 * @param type 资源类型 * @param onProgress 加载进度回调 * @param onComplete 加载完成回调 * @example // 加载进度事件 var onProgressCallback = (finished: number, total: number, item: any) => { console.log("资源加载进度", finished, total); } // 加载完成事件 var onCompleteCallback = () => { console.log("资源加载完成"); } oops.res.loadDir("game", onProgressCallback, onCompleteCallback); */ loadDir(bundleName: string, dir: string, type: AssetType | null, onProgress: ProgressCallback | null, onComplete: CompleteCallback | null): void; loadDir(bundleName: string, dir: string, onProgress: ProgressCallback | null, onComplete: CompleteCallback | null): void; loadDir(bundleName: string, dir: string, onComplete?: CompleteCallback | null): void; loadDir(bundleName: string, dir: string, type: AssetType | null, onComplete?: CompleteCallback | null): void; loadDir(dir: string, type: AssetType | null, onProgress: ProgressCallback | null, onComplete: CompleteCallback | null): void; loadDir(dir: string, onProgress: ProgressCallback | null, onComplete: CompleteCallback | null): void; loadDir(dir: string, onComplete?: CompleteCallback | null): void; loadDir(dir: string, type: AssetType | null, onComplete?: CompleteCallback | null): void; loadDir( bundleName: string, dir?: string | AssetType | ProgressCallback | CompleteCallback | null, type?: AssetType | ProgressCallback | CompleteCallback | null, onProgress?: ProgressCallback | CompleteCallback | null, onComplete?: CompleteCallback | null, ) { let args: ILoadResArgs | null = null; if (typeof dir === "string") { args = this.parseLoadResArgs(dir, type, onProgress, onComplete); args.bundle = bundleName; } else { args = this.parseLoadResArgs(bundleName, dir, type, onProgress); args.bundle = this.defaultBundleName; } args.dir = args.paths as string; this.loadByArgs(args); } /** * 通过资源相对路径释放资源 * @param path 资源路径 * @param bundleName 远程资源包名 */ release(path: string, bundleName?: string) { if (bundleName == null) bundleName = this.defaultBundleName; var bundle = assetManager.getBundle(bundleName); if (bundle) { var asset = bundle.get(path); if (asset) { this.releasePrefabtDepsRecursively(asset); } } } /** * 通过相对文件夹路径删除所有文件夹中资源 * @param path 资源文件夹路径 * @param bundleName 远程资源包名 */ releaseDir(path: string, bundleName?: string) { if (bundleName == null) bundleName = this.defaultBundleName; var bundle: AssetManager.Bundle | null = assetManager.getBundle(bundleName); if (bundle) { var infos = bundle.getDirWithPath(path); if (infos) { infos.map((info) => { this.releasePrefabtDepsRecursively(info.uuid); }); } if (path == "" && bundleName != "resources") { assetManager.removeBundle(bundle); } } } /** 释放预制依赖资源 */ private releasePrefabtDepsRecursively(uuid: string | Asset) { if (uuid instanceof Asset) { uuid.decRef(); // assetManager.releaseAsset(uuid); } else { var asset = assetManager.assets.get(uuid); if (asset) { asset.decRef(); // assetManager.releaseAsset(asset); } } // Cocos引擎内部已处理子关联资源的释放 // if (asset instanceof Prefab) { // var uuids: string[] = assetManager.dependUtil.getDepsRecursively(uuid)!; // uuids.forEach(uuid => { // var asset = assetManager.assets.get(uuid)!; // asset.decRef(); // }); // } } /** * 获取资源 * @param path 资源路径 * @param type 资源类型 * @param bundleName 远程资源包名 */ get(path: string, type?: __private.__types_globals__Constructor | null, bundleName?: string): T | null { if (bundleName == null) bundleName = this.defaultBundleName; var bundle: AssetManager.Bundle = assetManager.getBundle(bundleName)!; return bundle.get(path, type); } /** 打印缓存中所有资源信息 */ dump() { assetManager.assets.forEach((value: Asset, key: string) => { console.log(assetManager.assets.get(key)); }) console.log(`当前资源总数:${assetManager.assets.count}`); } private parseLoadResArgs( paths: string | string[], type?: AssetType | ProgressCallback | CompleteCallback | null, onProgress?: AssetType | ProgressCallback | CompleteCallback | null, onComplete?: ProgressCallback | CompleteCallback | null ) { let pathsOut: any = paths; let typeOut: any = type; let onProgressOut: any = onProgress; let onCompleteOut: any = onComplete; if (onComplete === undefined) { const isValidType = js.isChildClassOf(type as AssetType, Asset); if (onProgress) { onCompleteOut = onProgress as CompleteCallback; if (isValidType) { onProgressOut = null; } } else if (onProgress === undefined && !isValidType) { onCompleteOut = type as CompleteCallback; onProgressOut = null; typeOut = null; } if (onProgress !== undefined && !isValidType) { onProgressOut = type as ProgressCallback; typeOut = null; } } return { paths: pathsOut, type: typeOut, onProgress: onProgressOut, onComplete: onCompleteOut }; } private loadByBundleAndArgs(bundle: AssetManager.Bundle, args: ILoadResArgs): void { if (args.dir) { bundle.loadDir(args.paths as string, args.type, args.onProgress, args.onComplete); } else { if (typeof args.paths == 'string') { bundle.load(args.paths, args.type, args.onProgress, args.onComplete); } else { bundle.load(args.paths, args.type, args.onProgress, args.onComplete); } } } private loadByArgs(args: ILoadResArgs) { if (args.bundle) { if (assetManager.bundles.has(args.bundle)) { let bundle = assetManager.bundles.get(args.bundle); this.loadByBundleAndArgs(bundle!, args); } else { // 自动加载bundle assetManager.loadBundle(args.bundle, (err, bundle) => { if (!err) { this.loadByBundleAndArgs(bundle, args); } }) } } else { this.loadByBundleAndArgs(resources, args); } } }