lua调用C#
- tolua中lua调用C#是基于去反射。
- 把所有的c#类的public成员变量、成员函数,都导出到一个相对应的Wrap类中,而这些成员函数通过特殊的标记,映射到lua的虚拟机中,当在lua中调用相对应的函数时候,直接调用映射进去的c# wrap函数,然后再调用到实际的c#类,完成调用过程。
- 当lua虚拟机启动的时候,会将此wrap文件加载进lua虚拟机,然后lua就可以识别此调用了。
- 最后就形成了Lua 调用 Wrap , Wrap调用C#的模式,实现了Lua调用C#
生成wrap文件
- 生成Wrap文件需要使用者自己手动的去CustomSetting,填写需要Wrap的文件
- BindLua.cs 文件,里面有个叫Binding的函数,我们手动填写要绑定的类型会被添加到里面的list的里。
- 那里面会通过GenLuaBinders绑定wrap并注册到虚拟机
lua中对C#对象的交互
ObjectTranslator.cs
这个类代码不多,它存在的主要意义就是给lua中对C#对象的交互提供了基础,简单来说就是C#中的对象在传给lua时并不是直接把对象暴露给了lua,而是在这个OjbectTranslator里面注册并返回一个索引(可以理解为windows编程中的句柄),并把这个索引包装成一个userdata传递给lua,并且设置元表。具体可以查看tolua_pushnewudata代码。
而在lua需要通过上面传到lua里面的对象调用C#的方法时,它会调用ToLua.CheckObject或者ToLua.ToObject从ObjectTranslator获取真正的C#对象。
C#与Lua数据交互(lua虚拟栈)
- C#与lua的数据交互是基于一个Lua先进后出的虚拟栈
- 可以压入数字,字符串,表table,闭包func
C#与Lua通信(P/Invoke)
- 所有的通信都是基于P/Invoke模式(性能低)类似JNI
- P/Invoke:公共语言运行库(CLR)的interop功能(称为平台调用(P/Invoke))
- 命名空间:System.Runtime.InteropServices
tolua的优化方式汇总
- BinderLua太多wrap很慢(反射与去反射共存)
- Lua代码打入AssetBundle为了绕过苹果检测
- 动态注册Wrap文件到Lua虚拟机(tolua延伸)
- ToLuaExport. memberFilter的函数过滤
- 尽量减少c#调用lua的次数来做主题优化思想
- 尽量使用lua中的容器table取代c#中的所有容器
- 例子CallLuaFunction_02里附带了no gc alloc调用方式
- Lua的bytecode模式性能要低于Lua源码执行
- 取消动态参数:打开LuaFunction.cs文件,找到函数声明:
public object[] Call(params object[] args){
return call(args, null);
}
取消动态参数args,可用较笨方法,就是定义6-7个默认参数,不够再加。
- 安卓平台如果使用luajit的话,记得在lua最开始执行的地方请开启 jit.off(),性能会提升N倍。
- 记得安卓平台上在加上jit.opt.start(3),相当于c++程序-O3,可选范围0-3,性能还会提升。Luajit作者建议-O2
tolua部分代码说明
tolua#的核心运行时
tolua#的运行代码包含SourceGenerate下面的绑定代码以及ToLuaàBaseType代码以及Core下面的核心代码。接下来我们着重讲一下Core下面的几个主要类。
LuaAttribute.cs
它在tolua#生成绑定代码时做一些标示使用。Attribute 是一种可由用户自由定义的修饰符(Modifier),可以用来修饰各种需要被修饰的目标。特性Attribute 的作用是添加元数据。元数据可以被工具支持,比如:编译器用元数据来辅助编译,调试器用元数据来调试程序。Unity以及tolua#中就会用Attribute来辅助做一些事情。
LuaBaseRef.cs
Lua中对象对应C#中对象的一个基类(子类有LuaTable,LuaFunction,LuaThread),主要作用是有一个reference指向lua里面的对象,引用计数判断两个对象是否相等等。
LuaDll.cs
这个类的主要作用就是实现了C#调用原生代码的功能.
LuaState.cs
这里面是对真正的lua_State的封装,包括初始化lua路径,加载相应的lua文件,注册我们前面生成的绑定代码以及各种辅助函数。
ObjectTranslator.cs
接下来,我们着重说一下这个ObjectTranslator这个类,这个类代码不多,它存在的主要意义就是给lua中对C#对象的交互提供了基础,简单来说就是C#中的对象在传给lua时并不是直接把对象暴露给了lua,而是在这个OjbectTranslator里面注册并返回一个索引(可以理解为windows编程中的句柄),并把这个索引包装成一个userdata传递给lua,并且设置元表。具体可以查看tolua_pushnewudata代码。
而在lua需要通过上面传到lua里面的对象调用C#的方法时,它会调用ToLua.CheckObject或者ToLua.ToObject从ObjectTranslator获取真正的C#对象。
userdata
userdata实际上是一个指针地址,通过对这个userdata设置不同的metatable来区分userdata对应的c#类型
要更详细地了解userdata内容可以阅读 tolua#中的userdata @xsxjin
参考资料 http://richbabe.top/2018/07/20/ulua-tolua%E5%8E%9F%E7%90%86%E8%A7%A3%E6%9E%90/ @RichBaby