当前位置:网站首页>Unity notes ilruntime access
Unity notes ilruntime access
2022-07-23 15:54:00 【گ This is a QQ name】
file
Starting from scratch — ILRuntime
Delegate registration function
Unity Hot update ILRuntime_ Dark night __ The blog of -CSDN Blog _ilruntime
Mission
1. Access ILruntime
2. Access Ilriuntime Of Protobuf
Code
First, define your own layout ,( For example, I like to put the hot script normally Unity Inside , Set up the reference of your assembly and it's all right )
such as :

Editor playersetting Don't forget to change it ,
stay Unity Use in .NET 4.x | Microsoft Docs
Have a brief understanding of : In short, it is 4.xAPI more , But individually api Not all platforms support

Define the initial script in hotter :
using System;
using UnityEngine;
namespace HotFix
{
public class HotFixStart
{
public static void Start()
{
Debug.Log("Start---------------------------------");
}
}
}External call hotter management script :
Find your own hotter dll( Whatever you do, where you put it, and finally put this dll Just get our project ), hold dll Change to suffix txt Or is it bytes All of them are convenient for us to read this dll( Put it here. StreamingAssets Next, for the convenience of testing , If you want to be more dynamic, you can load it with your own resource loading tool, such as Addressable)
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
public class Startup : MonoBehaviour
{
private ILRuntime.Runtime.Enviorment.AppDomain appdomain;
void Start()
{
StartCoroutine(LoadILRuntime());
}
IEnumerator LoadILRuntime()
{
appdomain = new ILRuntime.Runtime.Enviorment.AppDomain();
UnityWebRequest webRequest = UnityWebRequest.Get(StreamingAssetsPath("HotFix.dll.txt"));
yield return webRequest.SendWebRequest();
if (webRequest.result != UnityWebRequest.Result.Success)
{
yield break;
}
byte[] dll = webRequest.downloadHandler.data;
webRequest.Dispose();
webRequest = UnityWebRequest.Get(StreamingAssetsPath("HotFix.pdb.txt"));
yield return webRequest.SendWebRequest();
if (webRequest.result != UnityWebRequest.Result.Success)
{
yield break;
}
byte[] pdb = webRequest.downloadHandler.data;
webRequest.Dispose();
appdomain.LoadAssembly(new MemoryStream(dll), new MemoryStream(pdb), new ILRuntime.Mono.Cecil.Pdb.PdbReaderProvider());
OnILRuntimeInitialized();
}
void OnILRuntimeInitialized()
{
appdomain.Invoke("HotFix.AppMain", "Start", null, null);
}
public string StreamingAssetsPath(string fileName)
{
string path = Application.streamingAssetsPath + "/" + fileName;
return path;
}
}Theoretically speaking, it's ok as long as you can run
Inherit script proxy across domains :
using ILRuntime.CLR.TypeSystem;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
/// <summary>
/// stay GameObject Real script objects mounted on MonoProxy
/// Runtime , It will transfer the logical execution to the corresponding hotchange script object of the binding ScriptObject
/// </summary>
public class MonoProxy : MonoBehaviour
{
/// <summary>
/// Now this MonoProxy Object mapping hotter script type string
/// </summary>
public string ScriptName;
/// <summary>
/// Mapping objects of the type of hotter scripts
/// </summary>
public object ScriptObject;
/// <summary>
/// The book MonoProxy Object is bound to a hotter script
/// </summary>
/// <param name="scriptName"></param>
public void Bind(string scriptName)
{
ScriptName = "HotFix." + scriptName;
ScriptObject = Startup.appdomain.Instantiate(ScriptName);
IType scriptIType = Startup.appdomain.LoadedTypes[ScriptName];
FieldInfo goField = scriptIType.ReflectionType.GetField("gameObject");
goField.SetValue(ScriptObject, gameObject);
Startup.appdomain.Invoke(ScriptName, "Awake", ScriptObject, null);
}
void Start()
{
Startup.appdomain.Invoke(ScriptName, "Start", ScriptObject, null);
}
void Update()
{
Startup.appdomain.Invoke(ScriptName, "Update", ScriptObject, null);
}
private void OnDestroy()
{
Startup.appdomain.Invoke(ScriptName, "OnDestroy", ScriptObject, null);
}
}Inherited pseudo Mono Script :
using System.Collections;
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
namespace HotFix
{
public class MonoBehaviourEX
{
public GameObject gameObject;
public Transform transform => gameObject.transform;
public virtual void Awake() { }
public virtual void Start() { }
public virtual void Update() { }
public virtual void OnDestroy() { }
public void StartCoroutineEx(IEnumerator coroutine)
{
gameObject.GetComponent<MonoProxy>().StartCoroutine(coroutine);
}
}
}Expand auxiliary script mount in hotfix :( In order to conform to their own habits, I like to use AddComponent only )
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace HotFix
{
public static class GameObjectEx
{
/// <summary>
/// to GameObject type , Extend a new function Bind, Just give GameObject Bind a hotter script object
/// </summary>
/// <param name="gameObject"></param>
/// <param name="scriptName"></param>
public static void Bind(this GameObject gameObject, string scriptName)
{
MonoProxy monoProxy = gameObject.AddComponent<MonoProxy>();
monoProxy.Bind(scriptName);
}
public static T Bind<T>(this GameObject gameObject)
{
MonoProxy monoProxy = gameObject.AddComponent<MonoProxy>();
string scriptName = typeof(T).Name;
Debug.Log(scriptName);
return (T)monoProxy.Bind(scriptName);
}
public static T AddComponent<T>(this GameObject gameObject) where T : MonoBehaviourEX
{
MonoProxy monoProxy = gameObject.AddComponent<MonoProxy>();
string scriptName = typeof(T).Name;
Debug.Log(scriptName);
return (T)monoProxy.Bind(scriptName);
}
}
}Co process adapter :
using ILRuntime.CLR.Method;
using ILRuntime.Runtime.Enviorment;
using ILRuntime.Runtime.Intepreter;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CoroutineAdapter : CrossBindingAdaptor
{
public override Type BaseCLRType
{
get
{
return null;
}
}
public override Type[] BaseCLRTypes
{
get
{
// Cross domain inheritance can only have 1 individual Adapter, Therefore, it should be avoided that a class implements multiple external interfaces at the same time , about coroutine It is IEnumerator<object>,IEnumerator and IDisposable,
//ILRuntime Although support , But be careful with this usage , Improper use can easily cause unexpected problems
// If daily development needs to realize multiple DLL External interface , Please be there. Unity Here, first make a base class to implement those interfaces , Then inherit the base class
return new Type[] { typeof(IEnumerator<object>), typeof(IEnumerator), typeof(IDisposable) };
}
}
public override Type AdaptorType
{
get
{
return typeof(Adaptor);
}
}
public override object CreateCLRInstance(ILRuntime.Runtime.Enviorment.AppDomain appdomain, ILTypeInstance instance)
{
return new Adaptor(appdomain, instance);
}
/// <summary>
/// Coroutine The generated class implements IEnumerator<System.Object>, IEnumerator, IDisposable So we should realize
/// This can be done through reflector And so on. IL Decompile software knows
/// </summary>
internal class Adaptor : IEnumerator<System.Object>, IEnumerator, IDisposable, CrossBindingAdaptorType
{
ILTypeInstance instance;
ILRuntime.Runtime.Enviorment.AppDomain appdomain;
public Adaptor()
{
}
public Adaptor(ILRuntime.Runtime.Enviorment.AppDomain appdomain, ILTypeInstance instance)
{
this.appdomain = appdomain;
this.instance = instance;
}
public ILTypeInstance ILInstance { get { return instance; } }
IMethod mCurrentMethod;
bool mCurrentMethodGot;
public object Current
{
get
{
if (!mCurrentMethodGot)
{
mCurrentMethod = instance.Type.GetMethod("get_Current", 0);
if (mCurrentMethod == null)
{
// Write here System.Collections.IEnumerator.get_Current Not directly get_Current Because coroutine The generated class implements this interface explicitly , adopt Reflector Wait for decompilation software to know
// In order to be compatible with others, only a single Current Attribute , So I took it directly from the top get_Current
mCurrentMethod = instance.Type.GetMethod("System.Collections.IEnumerator.get_Current", 0);
}
mCurrentMethodGot = true;
}
if (mCurrentMethod != null)
{
object res = appdomain.Invoke(mCurrentMethod, instance, null);
return res;
}
else
{
return null;
}
}
}
IMethod mDisposeMethod;
bool mDisposeMethodGot;
public void Dispose()
{
if (!mDisposeMethodGot)
{
mDisposeMethod = instance.Type.GetMethod("Dispose", 0);
if (mDisposeMethod == null)
{
mDisposeMethod = instance.Type.GetMethod("System.IDisposable.Dispose", 0);
}
mDisposeMethodGot = true;
}
if (mDisposeMethod != null)
{
appdomain.Invoke(mDisposeMethod, instance, null);
}
}
IMethod mMoveNextMethod;
bool mMoveNextMethodGot;
public bool MoveNext()
{
if (!mMoveNextMethodGot)
{
mMoveNextMethod = instance.Type.GetMethod("MoveNext", 0);
mMoveNextMethodGot = true;
}
if (mMoveNextMethod != null)
{
return (bool)appdomain.Invoke(mMoveNextMethod, instance, null);
}
else
{
return false;
}
}
IMethod mResetMethod;
bool mResetMethodGot;
public void Reset()
{
if (!mResetMethodGot)
{
mResetMethod = instance.Type.GetMethod("Reset", 0);
mResetMethodGot = true;
}
if (mResetMethod != null)
{
appdomain.Invoke(mResetMethod, instance, null);
}
}
public override string ToString()
{
IMethod m = appdomain.ObjectType.GetMethod("ToString", 0);
m = instance.Type.GetVirtualMethod(m);
if (m == null || m is ILMethod)
{
return instance.ToString();
}
else
return instance.Type.FullName;
}
}
}Add Protobuf
Found after importing Editor Folder Modify your own parameters
#if UNITY_2018_1_OR_NEWER
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using ProtoBuf;
using Google.Protobuf.Reflection;
using ProtoBuf.Reflection;
using System.IO;
public class Protogen
{
private static string ProtoPath = Application.dataPath + "/../../ProtoFiles";
private static string ExePath = Application.dataPath + "/../../Protoc/protoc-3.5.1-win32/bin/";
/// <summary>
/// Ignore here , This is the address for my own server
/// </summary>
private static string outPath = Application.dataPath + "/../../Server/proto/";
[MenuItem("CustomTools/Generate Protocs")]
public static void GenerateProtobufCS()
{
Generate(ProtoPath, new string[] { "NetMessage.proto" },
// This is your output address
Application.dataPath + "/ILRunimeFrameWork/Hotfix/ProtoCode");
}
[MenuItem("CustomTools/Generate ServerProtocs")]
public static void Generateser()
{
RunExeByProcess(outPath);
}
static void Generate(string inpath, string[] inprotos, string outpath)
{
var set = new FileDescriptorSet();
set.AddImportPath(inpath);
foreach (var inproto in inprotos)
{
set.Add(inproto, true);
}
set.Process();
var errors = set.GetErrors();
CSharpCodeGenerator.ClearTypeNames();
var files = CSharpCodeGenerator.Default.Generate(set);
int idx = 1;
foreach (var file in files)
{
EditorUtility.DisplayProgressBar("Generate", file.Name, idx / (1.0f * inprotos.Length));
var path = Path.Combine(outpath, file.Name);
File.WriteAllText(path, file.Text);
Debug.Log($"generated: {path}");
}
EditorUtility.ClearProgressBar();
AssetDatabase.Refresh();
}
//private string savePath = System.Environment.CurrentDirectory + @"\ Folder name ";
public static void RunExeByProcess(string arguments)
{
// Start a new thread
System.Diagnostics.Process process = new System.Diagnostics.Process();
// Called exe name
process.StartInfo.FileName = "GenForServer.bat";
process.StartInfo.WorkingDirectory = ExePath;
// Pass parameters
process.StartInfo.Arguments = arguments;
process.Start();
process.WaitForExit();// pause , Execution can continue only after the external program exits
if (process.ExitCode == 0)// Program exit
{
Debug.Log(" Successful implementation ");
}
}
}
#endifAt this time, the generated code is still useless : One is not Ilruntime Register in the environment , Another is the need for an auxiliary class ( It's written in the document that you can have a look ):
ilruntime register :
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
using SimpleJSON;
using System;
public class AppStart : MonoBehaviour
{
public static ILRuntime.Runtime.Enviorment.AppDomain appdomain;
void Start()
{
StartCoroutine(LoadILRuntime());
}
IEnumerator LoadILRuntime()
{
appdomain = new ILRuntime.Runtime.Enviorment.AppDomain();
/*UnityWebRequest webRequest = UnityWebRequest.Get(StreamingAssetsPath("Hotfix.dll.txt"));
yield return webRequest.SendWebRequest();
byte[] dll = webRequest.downloadHandler.data;
webRequest.Dispose();
webRequest = UnityWebRequest.Get(StreamingAssetsPath("Hotfix.pdb.txt"));
yield return webRequest.SendWebRequest();
byte[] pdb = webRequest.downloadHandler.data;
webRequest.Dispose();*/
byte[] dll = AssetLoader.Instance.CreateAsset<TextAsset>("Launch", "Assets/GAssets/Launch/Scriptdll/Hotfix.dll.bytes", gameObject).bytes;
byte[] pdb = AssetLoader.Instance.CreateAsset<TextAsset>("Launch", "Assets/GAssets/Launch/Scriptdll/Hotfix.pdb.bytes", gameObject).bytes;
yield return null;
appdomain.LoadAssembly(new MemoryStream(dll), new MemoryStream(pdb), new ILRuntime.Mono.Cecil.Pdb.PdbReaderProvider());
appdomain.RegisterCrossBindingAdaptor(new CoroutineAdapter());
appdomain.DelegateManager.RegisterFunctionDelegate<System.String, JSONNode>();
appdomain.DelegateManager.RegisterMethodDelegate<global::NetPacket>();
appdomain.DelegateManager.RegisterMethodDelegate<System.Int32>();
appdomain.DelegateManager.RegisterMethodDelegate<cfg.BagItem>();
appdomain.DelegateManager.RegisterDelegateConvertor<UnityEngine.Events.UnityAction>((act) =>
{
return new UnityEngine.Events.UnityAction(() =>
{
((Action)act)();
});
});
// register Protobuf relevant
ProtoBuf.PType.RegisterFunctionCreateInstance(PType_CreateInstance);
ProtoBuf.PType.RegisterFunctionGetRealType(PType_GetRealType);
//appdomain.RegisterCLRMethodRedirection(0, new Bright.Config.BeanBase.GetTypeId());
OnILRuntimeInitialized();
}
public static object PType_CreateInstance(string typeName)
{
return appdomain.Instantiate(typeName);
}
public static Type PType_GetRealType(object o)
{
Type type = o.GetType();
if (type.FullName == "ILRuntime.Runtime.Intepreter.ILTypeInstance")
{
var ilo = o as ILRuntime.Runtime.Intepreter.ILTypeInstance;
type = ProtoBuf.PType.FindType(ilo.Type.FullName);
}
return type;
}
void OnILRuntimeInitialized()
{
appdomain.Invoke("HotFix.HotfixMain", "Start", null, null);
}
public string StreamingAssetsPath(string fileName)
{
string path = Application.streamingAssetsPath + "/" + fileName;
return path;
}
}hotfix Assembly plus an auxiliary class
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace Helper
{
public sealed class ProtoHelper
{
public static byte[] EncodeWithName(object p)
{
var type = p.GetType();
var name = type.FullName;
using (var ms = new MemoryStream())
{
Serializer.Serialize(ms, p);
//var cos = new Google.Protobuf.CodedOutputStream(ms);
//((IMessage)p).Encode(cos); // Non reflective
//cos.Flush();
var nbs = Encoding.UTF8.GetBytes(name);
int nblen = nbs.Length;
if (nblen > 255)
{
throw new Exception("PB:name->" + name + " is To Long " + nblen + " > 255");
}
var buffer = new byte[ms.Length + nbs.Length + 1];
buffer[0] = (byte)((nblen >> 0) & 0xFF);
Buffer.BlockCopy(nbs, 0, buffer, 1, nblen);
ms.Position = 0;
ms.Read(buffer, 1 + nblen, (int)ms.Length);
return buffer;
}
}
public static object DecodeWithName(byte[] b, out string name)
{
var bytesLen = b[0];
name = Encoding.UTF8.GetString(b, 1, bytesLen);
using (var ms = new MemoryStream(b, 1 + bytesLen, b.Length - 1 - bytesLen))
{
Type T = Type.GetType(name);
if (name.Contains(".")) { name = name.Substring(name.LastIndexOf('.') + 1); }
return Serializer.Deserialize(T, ms);
//var o = Activator.CreateInstance(T);
//((IMessage)o).Decode(new Google.Protobuf.CodedInputStream(ms)); // Non reflective
//return o;
}
}
}
public interface IProtoRecv
{
void OnRecv(string name, object o);
}
public interface IMessage
{
void Encode(Google.Protobuf.CodedOutputStream writer);
void Decode(Google.Protobuf.CodedInputStream reader);
}
}Finally, call the function at your hot entry, such as ( This function is generated by you protobuf There is a function automatically in the file ):


Basically completed : All the functions should have , Be with you normally Unity Development should be similar ...
边栏推荐
- AWS篇1
- Find the minimum value and location in multiple numbers (with repetition)
- 记一次SQL优化
- List merging (summer vacation daily question 3)
- 作为测试人员,不能不懂的adb命令和操作
- String and integer convert each other
- C语言书写规范
- Axure advanced
- Idea starts multiple projects at once
- [attack and defense world web] difficulty Samsung 9 points introductory question (Part 1): simple_ js、mfw
猜你喜欢

云服务器ECS远程监控

基于Matlab的SSB信号调制和解调(内附源码)

A quietly rising domestic software is too strong!

超详细MP4格式分析
![php:filter伪协议之[BSidesCF 2020]Had a bad day](/img/ad/1e23fadb3f1ce36b297aaa767d9099.png)
php:filter伪协议之[BSidesCF 2020]Had a bad day
![[cloud native] install MySQL and redis services in the docker environment](/img/3d/61366e9421364eced63573eac89b57.png)
[cloud native] install MySQL and redis services in the docker environment

地图附近名片流量主小程序开发

Jsd-2204 session management filter day19

The landing process of 800V high-voltage fast charging was accelerated, and Junsheng Electronics was designated for the 500million euro project

Expression du suffixe (une question par jour pendant les vacances d'été 4)
随机推荐
[attack and defense world web] difficulty Samsung 9 points introductory question (Part 2): shrink, lottery
C # close current computer command
Find a specific number in an ordered array (binary search or half search)
Open source quadruped robot with design drawings and code "suggestions collection"
ten thousand and one hundred
Camera flashlight modification
对C语言最基本的代码解释
【无标题】
服务器性能调优经验总结
redis 哨兵模式
md5强碰撞,二次解码,
对专利的学习
[pyGame practice] playing poker? Win or lose? This card game makes me forget to eat and sleep.
Harbor image warehouse
C语言经典例题-两个分数相加
Bug modification
第一篇 项目基本情况介绍
Custom encapsulation pop-up box (with progress bar)
C# 关闭当前电脑指令
备份内容哈哈哈