Lua与C#交互初析

这篇具有很好参考价值的文章主要介绍了Lua与C#交互初析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

背景

项目是全Lua开发,导致的其中一个结果是会遇到lua的gc性能问题。而且相对于C#这种强类型语言,Lua因为其自由性,对于团队后期维护还是有一定的成本,不做好代码复审,相对不好维护。这个时候就需要我们自主了解Lua和C#交互的底层逻辑和实现原理,用以之后在lua测开发的时候做出良好的代码优化。

项目采用xlua结构与c#端进行交互,在个别地方和其他类型的lua(比如和tolua的加载机制)不一样,但lua底层都是一致的。在此次分享中会有一些知识专属于xlua范围。

Lua和C#交互逻辑

Lua文件加载

xLua定义了两种在C#中调用lua代码的方式:

  1. DoString("xxxxxxxxxxxx").这个函数一般不建议使用,LuaEnv中就有此段代码:

Lua与C#交互初析,lua,c#,交互,unity,游戏,游戏引擎

Lua与C#交互初析,lua,c#,交互,unity,游戏,游戏引擎

这段代码内部主要定义了在Lua中访问c#对象时进行的具体操作。这里具体干了什么事情,还需要留待未来探讨。

  1. 自定义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表里。

Lua与C#交互初析,lua,c#,交互,unity,游戏,游戏引擎

Lua与C#交互初析,lua,c#,交互,unity,游戏,游戏引擎

另外还有其他途径进行Xlua的生成,即从GenXlua生成XLua文件开始对这些方法、对象进行lua的装载和转换。

Lua与C#交互初析,lua,c#,交互,unity,游戏,游戏引擎

Lua与C#交互初析,lua,c#,交互,unity,游戏,游戏引擎

Lua与C#交互初析,lua,c#,交互,unity,游戏,游戏引擎

Lua与C#交互初析,lua,c#,交互,unity,游戏,游戏引擎

在这里看到了GenWrap这个函数,我们可以在里面看到XLua系统做了下面的几个操作:

Lua与C#交互初析,lua,c#,交互,unity,游戏,游戏引擎

不管是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++层)。

Lua与C#交互初析,lua,c#,交互,unity,游戏,游戏引擎

同理,下面的

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。

Lua与C#交互初析,lua,c#,交互,unity,游戏,游戏引擎

注意:因为xlua的整个wrap流程测试下来其实挺耗费时间的,再加上项目启动的时候要一下子加载很多个c#类到lua端,所以大胆推测点击开始按钮时候的卡顿现象有极大概率和LuaCallCSharp这方面有关。

(如果不走xlua定义的标签方式,那就需要走反射机制,虽然反射万能,可以为任意C#结构体构建出lua元表,但是是性能最差的方式)

挖坑

之后会找个时间详细探讨lua和C#的交互代码优化。文章来源地址https://www.toymoban.com/news/detail-772409.html

到了这里,关于Lua与C#交互初析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity中如何使用Rider调试C#和lua代码

    工作中经常需要调试lua代码,之前使用VS调试C#代码,使用Intellij Idea来调试lua代码,这样其实比较麻烦,所以查了一下,可以直接使用Rider来统一的调试C#和lua代码 Rider下载:Rider官网下载,根据需要选择对应的版本,建议使用Rider2020.1.0,参考链接 打开Unity,在preference中设置为

    2023年04月13日
    浏览(48)
  • Unity3D 如何把全部游戏逻辑都放到lua层实现详解

    Unity3D是一款非常流行的游戏开发引擎,它支持C#、JavaScript和Boo等脚本语言。然而,有时候我们可能希望将全部游戏逻辑都放到Lua层实现,这样可以更方便地进行游戏逻辑的修改和调试。本文将详细介绍如何使用Unity3D将全部游戏逻辑都放到Lua层实现。 对啦!这里有个游戏开发

    2024年01月16日
    浏览(55)
  • # Lua与C++交互(二)———— 交互

    基础调用 再来温习一下 myName = “beauty girl” C++想要获取myName的值,根据规则,它需要把myName压入栈中,这样lua就能看到; lua从堆栈中获取myName的值,此时栈顶为空; lua拿着myName去全局表中查找与之对应的字符串; 全局表找到,并返回\\\"beauty girl\\\"; lua把\\\"beauty girl\\\"压入栈中;

    2024年02月11日
    浏览(37)
  • Lua与C++交互

    1、lua和c++交互机制是基于一个虚拟栈,C++和lua之间的所有数据交互都通过这个虚拟栈来完成,无论何时C++想从lua中调用一个值,被请求的值将会被压入栈,C++想要传递一个值给Lua,首选将整个值压栈,然后就可以在Lua中调用。 2、lua中提供正向和反向索引,区别在于证书永远

    2024年02月08日
    浏览(39)
  • Lua与C++交互(一)————堆栈

    什么是Lua虚拟机 Lua本身是用C语言实现的,它是跨平台语言,得益于它本身的Lua虚拟机。 虚拟机相对于物理机,借助于操作系统对物理机器(CPU等硬件)的一种模拟、抽象,主要扮演CPU和内存的作用。 虚拟机的主要职责就是:执行字节码中的指令,管理全局状态(global_stat

    2024年02月11日
    浏览(42)
  • Lua与Java的交互方案

    Lua 和 Java 之间的交互可以通过多种方式实现,每种方式都有其优点和适用场景。以下是几种常见的方案: 1. JNI(Java Native Interface) JNI 是 Java 提供的一种标准编程接口,它允许 Java 代码与本地应用程序或库(例如 C/C++ 编写的程序)进行交互。通过 JNI,你可以编写本地方法来

    2024年04月23日
    浏览(39)
  • Linux下Lua和C++交互

    lua(wiki 中文 官方社区:lua-users)是一门开源、简明、可扩展且高效的弱类型解释型脚本语言。 由于其实现遵循C标准,它几乎能在所有的平台(windows、linux、MacOS、Android、iOS、PlayStation、XBox、wii等)上运行。 在Lua中,函数是对语句和表达式进行抽象的主要方法。既可以用来

    2024年02月16日
    浏览(35)
  • Lua:面向对象/C之间的交互

    前段时间对平台的任务感兴趣,其要求是一周内12篇博文,尝试了之后发现还是太敷衍了,之后还是回归到内容本身上来,尽量保证一篇博文的内容能涵盖足够多的知识点或者足够深的思考成分。 面向对象主要有三个方面:封装、继承和多态。Lua若做到了这三点,则认为是也

    2024年02月20日
    浏览(33)
  • Lua语言实现游戏动作

    Lua是一种轻量级的脚本语言,它具有高效性、可扩展性和易学性等优点。在游戏开发领域,Lua语言得到了广泛应用。Lua语言可以用来实现游戏动作,包括角色行走、攻击、技能释放等。本文将详细介绍如何使用Lua语言实现游戏动作。 一、Lua语言介绍 Lua语言是一种轻量级的脚

    2023年04月14日
    浏览(42)
  • lua的用户数据的使用与c语言交互

    在 Lua 中,用户数据(userdata)是一种特殊的数据类型,它可以用来表示外部的 C 或 C++ 对象,并将它们传递给 Lua 程序使用。用户数据是 Lua 与其他语言或系统进行交互的主要方式之一,它可以让 Lua 程序与其他语言或系统进行无缝的集成。 用户数据的使用一般分为以下几个步

    2024年02月09日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包