HybridCLR热更新中使用YooAsset时的LoadDll.cs

该文章提供了一个使用YooAsset库在HybridCLR框架下进行热更新的C#代码示例。通过初始化资源系统,下载并加载资源包,包括Hotfix.dll和AOTMetaAssemblyNames中的DLL,实现了在不同运行模式下的资源管理。在编辑器模拟模式、联机运行模式和单机模式下,资源系统的初始化有所不同。文章还包含了下载资源、处理下载进度和错误的回调方法。
摘要由CSDN通过智能技术生成

前言

HybridCLR 热更新中使用 YooAssetLoadDll.cs 脚本要做变更。

代码示例:LoadDll.cs

using HybridCLR;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using YooAsset;

public class LoadDll : MonoBehaviour
{
    // 资源系统运行模式
    public EPlayMode PlayMode = EPlayMode.EditorSimulateMode;

    //CDN地址
    public string DefaultHostServer = ""; //资源服务器地址
    public string FallbackHostServer = ""; //资源服务器地址

    public string HotDllName = "Hotfix.dll";

    //补充元数据dll的列表,Yooasset中不需要带后缀
    public static List<string> AOTMetaAssemblyNames { get; } = new List<string>()
    {
        "mscorlib.dll",
        "System.dll",
        "System.Core.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下载

    IEnumerator DownLoadAssetsByYooAssets(Action onDownloadComplete)
    {
        // 1.初始化资源系统
        YooAssets.Initialize();

        // 创建默认的资源包
        var package = YooAssets.CreatePackage("DefaultPackage");
        // 设置该资源包为默认的资源包,可以使用YooAssets相关加载接口加载该资源包内容。
        YooAssets.SetDefaultPackage(package);

        if (PlayMode == EPlayMode.EditorSimulateMode)
        {
            //编辑器模拟模式
            var initParameters = new EditorSimulateModeParameters();
            initParameters.SimulateManifestFilePath = 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);
        }
        Debug.Log("资源系统初始化完成。");

        //2.获取资源版本
        var operation = package.UpdatePackageVersionAsync();
        yield return operation;

        if (operation.Status != EOperationStatus.Succeed)
        {
            //更新失败
            Debug.Log("获取资源版本失败!");
            Debug.LogError(operation.Error);
            //TODO
            yield break;
        }
        string PackageVersion = operation.PackageVersion;

        //3.更新补丁清单
        var operation2 = package.UpdatePackageManifestAsync(PackageVersion);
        yield return operation2;

        if (operation2.Status != EOperationStatus.Succeed)
        {
            //更新失败
            Debug.Log("补丁清单更新失败!");
            Debug.LogError(operation2.Error);
            //TODO:
            yield break;
        }

        //4.下载补丁包
        yield return Download();

        //TODO:判断是否下载成功...
        //热更新Dll名称
        var Allassets = new List<string>
        {
            HotDllName,
            
        }.Concat(AOTMetaAssemblyNames);
        
        foreach (var asset in Allassets)
        {
            RawFileOperationHandle handle = package.LoadRawFileAsync(asset);
            //var handle = package.LoadAssetAsync<GameObject>(asset);
            yield return handle;
            byte[] fileData = handle.GetRawFileData();
            s_assetDatas[asset] = fileData;
            Debug.Log($"dll:{asset}  size:{fileData.Length}");
        }

        onDownloadComplete();
    }

    IEnumerator Download()
    {
        int downloadingMaxNum = 10;
        int failedTryAgain = 3;
        int timeout = 60;
        var package = YooAssets.GetPackage("DefaultPackage");
        var downloader = package.CreateResourceDownloader(downloadingMaxNum, failedTryAgain, timeout);

        //没有需要下载的资源
        if (downloader.TotalDownloadCount == 0)
        {
            Debug.Log("没有资源更新");
            yield break;
        }

        //需要下载的文件总数和总大小
        int totalDownloadCount = downloader.TotalDownloadCount;
        long totalDownloadBytes = downloader.TotalDownloadBytes;
        Debug.Log($"文件总数:{totalDownloadCount}:::总大小:{totalDownloadBytes}");
        //注册回调方法
        downloader.OnDownloadErrorCallback = OnDownloadErrorFunction;
        downloader.OnDownloadProgressCallback = OnDownloadProgressUpdateFunction;
        downloader.OnDownloadOverCallback = OnDownloadOverFunction;
        downloader.OnStartDownloadFileCallback = OnStartDownloadFileFunction;

        //开启下载
        downloader.BeginDownload();
        yield return downloader;

        //检测下载结果
        if (downloader.Status == EOperationStatus.Succeed)
        {
            //下载成功
            Debug.Log("更新完成!");
            //TODO:
        }
        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)
    {
        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));
    }

    // 内置文件查询服务类
    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.GetPackage("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}");
        }
    }
}

致谢:
bilibili博主:@我家的柯基叫团团 —— HybridCLR2.0X版本教程
感谢!如有侵权,联系删除!再次感谢!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值