[Lua]与c#的交互(二)

参考链接:

https://www.cnblogs.com/lijiajia/p/8284328.html

https://www.jianshu.com/p/7cc9ca7efe18

http://www.360doc.com/content/16/0830/21/7014874_587111940.shtml#

零.原理

lua与其他语言的交互,都是基于栈的结构来交互的。栈的元素为lua中的值(table,string,nil等8种基本类型)

如果用正数索引来表示,则栈底为1,索引往上递增;如果用负数索引来表示,则栈顶为-1,索引往下递减

lua与其他语言的交互过程如下:

一.c#调用lua

 1 using LuaInterface;
 2 using System;
 3 
 4 namespace TestLua
 5 {
 6     class Program
 7     {
 8         static IntPtr L;
 9 
10         static void Main(string[] args)
11         {
12             int sum;
13             L = LuaDLL.luaL_newstate();//创建lua状态机
14             LuaDLL.luaL_openlibs(L);//打开Lua状态机中所有Lua标准库
15             LuaDLL.luaL_dofile(L, "add.lua");//加载lua脚本
16             sum = LuaAdd(8, 9);
17             Console.WriteLine(sum);
18             LuaDLL.lua_close(L);//关闭lua状态机
19             Console.ReadKey();
20         }
21 
22         static int LuaAdd(int x, int y)
23         {
24             int sum = -1;
25             LuaDLL.lua_getglobal(L, "AddFunc");//函数名
26             LuaDLL.lua_pushnumber(L, x);//参数入栈
27             LuaDLL.lua_pushnumber(L, y);//参数入栈
28             LuaDLL.lua_call(L, 2, 1);//开始调用函数,有2个参数,1个返回值
29             sum = (int)LuaDLL.lua_tonumber(L, -1);//取出返回值
30             LuaDLL.lua_pop(L, 1);
31             return sum;
32         }
33     }
34 }

add.lua

1 function AddFunc(x,y)
2     return x + y
3 end

输出:

分析:

lua_getglobal(L, "AddFunc"),将lua中的全局变量AddFunc进栈

lua_pushnumber(L, x),将参数x进栈,当2个参数都进栈后,栈是这样的(从栈底到栈顶):AddFunc->8->9

lua_call(L, 2, 1),调用后,栈的元素都出栈,然后返回值进栈,栈是这样的(从栈底到栈顶):17

lua_tonumber(L, -1),将栈顶元素转换为number用于赋值

lua_pop(L, 1),栈顶元素出栈,此时栈为空

二.lua调用c#

 1 using LuaInterface;
 2 using System;
 3 
 4 namespace TestLua
 5 {
 6     class Program
 7     {
 8         static void Main(string[] args)
 9         {
10             IntPtr L = LuaDLL.luaL_newstate();//创建lua状态机
11             LuaDLL.luaL_openlibs(L);//打开Lua状态机中所有Lua标准库
12             LuaDLL.lua_pushstdcallcfunction(L, SayHello);
13             LuaDLL.lua_setglobal(L, "AAA");
14             LuaDLL.luaL_dostring(L, "print(AAA("123"))");
15             LuaDLL.lua_close(L);//关闭lua状态机
16             Console.ReadKey();
17         }
18 
19         static int SayHello(IntPtr L)
20         {
21             string s = LuaDLL.lua_tostring(L, 1);
22             LuaDLL.lua_pushstring(L, "Hello " + s);
23             return 1;
24         }
25     }
26 }

输出:

分析:

lua_pushstdcallcfunction(L, SayHello),将c#的方法SayHello进栈

lua_setglobal(L, "AAA"),将栈顶元素设置成lua中的全局变量AAA,此时栈顶是function类型,即AAA=function () end

luaL_dostring(L, "print(AAA("123"))"),在lua中将参数123进栈

lua_tostring(L, 1),在c#中将栈顶元素123转换为string用于操作,栈是这样的(从栈底到栈顶):123

lua_pushstring(L, "Hello " + s),在c#中将返回值进栈,供lua使用,栈是这样的(从栈底到栈顶):123->Hello 123

注意:

1.lua调用c#,涉及到将c#方法的注册到lua中,对应上面的语句lua_pushstdcallcfunction和lua_setglobal,其中lua_pushstdcallcfunction的原型为:

public static void lua_pushstdcallcfunction(IntPtr luaState, LuaCSFunction function);

而LuaCSFunction的原型为:

public delegate int LuaCSFunction(IntPtr luaState);

即要注册的方法返回值必须为int(表示返回值的个数),参数必须为IntPtr(指针,指向lua状态机)

2.每个注册的方法(如上面的SayHello)都有1个私有栈,并且第1个参数就在栈的1位置,第2个参数就在栈的2位置,以此类推

所以上面的LuaDLL.lua_tostring(L, 1)拿到的是第1个参数

3.如果注册的方法有返回值,则按照返回顺序依次入栈,最后一个返回值在栈的-1位置

三.unity相关

1.wrap文件

经过上面lua调用c#的介绍,再来看生成的wrap文件,会发现很熟悉(下面以UnityEngine_GameObjectWrap为例):

原文地址:https://www.cnblogs.com/lyh916/p/12234220.html