资源管理(4)——依赖关系

1、Windows.manifest         assetbundle相互依赖的关系         资源包的依赖关系   这种方式把依赖的图集全部加载出来,具体依赖哪个图加载不出来,
2、如果依赖的图集多,大部分图集都要load出来也释放不掉,不利于内存管理
不知道一个实例依赖哪些字体,依赖哪些sprite

3、UITask  在哪个Assetbundle里,同时要知道依赖于哪些asset   这个asset在不在内存里,如果不在对象池里,看这个资源在哪个bundle里,然后加载asset,最后再加载主资源

4、看的见的实例依赖的是asset,asset依赖的是Assetbundle,为了方便存储依赖关系,建一个资源类(AssetEntity),

依赖关系实体

需要加载依赖的时候,根据资源的完成信息名,找到assetEntity然后加载

 

5、怎么样拿到依赖关系?

    #region OnCreateDependenciesFile 生成依赖关系文件
    /// <summary>
    /// 生成依赖关系文件
    /// </summary>
    private void OnCreateDependenciesFile()
    {
        //第一次循环 把所有的Asset存储到一个列表里

        //临时列表
        List<AssetEntity> tempLst = new List<AssetEntity>();

        //循环设置文件夹包括子文件里边的项
        for (int i = 0; i < m_List.Count; i++)
        {
            AssetBundleEntity entity = m_List[i];//取到一个节点

            string[] folderArr = new string[entity.PathList.Count];
            for (int j = 0; j < entity.PathList.Count; j++)
            {
                string path = Application.dataPath + "/" + entity.PathList[j];
                //Debug.LogError("path=" + path);
                CollectFileInfo(tempLst, path);
            }
        }

        //
        int len = tempLst.Count;

        //资源列表
        List<AssetEntity> assetList = new List<AssetEntity>();

        //第二次循环来处理依赖关系
        for (int i = 0; i < len; i++)
        {
            AssetEntity entity = tempLst[i];

            AssetEntity newEntity = new AssetEntity();
            newEntity.Category = entity.Category;
            newEntity.AssetName = entity.AssetFullName.Substring(entity.AssetFullName.LastIndexOf("/") + 1);
            newEntity.AssetName = newEntity.AssetName.Substring(0, newEntity.AssetName.LastIndexOf("."));
            newEntity.AssetFullName = entity.AssetFullName;
            newEntity.AssetBundleName = entity.AssetBundleName;


            //加到新列表中
            assetList.Add(newEntity);

            //场景不需要检查依赖项
            if (entity.Category == AssetCategory.Scenes)
            {
                continue;
            }

            //实例化资源信息依赖项
            newEntity.DependsAssetList = new List<AssetDependsEntity>();

            //相当于点击右键,选择依赖项
            string[] arr = AssetDatabase.GetDependencies(entity.AssetFullName);
            foreach (string str in arr)
            {
                //如果这个资源在临时列表里,说明在download目录下
                if (!str.Equals(newEntity.AssetFullName, StringComparison.CurrentCultureIgnoreCase) && GetIsAsset(tempLst, str))
                {
                    //实例化依赖项,然后赋值,加到依赖项列表里面
                    AssetDependsEntity assetDepends = new AssetDependsEntity();
                    assetDepends.Category = GetAssetCategory(str);
                    assetDepends.AssetFullName = str;

                    //把依赖资源 加入到依赖资源列表
                    newEntity.DependsAssetList.Add(assetDepends);
                }
            }
        }

        //生成一个Json文件,用来观察
        string targetPath = Application.dataPath + "/../AssetBundles/" + dal.GetVersion() + "/" + arrBuildTarget[buildTargetIndex];
        if (!Directory.Exists(targetPath))
        {
            Directory.CreateDirectory(targetPath);
        }

        string strJsonFilePath = targetPath + "/AssetInfo.json"; //版本文件路径
        IOUtil.CreateTextFile(strJsonFilePath, LitJson.JsonMapper.ToJson(assetList));
        Debug.Log("生成 AssetInfo.json 完毕");


        //生成一个MMO_MemoryStream,然后写入文件流
        MMO_MemoryStream ms = new MMO_MemoryStream();
        //生成二进制文件
        len = assetList.Count;
        ms.WriteInt(len);

        //把生成的列表序列化成一个数据流
        for (int i = 0; i < len; i++)
        {
            AssetEntity entity = assetList[i];
            ms.WriteByte((byte)entity.Category);
            ms.WriteUTF8String(entity.AssetFullName);
            ms.WriteUTF8String(entity.AssetBundleName);

            if (entity.DependsAssetList != null)
            {
                //添加依赖资源
                int depLen = entity.DependsAssetList.Count;
                ms.WriteInt(depLen);
                for (int j = 0; j < depLen; j++)
                {
                    AssetDependsEntity assetDepends = entity.DependsAssetList[j];
                    ms.WriteByte((byte)assetDepends.Category);
                    ms.WriteUTF8String(assetDepends.AssetFullName);
                }
            }
            else
            {
                ms.WriteInt(0);
            }
        }

        //压缩成一个AssetInfo.bytes的文件
        string filePath = targetPath + "/AssetInfo.bytes"; //版本文件路径
        byte[] buffer = ms.ToArray();
        //压缩一下
        buffer = ZlibHelper.CompressBytes(buffer);
        FileStream fs = new FileStream(filePath, FileMode.Create);
        fs.Write(buffer, 0, buffer.Length);
        fs.Close();
        Debug.Log("生成 AssetInfo.bytes 完毕");
    }

资源实体

using System.Collections.Generic;

/// <summary>
/// Asset实体
/// </summary>
public class AssetEntity
{
    /// <summary>
    /// 资源分类
    /// </summary>
    public AssetCategory Category;

    /// <summary>
    /// 资源名称
    /// </summary>
    public string AssetName;

    /// <summary>
    /// 资源完整名称(路径)
    /// </summary>
    public string AssetFullName;

    /// <summary>
    /// 所属资源包(这个资源在哪一个Assetbundle里)
    /// </summary>
    public string AssetBundleName;
    
    /// <summary>
    /// 依赖资源
    /// </summary>
    public List<AssetDependsEntity> DependsAssetList;
}

资源分类 

/// <summary>
/// Asset分类
/// </summary>
public enum AssetCategory
{
    /// <summary>
    /// 
    /// </summary>
    None = 0,
    /// <summary>
    /// 声音
    /// </summary>
    Audio = 1,
    /// <summary>
    /// 自定义Shader
    /// </summary>
    CusShaders = 2,
    /// <summary>
    /// 表格
    /// </summary>
    DataTable = 3,
    /// <summary>
    /// 特效资源
    /// </summary>
    EffectSources = 4,
    /// <summary>
    /// 角色特效预设
    /// </summary>
    RoleEffectPrefab = 5,
    /// <summary>
    /// UI特效预设
    /// </summary>
    UIEffectPrefab = 6,
    /// <summary>
    /// 角色预设
    /// </summary>
    RolePrefab = 7,
    /// <summary>
    /// 角色资源
    /// </summary>
    RoleSources = 8,
    /// <summary>
    /// 场景
    /// </summary>
    Scenes = 9,
    /// <summary>
    /// 字体
    /// </summary>
    UIFont = 10,
    /// <summary>
    /// UI预设
    /// </summary>
    UIPrefab = 11,
    /// <summary>
    /// UI资源
    /// </summary>
    UIRes = 12,
    /// <summary>
    /// Lua脚本
    /// </summary>
    xLuaLogic = 13
}

依赖资源类

/// <summary>
/// Asset依赖项实体
/// </summary>
public class AssetDependsEntity 
{
    /// <summary>
    /// 资源分类
    /// </summary>
    public AssetCategory Category;

    /// <summary>
    /// 资源完整名称
    /// </summary>
    public string AssetFullName;
}

循环的列表来源   AssetBundleConfig.xml

    /// <summary>
    /// 构造函数
    /// </summary>
    void OnEnable()
    {
        string xmlPath = Application.dataPath + @"\YouYouFramework\Editor\AssetBundle\AssetBundleConfig.xml";
        dal = new AssetBundleDAL(xmlPath);
        m_List = dal.GetList();

        m_Dic = new Dictionary<string, bool>();

        for (int i = 0; i < m_List.Count; i++)
        {
            m_Dic[m_List[i].Key] = true;
        }
    }

循环列表,拿到路径,收集文件信息

 

如果是场景,直接赋值

如果是文件夹,遍历文件夹下所有的子文件,排除掉.meta,排除掉.idea

    #region CollectFileInfo 收集文件信息
    /// <summary>
    /// 收集文件信息
    /// </summary>
    /// <param name="tempLst"></param>
    /// <param name="folderPath"></param>
    private void CollectFileInfo(List<AssetEntity> tempLst, string folderPath)
    {
        //场景
        if (folderPath.IndexOf(".unity") != -1)
        {
            int index = folderPath.IndexOf("Assets/", StringComparison.CurrentCultureIgnoreCase);
            //路径
            string newPath = folderPath.Substring(index);

            AssetImporter import = AssetImporter.GetAtPath(newPath);

            AssetEntity entity = new AssetEntity();
            entity.AssetFullName = newPath.Replace("\\", "/");
            entity.Category = AssetCategory.Scenes;
            entity.AssetBundleName = import.assetBundleName + ".assetbundle";

            tempLst.Add(entity);
        }
        else
        {
            DirectoryInfo directory = new DirectoryInfo(folderPath);

            //拿到文件夹下所有文件
            FileInfo[] arrFiles = directory.GetFiles("*", SearchOption.AllDirectories);

            for (int i = 0; i < arrFiles.Length; i++)
            {
                FileInfo file = arrFiles[i];
                //排除.meta
                if (file.Extension == ".meta")
                {
                    continue;
                }

                string filePath = file.FullName; //全名 包含路径扩展名

                //Debug.LogError("filePath=" + filePath);
                int index = filePath.IndexOf("Assets\\", StringComparison.CurrentCultureIgnoreCase);

                //路径
                string newPath = filePath.Substring(index);
                //xlua用的idea,会生成idea文件
                if (newPath.IndexOf(".idea") != -1) //过滤掉idea文件
                {
                    continue;
                }

                AssetEntity entity = new AssetEntity();
                entity.AssetFullName = newPath.Replace("\\", "/");
                //获取资源分类 ,去掉文件名,只保留路径,
                entity.Category = GetAssetCategory(newPath.Replace(file.Name, "")); 
                //获取资源包名称 
                entity.AssetBundleName = GetAssetBundleName(newPath);
                tempLst.Add(entity);
            }
        }
    }
    #endregion

获取资源分类

#region GetAssetCategory 获取资源分类
    /// <summary>
    /// 获取资源分类,路径中包含的
    /// </summary>
    /// <param name="filePath"></param>
    /// <returns></returns>
    private AssetCategory GetAssetCategory(string filePath)
    {
        AssetCategory category = AssetCategory.None;

        if (filePath.IndexOf("Audio") != -1)
        {
            category = AssetCategory.Audio;
        }
        else if (filePath.IndexOf("CusShaders") != -1)
        {
            category = AssetCategory.CusShaders;
        }
        else if (filePath.IndexOf("DataTable") != -1)
        {
            category = AssetCategory.DataTable;
        }
        else if (filePath.IndexOf("EffectSources") != -1)
        {
            category = AssetCategory.EffectSources;
        }
        else if (filePath.IndexOf("RoleEffectPrefab") != -1)
        {
            category = AssetCategory.RoleEffectPrefab;
        }
        else if (filePath.IndexOf("UIEffectPrefab") != -1)
        {
            category = AssetCategory.UIEffectPrefab;
        }
        else if (filePath.IndexOf("RolePrefab") != -1)
        {
            category = AssetCategory.RolePrefab;
        }
        else if (filePath.IndexOf("RoleSources") != -1)
        {
            category = AssetCategory.RoleSources;
        }
        else if (filePath.IndexOf("Scenes") != -1)
        {
            category = AssetCategory.Scenes;
        }
        else if (filePath.IndexOf("UIFont") != -1)
        {
            category = AssetCategory.UIFont;
        }
        else if (filePath.IndexOf("UIPrefab") != -1)
        {
            category = AssetCategory.UIPrefab;
        }
        else if (filePath.IndexOf("UIRes") != -1)
        {
            category = AssetCategory.UIRes;
        }
        else if (filePath.IndexOf("xLuaLogic") != -1)
        {
            category = AssetCategory.xLuaLogic;
        }
        return category;
    }
    #endregion

获取资源包名称

    #region GetAssetBundleName 获取资源包的短路径
    /// <summary>
    /// 获取资源包的短路径
    /// </summary>
    /// <param name="newPath"></param>
    /// <returns></returns>
    private string GetAssetBundleName(string newPath)
    {
        //Debug.Log(newPath);
        if (newPath.LastIndexOf("\\") == -1) return null;
        AssetImporter import = AssetImporter.GetAtPath(newPath);
        if (import != null)
        {
            //直到AssetbundleName不是空的时候 
            if (!string.IsNullOrEmpty(import.assetBundleName))
            {
                //Debug.Log(import.assetBundleName);
                return import.assetBundleName + ".assetbundle";
            }
            else
            {
                //递归寻找上一级目录
                string path = newPath.Substring(0, newPath.Replace("\\", "/").LastIndexOf("/"));

                return GetAssetBundleName(path);
            }
        }
        return null;
    }
    #endregion

加载一个预设,先看这个预设在不在池里,在直接取,

如果不在,检查主资源,assetbundle在不在,如果不在,去磁盘load   bundle,然后加载主资源,加载主资源之前,还需要检测依赖项,循环依赖项,看依赖项有没全部加载出来,没加载出来,加载依赖项,看依赖项在哪个bundle中,看bundle在不在,如果不在把bundle加载出来,同一个asset,其余UI引用该资源,计数+1,大于1在内存中不会释放,UI销毁的时候对应的计数-1,隔段时间AssetPool检测一次,哪些资源引用计数为0可以释放,从内存中移除掉。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值