ILRuntimeユニティホットアップデート

免責事項:この記事はブロガーオリジナル記事です、続くBY-SAのCC 4.0を著作権契約、複製、元のソースのリンクと、この文を添付してください。
このリンク: https://blog.csdn.net/wangjiangrong/article/details/90294366

新しいプロジェクトでは、ILRuntime実施形態を更新するための熱の使用は、XLuaのようなとは異なり、このようにホット更新がされた純粋なC#を実装 Luaのコードは、クライアントを知っている必要はありませんので、。より詳細な説明は、公式ドキュメントを参照してくださいすることができます。

公式プレゼンテーションとドキュメント:http://ourpalm.github.io/ILRuntime/public/v1/guide/index.html

次のように現在大体理解:ゲームは2つの部分、Unityおよび修正プログラムに分かれています。ロジックゲームはここでの主な部分は修正プログラムで書かれているより多くの熱い部品を必要とし、その後Hotfix.dllファイルとして使用するユニティのためにそれをエクスポートする可能性があります。コードを更新する必要がある場合は、オンラインゲームの後、唯一のあなたは、コードの修正プログラムを修正し、その後、Hotfix.dllもっと熱くすることができ、新しいファイルを生成する必要があります。

その後、我々はこのようなプロセスを実装するために簡単なデモを使用します。アイデアは、ある元のUIロジック修正クラスない継承MonoBehaviourがないので、それはスタートとのインタフェースによって実現され、ここで、等を更新し、対応する呼部分Unityは、修正プログラムは、ライフサイクルで達成しました。操作の方法によりGameObject.Find対応する構成要素を発見しています。

 

ユニティエンジニアリング環境を作成します

まず、新しいユニティプロジェクトを作成し、その後、プロジェクトはILRuntimeがそれらを必要とする輸入の一部となる、それはMono.Cecil.20、Mono.Cecil.Pdbで公式のデモで、ILRuntime 3つのフォルダ(ILRuntime /アダプタ/エディタを削除します)

プレイヤーの設定を確認してください - > [その他の設定] - > [許可「危険な」コードオプション

 

修正プログラムのエンジニアリング環境を作成します

に示すように、>プロジェクト、修正プログラムという名前のC#クラスライブラリを作成 - >新規 - 私たちのVS、ファイルを開きます

その後、溶液 - >右基準では、参照を追加、など

どのUnityEngine.dll、UnityEngine.UI.dllとUnityEngine.CoreModule.dllユニティ、ユニティアセンブリ-CSharp.dllプロジェクトは、ライブラリの上に作成したインストールディレクトリにある三つのファイル/ ScriptAssembliesディレクトリ

注意:UnityEngine.dll新聞は、公式デモで間違ったことを見つけることができない場合UnityEngine.CoreModule.dllのみUnity2017.2のリリース後、以前のバージョンでは、追加することはできませんが、正しいディレクトリに再参照dllファイルそれはすることができます。

 

アダプタとのインタフェースを作成し、インターフェイスを実装

まず、処理修正プログラムのライフサイクルのために、ユニティにシンプルなインターフェイスを作成することができます

public interface IUI
{
    void Start();
    void Update();
}

その後、修正プログラムのプロジェクト、新しいクラスを作成Main.csは、インターフェイスのIUIを実装します

namespace Hotfix
{
    //IUI为unity中的接口,所以要在unity中实现一个继承适配器
    public class MainUI:IUI
    {
        public void Start()
        {

        }

        public void Update()
        {

        }
    }
}

IUIはユニティインタフェースであり、MainUIは修正プログラムのクラスであり、ILRuntimeがでありますので、クロスドメイン継承公式文書の概念は、あなたが熱よりDLLプロジェクトれるメインクラスの中の統一事業を継承する、または達成したい場合と述べましたインタフェースの主なプロジェクトは、あなたがユニティ主要継承アダプタでプロジェクトを実装する必要があります。

だから我々は、(文書コードに応じて変更)ユニティ、実装の継承アダプタのクラスInterfaceIUIAdaptor.csを作成

using ILRuntime.CLR.Method;
using ILRuntime.Runtime.Enviorment;
using ILRuntime.Runtime.Intepreter;
using System;

public class InterfaceIUIAdaptor : CrossBindingAdaptor
{
    public override Type BaseCLRType {
        get {
            return typeof(IUI);//这是你想继承的那个类
        }
    }

    public override Type AdaptorType {
        get {
            return typeof(Adaptor);//这是实际的适配器类
        }
    }

    public override object CreateCLRInstance(ILRuntime.Runtime.Enviorment.AppDomain appdomain, ILTypeInstance instance)
    {
        return new Adaptor(appdomain, instance);//创建一个新的实例
    }

    //实际的适配器类需要继承你想继承的那个类,并且实现CrossBindingAdaptorType接口
    public class Adaptor : IUI, CrossBindingAdaptorType
    {
        ILTypeInstance instance;
        ILRuntime.Runtime.Enviorment.AppDomain appdomain;

        IMethod m_Start;
        bool m_StartGot;

        IMethod m_Update;
        bool m_UpdateGot;

        public Adaptor()
        {

        }

        public Adaptor(ILRuntime.Runtime.Enviorment.AppDomain appdomain, ILTypeInstance instance)
        {
            this.appdomain = appdomain;
            this.instance = instance;
        }

        public ILTypeInstance ILInstance { get { return instance; } }

        //你需要重写所有你希望在热更脚本里面重写的方法,并且将控制权转到脚本里去
        public void Start()
        {
            if (!m_StartGot)
            {
                m_Start = instance.Type.GetMethod("Start", 0);
                m_StartGot = true;
            }
            if (m_Start != null)
            {
                appdomain.Invoke(m_Start, instance, null);//没有参数建议显式传递null为参数列表,否则会自动new object[0]导致GC Alloc
            }
        }

        public void Update()
        {
            if (!m_UpdateGot)
            {
                m_Update = instance.Type.GetMethod("Update", 0);
                m_UpdateGot = true;
            }
            if (m_Update != null)
            {
                appdomain.Invoke(m_Update, instance, null);
            }
        }
    }
}

 

读取Hotfix.dll文件,并执行其内部操作

首先我们将Hotfix工程中,解决方案右键生成,生成Hotfix.dll和Hotfix.pdb两个文件,将这两个文件拷贝到Unity的StreamingAssets目录下。

然后我们创建一个新的类 Launch.cs,在这里面我们首先读取上面的两个Hotfix文件,然后进行一些ILRuntime的预设置,例如绑定继承适配器,注册委托等。最后我们要在里面找到Hotfix中实现IUI接口的类,因为这些类就是我们的UI逻辑类,然后在自己的Start,Update等生命周期方法中,调用Hotfix中IUI类对应的方法。代码如下:

using ILRuntime.Runtime.Enviorment;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;

public class Launch : MonoBehaviour
{
    List<Action> DllUIUpdateList = new List<Action>();

    ILRuntime.Runtime.Enviorment.AppDomain appdomain;
    void Start()
    {
        StartCoroutine(LoadILRuntime());
    }

    IEnumerator LoadILRuntime()
    {
        //读取dll文件
        appdomain = new ILRuntime.Runtime.Enviorment.AppDomain();

        WWW www = new WWW(Application.streamingAssetsPath + "/Hotfix.dll");

        while (!www.isDone)
        {
            yield return null;
        }
        if (!string.IsNullOrEmpty(www.error))
        {
            Debug.LogError(www.error);
        }
        byte[] dll = www.bytes;
        www.Dispose();

        www = new WWW(Application.streamingAssetsPath + "/Hotfix.pdb");

        while (!www.isDone)
        {
            yield return null;
        }
        if (!string.IsNullOrEmpty(www.error))
        {
            Debug.LogError(www.error);
        }
        byte[] pdb = www.bytes;
        using (System.IO.MemoryStream fs = new MemoryStream(dll))
        {
            using (System.IO.MemoryStream p = new MemoryStream(pdb))
            {
                appdomain.LoadAssembly(fs, p, new Mono.Cecil.Pdb.PdbReaderProvider());
            }
        }

        OnILRuntimeInit();

        OnILRuntimeInitialized();
    }

    void Update()
    {
        if (DllUIUpdateList.Count > 0)
        {
            foreach(var update in DllUIUpdateList)
            {
                update();
            }
        }
    }

    void OnILRuntimeInit()
    {
        //跨域继承绑定适配器
        appdomain.RegisterCrossBindingAdaptor(new InterfaceIUIAdaptor());
        //Button点击事件的委托注册
        appdomain.DelegateManager.RegisterDelegateConvertor<UnityEngine.Events.UnityAction>((act) =>
        {
            return new UnityEngine.Events.UnityAction(() =>
            {
                ((Action)act)();
            });
        });
    }

    void OnILRuntimeInitialized()
    {        
        //获取Hotfix.dll内部定义的类
        List<Type> allTypes = new List<Type>();
        var values = appdomain.LoadedTypes.Values.ToList();
        foreach (var v in values)
        {
            allTypes.Add(v.ReflectionType);
        }
        //去重
        allTypes = allTypes.Distinct().ToList();

        DllUIUpdateList.Clear();
        foreach (var v in allTypes)
        {
            //找到实现IUI接口的类 Adaptor 前面写的适配器IUI的类
            if (v.IsClass && v.GetInterface("Adaptor") != null)
            {
                //生成实例
                var gs = appdomain.Instantiate<IUI>(v.FullName);

                //调用接口方法
                gs.Start();
                DllUIUpdateList.Add(gs.Update);
            }
        }
    }
}

注:代码中有一个委托注册的功能,是因为在Hotfix中调用UGUI的Button的onCkick,需要生成委托转换器,否则会报错

 

搭建UI及实现UI逻辑

Demo中,简单的在场景中创建一个简单的Button和Text,然后将Launch.cs挂到Canvas上即可。然后在我们之前Hotfix中创建的MainUI.cs中添加我们的UI逻辑:

using UnityEngine;
using UnityEngine.UI;

namespace Hotfix
{
    //IUI为unity中的接口,所以要在unity中实现一个继承适配器
    public class MainUI:IUI
    {
        Button m_btn;
        Text m_text;
        int count = 0;
        bool isClick = false;

        public void Start()
        {
            m_btn = GameObject.Find("Canvas/Button").GetComponent<Button>();
            m_text = GameObject.Find("Canvas/Text").GetComponent<Text>();
            m_text.text = "MainUI Start";

            //点击事件的委托需要在unity中实现委托转换器
            m_btn.onClick.AddListener(BtnClick);
        }

        public void Update()
        {
            if (isClick)
            {
                if (count % 20 == 0)
                {
                    m_text.text = "MainUI Update" + count / 20;
                }
                count++;
            }
        }

        void BtnClick()
        {
            isClick = true;
        }
    }
}

然后重新生成下dll文件,将原来Unity StreamingAssets下的文件替换掉即可(以后修改逻辑亦是如此,达到热更的效果)。

 

运行效果如下:

おすすめ

転載: blog.csdn.net/wangjiangrong/article/details/90294366