资源管理(15)—— 使用资源包加载器异步加载

编辑器移动路径需要修改

以前场景的后缀用的是.unity3d,现在统一改为assetbundle

以前生成版本文件的时候不包含扩展名name,现在把扩展名加了回来。版本文件包含扩展名

 

下面开始加载资源包

资源包加载器

资源包加载器

namespace YouYou
{
    /// <summary>
    /// 资源包加载器
    /// </summary>
    public class AssetBundleLoaderRoutine
    {
        /// <summary>
        /// 当前的资源包信息
        /// </summary>
        private AssetBundleInfoEntity m_CurrAssetBundleInfo;

        /// <summary>
        /// 资源包创建请求
        /// </summary>
        private AssetBundleCreateRequest m_CurrAssetBundleCreateRequest;

        /// <summary>
        /// 资源包创建请求更新
        /// </summary>
        public Action<float> OnAssetBundleCreateUpdate;

        /// <summary>
        /// 加载资源包完毕
        /// </summary>
        public Action<AssetBundle> OnLoadAssetBundleComplete;

        #region LoadAssetBundle 加载资源包
        /// <summary>
        /// 加载资源包
        /// </summary>
        public void LoadAssetBundle(string assetBundlePath)
        {
            m_CurrAssetBundleInfo = GameEntry.Resource.ResourceManager.GetAssetBundleInfo(assetBundlePath);

            //检查文件在可写区是否存在
            bool isExistsInLocal = GameEntry.Resource.ResourceManager.LocalAssetsManager.CheckFileExists(assetBundlePath);

            if (isExistsInLocal && !m_CurrAssetBundleInfo.IsEncrypt)
            {
                //如果资源包存在于可写区  并且没有加密
                m_CurrAssetBundleCreateRequest = AssetBundle.LoadFromFileAsync(string.Format("{0}/{1}", Application.persistentDataPath, assetBundlePath));
            }
            else
            {
                byte[] buffer = GameEntry.Resource.ResourceManager.LocalAssetsManager.GetFileBuffer(assetBundlePath);
                if (buffer == null)
                {
                    //如果可写区没有 那么就从只读区获取
                    GameEntry.Resource.ResourceManager.StreamingAssetsManager.ReadAssetBundle(assetBundlePath, (byte[] buff) =>
                    {
                        if (buff == null)
                        {
                            //如果只读区也没有,从CDN下载
                            GameEntry.Download.BeginDownloadSingle(assetBundlePath, onComplete: (string fileUrl) =>
                            {
                                buffer = GameEntry.Resource.ResourceManager.LocalAssetsManager.GetFileBuffer(fileUrl);
                                LoadAssetBundleAsync(buffer);
                            });
                        }
                        else
                        {
                            //从只读区加载资源包
                            LoadAssetBundleAsync(buff);
                        }
                    });
                }
                else
                {
                    //从可写区加载资源包
                    LoadAssetBundleAsync(buffer);
                }
            }
        }

        /// <summary>
        /// 异步加载资源包
        /// </summary>
        /// <param name="buffer"></param>
        private void LoadAssetBundleAsync(byte[] buffer)
        {
            if (m_CurrAssetBundleInfo.IsEncrypt)
            {
                //如果资源包是加密的,则解密
                buffer = SecurityUtil.Xor(buffer);
            }

            m_CurrAssetBundleCreateRequest = AssetBundle.LoadFromMemoryAsync(buffer);
        }
        #endregion

        /// <summary>
        /// 重置
        /// </summary>
        public void Reset()
        {
            m_CurrAssetBundleCreateRequest = null;
        }

        /// <summary>
        /// 更新
        /// </summary>
        public void OnUpdate()
        {
            UpdateAssetBundleCreateRequest();
        }

        #region UpdateAssetBundleCreateRequest 更新资源包请求
        /// <summary>
        /// 更新资源包请求
        /// </summary>
        private void UpdateAssetBundleCreateRequest()
        {
            if (m_CurrAssetBundleCreateRequest != null)
            {
                if (m_CurrAssetBundleCreateRequest.isDone)
                {
                    AssetBundle assetBundle = m_CurrAssetBundleCreateRequest.assetBundle;
                    if (assetBundle != null)
                    {
                        GameEntry.Log(LogCategory.Resource, "资源包=>{0} 加载完毕", m_CurrAssetBundleInfo.AssetBundleName);
                        Reset();//一定要早点Reset

                        if (OnLoadAssetBundleComplete != null) OnLoadAssetBundleComplete(assetBundle);
                    }
                    else
                    {
                        GameEntry.LogError("资源包=>{0} 加载失败", m_CurrAssetBundleInfo.AssetBundleName);
                        Reset();//一定要早点Reset

                        if (OnLoadAssetBundleComplete != null) OnLoadAssetBundleComplete(null);
                    }
                }
                else
                {
                    //加载进度
                    if (OnAssetBundleCreateUpdate != null) OnAssetBundleCreateUpdate(m_CurrAssetBundleCreateRequest.progress);
                }
            }
        }
        #endregion
    }
}

当前资源包信息

namespace YouYou
{
    /// <summary>
    /// AssetBundle版本文件信息实体
    /// </summary>
    public class AssetBundleInfoEntity
    {
        /// <summary>
        /// 资源包名称
        /// </summary>
        public string AssetBundleName;

        /// <summary>
        /// MD5码
        /// </summary>
        public string MD5;

        /// <summary>
        /// 文件大小(字节)
        /// </summary>
        public ulong Size;

        /// <summary>
        /// 是否初始数据
        /// </summary>
        public bool IsFirstData;

        /// <summary>
        /// 是否已经加密
        /// </summary>
        public bool IsEncrypt;

    }
}

获取CDN上的资源包信息

 

异步加载资源包

        /// <summary>
        /// 异步加载资源包
        /// </summary>
        /// <param name="buffer"></param>
        private void LoadAssetBundleAsync(byte[] buffer)
        {
            if (m_CurrAssetBundleInfo.IsEncrypt)
            {
                //如果资源包是加密的,则解密
                buffer = SecurityUtil.Xor(buffer);
            }

            m_CurrAssetBundleCreateRequest = AssetBundle.LoadFromMemoryAsync(buffer);
        }

异步加载返回的AssetBundleCreateRequest

更新资源包请求

        #region UpdateAssetBundleCreateRequest 更新资源包请求
        /// <summary>
        /// 更新资源包请求
        /// </summary>
        private void UpdateAssetBundleCreateRequest()
        {
            if (m_CurrAssetBundleCreateRequest != null)
            {
                //请求加载完毕,资源加载完了
                if (m_CurrAssetBundleCreateRequest.isDone)
                {
                    AssetBundle assetBundle = m_CurrAssetBundleCreateRequest.assetBundle;
                    if (assetBundle != null)
                    {
                        GameEntry.Log(LogCategory.Resource, "资源包=>{0} 加载完毕", m_CurrAssetBundleInfo.AssetBundleName);
                        Reset();//一定要早点Reset

                        //资源包加载完毕的回调
                        if (OnLoadAssetBundleComplete != null) OnLoadAssetBundleComplete(assetBundle);
                    }
                    else
                    {
                        GameEntry.LogError("资源包=>{0} 加载失败", m_CurrAssetBundleInfo.AssetBundleName);
                        Reset();//一定要早点Reset

                        if (OnLoadAssetBundleComplete != null) OnLoadAssetBundleComplete(null);
                    }
                }
                else
                {
                    //加载进度
                    if (OnAssetBundleCreateUpdate != null)
                    {
                        OnAssetBundleCreateUpdate(m_CurrAssetBundleCreateRequest.progress);
                    }
                }
            }
        }
        #endregion

加载器的使用

        /// <summary>
        /// 资源包加载器链表
        /// </summary>
        private LinkedList<AssetBundleLoaderRoutine> m_AssetBundleLoaderList;

        /// <summary>
        /// 资源加载器链表
        /// </summary>
        private LinkedList<AssetLoaderRoutine> m_AssetLoaderList;

加载器可能反复使用

对象池组件初始化的时候设置数量

加载资源包

        #region LoadAssetBundle 加载资源包
        /// <summary>
        /// 加载中的Bundle
        /// </summary>
        private Dictionary<string, LinkedList<Action<AssetBundle>>> m_LoadingAssetBundle = new Dictionary<string, LinkedList<Action<AssetBundle>>>();

        /// <summary>
        /// 加载资源包
        /// </summary>
        /// <param name="assetbundlePath"></param>
        /// <param name="onUpdate"></param>
        /// <param name="onComplete"></param>
        public void LoadAssetBundle(string assetbundlePath, Action<float> onUpdate = null, Action<AssetBundle> onComplete = null)
        {
            //Debug.LogError("加载资源包" + assetbundlePath);
            //1.判断资源包是否存在于AssetBundlePool
            ResourceEntity assetBundleEntity = GameEntry.Pool.PoolManager.AssetBundlePool.Spawn(assetbundlePath);
            if (assetBundleEntity != null)
            {
                //Debug.Log("资源包在资源池中存在 从资源池中加载AssetBundle");
                AssetBundle assetBundle = assetBundleEntity.Target as AssetBundle;
                if (onComplete != null) onComplete(assetBundle);
                return;
            }

            //2.判断Bundle是否加载到一半,防止高并发导致重复加载
            LinkedList<Action<AssetBundle>> lst = null;
            if (m_LoadingAssetBundle.TryGetValue(assetbundlePath, out lst))
            {
                //如果Bundle已经在加载中, 把委托加入对应的链表 然后直接return;
                lst.AddLast(onComplete);
                return;
            }
            else
            {
                //如果Bundle还没有开始加载, 把委托加入对应的链表 然后开始加载
                lst = GameEntry.Pool.DequeueClassObject<LinkedList<Action<AssetBundle>>>();
                lst.AddLast(onComplete);
                m_LoadingAssetBundle[assetbundlePath] = lst;
            }


            //加载器从池中取
            AssetBundleLoaderRoutine routine = GameEntry.Pool.DequeueClassObject<AssetBundleLoaderRoutine>();
            if (routine == null)
            {
                routine = new AssetBundleLoaderRoutine();
            }
                

            //加入链表开始循环
            m_AssetBundleLoaderList.AddLast(routine);

            //加载资源包
            routine.LoadAssetBundle(assetbundlePath);
            //资源包加载 进行中 回调
            routine.OnAssetBundleCreateUpdate = (float progress) =>
            {
                if (onUpdate != null) onUpdate(progress);
            };
            //资源包加载 结束 回调
            routine.OnLoadAssetBundleComplete = (AssetBundle assetbundle) =>
            {
                //资源包取池
                assetBundleEntity = GameEntry.Pool.DequeueClassObject<ResourceEntity>();
                assetBundleEntity.ResourceName = assetbundlePath;
                assetBundleEntity.IsAssetBundle = true;
                assetBundleEntity.Target = assetbundle;
                //资源包注册到资源池
                GameEntry.Pool.PoolManager.AssetBundlePool.Register(assetBundleEntity);

                for (LinkedListNode<Action<AssetBundle>> curr = lst.First; curr != null; curr = curr.Next)
                {
                    if (curr.Value != null) curr.Value(assetbundle);
                }
                //资源加载完毕后
                lst.Clear();//必须清空
                GameEntry.Pool.EnqueueClassObject(lst);
                m_LoadingAssetBundle.Remove(assetbundlePath);//从加载中的Bundle的Dic 移除

                //结束循环 回池,从链表中移除掉
                m_AssetBundleLoaderList.Remove(routine);
                //加载器回池
                GameEntry.Pool.EnqueueClassObject(routine);
            };
        }
        #endregion

               /// <summary>
        /// 异步加载数据表
        /// </summary>
        public void LoadDataTableAsync()
        {
#if ASSETBUNDLE
            GameEntry.Resource.ResourceLoaderManager.LoadAssetBundle(ConstDefine.DataTableAssetBundlePath, onComplete: (AssetBundle bundle) =>
            {
                //拿到Assetbundle的回调
                m_DataTableBundle = bundle;
                LoadDataTable();
            });
#else
            //加载表格
            LoadDataTable();
#endif
        }

现在已经拿到了Assetbundle,然后从Assetbundle中去加载表格了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值