说明
临时工先顶上来,回头整理施工。发现流水账叙述比较无趣和难懂,后面考虑更换形式。
ToLua版本1.0.6。
第一篇启动不深入过多细节,后面对特性进行深入解析。
部分代码进行了抽取,以c#、c、lua形式混写。实际以源码为准。
系列前置关卡:
- Lua语言。
- Unity使用经验。
- Lua与宿主语言交互经验。
- ToLua接入和使用经验。
tolua Unity工程和tolua_runtime源码(不给下载链接,搜索和查阅资料是一项基本功)。
ToLua基于LuaInterface,LuaInterface是一个实现lua和微软.Net平台的CLR混合编程的开源库,使得lua脚本可以实例化CLR对象,访问属性,调用方法甚至使用lua函数来处理事件。ToLua保留了LuaInterface基本形式,重写或移除了部分内容,使代码更加简洁,提供了对Unity的支持、拓展了lua5.1.4源码。而最大的改进在于,LuaInterface中lua访问CLR需要运行时反射,对于游戏应用来说效率不够理想,ToLua则提供了一套中间层导出工具,对于需要访问的CLR、Unity及自定义类预生成wrap文件,lua访问时只访问wrap文件,wrap文件接收lua传递来的参数,进行类型(值、对象、委托)转换,再调用真正工作的CLR对象和函数,最后将返回值返回给lua,有效地提高了效率。
核心功能及文件
- 提供Lua-c#值类型、对象类型转化操作交互层。(ObjectTranslator.cs、LuaFunction.cs、LuaTable.cs、ToLua.cs等)
- 提供Lua虚拟机创建、启动、销毁,Require、DoFile、DoString、Traceback等相关支持。(LuaState.cs、LuaStatic.cs)
- 提供导出工具,利用c#反射,对指定的c#类生成对应的wrap文件,启动后将所有wrap文件注册到lua虚拟机中。(ToLuaMenu.cs、ToLuaExport.cs、ToLuaTree.cs、LuaBinder.cs、CustomSetting.cs等)
- 提供c#对象和lua userdata对应关系,使该userdata能访问对应c#对象属性,调用对应c#对象函数。lua支持一定的面向对象(类、继承)。管理这些对象的内存分配与生命周期、GC。(LuaState.cs)
- 提供支持功能Lua Coroutine、反射等,Lua层重写部分性能有问题对象如Vector系列。(Vector3.lua等)
启动代码
ToLua启动只需要三句代码即可。但里面实际经历了一段漫长的日夜。
void Start()
{
lua = new LuaState(); // 启动1:创建tolua提供的LuaState对象。
lua.Start(); // 启动2:虚拟机初始化。
LuaBinder.Bind(lua); // 启动3:Lua-c#中间层wrap文件们分别向虚拟机注册自己。
}
启动1 :lua new LuaState()
实例化LuaState对象。类的成员属性按子类基类的顺序初始化,类的构造函数按基类子类顺序执行。
LuaState继承自LuaStatePtr,该类包含一个System.IntPtr L指针,即lua虚拟机栈,并提供了一系列LuaDLL API的封装,可以认为是LuaDLL的升级版。而成员属性中比较重要的有ObjectTranslator和LuaReflection,暂时我们只用关注ObjectTranslator。
// LuaState.cs
public class LuaState : LuaStatePtr, IDisposable {
public ObjectTranslator translator = new ObjectTranslator();
public LuaReflection reflection = new LuaReflection();
public LuaState()
{
...
}
}
启动1.1 : ObjectTranslator
ObjectTranslator主要用于缓存lua需要访问的c# object对象。提供了对象池以及添加、查询、删除对象方法。管理对象的生命周期。LuaObjectPool对象池包含了一个PoolNode对象列表进行循环复用,PoolNode对象包含对真正object的引用,以及一个当前空闲索引的链表,其策略类似于lua_ref。
public class ObjectTranslator {
//gc打印标志
public bool LogGC { get; set; }
// 静态单例
private static ObjectTranslator _translator = null;
// object对象在对象池中的索引。
public readonly Dictionary<object, int> objectsBackMap =
new Dictionary<object, int>(new CompareObject());
// object对象池。
public readonly LuaObjectPool objects = new LuaObjectPool();
// 延迟gc列表,目前只在GameObject.Destroy(go, float t)传递了参数t时使用。
private List<DelayGC> gcList = new List<DelayGC>();
public ObjectTranslator()
{
// 是否在RemoveObject时,打印信息
LogGC = false;
// 单例
_translator = this;
}
// 获得单例
public static ObjectTranslator Get(IntPtr L) {
return _translator;
}
// 缓存一个object,返回在LuaObjectPool中的索引。
public int AddObject(object obj) {...}