unity Addressable系统及其Xlua脚本热更新全过程详细解析(-)

21 篇文章 1 订阅
17 篇文章 0 订阅

1.本来关于Addressable 的文章已经写了2篇了,但对这个addressable系统有些地方还是不清楚怎么用,这次就用来记录一下结合xlua 实现资源和代码的全更新方案。
列取一下一开始遇到的问题:
1.xlua 开发的时候我们用的都是.lua 文件,这个是unity 无法识别的文件这个要怎么解决?
2.xlua 读取文件的bytes 都是同步读取方式,最新的addressable 很多的同步读取方式都已经弃用。怎么解决这个同步读取问题?
带着这些问题,下面介绍我提供的解决方案。

分享一下个人Demo工程:https://github.com/IsaWinding/AddressableXluaFramework.git
直接上干货:

  1. .lua 文件转.txt 文件,并且参与Addressable 的分组策略:
  [MenuItem("AddressableMenu/将Xlua .lua文件转为.txt 文件", false, 1)]
    public static void OnKeyUpdateAllLuaToTxt()
    {
        var txtPath = GameSettings.GetLuaTxtPath();
        var luaPath = GameSettings.GetLuaResourcesPath();
        //FileHelper.DeleteFilesExcept(txtPath, ".txt");
        FileHelper.DeleteCreateNewDirectory(txtPath);
        FileHelper.CopyDirectoryAndSuffix(luaPath, txtPath, ".lua", ".txt");
        AssetDatabase.Refresh();
    }

主要是复制.lua 文件到一个特定的.txt 问价夹下,并修改其后缀名。

   public static List<string> specPath = new List<string> { "LocalChange", "LocalDontChange", 
        "RemoteChange", "RemoteDontChange", "LuaTxt" };

特殊分组策略。主要将特殊的文件夹,作为组名进行分组。
在这里插入图片描述
分组策略介绍
a.LocalChange 组下的资源,会入初始包。如果后期更新的话,下面的资源会整体更新。
b.LocalNoChange 组下的资源,会入初始包。如果后期更新的话,会将有变化的资源列入新的RomateChange组,打入下次更新资源中。
c.RomateChange 组下的资源 ,不会入初始包,如果后期更新的话,下面的资源会整体更新。
d. RomateNoChange 组下的资源,不会入初始包。如果后期更新的话,会将有变化的资源列入新的RomateChange组,打入下次更新资源中。
清理上次打包的资源包括服务器热更新数据

    [MenuItem("AddressableMenu/清理上次打包的资源包括服务器热更新数据", priority = 2)]
    public static void ClearAllAddressBuild()
    {
        AddressableAssetSettings.CleanPlayerContent();
        var serverDataPath = GetServerDataPath();
        Debug.Log("clear serverdata " + serverDataPath);
        if (System.IO.Directory.Exists(serverDataPath))
        {
            System.IO.Directory.Delete(serverDataPath, true);
        }
    }

重新构建资源

    /// <summary>
    /// 重新构建Address资源
    /// </summary>
    [MenuItem("AddressableMenu/清理上次构建的资源并且重新打包", priority = 3)]
    public static void ReBuildAddress()
    {
        ClearAllAddressBuild();
        //1.更新最新的lua 文件
        OnKeyUpdateAllLuaToTxt();
        //2.对所有资源进行重新分组打标签
        LoopSetAllDirectorToAddress(GameSettings.GetABRootPath());
        AddressableAssetSettings.BuildPlayerContent();
    }
    /// 对比更新列表
    [MenuItem("AddressableMenu/获取和上次发包的差异列表", priority = 4)]
    public static void CheckForUpdateContent()
    {
        //与上次打包做资源对比
        string buildPath = ContentUpdateScript.GetContentStateDataPath(false);
        var m_Settings = AddressableAssetSettingsDefaultObject.Settings;
        List<AddressableAssetEntry> entrys = ContentUpdateScript.GatherModifiedEntries(m_Settings, buildPath);
        if (entrys.Count == 0)
        {
            Debug.Log("没有资源更新");
            return;
        }
        StringBuilder sbuider = new StringBuilder();
        sbuider.AppendLine("Need Update Assets:");
        foreach (var _ in entrys){
            sbuider.AppendLine(_.address);
        }
        Debug.Log(sbuider.ToString());
        //将被修改过的资源单独分组
        var groupName = string.Format("UpdateGroup_{0}", DateTime.Now.ToString("yyyyMMddHHmmss"));
        ContentUpdateScript.CreateContentUpdateGroup(m_Settings, entrys, groupName);
    }
    //迭代打包
    [MenuItem("AddressableMenu/迭代构建资源", priority = 5)]
    public static void BuildUpdate()
    {
        //1.更新最新的lua 文件
        OnKeyUpdateAllLuaToTxt();
        //2.对Lua 文件进行重新分组打标签
        LoopSetAllDirectorToAddress(GameSettings.GetLuaTxtPath());
        //3.对比更新列表
        CheckForUpdateContent();

        var path = ContentUpdateScript.GetContentStateDataPath(false);
        var m_Settings = AddressableAssetSettingsDefaultObject.Settings;
        AddressablesPlayerBuildResult result = ContentUpdateScript.BuildContentUpdate(AddressableAssetSettingsDefaultObject.Settings, path);
        Debug.Log("BuildFinish path = " + m_Settings.RemoteCatalogBuildPath.GetValue(m_Settings));
    }
    //迭代打包
    [MenuItem("AddressableMenu/复制服务器热更新资源到本地服务器WWW路径", priority = 6)]
    public static void CopyServerDataToLocalServer()
    {
        FileHelper.CopyDirectory(GetServerDataPath(),LocalServerWWWPath);
        Debug.Log("复制服务器热更新资源到本地服务器完成 路径:" +LocalServerWWWPath);
    }
    [MenuItem("AddressableMenu/打印构建路径", priority = 7)]
    public static void Test()
    {
        Debug.Log("BuildPath = " + Addressables.BuildPath);
        Debug.Log("PlayerBuildDataPath = " + Addressables.PlayerBuildDataPath);
        Debug.Log("RemoteCatalogBuildPath = " + AddressableAssetSettingsDefaultObject.Settings.RemoteCatalogBuildPath.GetValue(AddressableAssetSettingsDefaultObject.Settings));
    }
    private static void LoopSetAllDirectorToAddress(string pFileDirectorRoot)
    {
        if (Directory.Exists(pFileDirectorRoot))
        {
            SetDirectorABNameNull(pFileDirectorRoot);
            var dirctory = new DirectoryInfo(pFileDirectorRoot);
            var direcs = dirctory.GetDirectories("*", SearchOption.TopDirectoryOnly);
            if (direcs.Length > 0)
            {
                for (var i = 0; i < direcs.Length; i++)
                {
                    if (direcs[i].FullName != pFileDirectorRoot)
                    {
                        LoopSetAllDirectorToAddress(direcs[i].FullName);
                    }
                }
            }
        }
    }
    private static void SetDirectorABNameNull(string pFileDirectorRoot)
    {
        if (Directory.Exists(pFileDirectorRoot))
        {
            var dirctory = new DirectoryInfo(pFileDirectorRoot);
            var files = dirctory.GetFiles("*", SearchOption.TopDirectoryOnly);
            bool isAdd = false;
            for (var i = 0; i < files.Length; i++)
            {
                var file = files[i];
                if (file.Name.EndsWith(".meta"))
                    continue;
                string assetPath = file.FullName;
                assetPath = FormatFilePath(assetPath);
                var assetLength = UnityEngine.Application.dataPath.Length - 6;
                assetPath = assetPath.Substring(assetLength, assetPath.Length - assetLength);
                var groupName = GetGroupName(dirctory.Name, assetPath);
                AutoGroup(groupName, assetPath, groupName);
                isAdd = true;
            }
            if (isAdd)
                AssetDatabase.Refresh();
        }
    }
    public static string GetGroupName(string pDirctoryName, string pAssetPath)
    {
        var groupName = pDirctoryName;
        foreach (var item in specPath)
        {
            if (pAssetPath.Contains(item))
            {
                groupName = item;
                break;
            }
        }
        return groupName;
    }
    public static string FormatFilePath(string filePath)
    {
        var path = filePath.Replace('\\', '/');
        path = path.Replace("//", "/");
        return path;
    }
    public static void AutoGroup(string groupName, string assetPath,string pLable)
    {
        var settings = AddressableAssetSettingsDefaultObject.Settings;
        AddressableAssetGroup group = settings.FindGroup(groupName);
        if (group == null){
            group = CreatAssetGroup<System.Data.SchemaType>(settings, groupName);
        }
        var guid = AssetDatabase.AssetPathToGUID(assetPath);
        var entry = settings.CreateOrMoveEntry(guid, group);
        entry.address = assetPath;
        entry.SetLabel(pLable, true, true);
    }
    private static AddressableAssetGroup CreatAssetGroup<SchemaType>(AddressableAssetSettings settings, string groupName)
    {
        return settings.CreateGroup(groupName, false, false, false,
            new List<AddressableAssetGroupSchema> { settings.DefaultGroup.Schemas[0], settings.DefaultGroup.Schemas[1] }, typeof(SchemaType));
    }

游戏启动后的更新流程:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.UI;

public class AddressUpdater : MonoBehaviour
{
    private string str;
    public Text outputText;
    private List<object> _updateKeys = new List<object>();
    void Start(){
        UpdateCatalog();
    }
    /// <summary>
    /// 对比更新Catalog
    /// </summary>
    public async void UpdateCatalog(){
        str = "";
        var handlew = Addressables.InitializeAsync();
        await handlew.Task;
        //开始连接服务器检查更新
        var handle = Addressables.CheckForCatalogUpdates(false);
        await handle.Task;
        Debug.Log("check catalog status " + handle.Status);
        ShowLog("check catalog status " + handle.Status);
        if (handle.Status == AsyncOperationStatus.Succeeded)
        {
            List<string> catalogs = handle.Result;
            if (catalogs != null && catalogs.Count > 0)
            {
                foreach (var catalog in catalogs)
                {
                    ShowLog("catalog  " + catalog);
                }
                Debug.Log("download catalog start ");
                str += "download catalog start \n";
                outputText.text = str;
                var updateHandle = Addressables.UpdateCatalogs(catalogs, false);
                await updateHandle.Task;
                foreach (var item in updateHandle.Result)
                {
                    ShowLog("catalog result " + item.LocatorId);
                    foreach (var key in item.Keys){
                        Debug.Log("catalog key " + key);
                        ShowLog("catalog key " + key);
                    }
                    _updateKeys.AddRange(item.Keys);
                }
                ShowLog("download catalog finish " + updateHandle.Status);
            }
            else
            {
                Debug.Log("dont need update catalogs");
                ShowLog("dont need update catalogs");
            }
        }
        Addressables.Release(handle);
        DownLoad();
    }
    /// <summary>
    /// 主界面显示Log
    /// </summary>
    /// <param name="textStr"></param>
    private void ShowLog(string textStr){
        str += textStr + "\n";
        outputText.text = str;
    }
    public IEnumerator DownAssetImpl(){
        var downloadsize = Addressables.GetDownloadSizeAsync(_updateKeys);
        yield return downloadsize;
        Debug.Log("start download size :" + downloadsize.Result);
        ShowLog("start download size :" + downloadsize.Result);
        if (downloadsize.Result > 0){
            var download = Addressables.DownloadDependenciesAsync(_updateKeys);//, Addressables.MergeMode.Union
            yield return download;
            //await download.Task;
            if (download.Result != null)
            {
                Debug.Log("download result type " + download.Result.GetType());
                ShowLog("download result type " + download.Result.GetType());
                foreach (var item in download.Result as List<UnityEngine.ResourceManagement.ResourceProviders.IAssetBundleResource>)
                {
                    var ab = item.GetAssetBundle();
                    Debug.Log("ab name " + ab.name);
                    ShowLog("ab name " + ab.name);
                    foreach (var name in ab.GetAllAssetNames())
                    {
                        Debug.Log("asset name " + name);
                        ShowLog("asset name " + name);
                    }
                }
            }
            Addressables.Release(download);
        }
        Addressables.Release(downloadsize);
        OnLoadXLuaClient();
    }

    /// <summary>
    /// 下载资源
    /// </summary>
    public void DownLoad()
    {
        str = "";
        StartCoroutine(DownAssetImpl());
        //CtrlLoadSlider();
    }
 
    public void OnLoadXLuaClient()
    {
        //AddressLoadManager.LoadLuaTxtRes(()=> {
        //    if (XLuaClient.Instance == null)
        //    {
        //        var go = new GameObject("XLuaClient");
        //        go.AddComponent<XLuaClient>();
        //    }
        //    XLuaClient.Instance.StartMain();
        //    OnDownLoadFinish();
        //});
        if (XLuaClient.Instance == null)
        {
            var go = new GameObject("XLuaClient");
            go.AddComponent<XLuaClient>();
        }
        else
        {
            XLuaClient.Instance.OnClear();
        }
        OnDownLoadFinish();
    }
    public void OnDownLoadFinish()
    {
        ShowLog("下载资源完成!!");
        UnityEngine.SceneManagement.SceneManager.LoadScene("2_GameMain");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值