IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> Unity集成InjectFix对C#代码热修复 -> 正文阅读

[游戏开发]Unity集成InjectFix对C#代码热修复


InjectFix介绍

插件地址:https://github.com/Tencent/InjectFix

作用: 用于修复线上C# bug

流程: InjectFix包括Inject和Fix两个部分,发包的时候对需要修复的类进行插桩(Inject)处理,线上版本要写好加载热更补丁包的逻辑,通过生成Patch补丁进行资源热更的形式进行修复线上bug。

原理: InjectFix实现bug修复主要靠两部分:虚拟机负责新逻辑的解析执行;注入代码负责把调用重定向到虚拟机。
作者对Inject的介绍:https://segmentfault.com/a/1190000020375313

优势: 代码都以原生的方式执行,只有需要修复的代码会重定向到虚拟机执行,内部使用反射,不如xlua的静态warp,但考虑到只有少量函数需要修复,不会有大量性能损耗。


InjectFix使用说明

  1. InjectFix通过标签标注的形式,进行对代码插桩和生成补丁包生成处理。
  2. 标签分为注入和补丁。注入标签在发包前做。补丁标签在发包后修复阶段使用。
标签使用阶段用途用法
[Patch]补丁修复函数只能放在函数上
[Interpret]补丁新增属性,函数,类型放在属性,函数,类型上
[CustomBridge]注入interface和delegate桥接只能放在单独写一个静态类上,存储虚拟机的类适配到原生interface或者虚拟机的函数适配到原生delegate,该类不能放Editor目录
[Configure]注入配置类只能放在单独写一个存放在Editor目录下的类上
[IFix]注入可能需要修复函数的类的集合只能放在[Configure]类的一个静态属性上
[Filter]注入不想发生注入的函数只能放在[Configure]类的一个静态函数上

[IFix.Patch]

修复某个函数,该标签只能用在方法上,直接在方法上面标注一下[IFix.Patch]即可

[IFix.Patch]
private int Add(int a,int b)
{
     return a * b;
}

[IFix.Interpret]

新增个函数或者类,在属性,方法,类型上,直接在要新增的代码上面标注一下这个标签即可。
[IFix.Patch]和[IFix.Interpret]属于比较常用的修复Bug

[IFix.CustomBridge]

在注入阶段使用; 把一个虚拟机的类适配到原生interface或者把一个虚拟机的函数适配到原生delegate。

  1. 修复代码赋值一个闭包到一个delegate变量;
  2. 修复代码的Unity协程用了yield return;
  3. 新增一个函数,赋值到一个delegate变量;
  4. 新增一个类,赋值到一个原生interface变量;
  5. 新增函数,用了yield return;
    该标签只能用在类上,写上一个静态类,里面有一个静态字段,值就是interface和delegate的类型集合,该配置类不能放到Editor目录,且不能内嵌到另外一个类里头。
[IFix.CustomBridge]
public static class AdditionalBridge
{
 static List<Type> bridge = new List<Type>()
    {
      typeof(ISubSystem),
      typeof(IEnumerator), //如果之前使用过协程,可不做处理
      typeof(Test.MyDelegate)
    };
}

[IFix.Filter]

在注入阶段使用,过滤某些方法。在注入阶段,凡是在[IFix]标签下的属性里面的值,都会被注入适配代码,但如果不想对某个函数进行注入,可以用该标签进行过滤。该标签只能用在方法上,Configure类中的一个静态方法。

[Filter]
static bool Filter(System.Reflection.MethodInfo methodInfo)
{
    return methodInfo.DeclaringType.FullName == "Test" 
    && (methodInfo.Name == "Test2" || methodInfo.Name == "Test1");
}

项目中使用

【注入(发包前)】

  1. 可以单独对一个类型或者一个dll进行插桩配置,打包的时候会自动注入到程序集中去。
  2. 要修复Assets下dll的类,需要在InjectFixAssemblys中配置对应dll的路径信息

使用PatchManager.Load(stream)加载补丁:

string[] fixFileNames = Directory.GetFiles(fullFixFilePath, "*.bytes");
foreach (var fileName in fixFileNames)
{
	FileStream stream = new FileStream(fileName, FileMode.Open);
	if (stream != null)
	{
		try
		{
			PatchManager.Load(stream);
		}
		catch (Exception e)
		{
			Debug.LogError(e.ToString());
		}

		Debug.LogFormat("InjectFix load fix file {0} success and start pathch", fileName);
		stream.Dispose();
	}
}

【Fix补丁包(发包后需要修复)】
在需要修复的代码上面加上Patch标签,生成对应平台补丁包,走热更流程,完成修复。
PS:一个程序集生成一个补丁包,多个补丁包会自动卸载上一个,即使多次Load,只有最后一个会生效。

【接入】
具体接入参考官方文档


接入遇到的问题记录

1. 注入失败,提示下面报错

System.Exception: assembly may be not injected yet, cat find IFix.ILFixInterfaceBridge, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null

解决:

  • 确保出包之前注入成功,官方监听场景打包之后进行自动注入 ([UnityEditor.Callbacks.PostProcessScene]),确保注入注入之后不会触发编译,若触发编译(比如改变dll或者路径),则注入失效,需要手动调用IFixEditor.InjectAllAssemblys重新注入
  • 如果需要注入自定义程序集,需要改官方源码,官方会限定注入project\Library\ScriptAssemblies 路径下的程序集,若要注入Assets/Plugins下的程序集,需要去改对应路径和ScriptAssemblies限制,另外注入第三方dll会触发编译,需要重新注入ScriptAssemblies下的Assembly-CSharp.dll

2. 泛型Patch报错

Unhandled Exception:System.Exception: Utils/d__0 is CompilerGenerated

Unhandled Exception:System.InvalidProgramException: try to use a generic type definition: !0

InjectFix对于泛型支持有限制,不支持一个不确定的泛型方法,支持确定的泛型方法

更多错误汇集

官方Issues

后期有坑持续记录


赞赏与支持

【收藏与点赞】
觉得写的不错的可以收藏点赞转发噢~

【请作者喝杯咖啡】
觉得写的不错的可以请作者喝杯咖啡噢~
您的支持是我创作和分享的动力!
在这里插入图片描述


(完)

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-01-01 14:17:32  更:2022-01-01 14:19:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 20:37:28-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码