unity 熱更新 之資源加載

前言:

   熱更的話現在有很多流行的方式,xlua了等,這裏我只對資源這一部分進行簡單介紹,assetbundle的服務器下載和使用流程,代碼的更新後續在更

 首先,打包的比較簡單不過多贅述。這裏我保存了一下資源的依賴關係,並且把存儲的依賴關係存儲到了項目中,一塊打包。然後當我們使用assetbundle的時候,根據依賴關係進行download就可了。這一點一定要記得,因爲一開始想着從服務器下載存放bundle的整個文件夾,然後去讀取,後來發現過於繁瑣,而且不易實現,最後發現應該是使用一個表一樣的,根據需求去下在對應的bundle,然後去獲取資源就可以, ,沒必要在單獨存儲。

首先我們需要進行bundle tag設置,並將依賴,場景關係保存  這樣我們可以吧不同的場景打入不同的包體,減小包體大小,下載也能更快

  public static void SetBundleName()
    {
        //移除未使用的 tag
        AssetDatabase.RemoveUnusedAssetBundleNames();
        if (!Directory.Exists(ConfigSetting.SourcePath))
        {
            Debug.LogError("不存在該路徑");
            return;
        }
        DirectoryInfo dir = new DirectoryInfo(ConfigSetting .SourcePath );
        FileSystemInfo[] infos = dir.GetFileSystemInfos();
        for (int i = 0; i < infos .Length ; i++)
        {
            FileSystemInfo info = infos[i];
            if (info  is DirectoryInfo)
            {
                string path = ConfigSetting.SourcePath + info.Name;

                SetFodlerFiles(path,info .Name );
            }
        }
    }
 /// <summary>
    /// 設置整個文件夾內的文件
    /// </summary>
    /// <param name="path"></param>
    private static void SetFodlerFiles(string path,string fodlername )
    {
        Debug.Log("資源路徑:" + path);
        string savepath = ConfigSetting.BuildPath + fodlername;
        if(!Directory .Exists (savepath))
        {
            Directory.CreateDirectory(savepath);
        }
        //創建讀寫流
        FileStream fs = new FileStream(savepath  +"/" + fodlername+".txt", FileMode.OpenOrCreate);
        StreamWriter sw = new StreamWriter(fs);

        //存儲關聯關係
        Dictionary<string, string> dic_Infos = new Dictionary<string, string>();
        ChangeHead(path, dic_Infos);

        sw.WriteLine(dic_Infos.Count);//行數
        foreach (var item in dic_Infos )
        {
            sw.Write(item.Key);
            sw.Write("*");
            sw.Write(item.Value);
            sw.WriteLine();
        }
        //使用流結束關閉
        sw.Close();
        fs.Close();

    }
    /// <summary>
    /// 獲取相對路徑  D:/ZIZOUQI/Project/Assets/_Source/obj.u3d
    /// </summary>
    private static void ChangeHead(string fullpath,Dictionary<string, string> dic_Infos)
    {
        Debug.Log("fullpath:" + fullpath);// F:/U3D/HotFit/Assets/_Source/

        //得到的是 F:/U3D/HotFit/的長
        int count = fullpath.IndexOf("Assets");
        int length = fullpath.Length;
        string replacepath = fullpath.Substring(count, length - count);
        Debug.Log("replacepath:" + replacepath);// Assets/_Source/
        DirectoryInfo dir = new DirectoryInfo(fullpath);
        if (dir != null)
        {
            ListFiles(dir, replacepath,dic_Infos);
        }
        else
        {
            Debug.LogError("不存在路徑:" + fullpath);
        }
    }

    /// <summary>
    /// 遍歷文件夾
    /// </summary>
    /// <param name="info"></param>
    /// <param name="replacepath"></param>
    /// <param name="dic"></param>
    private static void ListFiles(FileSystemInfo info,string replacepath,Dictionary <string ,string> dic)
    {
        if (!info.Exists)
        {
            Debug.Log("不存在文件" + replacepath);
            return;
        }

        FileSystemInfo[] files = (info as DirectoryInfo ).GetFileSystemInfos();
        for (int i = 0; i < files .Length ; i++)
        {
            FileInfo file = files[i] as FileInfo;
            //操作文件
            if (file != null)
            {
                // Assets/_Source/
                ChangeMark(file, replacepath, dic);
            }else 
            //操作目錄
            {
                ListFiles(files[i], replacepath, dic);
            }
        }
    }
    /// <summary>
    /// 改變tag
    /// </summary>
    /// <param name="temp"></param>
    /// <param name="replacepath"></param>
    /// <param name="dic"></param>
    private  static void ChangeMark(FileInfo temp,string replacepath,Dictionary<string ,string> dic)
    {
        if (temp .Extension == ".meta")
        {
            return;
        }
        Debug.Log("文件路徑:"+replacepath);//Assets/_Source/
        string markStr = GetBundlePath(temp, replacepath);
        SetTag(temp,markStr, dic);
    }
    
    private static string GetWindowsPath(string path)
    {
        path =path .Replace ("\\","/");
        return path;
    }
    /// <summary>
    /// 計算標記值
    /// </summary>
    /// <param name="file"></param>
    /// <param name="replacepath"></param>
    /// <returns></returns>
    public static string GetBundlePath(FileInfo file,string replacepath)
    {
        string path = GetWindowsPath(file.FullName);
        //Debug.Log("windows:" + path);//F:/U3D/HotFit/Assets/_Source/TEST/New Folder/Cube.prefab
        int length = path.IndexOf(replacepath);
        //Debug.Log("length" + length);
        length += replacepath.Length+1;//replacepath Assets/_Source/ 
        //Debug.Log("length" + length);

        int namelength = path.LastIndexOf(file.Name);

        int templength = replacepath.LastIndexOf("/");

        string sceneHead = replacepath.Substring(templength +1,replacepath .Length -templength -1);
        Debug.Log("head:" + sceneHead);
        if (namelength -length > 0)
        {
            string substring = path.Substring(length,path .Length -length);
            string[] result = substring.Split('/');
            Debug.Log("result:" + result[0]);
            return sceneHead+"/"+ result[0];
        }else
        {
            return sceneHead;
        }
    }
    private static void SetTag(FileInfo file, string tag, Dictionary<string, string> dic)
    {
        Debug.Log("設置文件標籤:" + file.Name+" TAG:"+tag );
        int assetcount = file.FullName.IndexOf("Assets");
        string path = file.FullName.Substring(assetcount, file.FullName.Length - assetcount);
        AssetImporter imp = AssetImporter.GetAtPath(path);
        imp.assetBundleName = tag;
        if (file.Extension == ".unity")
        {
            imp.assetBundleVariant = "u3d";
        } else
        {
            imp.assetBundleVariant = "ld";
        }
        string name = null;
        string[] subs = tag.Split('/');
        if (subs.Length > 1)
        {
            name = subs[1];
        } else
        {
            name = tag;
        }
        string assetpath = tag.ToLower() + "." + imp.assetBundleVariant;
        if (!dic.ContainsKey(name))
        {
            Debug.Log("key:"+name +"  value:"+assetpath );
            dic.Add(name, assetpath);
        }
    }

這個比較複雜,進行了一系列的計算轉化的,就是爲了映射你的資源目錄zeya

好,放打包腳本,該方法是編輯器擴展方法,頭文件沒放,可以自行添加

    /// <summary>
    /// 打包
    /// </summary>
    /// <param name="target"></param>
    private static void Build(BuildPlat  plat,BuildTarget target)
    {
        string path = ConfigSetting.BuildPath + plat.ToString() + "/";
        if(!Directory .Exists (path))
        {
            Directory.CreateDirectory(path);
        }
        Debug.Log("打包路徑:" + path);
        BuildPipeline.BuildAssetBundles(path, BuildAssetBundleOptions.ChunkBasedCompression, target);
        Debug.Log("打包完成");
        AssetDatabase.Refresh();//刷新文件
    }

當設置了tag,並打包後,會輸出打包完成。並且會在streamingasset下生產對應的文件夾 以win64爲例,打開後內容如下,如果出現說明完成打包。

接下來是上傳文件到服務器,我們採取http協議,使用hfs 進行測試。hfs是一個輕量級的文件服務器,不需要安裝,雙擊運行就行了

然後關於下載,要首先下載win64bundle,獲取manifest文件,然後讀取項目中的配置文件,根據對應的路徑進行資源加載

bundle下載:

 UnityWebRequest req = UnityWebRequestAssetBundle.GetAssetBundle(manifestPath);
        yield return req.SendWebRequest();
        while (req.downloadProgress < 1.0f)
        {
            yield return null;
        }
      AssetBundle  bundle = DownloadHandlerAssetBundle.GetContent(req);
        assetmanifest = bundle.LoadAsset("AssetBundleManifest") as AssetBundleManifest;

讀取配置文件

    /// <summary>
    /// 讀取配置文件
    /// </summary>
    /// <param name="filename"></param>
    public void ReadConfigFile()
    {
        string PATH = ConfigSetting.OutSourcePath+manager .SceneName +".txt";
        Debug.Log("配置信息 path:" + PATH);
        FileStream fs = new FileStream(PATH, FileMode.Open);
        StreamReader sr = new StreamReader(fs);
        int linecount = int.Parse(sr.ReadLine());
        for (int i = 0; i < linecount; i++)
        {
            string[] data = sr.ReadLine().Split ('*');
            Debug.Log("bundlename:"+data [0] + "   bundle:" + data [1]);
            allAsset.Add(data[0], data[1]);
        }
        sr.Close();
        fs.Close();
    }

經過測試確實是可以的,有問題歡迎來諮

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章