UNPKG

dragonbones-runtime

Version:

the tools to build dragonbones file for diffrent framework

279 lines (270 loc) 9.13 kB
////////////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2014-present, Egret Technology. // All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of the Egret nor the // names of its contributors may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY EGRET AND CONTRIBUTORS "AS IS" AND ANY EXPRESS // OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. // IN NO EVENT SHALL EGRET AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;LOSS OF USE, DATA, // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ////////////////////////////////////////////////////////////////////////////////////// namespace RES { /** * @class RES.ResourceLoader * @classdesc * @extends egret.EventDispatcher * @private */ export class ResourceLoader extends egret.EventDispatcher{ /** * 构造函数 * @method RES.ResourceLoader#constructor */ public constructor(){ super(); } /** * 最大并发加载数 */ public thread: number = 2; /** * 正在加载的线程计数 */ private loadingCount:number = 0; /** * 一项加载结束回调函数。无论加载成功或者出错都将执行回调函数。示例:callBack(resItem:ResourceItem):void; * @member {Function} RES.ResourceLoader#callBack */ public callBack:Function = null; /** * RES单例的引用 * @member {any} RES.ResourceLoader#resInstance */ public resInstance:any = null; /** * 当前组加载的项总个数,key为groupName */ private groupTotalDic:any = {}; /** * 已经加载的项个数,key为groupName */ private numLoadedDic:any = {}; /** * 正在加载的组列表,key为groupName */ private itemListDic:any = {}; /** * 加载失败的组,key为groupName */ private groupErrorDic:any = {}; private retryTimesDic: any = {}; public maxRetryTimes = 3; private failedList: Array<ResourceItem> = new Array<ResourceItem>(); /** * 优先级队列,key为priority,value为groupName列表 */ private priorityQueue:any = {}; /** * 检查指定的组是否正在加载中 * @method RES.ResourceLoader#isGroupInLoading * @param groupName {string} * @returns {boolean} */ public isGroupInLoading(groupName:string):boolean{ return this.itemListDic[groupName]!==undefined; } /** * 开始加载一组文件 * @method RES.ResourceLoader#loadGroup * @param list {egret.Array<ResourceItem>} 加载项列表 * @param groupName {string} 组名 * @param priority {number} 加载优先级 */ public loadGroup(list:Array<ResourceItem>,groupName:string,priority:number=0):void{ if(this.itemListDic[groupName]||!groupName) return; if(!list||list.length==0){ egret.$warn(3201, groupName); let event:ResourceEvent = new ResourceEvent(ResourceEvent.GROUP_LOAD_ERROR); event.groupName = groupName; this.dispatchEvent(event); return; } if(this.priorityQueue[priority]) this.priorityQueue[priority].push(groupName); else this.priorityQueue[priority] = [groupName]; this.itemListDic[groupName] = list; let length:number = list.length; for(let i:number=0;i<length;i++){ let resItem:ResourceItem = list[i]; resItem.groupName = groupName; } this.groupTotalDic[groupName] = list.length; this.numLoadedDic[groupName] = 0; this.next(); } /** * 延迟加载队列 */ private lazyLoadList:Array<ResourceItem> = new Array<ResourceItem>(); /** * 加载一个文件 * @method RES.ResourceLoader#loadItem * @param resItem {egret.ResourceItem} 要加载的项 */ public loadItem(resItem:ResourceItem):void{ this.lazyLoadList.push(resItem); resItem.groupName = ""; this.next(); } /** * 资源解析库字典类 */ private analyzerDic:any = {}; /** * 加载下一项 */ private next():void{ while(this.loadingCount<this.thread) { let resItem:ResourceItem = this.getOneResourceItem(); if(!resItem) break; this.loadingCount++; if(resItem.loaded){ this.onItemComplete(resItem); } else{ let analyzer:AnalyzerBase = this.resInstance.$getAnalyzerByType(resItem.type); analyzer.loadFile(resItem,this.onItemComplete,this); } } } /** * 当前应该加载同优先级队列的第几列 */ private queueIndex:number = 0; /** * 获取下一个待加载项 */ private getOneResourceItem():ResourceItem{ if (this.failedList.length > 0) return this.failedList.shift(); let maxPriority:number = Number.NEGATIVE_INFINITY; for(let p in this.priorityQueue){ maxPriority = Math.max(maxPriority,<number><any> p); } let queue:any[] = this.priorityQueue[maxPriority]; if(!queue||queue.length==0){ if(this.lazyLoadList.length==0) return null; //后请求的先加载,以便更快获取当前需要的资源 return this.lazyLoadList.pop(); } let length:number = queue.length; let list:Array<ResourceItem>; for(let i:number=0;i<length;i++){ if(this.queueIndex>=length) this.queueIndex = 0; list = this.itemListDic[queue[this.queueIndex]]; if(list.length>0) break; this.queueIndex++; } if(list.length==0) return null; return list.shift(); } /** * 加载结束 */ private onItemComplete(resItem:ResourceItem):void{ this.loadingCount--; let groupName:string = resItem.groupName; if(!resItem.loaded){//加载失败 let times = this.retryTimesDic[resItem.name] || 1; if (times > this.maxRetryTimes) { delete this.retryTimesDic[resItem.name]; ResourceEvent.dispatchResourceEvent(this.resInstance, ResourceEvent.ITEM_LOAD_ERROR, groupName, resItem); } else { this.retryTimesDic[resItem.name] = times + 1; this.failedList.push(resItem); this.next(); return; } } if(groupName){ this.numLoadedDic[groupName]++; let itemsLoaded:number = this.numLoadedDic[groupName]; let itemsTotal:number = this.groupTotalDic[groupName]; if(!resItem.loaded){ this.groupErrorDic[groupName] = true; } ResourceEvent.dispatchResourceEvent(this.resInstance,ResourceEvent.GROUP_PROGRESS,groupName,resItem,itemsLoaded,itemsTotal); if(itemsLoaded==itemsTotal){ let groupError:boolean = this.groupErrorDic[groupName]; this.removeGroupName(groupName); delete this.groupTotalDic[groupName]; delete this.numLoadedDic[groupName]; delete this.itemListDic[groupName]; delete this.groupErrorDic[groupName]; if(groupError){ ResourceEvent.dispatchResourceEvent(this,ResourceEvent.GROUP_LOAD_ERROR,groupName); } else{ ResourceEvent.dispatchResourceEvent(this,ResourceEvent.GROUP_COMPLETE,groupName); } } } else{ this.callBack.call(this.resInstance,resItem); } this.next(); } /** * 从优先级队列中移除指定的组名 */ private removeGroupName(groupName:string):void{ for(let p in this.priorityQueue){ let queue:any[] = this.priorityQueue[p]; let index:number = 0; let found:boolean = false; let length:number = queue.length; for(let i:number=0;i<length;i++){ let name:string = queue[i]; if(name==groupName){ queue.splice(index,1); found = true; break; } index++; } if(found){ if(queue.length==0){ delete this.priorityQueue[p]; } break; } } } } }