diff --git a/assets/Script/example/ResExample.ts b/assets/Script/example/ResExample.ts index bb71db3..d720817 100644 --- a/assets/Script/example/ResExample.ts +++ b/assets/Script/example/ResExample.ts @@ -1,4 +1,4 @@ -import { kx } from "../res/ResLoader"; +import { resLoader } from "../res/ResLoader"; const { ccclass, property } = cc._decorator; @@ -19,11 +19,11 @@ export default class NetExample extends cc.Component { onUnloadRes() { this.attachNode.removeAllChildren(true); - cc.loader.releaseRes("Prefab/HelloWorld"); + resLoader.releaseRes("Prefab/HelloWorld"); } onMyLoadRes() { - kx.loader.loadRes("Prefab/HelloWorld", cc.Prefab, (error: Error, prefab: cc.Prefab) => { + resLoader.loadRes("Prefab/HelloWorld", cc.Prefab, (error: Error, prefab: cc.Prefab) => { if (!error) { cc.instantiate(prefab).parent = this.attachNode; } @@ -32,7 +32,7 @@ export default class NetExample extends cc.Component { onMyUnloadRes() { this.attachNode.removeAllChildren(true); - kx.loader.releaseRes("Prefab/HelloWorld"); + resLoader.releaseRes("Prefab/HelloWorld"); } onDump() { diff --git a/assets/Script/res/ResLoader.ts b/assets/Script/res/ResLoader.ts index b7093a7..7194b48 100644 --- a/assets/Script/res/ResLoader.ts +++ b/assets/Script/res/ResLoader.ts @@ -7,298 +7,296 @@ * 2018-7-17 by 宝爷 */ -export namespace kx { +// 资源加载的处理回调 +export type ProcessCallback = (completedCount: number, totalCount: number, item: any) => void; +// 资源加载的完成回调 +export type CompletedCallback = (error: Error, resource: any) => void; - // 资源加载的处理回调 - export type ProcessCallback = (completedCount: number, totalCount: number, item: any) => void; - // 资源加载的完成回调 - export type CompletedCallback = (error: Error, resource: any) => void; - - // 引用和使用的结构体 - interface CacheInfo { - refs: Set, - uses: Set - } - - // LoadRes方法的参数结构 - interface LoadResArgs { - url: string, - type?: typeof cc.Asset, - onCompleted?: CompletedCallback, - onProgess?: ProcessCallback, - use?: string, - } - - // ReleaseRes方法的参数结构 - interface ReleaseResArgs { - url: string, - type?: typeof cc.Asset, - use?: string, - } - - // 兼容性处理 - let isChildClassOf = cc.js["isChildClassOf"] - if (!isChildClassOf) { - isChildClassOf = cc["isChildClassOf"]; - } - - export class ResLoader { - - private _resMap: Map = new Map(); - - /** - * 从cc.loader中获取一个资源的item - * @param url 查询的url - * @param type 查询的资源类型 - */ - private _getResItem(url: string, type: typeof cc.Asset): any { - let ccloader: any = cc.loader; - let item = ccloader._cache[url]; - if (!item) { - let uuid = ccloader._getResUuid(url, type, false); - if (uuid) { - let ref = ccloader._getReferenceKey(uuid); - item = ccloader._cache[ref]; - } - } - return item; - } - - /** - * loadRes方法的参数预处理 - */ - private _makeLoadResArgs(): LoadResArgs { - if (arguments.length < 1 || typeof arguments[0] != "string") { - console.error(`_makeLoadResArgs error ${arguments}`); - return null; - } - let ret: LoadResArgs = { url: arguments[0] }; - for (let i = 1; i < arguments.length; ++i) { - if (i == 1 && isChildClassOf(arguments[i], cc.RawAsset)) { - // 判断是不是第一个参数type - ret.type = arguments[i]; - } else if (i == arguments.length - 1 && typeof arguments[i] == "string") { - // 判断是不是最后一个参数use - ret.use = arguments[i]; - } else if (typeof arguments[i] == "function") { - // 其他情况为函数 - if (arguments.length > i + 1 && typeof arguments[i + 1] == "function") { - ret.onProgess = arguments[i]; - } else { - ret.onCompleted = arguments[i]; - } - } - } - return ret; - } - - /** - * releaseRes方法的参数预处理 - */ - private _makeReleaseResArgs(): ReleaseResArgs { - if (arguments.length < 1 || typeof arguments[0] != "string") { - console.error(`_makeReleaseResArgs error ${arguments}`); - return null; - } - let ret: ReleaseResArgs = { url: arguments[0] }; - for (let i = 1; i < arguments.length; ++i) { - if (typeof arguments[i] == "string") { - ret.use = arguments[i]; - } else { - ret.type = arguments[i]; - } - } - return ret; - } - - /** - * 生成一个资源使用Key - * @param where 在哪里使用,如Scene、UI、Pool - * @param who 使用者,如Login、UIHelp... - * @param why 使用原因,自定义... - */ - public makeUseKey(where: string, who: string = "none", why: string = ""): string { - return `use_${where}_by_${who}_for_${why}`; - } - - /** - * 获取资源缓存信息 - * @param key 要获取的资源url - */ - public getCacheInfo(key: string): CacheInfo { - if (!this._resMap.has(key)) { - this._resMap.set(key, { - refs: new Set(), - uses: new Set() - }); - } - return this._resMap.get(key); - } - - /** - * 开始加载资源 - * @param url 资源url - * @param type 资源类型,默认为null - * @param onProgess 加载进度回调 - * @param onCompleted 加载完成回调 - * @param use 资源使用key,根据makeUseKey方法生成 - */ - public loadRes(url: string, use?: string); - public loadRes(url: string, onCompleted: CompletedCallback, use?: string); - public loadRes(url: string, onProgess: ProcessCallback, onCompleted: CompletedCallback, use?: string); - public loadRes(url: string, type: typeof cc.Asset, use?: string); - public loadRes(url: string, type: typeof cc.Asset, onCompleted: CompletedCallback, use?: string); - public loadRes(url: string, type: typeof cc.Asset, onProgess: ProcessCallback, onCompleted: CompletedCallback, use?: string); - public loadRes() { - let resArgs: LoadResArgs = this._makeLoadResArgs.apply(this, arguments); - console.time("loadRes|" + resArgs.url); - let finishCallback = (error: Error, resource: any) => { - // 反向关联引用(为所有引用到的资源打上本资源引用到的标记) - let addDependKey = (item, refKey) => { - if (item && item.dependKeys && Array.isArray(item.dependKeys)) { - for (let depKey of item.dependKeys) { - // 记录该资源被我引用 - this.getCacheInfo(depKey).refs.add(refKey); - cc.log(`${depKey} ref by ${refKey}`); - let ccloader: any = cc.loader; - let depItem = ccloader._cache[depKey] - addDependKey(depItem, refKey) - } - } - } - - let item = this._getResItem(resArgs.url, resArgs.type); - if (item && item.id) { - addDependKey(item, item.id); - } else { - cc.warn(`addDependKey item error1! for ${resArgs.url}`); - } - - // 给自己加一个自身的引用 - if (item) { - let info = this.getCacheInfo(item.id); - info.refs.add(item.id); - // 更新资源使用 - if (resArgs.use) { - info.uses.add(resArgs.use); - } - } - - // 执行完成回调 - if (resArgs.onCompleted) { - resArgs.onCompleted(error, resource); - } - console.timeEnd("loadRes|" + resArgs.url); - }; - - // 预判是否资源已加载 - let res = cc.loader.getRes(resArgs.url, resArgs.type); - if (res) { - finishCallback(null, res); - } else { - cc.loader.loadRes(resArgs.url, resArgs.type, resArgs.onProgess, finishCallback); - } - } - - /** - * 释放资源 - * @param url 要释放的url - * @param type 资源类型 - * @param use 要解除的资源使用key,根据makeUseKey方法生成 - */ - public releaseRes(url: string, use?: string); - public releaseRes(url: string, type: typeof cc.Asset, use?: string) - public releaseRes() { - /**暂时不释放资源 */ - // return; - - let resArgs: ReleaseResArgs = this._makeReleaseResArgs.apply(this, arguments); - let item = this._getResItem(resArgs.url, resArgs.type); - if (!item) { - console.warn(`releaseRes item is null ${resArgs.url} ${resArgs.type}`); - return; - } - cc.log("resloader release item"); - // cc.log(arguments); - let cacheInfo = this.getCacheInfo(item.id); - if (resArgs.use) { - cacheInfo.uses.delete(resArgs.use) - } - this._release(item, item.id); - } - - // 释放一个资源 - private _release(item, itemUrl) { - if (!item) { - return; - } - let cacheInfo = this.getCacheInfo(item.id); - // 解除自身对自己的引用 - cacheInfo.refs.delete(itemUrl); - - if (cacheInfo.uses.size == 0 && cacheInfo.refs.size == 0) { - // 解除引用 - let delDependKey = (item, refKey) => { - if (item && item.dependKeys && Array.isArray(item.dependKeys)) { - for (let depKey of item.dependKeys) { - let ccloader: any = cc.loader; - let depItem = ccloader._cache[depKey] - this._release(depItem, refKey); - } - } - } - delDependKey(item, itemUrl); - //如果没有uuid,就直接释放url - if (item.uuid) { - cc.loader.release(item.uuid); - cc.log("resloader release item by uuid :" + item.id); - } else { - cc.loader.release(item.id); - cc.log("resloader release item by url:" + item.id); - } - this._resMap.delete(item.id); - } - } - - /** - * 判断一个资源能否被释放 - * @param url 资源url - * @param type 资源类型 - * @param use 要解除的资源使用key,根据makeUseKey方法生成 - */ - public checkReleaseUse(url: string, use?: string): boolean; - public checkReleaseUse(url: string, type: typeof cc.Asset, use?: string): boolean - public checkReleaseUse() { - let resArgs: ReleaseResArgs = this._makeReleaseResArgs.apply(this, arguments); - let item = this._getResItem(resArgs.url, resArgs.type); - if (!item) { - console.log(`cant release,item is null ${resArgs.url} ${resArgs.type}`); - return true; - } - - let cacheInfo = this.getCacheInfo(item.id); - let checkUse = false; - let checkRef = false; - - if (resArgs.use && cacheInfo.uses.size > 0) { - if (cacheInfo.uses.size == 1 && cacheInfo.uses.has(resArgs.use)) { - checkUse = true; - } else { - checkUse = false; - } - } else { - checkUse = true; - } - - if ((cacheInfo.refs.size == 1 && cacheInfo.refs.has(item.id)) || cacheInfo.refs.size == 0) { - checkRef = true; - } else { - checkRef = false; - } - - return checkUse && checkRef; - } - } - - export let loader: ResLoader = new ResLoader(); +// 引用和使用的结构体 +interface CacheInfo { + refs: Set, + uses: Set } + +// LoadRes方法的参数结构 +interface LoadResArgs { + url: string, + type?: typeof cc.Asset, + onCompleted?: CompletedCallback, + onProgess?: ProcessCallback, + use?: string, +} + +// ReleaseRes方法的参数结构 +interface ReleaseResArgs { + url: string, + type?: typeof cc.Asset, + use?: string, +} + +// 兼容性处理 +let isChildClassOf = cc.js["isChildClassOf"] +if (!isChildClassOf) { + isChildClassOf = cc["isChildClassOf"]; +} + +export class ResLoader { + + private _resMap: Map = new Map(); + + /** + * 从cc.loader中获取一个资源的item + * @param url 查询的url + * @param type 查询的资源类型 + */ + private _getResItem(url: string, type: typeof cc.Asset): any { + let ccloader: any = cc.loader; + let item = ccloader._cache[url]; + if (!item) { + let uuid = ccloader._getResUuid(url, type, false); + if (uuid) { + let ref = ccloader._getReferenceKey(uuid); + item = ccloader._cache[ref]; + } + } + return item; + } + + /** + * loadRes方法的参数预处理 + */ + private _makeLoadResArgs(): LoadResArgs { + if (arguments.length < 1 || typeof arguments[0] != "string") { + console.error(`_makeLoadResArgs error ${arguments}`); + return null; + } + let ret: LoadResArgs = { url: arguments[0] }; + for (let i = 1; i < arguments.length; ++i) { + if (i == 1 && isChildClassOf(arguments[i], cc.RawAsset)) { + // 判断是不是第一个参数type + ret.type = arguments[i]; + } else if (i == arguments.length - 1 && typeof arguments[i] == "string") { + // 判断是不是最后一个参数use + ret.use = arguments[i]; + } else if (typeof arguments[i] == "function") { + // 其他情况为函数 + if (arguments.length > i + 1 && typeof arguments[i + 1] == "function") { + ret.onProgess = arguments[i]; + } else { + ret.onCompleted = arguments[i]; + } + } + } + return ret; + } + + /** + * releaseRes方法的参数预处理 + */ + private _makeReleaseResArgs(): ReleaseResArgs { + if (arguments.length < 1 || typeof arguments[0] != "string") { + console.error(`_makeReleaseResArgs error ${arguments}`); + return null; + } + let ret: ReleaseResArgs = { url: arguments[0] }; + for (let i = 1; i < arguments.length; ++i) { + if (typeof arguments[i] == "string") { + ret.use = arguments[i]; + } else { + ret.type = arguments[i]; + } + } + return ret; + } + + /** + * 生成一个资源使用Key + * @param where 在哪里使用,如Scene、UI、Pool + * @param who 使用者,如Login、UIHelp... + * @param why 使用原因,自定义... + */ + public makeUseKey(where: string, who: string = "none", why: string = ""): string { + return `use_${where}_by_${who}_for_${why}`; + } + + /** + * 获取资源缓存信息 + * @param key 要获取的资源url + */ + public getCacheInfo(key: string): CacheInfo { + if (!this._resMap.has(key)) { + this._resMap.set(key, { + refs: new Set(), + uses: new Set() + }); + } + return this._resMap.get(key); + } + + /** + * 开始加载资源 + * @param url 资源url + * @param type 资源类型,默认为null + * @param onProgess 加载进度回调 + * @param onCompleted 加载完成回调 + * @param use 资源使用key,根据makeUseKey方法生成 + */ + public loadRes(url: string, use?: string); + public loadRes(url: string, onCompleted: CompletedCallback, use?: string); + public loadRes(url: string, onProgess: ProcessCallback, onCompleted: CompletedCallback, use?: string); + public loadRes(url: string, type: typeof cc.Asset, use?: string); + public loadRes(url: string, type: typeof cc.Asset, onCompleted: CompletedCallback, use?: string); + public loadRes(url: string, type: typeof cc.Asset, onProgess: ProcessCallback, onCompleted: CompletedCallback, use?: string); + public loadRes() { + let resArgs: LoadResArgs = this._makeLoadResArgs.apply(this, arguments); + console.time("loadRes|" + resArgs.url); + let finishCallback = (error: Error, resource: any) => { + // 反向关联引用(为所有引用到的资源打上本资源引用到的标记) + let addDependKey = (item, refKey) => { + if (item && item.dependKeys && Array.isArray(item.dependKeys)) { + for (let depKey of item.dependKeys) { + // 记录该资源被我引用 + this.getCacheInfo(depKey).refs.add(refKey); + cc.log(`${depKey} ref by ${refKey}`); + let ccloader: any = cc.loader; + let depItem = ccloader._cache[depKey] + addDependKey(depItem, refKey) + } + } + } + + let item = this._getResItem(resArgs.url, resArgs.type); + if (item && item.id) { + addDependKey(item, item.id); + } else { + cc.warn(`addDependKey item error1! for ${resArgs.url}`); + } + + // 给自己加一个自身的引用 + if (item) { + let info = this.getCacheInfo(item.id); + info.refs.add(item.id); + // 更新资源使用 + if (resArgs.use) { + info.uses.add(resArgs.use); + } + } + + // 执行完成回调 + if (resArgs.onCompleted) { + resArgs.onCompleted(error, resource); + } + console.timeEnd("loadRes|" + resArgs.url); + }; + + // 预判是否资源已加载 + let res = cc.loader.getRes(resArgs.url, resArgs.type); + if (res) { + finishCallback(null, res); + } else { + cc.loader.loadRes(resArgs.url, resArgs.type, resArgs.onProgess, finishCallback); + } + } + + /** + * 释放资源 + * @param url 要释放的url + * @param type 资源类型 + * @param use 要解除的资源使用key,根据makeUseKey方法生成 + */ + public releaseRes(url: string, use?: string); + public releaseRes(url: string, type: typeof cc.Asset, use?: string) + public releaseRes() { + /**暂时不释放资源 */ + // return; + + let resArgs: ReleaseResArgs = this._makeReleaseResArgs.apply(this, arguments); + let item = this._getResItem(resArgs.url, resArgs.type); + if (!item) { + console.warn(`releaseRes item is null ${resArgs.url} ${resArgs.type}`); + return; + } + cc.log("resloader release item"); + // cc.log(arguments); + let cacheInfo = this.getCacheInfo(item.id); + if (resArgs.use) { + cacheInfo.uses.delete(resArgs.use) + } + this._release(item, item.id); + } + + // 释放一个资源 + private _release(item, itemUrl) { + if (!item) { + return; + } + let cacheInfo = this.getCacheInfo(item.id); + // 解除自身对自己的引用 + cacheInfo.refs.delete(itemUrl); + + if (cacheInfo.uses.size == 0 && cacheInfo.refs.size == 0) { + // 解除引用 + let delDependKey = (item, refKey) => { + if (item && item.dependKeys && Array.isArray(item.dependKeys)) { + for (let depKey of item.dependKeys) { + let ccloader: any = cc.loader; + let depItem = ccloader._cache[depKey] + this._release(depItem, refKey); + } + } + } + delDependKey(item, itemUrl); + //如果没有uuid,就直接释放url + if (item.uuid) { + cc.loader.release(item.uuid); + cc.log("resloader release item by uuid :" + item.id); + } else { + cc.loader.release(item.id); + cc.log("resloader release item by url:" + item.id); + } + this._resMap.delete(item.id); + } + } + + /** + * 判断一个资源能否被释放 + * @param url 资源url + * @param type 资源类型 + * @param use 要解除的资源使用key,根据makeUseKey方法生成 + */ + public checkReleaseUse(url: string, use?: string): boolean; + public checkReleaseUse(url: string, type: typeof cc.Asset, use?: string): boolean + public checkReleaseUse() { + let resArgs: ReleaseResArgs = this._makeReleaseResArgs.apply(this, arguments); + let item = this._getResItem(resArgs.url, resArgs.type); + if (!item) { + console.log(`cant release,item is null ${resArgs.url} ${resArgs.type}`); + return true; + } + + let cacheInfo = this.getCacheInfo(item.id); + let checkUse = false; + let checkRef = false; + + if (resArgs.use && cacheInfo.uses.size > 0) { + if (cacheInfo.uses.size == 1 && cacheInfo.uses.has(resArgs.use)) { + checkUse = true; + } else { + checkUse = false; + } + } else { + checkUse = true; + } + + if ((cacheInfo.refs.size == 1 && cacheInfo.refs.has(item.id)) || cacheInfo.refs.size == 0) { + checkRef = true; + } else { + checkRef = false; + } + + return checkUse && checkRef; + } +} + +export let resLoader: ResLoader = new ResLoader(); + diff --git a/assets/Script/ui/UIManager.ts b/assets/Script/ui/UIManager.ts index cf3e3c7..62d7082 100644 --- a/assets/Script/ui/UIManager.ts +++ b/assets/Script/ui/UIManager.ts @@ -1,5 +1,5 @@ -import { kx } from "../res/ResLoader" import { UIView, UIShowTypes } from "./UIView"; +import { resLoader, ProcessCallback } from "../res/ResLoader"; /** * UIManager界面管理类 @@ -197,7 +197,7 @@ export class UIManager { } let useKey = this.makeUseKey(); - kx.loader.loadRes(uiPath, (err: Error, prefab: cc.Prefab) => { + resLoader.loadRes(uiPath, (err: Error, prefab: cc.Prefab) => { // 检查加载资源错误 if (err) { cc.log(`getOrCreateUI loadRes ${uiId} faile, path: ${uiPath} error: ${err}`); @@ -209,7 +209,7 @@ export class UIManager { if (null == uiNode) { cc.log(`getOrCreateUI instantiate ${uiId} faile, path: ${uiPath}`); completeCallback(null); - kx.loader.releaseRes(uiPath, cc.Prefab); + resLoader.releaseRes(uiPath, cc.Prefab); return; } // 检查组件获取错误 @@ -218,7 +218,7 @@ export class UIManager { cc.log(`getOrCreateUI getComponent ${uiId} faile, path: ${uiPath}`); uiNode.destroy(); completeCallback(null); - kx.loader.releaseRes(uiPath, cc.Prefab); + resLoader.releaseRes(uiPath, cc.Prefab); return; } // 异步加载UI预加载的资源 @@ -237,7 +237,7 @@ export class UIManager { * @param uiArgs 初始化参数 * @param progressCallback 加载进度回调 */ - private getOrCreateUIWithProgress(uiId: number, completeCallback: (uiView: UIView) => void, uiArgs: any, progressCallback: kx.ProcessCallback): void { + private getOrCreateUIWithProgress(uiId: number, completeCallback: (uiView: UIView) => void, uiArgs: any, progressCallback: ProcessCallback): void { // 如果找到缓存对象,则直接返回 let uiView: UIView = this.UICache[uiId]; if (uiView) { @@ -254,7 +254,7 @@ export class UIManager { } let useKey = this.makeUseKey(); - kx.loader.loadRes(uiPath, progressCallback, (err: Error, prefab: cc.Prefab) => { + resLoader.loadRes(uiPath, progressCallback, (err: Error, prefab: cc.Prefab) => { // 检查加载资源错误 if (err) { cc.log(`getOrCreateUI loadRes ${uiId} faile, path: ${uiPath} error: ${err}`); @@ -266,7 +266,7 @@ export class UIManager { if (null == uiNode) { cc.log(`getOrCreateUI instantiate ${uiId} faile, path: ${uiPath}`); completeCallback(null); - kx.loader.releaseRes(uiPath, cc.Prefab); + resLoader.releaseRes(uiPath, cc.Prefab); return; } // 检查组件获取错误 @@ -275,7 +275,7 @@ export class UIManager { cc.log(`getOrCreateUI getComponent ${uiId} faile, path: ${uiPath}`); uiNode.destroy(); completeCallback(null); - kx.loader.releaseRes(uiPath, cc.Prefab); + resLoader.releaseRes(uiPath, cc.Prefab); return; } // 异步加载UI预加载的资源 @@ -397,7 +397,7 @@ export class UIManager { }, uiArgs); } - public openWithProgress(uiId: number, uiArgs: any, progressCallback: kx.ProcessCallback) { + public openWithProgress(uiId: number, uiArgs: any, progressCallback: ProcessCallback) { let uiInfo: UIInfo = { uiId: uiId, uiArgs: uiArgs, diff --git a/assets/Script/ui/UIView.ts b/assets/Script/ui/UIView.ts index 41dbfa7..e8c2b20 100644 --- a/assets/Script/ui/UIView.ts +++ b/assets/Script/ui/UIView.ts @@ -1,4 +1,4 @@ -import { kx } from "../res/ResLoader" +import { resLoader, CompletedCallback } from "../res/ResLoader" /** * UIView界面基础类 @@ -104,7 +104,7 @@ export class UIView extends cc.Component { */ public getUseKey(): string { if (!this.useKey) { - this.useKey = kx.loader.makeUseKey("UI_", this.UIid.toString(), `${++UIView.uiIndex}`); + this.useKey = resLoader.makeUseKey("UI_", this.UIid.toString(), `${++UIView.uiIndex}`); } return this.useKey; } @@ -116,9 +116,9 @@ export class UIView extends cc.Component { * @param type 类型,如cc.Prefab,cc.SpriteFrame,cc.Texture2D * @param onCompleted */ - public loadRes(url: string, type: typeof cc.Asset, onCompleted: kx.CompletedCallback) { + public loadRes(url: string, type: typeof cc.Asset, onCompleted: CompletedCallback) { let useStr = this.getUseKey(); - kx.loader.loadRes(url, type, (error: Error, res) => { + resLoader.loadRes(url, type, (error: Error, res) => { if (!error) { this.autoRes.push({ url: url, type: type }); } @@ -132,7 +132,7 @@ export class UIView extends cc.Component { public releaseAutoRes() { for (let index = 0; index < this.autoRes.length; index++) { const element = this.autoRes[index]; - kx.loader.releaseRes(element.url, + resLoader.releaseRes(element.url, element.type, element.use || this.getUseKey()); } }