首页 > 其他分享 >ILRuntime是如何与Unity互相调用的

ILRuntime是如何与Unity互相调用的

时间:2024-01-23 09:34:15浏览次数:28  
标签:ILRuntime 调用 Assembly AppDomain appDomain Unity CSharp

ILRuntime是一个跨平台CLR实现,它可以在多个平台上运行C#代码,包括Android、iOS、Windows、Linux等等。ILRuntime的实现方式是将C#代码编译成IL代码,然后在运行时通过JIT或AOT的方式将IL代码转换为机器代码,从而实现跨平台的效果。ILRuntime的主要功能包括热更新、动态加载、代码加密等等。

对啦!这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础小白,也有一些正在从事游戏开发的技术大佬,欢迎你来交流学习。

二、Unity与ILRuntime的集成

Unity与ILRuntime的集成主要包括以下几个步骤:

1、添加ILRuntime的插件

首先需要将ILRuntime的插件添加到Unity项目中,这可以通过Unity Asset Store中搜索“ILRuntime”来获取。

2、修改Unity项目的脚本编译方式

默认情况下,Unity项目中的脚本会被编译为Mono或IL2CPP,但是为了使用ILRuntime,需要将脚本编译为.NET Standard 2.0。这可以通过修改Unity项目的Player Settings来实现,在Player Settings中选择“Other Settings”并将“Scripting Runtime Version”设置为.NET 4.x Equivalent,同时将“Api Compatibility Level”设置为.NET Standard 2.0。

3、创建ILRuntime的AppDomain

ILRuntime的AppDomain是一个独立的运行环境,它可以加载和运行IL代码。在Unity项目中,需要在启动时创建一个ILRuntime的AppDomain,并将IL代码加载到AppDomain中。这可以通过在Unity项目中创建一个启动脚本来实现。在启动脚本中,需要使用ILRuntime的API加载和运行IL代码,例如:

using ILRuntime.Runtime.Enviorment;

public class Startup : MonoBehaviour
{
    private AppDomain appDomain;

    private void Start()
    {
        appDomain = new AppDomain();
        appDomain.LoadAssembly("Assembly-CSharp");
        appDomain.Invoke("Assembly-CSharp.Main", "Start", null);
    }

    private void Update()
    {
        appDomain.Invoke("Assembly-CSharp.Main", "Update", null);
    }
}

 

在上面的代码中,创建了一个ILRuntime的AppDomain,并将“Assembly-CSharp”程序集加载到AppDomain中。然后在Start和Update方法中,通过AppDomain的Invoke方法调用“Assembly-CSharp.Main”类的“Start”和“Update”方法。

三、Unity与ILRuntime的交互

Unity与ILRuntime之间的交互主要通过以下几种方式实现:

1、使用ILRuntime的API调用Unity的API

ILRuntime提供了一些API来调用Unity的API,例如:

using UnityEngine;
using ILRuntime.Runtime.Enviorment;

public class Main : MonoBehaviour
{
    private AppDomain appDomain;

    private void Start()
    {
        appDomain = new AppDomain();
        appDomain.LoadAssembly("Assembly-CSharp");
        appDomain.Invoke("Assembly-CSharp.Main", "Start", null);

        var go = appDomain.Instantiate("Assembly-CSharp.TestGameObject");
        var transform = go.GetComponent<Transform>();
        transform.position = new Vector3(1, 2, 3);
    }

    private void Update()
    {
        appDomain.Invoke("Assembly-CSharp.Main", "Update", null);
    }
}

 

在上面的代码中,使用ILRuntime的API创建了一个GameObject,并获取了它的Transform组件,然后设置了Transform的位置。

2、使用Unity的API调用ILRuntime的API

Unity可以通过反射机制调用ILRuntime中的API,例如:

using UnityEngine;
using System.Reflection;
using ILRuntime.Runtime.Enviorment;

public class Main : MonoBehaviour
{
    private AppDomain appDomain;

    private void Start()
    {
        appDomain = new AppDomain();
        appDomain.LoadAssembly("Assembly-CSharp");
        appDomain.Invoke("Assembly-CSharp.Main", "Start", null);

        var type = appDomain.LoadedTypes["Assembly-CSharp.TestClass"];
        var method = type.GetMethod("TestMethod");
        method.Invoke(null, null);
    }

    private void Update()
    {
        appDomain.Invoke("Assembly-CSharp.Main", "Update", null);
    }
}

 

在上面的代码中,使用Unity的反射机制获取了ILRuntime中的“Assembly-CSharp.TestClass”类型和“TestMethod”方法,并调用了它。

3、使用委托实现Unity和ILRuntime的互相调用

ILRuntime提供了一个DelegateBridge类,它可以将Unity和ILRuntime中的委托类型互相转换。例如:

using UnityEngine;
using System;
using ILRuntime.Runtime.Enviorment;

public class Main : MonoBehaviour
{
    private AppDomain appDomain;

    private void Start()
    {
        appDomain = new AppDomain();
        appDomain.LoadAssembly("Assembly-CSharp");
        appDomain.Invoke("Assembly-CSharp.Main", "Start", null);

        var type = appDomain.LoadedTypes["Assembly-CSharp.TestClass"];
        var method = type.GetMethod("TestMethod");
        var action = DelegateBridge.CreateDelegate(typeof(Action), method) as Action;
        action();
    }

    private void Update()
    {
        appDomain.Invoke("Assembly-CSharp.Main", "Update", null);
    }
}

 

在上面的代码中,使用DelegateBridge类将ILRuntime中的“Assembly-CSharp.TestClass.TestMethod”方法转换为Unity的Action委托类型,并调用了它。

四、ILRuntime的热更新

ILRuntime的热更新是指在运行时替换IL代码,从而实现应用程序的更新。ILRuntime的热更新主要包括以下几个步骤:

1、在ILRuntime的AppDomain中替换IL代码

ILRuntime的AppDomain可以在运行时加载和卸载IL代码,因此可以在运行时替换IL代码。例如:

using UnityEngine;
using ILRuntime.Runtime.Enviorment;

public class Main : MonoBehaviour
{
    private AppDomain appDomain;

    private void Start()
    {
        appDomain = new AppDomain();
        appDomain.LoadAssembly("Assembly-CSharp");
        appDomain.Invoke("Assembly-CSharp.Main", "Start", null);
    }

    private void Update()
    {
        appDomain.Invoke("Assembly-CSharp.Main", "Update", null);

        // 热更新
        var newIL = File.ReadAllBytes("Assembly-CSharp.dll");
        appDomain.LoadAssembly(newIL);
        appDomain.Invoke("Assembly-CSharp.Main", "OnHotUpdate", null);
    }
}

 

在上面的代码中,使用ILRuntime的API加载了“Assembly-CSharp”程序集,并在Update方法中热更新了IL代码。

2、使用Unity的AssetBundle实现热更新

ILRuntime的热更新也可以使用Unity的AssetBundle来实现,这可以通过将IL代码打包为AssetBundle,并在运行时下载和加载AssetBundle来实现。例如:

using UnityEngine;
using System.Collections;
using ILRuntime.Runtime.Enviorment;

public class Main : MonoBehaviour
{
    private AppDomain appDomain;

    private void Start()
    {
        StartCoroutine(DownloadAndLoadAssetBundle());
    }

    private void Update()
    {
        appDomain.Invoke("Assembly-CSharp.Main", "Update", null);
    }

    private IEnumerator DownloadAndLoadAssetBundle()
    {
        var request = UnityWebRequestAssetBundle.GetAssetBundle("http://localhost/Assembly-CSharp.assetbundle");
        yield return request.SendWebRequest();
        var assetBundle = DownloadHandlerAssetBundle.GetContent(request);
        var il = assetBundle.LoadAsset<TextAsset>("Assembly-CSharp.dll");
        appDomain = new AppDomain();
        appDomain.LoadAssembly(il.bytes);
        appDomain.Invoke("Assembly-CSharp.Main", "Start", null);
    }
}

 

在上面的代码中,使用Unity的WebRequest下载了“Assembly-CSharp.assetbundle”文件,并使用AssetBundle加载了“Assembly-CSharp.dll”文件,并将IL代码加载到ILRuntime的AppDomain中。

标签:ILRuntime,调用,Assembly,AppDomain,appDomain,Unity,CSharp
From: https://www.cnblogs.com/bycw/p/17981641

相关文章

  • Unity 如何基于addressable来做资源管理
    一、什么是Addressable系统Addressable系统是Unity2018.3版本中推出的一种资源管理方案,它可以帮助我们更好地管理游戏中的资源。在以往的游戏开发中,我们通常使用Resources来进行资源加载,但是这种方式存在很多问题,比如加载速度慢、内存占用高等。Addressable系统可以解决这些问题......
  • Unity如何设计一个技能系统
    一、技能系统的设计思路技能系统是游戏中非常重要的一部分,因此在设计技能系统时需要考虑以下几个方面:对啦!这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础小白,也有一些正在从事游戏开发的技术大佬,欢迎你来交流学习。1.技能类型不同的游戏有不同的技能类型,例如魔......
  • 若依框架解读(微服务版)——2.模块间的调用逻辑(ruoyi-api模块)(OpenFeign)(@innerAuth)
    模块之间的关系我们可以了解到一共有这么多服务,我们先启动这三个服务其中rouyi–api模块是远程调用也就是提取出来的openfeign的接口ruoyi–commom是通用工具模块其他几个都是独立的服务ruoyi-api模块api模块当中有几个提取出来的OpenFeign的接口分别为文件,日志,用户服务......
  • Unity3D 协程的优缺点详解
    前言Unity3D是一款强大的游戏开发引擎,它提供了许多功能和工具,以帮助开发者创建高质量的游戏。其中一个非常重要的功能就是协程(Coroutine)。协程是一种特殊的函数,它可以在执行过程中暂停并在稍后的时间点继续执行。在本文中,我们将详细探讨Unity3D协程的优缺点,并提供一些技术详解和......
  • GDB调试之直接调用函数 (十九)
    常用命令:p表达式:求表达式的值并显示结果值。表达式可以包括对正在调试的程序中的函数的调用,即使函数返回值是void,也会显示。call表达式:求表达式的值并显示结果值,如果是函数调用,返回值是void的话,不显示void返回值。调试代码如下:#include<iostream>#include<cstring>usin......
  • [AHK2] wt调用命令
    最近在研究mc服务器,一般启动时使用bat文件就可以,但是我想在终端中运行而不是在cmd中。查了wt和pwsh的文档写出了下面的脚本。作用仅仅是在wt中运行java这条命令。脚本包括一些变量,其中:reuse表示是否打开一个新的wt实例。headC表示在调用jar前运行的powershell命令。javaC中......
  • 【解决方案】如何使用 Http API 代替 OpenFeign 进行远程服务调用
    目录前言一、何为OpenFeign1.1@FeignClient注解1.2注意事项二、常见的HttpAPI2.1Apache2.2Okhttp2.3Hutool三、RestTemplate3.1详解.execute()四、文章小结前言看到标题大家可能会有点疑惑吧:OpenFeign不是挺好用的吗?尤其是微服务之间的远程调用,平时用的也挺习惯的,为啥要替换呢......
  • Unity:Couldn't open include file 'Packages/com.unity.render-pipelines.universal/S
    初学Shader,Unity报错↑,总之是找不到ulsl的Core文件,网上找的其他解决方案例如删除文件夹再生成或者改变shader的某些属性,但是根本找不到。最终找到原因是项目类型不同,要把传统3D升级成URP项目。解决办法:安装UniversalRP拓展1.在unity中打开需要升级的场景,SaveAs一份并打开该场......
  • Linux 文件被进程调用情况下误删文件修复
    具体的原理为:当进程打开了某个文件时,只要该进程保持打开该文件,即使将文件删除,它依然存在于磁盘中。进程并不知道文件已经被删除,它仍然可以通过打开该文件时提供给它的文件描述符进行读取和写入。除了该进程之外,这个文件是不可见的,因为已经删除了其相应的目录索引节点。......
  • WPF 使用CommunityToolkit.Mvvm实现Binding示例
    WPF在国内的发展一言难尽。属于那种死不死,活不活的状态。现在应用最多的场景就是上位机了。最近研究了一下WPF中重要的特性之一Binding。如果你没有学会它,基本WPF就没有学明白。研究Binding的时候,我也用了MVVM特性,这也是WPF必学的科目之一。我原来用的是MVVMLight。可是后来......