【学习笔记】从零开始学ToLua(四)tolua原理解析

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

https://www.cnblogs.com/yptianma/p/11797925.html @天马yp

### TOlua框架的热更新实现原理 TOlua框架的热更新实现主要依赖于Lua与C#之间的交互机制。通过TOluaLua脚本可以调用C#中的方法和对象,同时C#也可以调用Lua中的函数。这种双向调用机制是实现热更新的核心基础[^1]。 #### 1. Lua与C#对象的交互 在TOlua中,C#对象并不会直接暴露给Lua。相反,这些对象会被注册到一个名为`ObjectTranslator`的组件中,并返回一个索引值(类似于Windows编程中的句柄)。这个索引值会被包装成一个`userdata`传递给Lua,并且设置相应的元表(metatable),从而允许Lua通过元表操作C#对象[^2]。 #### 2. 初始化过程 在TOlua的初始化阶段,会加载一个名为`tollua.lua`的文件。该文件通过`require`引入了对Unity性能优化后的类型定义,例如`Vector3`、`Vector2`、`Bound`等。这些类型的Lua方法会被缓存到C#中,以便后续快速调用[^3]。 #### 3. 热更新的具体实现 热更新的核心思想是将游戏逻辑从C#代码中分离出来,转移到Lua脚本中。这样可以在不重新编译C#代码的情况下,仅通过替换Lua脚本实现功能的修改或新增。具体实现步骤如下: - **脚本加载**:通过LuaState加载Lua脚本文件。这通常通过`DoFile`方法完成。 - **动态绑定**:使用TOlua提供的API将Lua函数绑定到C#中。例如,可以通过`LuaFunction`类来调用Lua中的函数。 - **运行时替换**:当需要更新逻辑时,只需重新加载Lua脚本文件,而无需重启游戏或重新编译C#代码。 #### 4. 性能优化 为了提高性能,TOlua会对一些常用的Unity类型进行重写和优化。例如,对于`Vector3`的操作,TOlua会在Lua层面上提供更高效的实现方式,避免频繁的跨语言调用带来的性能开销[^3]。 ```csharp // 示例:通过TOlua调用Lua函数 using XLua; public class Example : MonoBehaviour { private LuaEnv luaEnv = new LuaEnv(); void Start() { // 加载Lua脚本 luaEnv.DoString("function Test() print('Hello from Lua!') end"); // 调用Lua函数 var func = luaEnv.Global.GetInPath<LuaFunction>("Test"); if (func != null) { func.Call(); func.Dispose(); } } void OnDestroy() { luaEnv.Dispose(); } } ``` #### 5. 注意事项 尽管TOlua提供了强大的热更新能力,但在实际项目中需要注意以下几点: - **兼容性问题**:确保Lua脚本与C#代码之间的接口保持一致,避免因版本差异导致错误。 - **性能问题**:虽然TOlua对部分类型进行了优化,但频繁的跨语言调用仍可能导致性能瓶颈。 - **调试困难**:相较于纯C#开发,Lua脚本的调试相对复杂,建议使用专门的调试工具。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值