Unity ILRuntime 調用方法一覽


Unity C#熱更新方案 ILRuntime學習筆記

 

一、主工程調用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

CLRBinding.png

當然,使用前要配置你熱更dll的路徑和生成文件的路徑。
在Unity查找ILRuntimeCLRBinding這個類,修改其中路徑。

#if UNITY_EDITOR using 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的接口可以用代理的方式。
調用時要注意性能問題,可以進行優化。

轉發自:  https://segmentfault.com/a/1190000023290547    感謝冰封百度大佬

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM