一、主工程调用Hotfix代码

假如Hotfix工程里有一个Test类,该如何调用该类的办法呢?

namespace Hotfix {    public class Test {        // 实例办法        public string GetName() {            return "test";        }        // 静态方法        public static float Sum(float a, float b) {            return a + b;        }    }}

1.调用静态方法

// 获取类型IType type = appdomain.LoadedTypes["Hotfix.Test"];// 获取办法IMethod method = type.GetMethod("Sum", 2);// 调用办法object returnValue = appdomain.Invoke(method, null, 1, 2);// 输入返回值print("静态方法返回值:" + returnValue);

2.调用实例办法

// 获取类型IType type = appdomain.LoadedTypes["Hotfix.Test"];// 创立实例object instance = (type as ILType).Instantiate();// 获取办法IMethod method = type.GetMethod("GetName", 0);// 调用办法object returnValue = appdomain.Invoke(method, instance);// 输入返回值print("静态方法返回值:" + returnValue);

二、Hotfix调用主工程代码

Hotfix调用主工程代码间接调用即可,无需特地步骤。

namespace Hotfix {    using UnityEngine;    public class Test {        // 调用主工程办法        private void CallUnity() {            Debug.Log(Application.streamingAssetsPath);        }    }}

三、Hotfix响应MonoBehaviour事件

Hotfix响应MonoBehaviour中的事件,能够用代理办法实现。

1.在Unity中新建一个Mono脚本,实现本人须要的接口,在这些接口被调用时,调用代理事件

namespace GameUtils.Triggers {    using System;    using UnityEngine;    /// <summary>    /// <para>MonoBehaviour 根本事件触发器 触发以下事件</para>    /// OnEnable、Start、OnDisable、OnDestroy    /// </summary>    public class MonoBehaviourEventTrigger : MonoBehaviour {        public Action onEnable;        public Action start;        public Action update        public Action onDisable;        public Action onDestroy;        private void OnEnable() {            if (onEnable != null) onEnable.Invoke();        }        private void Start() {            if (start != null) start.Invoke();        }        private void OnDisable() {            if (onDisable != null) onDisable.Invoke();        }                private void Update() {            if (update != null) update.Invoke();        }        private void OnDestroy() {            if (onDestroy != null) onDestroy.Invoke();        }    }}

2.在Hotfix工程中这样调用:

namespace Hotfix {    using UnityEngine;    using GameUtils.Triggers;    public class Test {        private void MonoTest() {            GameObject obj = new GameObject("Test");            MonoBehaviourEventTrigger monoTrigger = obj.AddComponent<MonoBehaviourEventTrigger>();            monoTrigger.start = Start;            monoTrigger.update = Update;            monoTrigger.onDestroy = OnDestroy;        }        private void Start() {            Debug.Log("Start");        }                private void Update() {            // 鼠标按下时,做射线碰撞检测            if (Input.GetMouseButtonDown(0)) {                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);                RaycastHit hit;                if (Physics.Raycast(ray, out hit, 1000)) {                    Debug.Log(hit.point);                }            }        }        private void OnDestroy() {            Debug.Log("OnDestroy");        }    }}

注:因为Mono接口是主工程中的,不能热更,所以要提前写好所有接口以供热更代码调用。Mono中的接口泛滥,如果全副用一个类实现的话太过冗余,我这里做了一下优化,把不同性能的接口分组到不同的脚本中,由一个对立的Mono依据调用状况动静增加,在set里实现调用时的动静增加脚本性能,应用时还是一样不便,代码太长就不贴了。

3.带参数的Action

留神,带参数的Action在跨域调用前要在主工程里注册参数。
否则调用会报错。

private void RegistDelegate() {        DelegateManager manager = appdomain.DelegateManager;        manager.RegisterMethodDelegate<bool>();        manager.RegisterMethodDelegate<byte>();        manager.RegisterMethodDelegate<sbyte>();        manager.RegisterMethodDelegate<char>();        manager.RegisterMethodDelegate<short>();        manager.RegisterMethodDelegate<ushort>();        manager.RegisterMethodDelegate<int>();        manager.RegisterMethodDelegate<uint>();        manager.RegisterMethodDelegate<long>();        manager.RegisterMethodDelegate<ulong>();        manager.RegisterMethodDelegate<float>();        manager.RegisterMethodDelegate<double>();        manager.RegisterMethodDelegate<string>();        manager.RegisterMethodDelegate<object>();        manager.RegisterMethodDelegate<Collider>();        manager.RegisterMethodDelegate<Collision>();        manager.RegisterMethodDelegate<BaseEventData>();        manager.RegisterMethodDelegate<PointerEventData>();        manager.RegisterMethodDelegate<Object>();        manager.RegisterMethodDelegate<GameObject>();                appdomain.DelegateManager.RegisterDelegateConvertor<UnityEngine.Events.UnityAction>((action) => {            return new UnityEngine.Events.UnityAction(() => {                ((System.Action)action)();            });        });    }

四、跨域调用性能优化

跨域调用的性能是很差的。性能优化的形式如下:

1.主工程调用Hotfix时,多用type.GetMethod()去调用。

// 1.用string调用办法:appdomain.Invoke("Hotfix.Test", "Sum", null, null);// 2.用Method调用办法性能更好IType type = appdomain.LoadedTypes["Hotfix.Test"];IMethod method = type.GetMethod("Sum", 2);appdomain.Invoke(method, instance, 1, 2);

2.Hotfix调用主工程代码时,能够用CLRBinding优化。

官网提供了一个工具,能够实现Hotfix调用的优化,该工具会主动剖析热更dll中调用的办法,主动生成CLRBinding类。

应用形式是:在unity顶部菜单中选择ILRuntime > Generate CLR Binding Code by Analysis

当然,应用前要配置你热更dll的门路和生成文件的门路。
在Unity查找ILRuntimeCLRBinding这个类,批改其中门路。

#if UNITY_EDITORusing UnityEditor;using UnityEngine;using System;using System.Text;using System.Collections.Generic;using ILRuntimeDemo;[System.Reflection.Obfuscation(Exclude = true)]public class ILRuntimeCLRBinding{   [MenuItem("ILRuntime/Generate CLR Binding Code by Analysis")]    static void GenerateCLRBindingByAnalysis()    {        //用新的剖析热更dll调用援用来生成绑定代码        ILRuntime.Runtime.Enviorment.AppDomain domain = new ILRuntime.Runtime.Enviorment.AppDomain();                using (System.IO.FileStream fs = new System.IO.FileStream("Assets/StreamingAssets/Hotfix.dll", System.IO.FileMode.Open, System.IO.FileAccess.Read))        {            domain.LoadAssembly(fs);            //Crossbind Adapter is needed to generate the correct binding code            InitILRuntime(domain);            ILRuntime.Runtime.CLRBinding.BindingCodeGenerator.GenerateBindingCode(domain, "Assets/Game/ILRuntime/Generated");        }        AssetDatabase.Refresh();    }    static void InitILRuntime(ILRuntime.Runtime.Enviorment.AppDomain domain)    {        //这里须要注册所有热更DLL中用到的跨域继承Adapter,否则无奈正确抓取援用        domain.RegisterCrossBindingAdaptor(new MonoBehaviourAdapter());        domain.RegisterCrossBindingAdaptor(new CoroutineAdapter());        domain.RegisterCrossBindingAdaptor(new TestClassBaseAdapter());        domain.RegisterValueTypeBinder(typeof(Vector3), new Vector3Binder());    }}#endif

总结:
主工程调用Hotfix代码时比拟麻烦,要用相似反射的模式。
Hotfix调用主工程代码很容易,失常怎么写就怎么写。
Hotfix调用MonoBehaviour的接口能够用代理的形式。
调用时要留神性能问题,能够进行优化。