欢迎光临散文网 会员登陆 & 注册

HybridCLR2.0X版本教程

2023-03-09 18:16 作者:我家的柯基叫团团  | 我要投稿

using Codice.Client.BaseCommands.Download;

using Cysharp.Threading.Tasks;

using HybridCLR;

using System;

using System.Collections;

using System.Collections.Generic;

using System.Linq;

using UnityEditor;

using UnityEngine;

using UnityEngine.UI;

using YooAsset;


public class LoadDll : MonoBehaviour

{


  // 资源系统运行模式

  public EPlayMode PlayMode = EPlayMode.EditorSimulateMode;


  //CDN地址

  public string DefaultHostServer = "http://192.168.3.3/Package/";

  public string FallbackHostServer = "http://192.168.3.3/Package/";


  //热更新的dll名称

  public string HotDllName = "Hotfix.dll";



  //弹窗对象,此对象当前为AOT层中的预制体对象,不放入热更新

  public GameObject tx;


  //补充元数据dll的列表,Yooasset中不需要带后缀

  public static List<string> AOTMetaAssemblyNames { get; } = new List<string>()

  {

    "mscorlib.dll",

    "System.dll",

    "System.Core.dll",

    "UniTask.dll"

  };


  //获取资源二进制

  private static Dictionary<string, byte[]> s_assetDatas = new Dictionary<string, byte[]>();

  public static byte[] GetAssetData(string dllName)

  {

    return s_assetDatas[dllName];

  }



  void Start()

  {

    //初始化BetterStreamingAssets插件

    BetterStreamingAssets.Initialize();

    StartCoroutine(DownLoadAssetsByYooAssets(this.StartGame));

  }




  #region Yooasset下载


  /// <summary>

  /// 获取下载信息

  /// </summary>

  /// <param name="onDownloadComplete"></param>

  /// <returns></returns>

  IEnumerator DownLoadAssetsByYooAssets(Action onDownloadComplete)

  {

    // 1.初始化资源系统

    YooAssets.Initialize();


    // 创建默认的资源包

    var package = YooAssets.CreateAssetsPackage("DefaultPackage");


    // 设置该资源包为默认的资源包,可以使用YooAssets相关加载接口加载该资源包内容。

    YooAssets.SetDefaultAssetsPackage(package);


    if (PlayMode == EPlayMode.EditorSimulateMode)

    {

      //编辑器模拟模式

      var initParameters = new EditorSimulateModeParameters();

      initParameters.SimulatePatchManifestPath = EditorSimulateModeHelper.SimulateBuild("DefaultPackage");

      yield return package.InitializeAsync(initParameters);

    }

    else if (PlayMode == EPlayMode.HostPlayMode)

    {

      //联机运行模式

      var initParameters = new HostPlayModeParameters();

      initParameters.QueryServices = new QueryStreamingAssetsFileServices();

      initParameters.DefaultHostServer = DefaultHostServer;

      initParameters.FallbackHostServer = FallbackHostServer;

      yield return package.InitializeAsync(initParameters);

    }

    else if (PlayMode == EPlayMode.OfflinePlayMode)

    {

      //单机模式

      var initParameters = new OfflinePlayModeParameters();

      yield return package.InitializeAsync(initParameters);



    }


    //2.获取资源版本

    var operation = package.UpdatePackageVersionAsync();

    yield return operation;


    if (operation.Status != EOperationStatus.Succeed)

    {

      //更新失败、显示弹窗窗口     

      tx= Instantiate(Resources.Load<GameObject>("ShowMsgBox"));

      tx.transform.GetChild(0).GetChild(0).GetChild(0).GetComponent<Text>().text = "资源下载失败,资源服务端未开启";

      tx.transform.GetChild(0).GetChild(0).GetChild(1).GetComponent<Button>().onClick.AddListener(() => 

      {

#if !UNITY_EDITOR

        Application.Quit();

#else

      EditorApplication.isPlaying = false;

#endif

        DestroyImmediate(tx);

      });

      Debug.LogError(operation.Error);

      yield break;

    }

    string PackageVersion = operation.PackageVersion;


    //3.更新补丁清单

    var operation2 = package.UpdatePackageManifestAsync(PackageVersion);

    yield return operation2;


    if (operation2.Status != EOperationStatus.Succeed)

    {

      //更新失败

      Debug.LogError(operation2.Error);

      //TODO:

      yield break;

    }

    //4.下载补丁包信息,反馈到弹窗

    yield return Download();


  }


  /// <summary>

  /// 获取下载的信息大小,显示弹窗上

  /// </summary>

  /// <returns></returns>

  IEnumerator Download()

  {

    int downloadingMaxNum = 10;

    int failedTryAgain = 3;

    int timeout = 60;

    var package = YooAssets.GetAssetsPackage("DefaultPackage");

    var downloader = package.CreatePatchDownloader(downloadingMaxNum, failedTryAgain, timeout);


    //没有需要下载的资源

    if (downloader.TotalDownloadCount == 0)

    {

      Debug.Log("没有资源更新,直接进入游戏加载环节");

      StartCoroutine(GotoStatr());

      yield break;

    }

    //需要下载的文件总数和总大小

    int totalDownloadCount = downloader.TotalDownloadCount;

    long totalDownloadBytes = downloader.TotalDownloadBytes;

    Debug.Log($"文件总数:{totalDownloadCount}:::总大小:{totalDownloadBytes}");


    //显示更新提示UI界面 

    tx = Instantiate(Resources.Load<GameObject>("ShowMsgBox"));

    tx.transform.GetChild(0).GetChild(0).GetChild(0).GetComponent<Text>().text = $"文件总数:{totalDownloadCount},总大小:{totalDownloadBytes}KB";

    tx.transform.GetChild(0).GetChild(0).GetChild(1).GetComponent<Button>().onClick.AddListener(() =>

    {

      StartCoroutine(GetDownload());

    });

  }


  /// <summary>

  /// 按键回调下载

  /// </summary>

  /// <returns></returns>

  IEnumerator GetDownload() 

  {

    int downloadingMaxNum = 10;

    int failedTryAgain = 3;

    int timeout = 60;

    var package = YooAssets.GetAssetsPackage("DefaultPackage");

    var downloader = package.CreatePatchDownloader(downloadingMaxNum, failedTryAgain, timeout);


    //注册回调方法

    downloader.OnDownloadErrorCallback = OnDownloadErrorFunction;

    downloader.OnDownloadProgressCallback = OnDownloadProgressUpdateFunction;

    downloader.OnDownloadOverCallback = OnDownloadOverFunction;

    downloader.OnStartDownloadFileCallback = OnStartDownloadFileFunction;


    //开启下载

    downloader.BeginDownload();

    yield return downloader;

    //检测下载结果

    if (downloader.Status == EOperationStatus.Succeed)

    {

      //下载成功

      StartCoroutine(GotoStatr());

      Debug.Log("更新完成!");

    }

    else

    {

      //下载失败

      Debug.LogError("更新失败!");

      //TODO:

    }


  }


  /// <summary>

  /// 开始下载

  /// </summary>

  /// <param name="fileName"></param>

  /// <param name="sizeBytes"></param>

  /// <exception cref="NotImplementedException"></exception>

  private void OnStartDownloadFileFunction(string fileName, long sizeBytes)

  {

    Debug.Log(string.Format("开始下载:文件名:{0}, 文件大小:{1}", fileName, sizeBytes));

  }


  /// <summary>

  /// 下载完成

  /// </summary>

  /// <param name="isSucceed"></param>

  /// <exception cref="NotImplementedException"></exception>

  private void OnDownloadOverFunction(bool isSucceed)

  {

    Debug.Log("下载" + (isSucceed ? "成功" : "失败"));

  }


  /// <summary>

  /// 更新中

  /// </summary>

  /// <param name="totalDownloadCount"></param>

  /// <param name="currentDownloadCount"></param>

  /// <param name="totalDownloadBytes"></param>

  /// <param name="currentDownloadBytes"></param>

  /// <exception cref="NotImplementedException"></exception>

  private void OnDownloadProgressUpdateFunction(int totalDownloadCount, int currentDownloadCount, long totalDownloadBytes, long currentDownloadBytes)

  {

    tx.transform.GetChild(0).GetChild(0).GetChild(0).GetComponent<Text>().text = string.Format("文件总数:{0}, 已下载文件数:{1}, 下载总大小:{2}, 已下载大小:{3}", totalDownloadCount, currentDownloadCount, totalDownloadBytes, currentDownloadBytes);


    Debug.Log(string.Format("文件总数:{0}, 已下载文件数:{1}, 下载总大小:{2}, 已下载大小:{3}", totalDownloadCount, currentDownloadCount, totalDownloadBytes, currentDownloadBytes));

  }


  /// <summary>

  /// 下载出错

  /// </summary>

  /// <param name="fileName"></param>

  /// <param name="error"></param>

  /// <exception cref="NotImplementedException"></exception>

  private void OnDownloadErrorFunction(string fileName, string error)

  {

    Debug.LogError(string.Format("下载出错:文件名:{0}, 错误信息:{1}", fileName, error));

  }


  /// <summary>

  /// 完成下载验证开始进入游戏

  /// </summary>

  /// <returns></returns>

  IEnumerator GotoStatr()

  {

    var package = YooAssets.GetAssetsPackage("DefaultPackage");

    //热更新Dll名称

    var Allassets = new List<string>

      {

        HotDllName,


      }.Concat(AOTMetaAssemblyNames);

    foreach (var asset in Allassets)

    {

      RawFileOperationHandle handle = package.LoadRawFileAsync(asset);

      yield return handle;

      byte[] fileData = handle.GetRawFileData();

      s_assetDatas[asset] = fileData;

      Debug.Log($"dll:{asset} size:{fileData.Length}");

    }

    DestroyImmediate(tx);

    StartGame();

  }



  // 内置文件查询服务类

  private class QueryStreamingAssetsFileServices : IQueryServices

  {

    public bool QueryStreamingAssets(string fileName)

    {

      // 注意:使用了BetterStreamingAssets插件,使用前需要初始化该插件!

      string buildinFolderName = YooAssets.GetStreamingAssetBuildinFolderName();

      return BetterStreamingAssets.FileExists($"{buildinFolderName}/{fileName}");

    }

  }


#endregion






  void StartGame()

  {

    LoadMetadataForAOTAssemblies();


#if !UNITY_EDITOR

    System.Reflection.Assembly.Load(GetAssetData("Hotfix.dll"));

#endif

    //委托加载方式,加载prefab

    var package = YooAssets.GetAssetsPackage("DefaultPackage");

    AssetOperationHandle handle = package.LoadAssetAsync<GameObject>("HotUpdatePrefab");

    handle.Completed += Handle_Completed;

  }

  private void Handle_Completed(AssetOperationHandle obj)

  {

    GameObject go = obj.InstantiateSync();

    Debug.Log($"Prefab name is {go.name}");

  }



  /// <summary>

  /// 为aot assembly加载原始metadata, 这个代码放aot或者热更新都行。

  /// 一旦加载后,如果AOT泛型函数对应native实现不存在,则自动替换为解释模式执行

  /// </summary>

  private static void LoadMetadataForAOTAssemblies()

  {

    /// 注意,补充元数据是给AOT dll补充元数据,而不是给热更新dll补充元数据。

    /// 热更新dll不缺元数据,不需要补充,如果调用LoadMetadataForAOTAssembly会返回错误

    HomologousImageMode mode = HomologousImageMode.SuperSet;

    foreach (var aotDllName in AOTMetaAssemblyNames)

    {

      byte[] dllBytes = GetAssetData(aotDllName);

      // 加载assembly对应的dll,会自动为它hook。一旦aot泛型函数的native函数不存在,用解释器版本代码

      LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, mode);

      Debug.Log($"LoadMetadataForAOTAssembly:{aotDllName}. mode:{mode} ret:{err}");

    }

  }

}


HybridCLR2.0X版本教程的评论 (共 条)

分享到微博请遵守国家法律