# FAQ ## xLua发布包怎么用? xLua目前以zip包形式发布,在工程目录下解压即可。 ## xLua可以放别的目录吗? 可以,但生成代码目录需要配置一下(默认放Assets\XLua\Gen目录),具体可以看《XLua的配置.doc》的GenPath配置介绍。 更改目录要注意的是:生成代码和xLua核心代码必须在同一程序集。如果你要用热补丁特性,xLua核心代码必须在Assembly-CSharp程序集。 ## xLua的配置 如果你用的是lua编程,你可能需要把一些频繁访问的类配置到LuaCallCSharp,这些类的成员如果有条件编译(大多数情况下是UNITY_EDITOR)的话,你需要通过BlackList配置排除;如果你需要通过delegate回调到lua的地方,得把这些delegate配置到CSharpCallLua。 如果你用的是热补丁,你需要把要注入的代码加到Hotfix列表;如果你需要通过delegate回调到lua的地方,也得把这些delegate配置到CSharpCallLua。 xLua提供了强大的动态配置,让你可以结合反射实现任意的自动化配置,动态配置介绍看[这里](configure.md)。xLua希望你能根据自身项目的需求自行配置,同时为了方便部分对反射api了解不够的童鞋,xLua也针对上面两者方式分别写了参考配置:[ExampleConfig.cs](../Editor/ExampleConfig.cs),直接打开相应部分的注释即可使用。 ## lua源码只能以txt后缀? 什么后缀都可以。 如果你想以TextAsset打包到安装包(比如放到Resources目录),Unity不认lua后缀,这是Unity的规则。 如果你不打包到安装包,就没有后缀的限制:比如自行下载到某个目录(这也是热更的正确姿势),然后通过CustomLoader或者设置package.path去读这个目录。 那为啥xLua本身带的lua源码(包括示例)为什么都是txt结尾呢?因为xLua本身就一个库,不含下载功能,也不方便运行时去某个地方下载代码,通过TextAsset是较简单的方式。 ## 编辑器(或非il2cpp的android)下运行正常,ios下运行调用某函数报“attempt to call a nil value” il2cpp默认会对诸如引擎、c#系统api,第三方dll等等进行代码剪裁。简单来说就是这些地方的函数如果你C#代码没访问到的就不编译到你最终发布包。 解决办法:增加引用(比如配置到LuaCallCSharp,或者你自己C#代码增加那函数的访问),或者通过link.xml配置(当配置了ReflectionUse后,xlua会自动帮你配置到link.xml)告诉il2cpp别剪裁某类型。 ## Unity 2018及以上版本兼容性问题解决 2.1.14前的版本都建议先升级到2.1.14,升级后,还有如下两个使用注意事项: 1、默认配置不生成代码运行会报错 这是因为Api Compatibility Level设置为.NET Standard 2.0,而.NET Standard 2.0不支持emit导致的。 解决方案:平时开发Api Compatibility Level设置为.NET 4.x,就能支持编辑器不生成代码开发。发布手机版本时,按Unity官方的建议,可配置为.NET Standard 2.0,包会更小些。 2、生成代码后,一些系统类型的生成代码会报一些方法不存在。 据研究表明,Unity 2018设置.NET 4.X Equivalent的话,其运行和编译用的库不一致,前者比后者多一些API。 运行用的是:unity安装目录\Editor\Data\MonoBleedingEdge\lib\mono\unityjit\mscorlib.dll 编译链接的是:unity安装目录\Editor\Data\MonoBleedingEdge\lib\mono\4.7.1-api\mscorlib.dll 解决办法:用黑名单排除报错方法即可。不过2019年8月6号以前的版本的黑名单配置对泛型不友好,要一个个泛型实例的配置(比如,Dictionary和Dictionary要分别配置),而目前发现该问题主要出在泛型Dictionary上。可以更新到2019年8月6号之后的版本,该版本支持配置一个过滤器对泛型方法过滤。这里有对unity 2018的Dictionary的[针对性配置](https://github.com/Tencent/xLua/blob/master/Assets/XLua/Editor/ExampleConfig.cs#L277),直接拷贝使用,如果碰到其它泛型也有多出来的方法,参考Dictionary进行配置。 ## Plugins源码在哪里可以找到,怎么使用? Plugins源码位于xLua_Project_Root/build下。 源码编译依赖cmake,安装cmake后执行make_xxxx_yyyy.zz即可,xxxx代表平台,比如ios,android等,yyyy是要集成的虚拟机,有lua53和luajit两者,zz是后缀,windows下是bat,其它平台是sh。 windows编译依赖Visual Studio 2015。 android编译在linux下执行,依赖NDK,并且需要把脚本中ANDROID_NDK指向NDK的安装目录。 ios和osx需要在mac下编译。 ## 报类似“xlua.access, no field __Hitfix0_Update”的错误怎么解决? 按[Hotfix操作指南](hotfix.md)一步步操作,以及注意事项。确保上述步骤完成后,可尝试使用[解决方案](https://github.com/Tencent/xLua/issues/850)。 出现这报错,肯定是这个导致的:最终包的这个方法(函数)没注入。 但造成“最终包的这个方法(函数)没注入”的原因会有很多:比如没按文档操作,注入失败,比如Hotfix列表漏了这个类,比如你的打包脚本在注入后,又触发了重新编译,覆盖了注入结果。。。 统一的解决方式是找出并解决导致“最终包的这个方法(函数)没注入”的具体原因。 ## visual studio 2017下编译UWP原生库 visual studio 2017需要安装:1、“工作负载”下的“通用Window平台开发”;2、“单个组件”下的“用于ARM的Visual C++编译器和库”、“用于ARM64的Visual C++编译器和库”、“是用于ARM64的C++通用Windows平台工具” ## visual studio 2015下编译原生库 把build\vs2015下的bat文件拷贝到build目录,覆盖同名文件 ## 报“please install the Tools” 没有把Tools安装到Assets平级目录,安装包,或者master下都能找到这个目录。 ## 报“This delegate/interface must add to CSharpCallLua : XXX”异常怎么解决? 在编辑器下xLua不生成代码都可以运行,出现这种提示,要么是该类型没加CSharpCallLua,要么是加之前生成过代码,没重新执行生成。 解决办法,确认XXX(类型名)加上CSharpCallLua后,清除代码后运行。 如果编辑器下没问题,发布到手机报这错,表示你发布前没生成代码(执行“XLua/Generate Code”)。 如果你Unity版本大于或等于2018,看下前面兼容性的章节。 ## unity5.5以上执行"XLua/Hotfix Inject In Editor"菜单会提示"WARNING: The runtime version supported by this application is unavailable." 这是因为注入工具是用.net3.5编译,而unity5.5意思MonoBleedingEdge的mono环境并没3.5支持导致的,不过一般而言都向下兼容,目前为止也没发现该warning带来什么问题。 可能有人发现定义INJECT_WITHOUT_TOOL用内嵌模式会没有该warning,但问题是这模式是调试问题用的,不建议使用,因为可能会有一些库冲突问题。 ## hotfix下怎么触发一个event 首先通过xlua.private_accessible开启私有成员访问。 跟着通过对象的"&事件名"字段调用delegate,例如self\['&MyEvent'\](),其中MyEvent是事件名。 ## 怎么对Unity Coroutine的实现函数打补丁? 见[Hotfix操作指南](hotfix.md)相应章节。 ## 支持NGUI(或者UGUI/DOTween等等)么? 支持,xLua最主要的特性是让你原来用C#写的地方可以换成用lua写,你C#能用的插件,基本都能用。 ## 如果需要调试,CustomLoader的filepath参数该如何处理? lua里头调用require 'a.b'时,CustomLoader会被调用,并传入字符串"a.b",你需要理解这字符串,(从文件/内存/网络等)加载好lua文件,返回两个东西,第一个是调试器可以理解的路径,比如:a/b.lua,这个通过设置ref类型的filepath参数返回,第二个是UTF8格式的源码的字节流(byte[]),通过返回值返回。 ## 什么是生成代码? xLua支持的lua和C#间交互技术之一,这种技术通过生成两者间的适配代码来实现交互,性能较好,是推荐的方式。 另一种交互技术是反射,这种方式对安装包的影响更少,可以在性能要求不高或者对安装包大小很敏感的场景下使用。 ## 改了接口后,之前生成的代码出现错误怎么办? 清除掉生成代码(执行“Clear Generated Code”菜单,如果你重启过,会找不到这个菜单,这时你可以手动删除整个生成代码目录),等编译完成后重新生成。 ## 应该什么时候生成代码? 开发期不建议生成代码,可以避免很多由于不一致导致的编译失败,以及生成代码本身的编译等待。 build手机版本前必须执行生成代码,建议做成自动化的。 做性能调优,性能测试前必须执行生成代码,因为生成和不生成性能的区别还是很大的。 ## CS名字空间下有所有C# API是不是很占内存? 由于用了lazyload,这个“有”只是个虚拟的概念,比如UnityEngine.GameObject,是访问第一次CS.UnityEngine.GameObject或者第一个实例往lua传送才加载该类型方法,属性等。 ## LuaCallSharp以及CSharpCallLua两种生成各在什么场景下用? 看调用者和被调用者,比如要在lua调用C#的GameObject.Find函数,或者调用gameobject的实例方法,属性等,GameObject类要加LuaCallSharp,而想把一个lua函数挂到UI回调,这是调用者是C#,被调用的是一个lua函数,所以回调声明的delegate要加CSharpCallLua。 有时会比较迷惑人,比如List.Find(Predicate match)的调用,List当然是加LuaCallSharp,而Predicate却要加CSharpCallLua,因为match的调用者在C#,被调用的是一个lua函数。 更无脑一点的方式是看到“This delegate/interface must add to CSharpCallLua : XXX”,就把XXX加到CSharpCallLua即可。 ## 值类型传递会有gc alloc么? 如果你使用的是delegate调用lua函数,或者用LuaTable、LuaFunction的无gc接口,或者数组的话,以下值类型都是没gc的: 1、所有的基本值类型(所有整数,所有浮点数,decimal); 2、所有的枚举类型; 3、字段只包含值类型的struct,可嵌套其它只包含值类型struct; 其中2、3需要把该类型加到GCOptimize。 ## 反射在ios下可用吗? ios下的限制有两个:1、没有jit;2、代码剪裁(stripping); 对于C#通过delegate或者interface调用lua,如果不生成代码是用反射的emit,这依赖jit,所以这目前只在编辑器可用。 对于lua调用C#,主要会被代码剪裁影响,这时你可以配置ReflectionUse(不要配LuaCallSharp),执行“Generate Code”,这时不会对该类生成封装代码,而是生成link.xml把该类配置为不剪裁。 简而言之,除了CSharpCallLua是必须的(这类生成代码往往不多),LuaCallSharp生成都可以改为用反射。 ## 支持泛型方法的调用么? 1、泛型约束到某个基类的支持,看例子:(../Examples/09_GenericMethod/) 2、没有泛型约束的建议封装为非泛型使用 如果是静态方法,可以自己写个封装来实例化泛型方法。 如果是成员方法,xLua支持扩展方法,你可以添加一个扩展方法来实例化泛型方法。该扩展方法使用起来就和普通成员方法一样。 ```csharp // C# public static Button GetButton(this GameObject go) { return go.GetComponent