HybridCLR2.0X版本教程

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
{
??// 資源系統(tǒng)運行模式
??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;
??//補充元數(shù)據(jù)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.初始化資源系統(tǒng)
????YooAssets.Initialize();
????// 創(chuàng)建默認的資源包
????var package = YooAssets.CreateAssetsPackage("DefaultPackage");
????// 設置該資源包為默認的資源包,可以使用YooAssets相關加載接口加載該資源包內(nèi)容。
????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)
????{
??????//聯(lián)機運行模式
??????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("沒有資源更新,直接進入游戲加載環(huán)節(jié)");
??????StartCoroutine(GotoStatr());
??????yield break;
????}
????//需要下載的文件總數(shù)和總大小
????int totalDownloadCount = downloader.TotalDownloadCount;
????long totalDownloadBytes = downloader.TotalDownloadBytes;
????Debug.Log($"文件總數(shù):{totalDownloadCount}:::總大小:{totalDownloadBytes}");
????//顯示更新提示UI界面?
????tx = Instantiate(Resources.Load<GameObject>("ShowMsgBox"));
????tx.transform.GetChild(0).GetChild(0).GetChild(0).GetComponent<Text>().text = $"文件總數(shù):{totalDownloadCount},總大小:{totalDownloadBytes}KB";
????tx.transform.GetChild(0).GetChild(0).GetChild(1).GetComponent<Button>().onClick.AddListener(() =>
????{
??????StartCoroutine(GetDownload());
????});
??}
??/// <summary>
??/// 按鍵回調(diào)下載
??/// </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);
????//注冊回調(diào)方法
????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("文件總數(shù):{0}, 已下載文件數(shù):{1}, 下載總大?。簕2}, 已下載大?。簕3}", totalDownloadCount, currentDownloadCount, totalDownloadBytes, currentDownloadBytes);
????Debug.Log(string.Format("文件總數(shù):{0}, 已下載文件數(shù):{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();
??}
??// 內(nèi)置文件查詢服務類
??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泛型函數(shù)對應native實現(xiàn)不存在,則自動替換為解釋模式執(zhí)行
??/// </summary>
??private static void LoadMetadataForAOTAssemblies()
??{
????/// 注意,補充元數(shù)據(jù)是給AOT dll補充元數(shù)據(jù),而不是給熱更新dll補充元數(shù)據(jù)。
????/// 熱更新dll不缺元數(shù)據(jù),不需要補充,如果調(diào)用LoadMetadataForAOTAssembly會返回錯誤
????HomologousImageMode mode = HomologousImageMode.SuperSet;
????foreach (var aotDllName in AOTMetaAssemblyNames)
????{
??????byte[] dllBytes = GetAssetData(aotDllName);
??????// 加載assembly對應的dll,會自動為它hook。一旦aot泛型函數(shù)的native函數(shù)不存在,用解釋器版本代碼
??????LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, mode);
??????Debug.Log($"LoadMetadataForAOTAssembly:{aotDllName}. mode:{mode} ret:{err}");
????}
??}
}