unity 使用hybridclr进行热更新怎么修复unity脚本错误解决加载热更dll后脚本丢失?

HybridCLR是一个特性完整、零成本、高性能、低内存的近乎完美的Unity全平台原生C#热更方案。HybridCLR扩充了IL2CPP的代码,使它由纯AOT Runtime变成“AOT+Interpreter“混合Runtime,进而原生支持动态加载Assembly,使得基于IL2CPP Backend打包的游戏不仅能在Android平台,也能在iOS、Consoles等限制了JIT的平台上高效地以AOT+interpreter混合模式执行。HybridCLR开创性地实现了“Differential Hybrid Dll“技术。即可以对AOT Dll任意增删改,会智能地让变化或者新增的类和函数以Interpreter模式运行,但未改动的类和函数以AOT方式运行,让热更新的游戏逻辑的运行性能基本达到原生AOT的水平。HybridCLR(wolong)原作者walon(focus-creative-games创始人)将该系列课程放入UWA学堂连载更新,现已【免费上线UWA学堂】,本文先带大家对HybridCLR——划时代的Unity原生C#热更新技术有个简单的了解,更多内容可前往UWA学堂查看。1. 基础概念1.1 CLRCLR即Common Language Runtime,中文叫公共语言运行时,是让.NET程序执行所需的外部服务的集合,是.NET平台的核心和最重要的组件,类似于Java的JVM。更详细介绍请看《公共语言运行时 (CLR) 概述》。1.2 IL2CPPIL2CPP是Unity开发的跨平台CLR解决方案,诞生它的一个关键原因是Unity需要跨平台运行。但一些平台如iOS,这种禁止JIT并导致依赖JIT的官方CLR虚拟机无法运行,而是必须使用AOT技术将Mananged程序提前转化为目标平台的静态原生程序后再运行。而Mono虽然也支持AOT,但性能较差以及跨平台支持不佳。IL2CPP方案包含一套AOT运行时以及一套DLL到C++代码及元数据的转换工具,使得原始的C#开发的代码最终能在iOS这样的平台运行起来。1.3 IL2CPP与热更新很不幸,不像Mono有Hybrid mode execution,可支持动态加载DLL。IL2CPP是一个纯静态的AOT运行时,不支持运行时加载DLL,因此不支持热更新。目前Unity平台的主流热更新方案xLua、ILRuntime之类都是引入一个第三方VM(Virtual Machine),在VM中解释执行代码,来实现热更新。这里我们只分析使用C#为开发语言的热更新方案。这些热更新方案的VM与IL2CPP是独立的,意味着它们的元数据系统是不相通的,在热更新里新增一个类型是无法被IL2CPP所识别的(例如,通过System.Activator.CreateInstance是不可能创建出这个热更新类型的实例),这种看起来像,但实际上又不是的伪CLR虚拟机,在与IL2CPP这种复杂的CLR运行时交互时,会产生极大量的兼容性问题,另外还有严重的性能问题。一个大胆的想法是,是否有可能对IL2CPP运行时进行扩充,添加Interpreter模块,进而实现Mono hybrid mode execution这样机制?这样一来就能彻底支持热更新,并且兼容性极佳。对开发者来说,除了解释模式运行的部分执行得比较慢,其他方面跟标准的运行时没有区别。对IL2CPP加以了解并且深思熟虑后的答案是——确实是可行的!具体分析参见第二节《关于HybridCLR可行性的思维实验》 。这个想法诞生了HybridCLR,Unity平台第一个支持iOS的跨平台原生C#热更新方案!2. 原理HybridCLR扩充了IL2CPP运行时,将它由AOT运行时改造为“AOT + interpreter”双引擎的混合运行时,进而完美支持在iOS这种禁止JIT的平台上以解释模式无缝地运行动态加载的DLL。如下图所示:更具体一些,至少需要实现以下功能:加载和解析DLL元数据动态注册元数据,其中关键为Hook动态函数的执行流到解释器函数实现一个高效正确的解释器正确处理GC及多线程等运行时机制3. 特性3.1 标准运行时特性近乎完整实现了ECMA-335规范,不支持的特性仅包括:不支持Delegate的BeginInvoke,EndInvoke。纯粹是觉得没必要实现。不支持MonoPInvokeCallbackAttribute。意味着你如果同时还接了Lua,你没法直接将热更新的C#函数注册到Lua中,但有一个不复杂的办法能做到这点。由于HybridCLR极其完整的实现,让使用HybridCLR后的C#开发体验跟Editor下Mono开发几乎完全相同(除了调用一些IL2CPP没实现的.net framework函数,非专家级别的开发者难以构造出HybridCLR不支持的用例)。另外,由于是运行时级别的实现,HybridCLR支持这些特性的同时,不需要你额外生成或者调整任何代码。对于开发者来说,相比Unity下原生C#开发,零额外的学习和开发成本。3.2 AOT相关特性由于IL2CPP AOT模块的存在,IL2CPP比标准运行时多了一些不存在的机制,因此HybridCLR也有一些额外的特性:支持使用Interpreter Assembly替换AOT Assembly(限制:必须不存在其他AOT Assembly对它的直接引用)。支持补充元数据机制,彻底支持AOT泛型,参见《AOT泛型限制及原理介绍》。支持AOT Hotfix,可以修复AOT模块的Bug。支持任意C#函数注册到Lua之类的虚拟机,不限于Static函数,并且也不需要MonoPInvokeCallbackAttribute。条件是注册和回调方式需要略微调整。3.3 Unity相关特性完美支持Unity的Assembly Def模块机制。完美支持代码中挂载热更新脚本,无使用场景限制完美支持资源上挂载热更新脚本,但要求打包工作流有少许调整,参见《MonoBehaviour相关工作流》。4. 与其他流行的C#热更新方案的区别从原理来说,HybridCLR几乎将热更新技术做到理论上的极限,与当前所有主流热更新方案不在一个层次。4.1 本质比较HybridCLR是原生的C#热更新方案。通俗地说,IL2CPP相当于Mono的AOT模块,HybridCLR相当于Mono的Interpreter模块,两者合一成为完整Mono。HybridCLR使得IL2CPP变成一个全功能的Runtime,原生(即通过System.Reflection.Assembly.Load)支持动态加载DLL,从而支持iOS平台的热更新。正因为hHybridCLR是原生Runtime级别实现,热更新部分的类型与主工程AOT部分类型是完全等价并且无缝统一的。可以随意调用、继承、反射或多线程,不需要生成代码或者写适配器。其他热更新方案则是独立VM,与IL2CPP的关系本质上相当于Mono中嵌入Lua的关系。因此类型系统不统一,为了让热更新类型能够继承AOT部分类型,需要写适配器,并且解释器中的类型不能为主工程的类型系统所识别。特性不完整、开发麻烦、运行效率低下。4.2 实际使用体验或者特性比较HybridCLR学习和使用成本几乎为零。HybridCLR让IL2CPP变成全功能的Runtime,学习和使用成本几乎为零,几乎零侵入性。而其他方案则有大量的坑和需要规避的规则,学习和使用成本较高,需要对原项目作大量改造。HybridCLR可以使用所有C#的特性,而其他方案往往有大量的限制。HybridCLR中可以直接支持使用和继承主工程中的类型,其他方案要写适配器或者生成代码。HybridCLR中热更新部分元数据与AOT元数据无缝统一,像反射代码能够正常工作的,AOT部分也可以通过标准Reflection接口创建出热更新对象。其他方案做不到。HybridCLR对多线程支持良好。像多线程、ThreadStatic、Async等等特性都是HybridCLR直接支持,其他方案除了Async特性外均难以支持。HybridCLR中Unity工作流与原生几乎完全相同。HybridCLR中热更新MonoBehaviour可以直接挂载在热更新资源上,并且正确工作。其他方案不行。HybridCLR兼容性极高。各种第三方库只要在IL2CPP下能工作,在HybridCLR下也能正常工作。其他方案往往要大量魔改源码。HybridCLR内存效率极高。HybridCLR中热更新类型与主工程的AOT类型完全等价,占用一样多的空间。其他方案的同等类型则是假类型,不仅不能被Runtime识别,还多占了数倍空间。HybridCLR执行效率高。HybridCLR中热更新部分与主工程AOT部分交互属于IL2CPP内部交互,效率极高。而其他方案则是独立虚拟机与IL2CPP之间的效率,不仅交互麻烦还效率低下。5. 运行性能实际性能如理论估计,全面并且大幅胜出当前主流的xLua、Puerts、ILRuntime之类的热更新方案。基础指令(数值计算及条件跳转等指令),由于各个语言之间差距不大,因此胜出不明显。对象模型指令。由于没有跨语言交互的成本,几乎是数倍到数十倍的提升(如果指令自身消耗特别大,则差距不那么明显)。性能测试用例来自ILRuntime提供的标准测试用例,测试项目来自Don't worry的github仓库。测试结果显示,绝大多数测试用例都有数倍到数十倍的性能差距,差距极其夸张。唯独数值计算跟xLua有少量劣势,这是因为当前HybridCLR未对指令作任何优化,后续优化版本大多数基础指令都将有100~300%的性能提升。6. 内存HybridCLR是运行时级别的实现,因为热更新的脚本,除了执行代码是以解释模式执行,其他方式跟AOT部分的类型是完全相同的,包括占用内存。6.1 对象内存大小对比Lua的计算规则略复杂,参见《Lua数据结构和内存占用分析》。空Table占56字节,每多一个字段至少多占32字节。ILRuntime的类型除了Enum外统一以IlTypeInstance表达,空类型占72字节,每多一个字段至少多用16字节。如果对象中包含引用类型数据,则整体又至少多24字节,并且每多一个Object字段多8字节。7. 当前稳定性状况技术评估上目前稳定性处于Beta版本。由于HybridCLR技术原理的先进性,Bug本质上不多,稳定得非常快。已经有一段时间未收到2020.3.33版本的Bug反馈。目前PC、Android、iOS已跑通所有单元测试,可稳定体验使用。2022.6.7第一款使用HybridCLR的Android和iOS双端休闲游戏正式上线。2022.7将有至少2款重度项目和2款中度游戏上线。2022年预计有几十款中重度项目及超过一百款轻度或者独立游戏上线。已经有几十个大中型游戏项目较完整地接入HybridCLR,并且其中一些在紧锣密鼓作上线前测试。具体参见收集的一些完整接入的商业项目列表。8. 总结HybridCLR是一个划时代的Unity平台C#原生热更新技术,它将国内Unity开发的技术框架水平提高到新的高度,并深刻地改变Unity平台的开发生态。本文内容就介绍到这里啦,更多内容可以前往UWA学堂进行阅读。
一.前言HybridCLR(代号wolong)是一个特性完整、零成本、高性能、低内存的近乎完美的Unity全平台原生c#热更方案。官方提供了完整的教程:HybridCLR快速上手官方还提供了一个简易的小Demo,演示了如何使用HybridCLR实现热更新。hybridclr_trial官方文档其实已经非常详细了,我写本文目的主要为了记录一下我的接入过程。我们可以下载官方的示例Demo,我们参考Demo更容易理解HybridCLR。二.环境配置第一步环境配置,我们需要把hybridclr_unity插件导入到项目中。方法有很多,官方推荐通过packageManager安装,也可以直接github下载,放到工程中。参考官方教程:安装HybridCLR三.配置ProjectSettingScriptingBackend为il2cppApi Compatability Level 切换为.Net 4检查bybridclr_trial示例是否设置正常。参考官方教程:
官方入门文档参考:https://focus-creative-games.github.io/hybridclr/start_up/#安装和环境搭建1.先下载下来两个包 一个解释器 一个修改Unity IL2CPP 的代码包 (注意Unity 版本要求为2020.3.33 作者还在扩展后续版本)解释器下载:https://github.com/focus-creative-games/hybridclr2020.3.33 IL2CPP 库修改下载:https://github.com/focus-creative-games/il2cpp_plus/tree/2020.3.33官方实例工程下载:https://github.com/focus-creative-games/hybridclr_trial.git对应下载完毕如下图所示2 拷贝 hybridclr/huatuo 目录 到 il2cpp_plus/libi2cpp 目录下3. 复制第2步修改的libil2cpp 文件夹 替换掉Unity 2020.3.33 编辑器的libil2cpp文件夹(替换前建议先备份一下)找到对应Unity 安装目录 打开搞定 环境设置完毕 可以打开实例工程看看4 哦豁 报错 小问题 看看他说少文件了 打开他说的目录看看4.1 修改init_local_il2cpp_data.bat 文件 改成对应Unity 安装目录 双击运行 他会生成一个LocalIl2CppData 文件注意圈起来的地方都得改一下 最后两个地址 对应上面从git上下载下来的路径把这个拷贝 加个覆盖不提示双击 bat提示成功就可以了可以看到 生成了一个 LocalIl2CppData 目录就可以了5 重新打开工程 让他加载一下 就不会报错了 打开示例main场景6 先编个包测试一下 (方便测试 我先编个PC包把)6.1如果提示 IL2CPP not installed 表示安装Unity 的时候漏勾选了 没下载Window下的IL2CPP 打包环境打开Unity Hub 点击安装 选中对应版本 右键 添加模块6.2直接点Build 选个目录 我这边新建一个Build 目录 放这里面了然后等 他loading 完 看看到 有个exe 编译完成6.3 打开 鼠标画全可以打开控制台 可以看到这个打印日志输出了6.4 现在对这个C# 进行简单修改看看7.先编DLL7.1 再把DLL 变成ab 包7.2 刚刚的DLL 被编到了common 里面 直接手动拷贝 覆盖进去(模拟更新下载)7.3 直接替换掉Build 目录下的StreamingAssets同名文件7.4 再打开exe 看看效果有打印了 完美

我要回帖

更多关于 怎么修复unity脚本错误 的文章