123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- import AssetsBundleMgr from "../../utils/AssetsBundleMgr";
- import { EResType } from "./ResBaseAsset";
- import { ResCollector } from "./ResCollector";
- const { ccclass } = cc._decorator;
- declare global {
- /**
- * !API
- */
- interface IResKeeper {
- // 组件销毁时自动释放某个资源
- AutoReleaseAsset<T extends cc.Asset>(asset: T, url: string): void;
- // 加载资源
- LoadResCollector(resCollector: ResCollector, promise: IPromiseFunc): Promise<void>;
- }
- }
- /**
- * 销毁时自动释放资源组件
- */
- // @ccclass("ResKeeper")
- @ccclass
- export class ResKeeper extends cc.Component implements IResKeeper {
- /** 是否调试状态 */
- static DEBUG: boolean = CC_PREVIEW ? true : false;
- private _i_LoadedAssets: Array<AssetKeepItem> = undefined;
- /** 已加载资源列表 */
- private get m_LoadedAssets(): Array<AssetKeepItem> {
- if (!this._i_LoadedAssets) {
- this._i_LoadedAssets = [];
- }
- return this._i_LoadedAssets;
- }
- /**
- * 从目标节点或其父节点递归查找一个资源挂载(销毁时自动释放)组件
- * @param attachNode 目标节点
- * @param autoCreate 当目标节点找不到 ResKeeper 时是否自动创建一个
- */
- public static Get(attachNode: cc.Node, autoCreate: boolean = false): IResKeeper {
- if (attachNode && cc.isValid(attachNode)) {
- let ret = attachNode.getComponent(ResKeeper);
- if (!ret) {
- if (autoCreate) {
- return attachNode.addComponent(ResKeeper);
- } else {
- if (!attachNode.parent) {
- console.error(`ResKeeper >> attachNode 的父节点不存在 >> attachNode.name = ${attachNode.name}`);
- return null;
- }
- return ResKeeper.Get(attachNode.parent, autoCreate);
- }
- }
- return ret;
- }
- console.error(`ResKeeper >> attachNode 为空节点`);
- return null;
- }
- /**
- * 加载自动释放的资源
- * @param resCollector
- */
- async LoadResCollector(resCollector: ResCollector, promise: IPromiseFunc): Promise<void> {
- const that = this;
- let __bindAutoReleaseAssetToComp = <T extends cc.Asset>(url: string, res: T) => {
- // 性能调优: 调试状态才打印加载的 url
- // ResKeeper.DEBUG && console.log(`url: ${url} 加载成功`)
- if (cc.isValid(that)) {
- that.AutoReleaseAsset(res, url);
- } else {
- console.warn("资源加载完毕时,节点已不可用")
- }
- }
- let _onResLoaded = (url: string, err, res, resolve) => {
- if (err) {
- console.error(err);
- /** 释放加载项 */
- resolve();
- return;
- }
- __bindAutoReleaseAssetToComp(url, res);
- resolve();
- }
- let proArr: Promise<cc.Asset>[] = [];
- resCollector.GetResList().forEach(loadAssetItem => {
- proArr.push(new Promise((resolve, reject) => {
- switch (loadAssetItem.typ) {
- case EResType.Prefab: {
- const bundleUrl = loadAssetItem.data;
- AssetsBundleMgr.loadBundle(bundleUrl.bundle, (err, bundle) => {
- if (err) {
- console.log("SpineNode:bundle load failed:", err)
- return
- }
- // let cacheAsset = bundle.get(bundleUrl.url, cc.Prefab);
- // if (cacheAsset) {
- // _onResLoaded(bundleUrl.url, err, cacheAsset, resolve);
- // } else {
- bundle.load(bundleUrl.url, cc.Prefab, (err: Error, asset: cc.Prefab) => {
- _onResLoaded(bundleUrl.url, err, asset, resolve);
- })
- // }
- })
- } break;
- case EResType.Spine: {
- const bundleUrl = loadAssetItem.data;
- AssetsBundleMgr.loadBundle(bundleUrl.bundle, (err, bundle) => {
- if (err) {
- console.log("SpineNode:bundle load failed:", err)
- return
- }
- // let cacheAsset = bundle.get(bundleUrl.url, cc.Prefab);
- // if (cacheAsset) {
- // _onResLoaded(bundleUrl.url, err, cacheAsset, resolve);
- // } else {
- bundle.load(bundleUrl.url, sp.SkeletonData, (err: Error, asset: sp.SkeletonData) => {
- _onResLoaded(bundleUrl.url, err, asset, resolve);
- })
- // }
- })
- } break;
- case EResType.SpriteFrame: {
- const bundleUrl = loadAssetItem.data;
- AssetsBundleMgr.loadBundle(bundleUrl.bundle, (err, bundle) => {
- if (err) {
- console.log("SpriteFrame:bundle load failed:", err)
- return
- }
- bundle.load(bundleUrl.url, cc.SpriteFrame, (err: Error, asset: cc.SpriteFrame) => {
- _onResLoaded(bundleUrl.url, err, asset, resolve);
- })
- })
- } break;
- case EResType.Json: {
- const bundleUrl = loadAssetItem.data;
- AssetsBundleMgr.loadBundle(bundleUrl.bundle, (err, bundle) => {
- if (err) {
- console.log("SpriteFrame:bundle load failed:", err)
- return
- }
- bundle.load(bundleUrl.url, cc.JsonAsset, (err: Error, asset: cc.JsonAsset) => {
- _onResLoaded(bundleUrl.url, err, asset, resolve);
- })
- })
- } break;
- default: {
- console.error(`【ResKeeper】 >> 未处理的资源加载类型 ${loadAssetItem.typ}`)
- } break;
- }
- }))
- });
- return promise(async (resolve, reject) => {
- await Promise.all(proArr).then((values) => {
- resolve();
- });
- });
- }
- /**
- * 添加自动释放引用
- * @param keepItem
- */
- AutoReleaseAsset<T extends cc.Asset>(asset: T, url: string): void {
- /** Borrow 时自动添加了引用计数,销毁时,解引用即可 */
- this.m_LoadedAssets.push(new AssetKeepItem(asset, url));
- }
- /**
- * 释放所有引用的资源
- */
- onDestroy() {
- if (this._i_LoadedAssets) {
- this._i_LoadedAssets.forEach(it => {
- if (it && it.DecRef) {
- it.DecRef()
- }
- });
- this._i_LoadedAssets = undefined;
- }
- }
- }
- class AssetKeepItem {
- // --------------------------------
- mAsset: cc.Asset;
- mUrl: string;
- constructor(asset: cc.Asset, url: string) {
- this.mAsset = asset;
- this.mUrl = url;
- this.AddRef();
- }
- public AddRef(): void {
- this.mAsset.addRef();
- }
- public DecRef(): void {
- this.mAsset.decRef();
- }
- }
|