|
根据前面的文章,我们会发现我们会在很多类前面加很多XLua的标签,有LuaCallCSharp,CSharpCallLua,Hotfix 等等。关于这些配置的作用官方文档也有相应的说明:https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/configure.md。这里我已个人理解和一些demo,对几个比较重要的标签详细记录一下。
打标签的方式
xLua所有的配置都支持三种方式:打标签;静态列表;动态列表。
配置有两必须,两建议:
列表方式均必须是static的字段/属性
- 列表方式均必须放到一个static类
- 建议不用标签方式
- 建议列表方式配置放Editor目录
打标签
xLua用白名单来指明生成哪些代码,而白名单通过attribute来配置,比如你想从lua调用c#的某个类,希望生成适配代码,你可以为这个类型打一个LuaCallCSharp标签:- [LuaCallCSharp]
- public classA {
- }
复制代码 该方式方便,但在il2cpp下会增加不少的代码量,不建议使用。
静态列表
有时我们无法直接给一个类型打标签,比如系统api,没源码的库,或者实例化的泛化类型,这时你可以在一个静态类里声明一个静态字段,该字段的类型除BlackList和AdditionalProperties之外只要实现了IEnumerable<Type>就可以了(这两个例外后面具体会说),然后为这字段加上标签:- [LuaCallCSharp]
- public static List<Type> mymodule_lua_call_cs_list = new List<Type>() {
- typeof(GameObject),
- typeof(Dictionary<string, int>),
- };
复制代码 这个字段需要放到一个静态类里头,建议放到Editor目录。动态列表
声明一个静态属性,打上相应的标签即可。- [Hotfix]
- public static List<Type> by_property {
- get {
- return (from type in Assembly.Load("Assembly-CSharp").GetTypes()
- where type.Namespace == "XXXX"
- select type).ToList();
- }
- }
复制代码 Getter是代码,你可以实现很多效果,比如按名字空间配置,按程序集配置等等。
这个字段需要放到一个静态类里头,建议放到Editor目录。
[CSharpCallLua]
首先是[CSharpCallLua]这个标签,看过C#调用Lua的小伙伴们,肯定不会陌生。当我们要把lua中的table映射到C#中的interface或把lua中的function映射到C#中的delegate的时候,就需要给interface和delegate添加该标签,否则就会报错(InvalidCastException: This type must add to CSharpCallLua: XXX)。添加好标签后需要执行XLua->Generate Code,这个时候XLua会将我们打上标签的代码生成对应的代码(生成代码默认放在"Assets/XLua/Gen/"下)。
热更的建议:用反射找出所有函数参数、字段、属性、事件涉及的delegate类型,标注CSharpCallLua;
XLua会针对每个interface生成一个对应的脚本(文件名为 interface全路径名称 + Bridge),例如我们前面的例子中用到的如下interface,XLua会生成CSCallLuaItfDBridge脚本。同时在生成XLuaGenAutoRegister.cs文件中会添加对应的配置,如下:- public class CSCallLua{
- [CSharpCallLua]
- public interface ItfD {
- int f1 { get; set; }
- int f2 { get; set; }
- int add(int a, int b);
- }
- }
复制代码
这种方式就属于上述的打标签,是官方不建议使用的方式,那我们看看如何用静态列表,动态列表来实现:
我们先用静态列表实现,按照官方建议,我们现在Editor目录下新建一个XLuaConfig.cs的脚本,内容如下(记得把之前在interface前加的CSharpCallLua的标签删除)- namespace MyExamples {
- public static class XLuaConfig {
- [CSharpCallLua]
- public static List<Type> cSharpCallLuaList = new List<Type>(){
- typeof(CSCallLua.ItfD),
- };
- }
- }
复制代码 然后我们执行XLua->Clean Generate Code后执行XLua->Generate Code。会发现相比之前的在gen下生产的代码是一样的。
接着是动态列表的写法,动态相比静态,我们可以用函数来实现需要添加的类别,这样就可以进行例如读配置,按条件筛选等等功能,如下:- [CSharpCallLua]
- public static List<Type> by_property {
- get {
- //可以添加一些逻辑代码筛选,比如
- List<Type> list = new List<Type>(){
- typeof(CSCallLua.ItfD),
- };
- return (from type in list
- where type.FullName.Contains("CSCallLua")
- select type).ToList();
- }
- }
复制代码 delegate和interface同理。但是有一点不同的事,将delegate打入标签生成代码时,并不会生成一个新的脚本文件,而是会将所有的delegat配置到DelegatesGensBridge.cs文件中,如下我们为CSCallLua.FDelegate打标签生成代码后。
[LuaCallCSharp]
和上面的一样,我们在前面Lua调用C#的时候会用到这个标签,我们先来看看官方给的定义:
一个C#类型加了这个配置,xLua会生成这个类型的适配代码(包括构造该类型实例,访问其成员属性、方法,静态属性、方法),否则将会尝试用性能较低的反射方式来访问。
一个类型的扩展方法(Extension Methods)加了这配置,也会生成适配代码并追加到被扩展类型的成员方法上。
xLua只会生成加了该配置的类型,不会自动生成其父类的适配代码,当访问子类对象的父类方法,如果该父类加了LuaCallCSharp配置,则执行父类的适配代码,否则会尝试用反射来访问。
反射访问除了性能不佳之外,在il2cpp下还有可能因为代码剪裁而导致无法访问,后者可以通过下面介绍的ReflectionUse标签来避免。
热更建议:业务代码、引擎API、系统API,需要在Lua补丁里头高性能访问的类型,加上LuaCallCSharp。引擎API、系统API可能被代码剪裁调(C#无引用的地方都会被剪裁),如果觉得可能会新增C#代码之外的API调用,这些API所在的类型要么加LuaCallCSharp,要么加ReflectionUse。
上面这些就是官方给的解释,一样的,我们在之前里例子中,添加该标签然后Generate Code之后会发现,同样会生成一个新的C#脚本(namespace+classname+wrap)。
根据官方解释我们知道该标签并不是必要的,如果没有该标签会用反射的方式去访问,只是性能较差,这里我们可以用前面的demo简单的测试一下:
lua代码如下,我们用到了C#中的GameObject,ParticleSystem和Test三个类- local GameObject = CS.UnityEngine.GameObject;
- local go = GameObject('go');
- --typeof
- go:AddComponent(typeof(CS.UnityEngine.ParticleSystem));
- --访问成员方法属性
- local Test = CS.MyExamples.Test;
- local test = Test();
- test.index = 66;
- print('test.index---'..test.index);
复制代码 在C#处,我们只需执行lua代码的前后记录下时间算个时间差即可- void Start () {
- luaenv = new LuaEnv();
- float start = Time.realtimeSinceStartup;
- luaenv.DoString(script);
- float end = Time.realtimeSinceStartup;
- Debug.Log(String.Format("{0:F6}", end - start));
- }
复制代码 在不打标签的情况下,即反射访问,运行结果如下:
然后我们打标签,Generate Code之后运行,结果如下:- [LuaCallCSharp]
- public static List<Type> luaCallCSharpList = new List<Type>() {
- typeof(Action),
- typeof(GameObject),
- typeof(ParticleSystem),
- };
复制代码
可以发现短短的几行代码,三个类的访问,反射访问慢了四五倍。
ReflectionUse
上面说到,如果没有添加LuaCallCSharp标签,lua会使用反射的方式去C#中的类型,但是这种方式除了性能不好外,还有个隐患就是在il2cpp下还有可能因为代码剪裁而导致无法访问。所以就轮到ReflectionUse这个标签出场了。
一个C#类型类型加了这个配置,xLua会生成link.xml阻止il2cpp的代码剪裁。
对于扩展方法,必须加上LuaCallCSharp或者ReflectionUse才可以被访问到。
建议所有要在Lua访问的类型,要么加LuaCallCSharp,要么加上ReflectionUse,这才能够保证在各平台都能正常运行。
BlackList
顾名思义,黑名单的功能,如果你不要生成一个类型的一些成员的适配代码,你可以通过这个配置来实现。
标签方式比较简单,对应的成员上加就可以了。
列表配置的方式就比较复杂(由于考虑到有可能需要把重载函数的其中一个重载列入黑名单),类型是List<List<string>>,List<List<string>>中的每一个List<string>对应一个类别的其中一个屏蔽(即若同一个类型需要屏蔽多个成员,则要多个List<string>一一对应)。每个List<string>里面的String即对应屏蔽信息,第一个string为类别的全称(namespace name+class name),第二个string对应要屏蔽的成员,若成员为方法,则需要在第三个以及之后(第四,第五...)加上方法参数的全称(这样就可以做到重载方法的区分)。
例如,我们有如下的class:- public class NeedBlackListClass {
- public int x;
- public string s;
- public void Add(int y) {
- x += y;
- Debug.Log("add---x:" + x);
- }
- public void Add(int y, GameObject go) {
- x += y;
- Debug.Log("add---x:" + x + "----go---" + go.name);
- }
- }
复制代码 现需要屏蔽s属性和Add(int y, GameObject go)方法,对应的列表定义如下:- [BlackList]
- public static List<List<string>> blackList = new List<List<string>>() {
- new List<string>(){ "MyExamples.NeedBlackListClass", "s"},
- new List<string>(){ "MyExamples.NeedBlackListClass", "Add", "System.Int32", "UnityEngine.GameObject"},
- };
复制代码 然后Generate Code之后,在lua中访问s的时候就会报错(LuaException: cannot set s, no such field)访问Add(int y, GameObject go)方法则会去调用Add(int y)方法。
备注:我们也可以去看生成的对应wrap代码里面的内容:
Hotfix
hotfix标签,看过前面热更新的话就知道这是用于标识要热更的类型(可以是class或namespace)。若不在该标签下的类型,则无法用xlua.hotfix进行热更。- [Hotfix]
- public static List<Type> by_field = new List<Type>() {
- typeof(HotFixSubClass),
- typeof(GenericClass<>),
- };
- [Hotfix]
- public static List<Type> by_property {
- get {
- return (from type in Assembly.Load("Assembly-CSharp").GetTypes()
- where type.Namespace == "XXXX"
- select type).ToList();
- }
- }
复制代码
生成期配置
下面配置,必须放到Editor目录下
CSObjectWrapEditor.GenPath
配置生成代码的放置路径,类型是string。默认放在"Assets/XLua/Gen/"下,如。- [CSObjectWrapEditor.GenPath]
- public static string genPath = "Assets/Scripts/Tools/XLua/Gen/";
复制代码 CSObjectWrapEditor.GenCodeMenu
该配置用于生成引擎的二次开发,一个无参数函数加了这个标签,在执行"XLua/Generate Code"菜单时,执行结束会触发这个函数的调用。- [CSObjectWrapEditor.GenCodeMenu]
- public static void XLuaGenerateCodeFinish() {
- Debug.Log("XLuaGenerateCodeFinish");
- }
复制代码
其他一些不常用的标签大家自己可以自己看一下官方文档。若之后发现有需要注意的点会再补充。 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|