背景
项目是全Lua开发,导致的其中一个结果是会遇到lua的gc性能问题。而且相对于C#这种强类型语言,Lua因为其自由性,对于团队后期维护还是有一定的成本,不做好代码复审,相对不好维护。这个时候就需要我们自主了解Lua和C#交互的底层逻辑和实现原理,用以之后在lua测开发的时候做出良好的代码优化。
项目采用xlua结构与c#端进行交互,在个别地方和其他类型的lua(比如和tolua的加载机制)不一样,但lua底层都是一致的。在此次分享中会有一些知识专属于xlua范围。
Lua和C#交互逻辑
Lua文件加载
xLua定义了两种在C#中调用lua代码的方式:
-
DoString("xxxxxxxxxxxx").这个函数一般不建议使用,LuaEnv中就有此段代码:
这段代码内部主要定义了在Lua中访问c#对象时进行的具体操作。这里具体干了什么事情,还需要留待未来探讨。
-
自定义loader来加载文件。
通过调用LuaEnv中的AddLoader注册回调,这样每当lua脚本中调用require函数时,都会将参数传回给回调。如果这个回调返回null,则证明loader找不到相应的lua脚本,否则返回lua脚本的内容。
有了这种加载方式,则方便处理热更新下来的lua文件,或者是加密的文件,在回调中进行相应的操作即可。参考代码如下:
LuaEnv luaenv = new LuaEnv(); luaenv.AddLoader(MyLoader);
上述两种方式中,用自定义loader的一个好处就是,文件即便是已经加密也可以自己写loader读取文件解密后返回即可。
Lua和C#如何互相调用方法、对象(浅层)
xlua定义了独有的调用方式。在程序员层面上,我们只需要在c#代码某处加上LuaCallCSharp就可以在lua端调用代码。
[CSharpCallLua] public static List<Type> csharpCallLuaList = new List<Type>
{
typeof(System.Func<LuaTable>),
typeof(System.Action),
typeof(System.Action<object>),
typeof(System.Action<object, object>),
typeof(System.Action<string>),
typeof(System.Action<LuaTable>),
typeof(System.Action<LuaTable, GameObject>),
typeof(System.Action<LuaTable, Transform>),
typeof(System.Action<LuaTable, GameObject, object>),
typeof(System.Action<LuaTable, GameObject, bool>),
typeof(System.Action<LuaTable, GameObject, GameObject>),
typeof(System.Action<string, object>),
typeof(System.Action<int, byte[], int, string>),
typeof(System.Action<LuaTable, float>),
typeof(System.Action<LuaTable, float, string>),
typeof(System.Action<LuaTable, int, string>),
typeof(System.Action<LuaTable, string>),
typeof(System.Func<LuaTable, int, string, string>),
typeof(System.Func<LuaTable, string, bool>),
typeof(System.Func<LuaTable, string, string>),
typeof(Common.Util.ActionInt<LuaTable, int, string>),
typeof(Common.Util.ActionInt<LuaTable, int, string, string, string>),
typeof(Common.Util.ActionInt<LuaTable, int, string, string, string,int>),
typeof(Common.Util.ActionInt<LuaTable, int, byte[], int, string>),
typeof(Common.Util.ActionInt<LuaTable, int, LuaTable>),
typeof(Common.Util.ActionInt<LuaTable, int>),
typeof(Common.Util.ActionInt<LuaTable, System.Object>),
typeof(Common.Util.ActionInt<LuaTable>),
typeof(Common.Util.ActionInt<LuaTable, string>),
typeof(Common.Util.ActionStr<LuaTable>),
。。。
};
[LuaCallCSharp] public static List<Type> luaCallCsharpList = new List<Type>
{
//---Spine
typeof(Spine.Unity.SkeletonAnimation),
typeof(Spine.Unity.SkeletonRenderer),
typeof(Spine.Unity.SkeletonGraphic),
。。。
};
Lua Call C#代码的时候,C#处生成的代码基本都需要打标签[LuaCallCSharp]。
同理,C# call Lua代码的时候,都需要打标签[CSharpCallLua]。
在哪里进行C#代码和lua代码之间的转换的?
我们可以追踪哪里调用了这几个标签。在Generator.GenLuaRegister中可以看到对LuaCallCSharp的循环操作,这个方法会把这个类的静态方法(BeginClassRegister)、成员方法(BeginObjectRegister)注册到lua表里。
另外还有其他途径进行Xlua的生成,即从GenXlua生成XLua文件开始对这些方法、对象进行lua的装载和转换。
在这里看到了GenWrap这个函数,我们可以在里面看到XLua系统做了下面的几个操作:
不管是GenLuaRegister还是GenWrap,里面都调用了核心方法GenOne,所有lua生成器都是在这边启动的。
通过LuaTemplate.Compile把模板文件.tpl.txt文件转成可执行的lua代码并加载进内存。
type_info_getter(type, type_info);设置lua代码要用到的参数。
LuaTemplate.Execute(template, type_info):执行lua代码进行文件生成。
生成流程就是:
1.Generator收集这种类型需要导出的对象。
2.通过LuaTemplate把对应的.tpl.txt文件转成可执行的lua代码。
3.在GenOne方法里给上一步生成的lua代码赋值全局变量。
4.执行lua代码生成wrap文件。
每个wrap文件都是对一个c#类的包装,在lua中,通过对wrap类中的函数调用,间接的对c#实例进行操作。
比如当我们在lua端调用以下代码时,实际上程序做了哪些事情?
local go = CS.UnityEngine.GameObject() local trans = go.transform
实际上我们可以追踪到LuaClassWrap.tpl.txt(LuaClassWrap:负责所有类的wrap的生成)中看到其实现(这中间的部分操作涉及到c++层)。
同理,下面的
Utils.BeginClassRegister(type, L, __CreateInstance, <%=cls_field_count%>, <%=cls_getter_count%>, <%=cls_setter_count%>);
即代表给这个类的静态值创建元表。
于是在lua层就有了c#的这些静态值和非静态值,也就可以调用相关函数了。
那么我们又如何让lua端代码走c#的生命周期呢?答案就是在lua端通过调用AddComponent(typeof(LuaBehaviour))来绑定LuaBehaviour.cs并且在C#端走lua的Awake\Start\Update。
注意:因为xlua的整个wrap流程测试下来其实挺耗费时间的,再加上项目启动的时候要一下子加载很多个c#类到lua端,所以大胆推测点击开始按钮时候的卡顿现象有极大概率和LuaCallCSharp这方面有关。
(如果不走xlua定义的标签方式,那就需要走反射机制,虽然反射万能,可以为任意C#结构体构建出lua元表,但是是性能最差的方式)文章来源:https://www.toymoban.com/news/detail-772409.html
挖坑
之后会找个时间详细探讨lua和C#的交互代码优化。文章来源地址https://www.toymoban.com/news/detail-772409.html
到了这里,关于Lua与C#交互初析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!