U3D客户端框架(资源管理篇)之主资源加载器模块设计实现

一、主资源加载器模块设计实现

作用

主资源加载器是为面向用户而设计的上层应用层类,用户使用主资源加载器作为文件加载器加载文件,
加载器可以通过Assetbundle方式加载,Http方式加载资源。


UML类图设计

在这里插入图片描述

前置模块

主资源加载器需要引用到一些基础模块和一些基础的加载器:可写区域管理器(LocalAssetsManager),资源加载器(ResourceLoaderManager),任务管理器(TaskManager),资源池(AssetPool),资源包池(AssetBundlePool),资源加载管理器(ResourceLoaderManager)如果还没有实现以上的前置模块,可以点击下方的引用连接,先实现基础部分,再来实现上层部分,就像是造楼房一样,如果没有地基,是不可能直接从2楼开始造楼房的。!!还漏了一些,文章后面就补上!!

前置模块
任务管理器(TaskManager) :https://blog.csdn.net/qq_33531923/article/details/128545543


加载资源(Asset)设计

主资源加载器可以用来加载Assetbundle中的Asset资源, 主资源加载加载Asset时候会使用对象池池技术优化资源,主加载器对资源进行了分类,以便于对资源的管理和分类.

1).会先从对象池中获取该资源是否存在池中,如果存在,认为资源存在,则会直接回调OnComplete回调,完成资源加载;
2).加载时会从打包时候记录的AssetInfo.bytes文件中获取该文件的依赖assetbundle信息,会优先加载依赖的assetbundle/asset,
然后最后加载主资源,
3).引用资源加载完成后,会将引用资源存到AssetBundlePool内,使关闭当前任务执行器关闭;
4).主资源加载完成后,会将主资源保存下来,使关闭当前任务执行器关闭;
5).然后开启任务执行器,行进轮询加载,把所有要加载的资源存放到一个任务组内,进行轮询更新处理;
6).当所有的依赖文件和主文件加载完毕后,会调用用户给定的OnComplete函数,会再次检查一次资源池中是否存在相同资源, 必须要检查,否则可能引起引用计数会出错,如果存在相同资源说明同时有两处在加载相同资源,直接使用池中资源即可;如果不存在,则注册资源数据到资源池中,以便下次取用;


二、主资源加载器(MainAssetLoaderRoutine)代码实现

    //主资源加载器
    public class MainAssetLoaderRoutine
    {
    
    
        //当前的资源信息实体
        private AssetEntity m_CurrAssetEntity;

        //当前的资源实体
        private ResourceEntity m_CurrResourceEntity;

        //主资源包
        private AssetBundle m_MainAssetBundle;

        //依赖资源包名字哈希
        private HashSet<string> m_DependsAssetBundleNames = new HashSet<string>();

        //主资源加载完毕(资源加载完毕;完整资源加载完毕)
        private BaseAction<ResourceEntity> m_OnComplete;


        //真正的加载主资源
        public void LoadMainAsset()
        {
    
    
            //1.从分类资源池(AssetPool)中 查找某个资源
            m_CurrResourceEntity = GameEntry.Pool.AssetPool[m_CurrAssetEntity.Category].Spawn(m_CurrAssetEntity.AssetFullName);

            //如果要找的资源,在资源池中
            if (m_CurrResourceEntity != null)
            {
    
    
                m_OnComplete?.Invoke(m_CurrResourceEntity);
                return;
            }

            //2.加载这个资源所依赖的资源包
            List<AssetDependsEntity> dependsAssetList = m_CurrAssetEntity.ListDependsAsset;
            if (dependsAssetList != null)
            {
    
    
                foreach (AssetDependsEntity assetDependsEntity in dependsAssetList)
                {
    
    
                    //根绝资源分类和资源完整名字,去资源加载器里查找这个资源的信息
                    AssetEntity assetEntity = GameEntry.Resource.ResLoaderManager.GetAssetEntity(assetDependsEntity.Category, assetDependsEntity.AssetFullName);

                    //查询的到就把包名记录下来
                    if (assetEntity != null)
                    {
    
    
                        m_DependsAssetBundleNames.Add(assetEntity.AssetBundleName);
                    }
                }
            }

            //3.循环 依赖的资源哈希表,加入任务组
            TaskGroup taskGroup = GameEntry.Task.CreateTaskGroup();
            foreach (string assetBundleName in m_DependsAssetBundleNames)
            {
    
    
                TaskRoutine taskRoutine = GameEntry.Task.CreateTaskRoutine();
                taskRoutine.CurrTask = () =>
                {
    
    
                    //依赖资源,只是加载资源包
                    GameEntry.Resource.ResLoaderManager.LoadAssetBundle(assetBundleName, onComplete: (AssetBundle bundle) =>
                      {
    
    
                          taskRoutine.Leave();
                      });
                };

                taskGroup.AddTask(taskRoutine);
            }

            //4.加载主资源包
            TaskRoutine taskRoutineLoadMainAssetBundle = GameEntry.Task.CreateTaskRoutine();
            taskRoutineLoadMainAssetBundle.CurrTask = () =>
              {
    
    
                  GameEntry.Resource.ResLoaderManager.LoadAssetBundle(m_CurrAssetEntity.AssetBundleName, onComplete: (AssetBundle bundle) =>
                    {
    
    
                        m_MainAssetBundle = bundle;
                        taskRoutineLoadMainAssetBundle.Leave();
                    });
              };

            //把主资源任务 最后一个加载任务组里
            taskGroup.AddTask(taskRoutineLoadMainAssetBundle);

            //依赖的assetbundle和主资源包加载完成后的任务回调
            taskGroup.OnComplete = () =>
              {
    
    
                  if (m_MainAssetBundle == null)
                  {
    
    
                      GameEntry.LogError(" MainAssetBundle not exist:" + m_CurrAssetEntity.AssetFullName);
                  }

                  GameEntry.Resource.ResLoaderManager.LoadAsset(m_CurrAssetEntity.AssetFullName, m_MainAssetBundle, onComplete: (UnityEngine.Object obj) =>
                     {
    
    
                         //再次检查,  很重要,不检查引用计数会出错
                         //再获取一次,如果又又了,可能是其他地方已经加载完注册进去了
                         m_CurrResourceEntity = GameEntry.Pool.AssetPool[m_CurrAssetEntity.Category].Spawn(m_CurrAssetEntity.AssetFullName);
                         if (m_CurrResourceEntity != null)
                         {
    
    
                             m_OnComplete?.Invoke(m_CurrResourceEntity);
                             Reset();

                             //如果这个资源在这之前可能被加载了,被注册了,则不用再new一次了,否则之前的引用计数会丢失,导致引用计数出现问题
                             //返回
                             return;
                         }

                         m_CurrResourceEntity = GameEntry.Pool.DequeueClassObject<ResourceEntity>();
                         m_CurrResourceEntity.Category = m_CurrAssetEntity.Category;
                         m_CurrResourceEntity.IsAssetBundle = false;
                         m_CurrResourceEntity.ResourceName = m_CurrAssetEntity.AssetFullName;
                         m_CurrResourceEntity.Target = obj;

                         GameEntry.Pool.AssetPool[m_CurrAssetEntity.Category].Register(m_CurrResourceEntity);
                         m_OnComplete?.Invoke(m_CurrResourceEntity);
                         Reset();
                     });
              };

            taskGroup.Run(true);
        }

        //加载主资源
        public void LoadAsset(AssetCategory assetCategory, string assetFullName, BaseAction<ResourceEntity> onComplete = null)
        {
    
    
#if DISABLE_ASSETBUNDLE && UNITY_EDITOR
            m_CurrResourceEntity = GameEntry.Pool.DequeueClassObject<ResourceEntity>();
            m_CurrResourceEntity.Category = assetCategory;
            m_CurrResourceEntity.IsAssetBundle = false;
            m_CurrResourceEntity.ResourceName = assetFullName;
            m_CurrResourceEntity.Target = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(assetFullName);
            onComplete?.Invoke(m_CurrResourceEntity);
#else
            m_OnComplete = onComplete;
            m_CurrAssetEntity = GameEntry.Resource.ResLoaderManager.GetAssetEntity(assetCategory,assetFullName);
            if (m_CurrAssetEntity == null)
            {
    
    
                Debug.LogError("assetFullName no exists "+assetFullName);
                return;
            }
            LoadMainAsset();
#endif
        }

        //重置
        private void Reset()
        {
    
    
            m_OnComplete = null;
            m_CurrAssetEntity = null;
            m_CurrResourceEntity = null;
            m_MainAssetBundle = null;
            m_DependsAssetBundleNames.Clear();
            GameEntry.Pool.EnqueueClassObject(this);
        }
    }

我爱写代码

猜你喜欢

转载自blog.csdn.net/qq_33531923/article/details/128545388
今日推荐