价格 | 面议 |
---|---|
区域 | 全国 |
来源 | 广州杰肯狸网络科技有限公司 |
详情描述:
META FORCE系统属于我们的社区,并且是完全的去中心化,这意味着它是透明的,安全的,技术唯【Congge420】并且能够抵抗外部影响。 三个步骤: 加载lua代码到vm中,对应api-luaL_loadbuffer luaL_loadbuffer会同时在栈上压入代码块的指针 执行lua代码,对应api-lua_pcall lua_pcall会从栈上依次弹出{nargs}个数据作为函数参数,再弹出函数进行执行,并将结果压入栈 如果lua代码有返回值,那么通过lua_toXXX相关api从栈上获取结果 完整的代码如下: private bool DoLuaCode(System.IntPtr L,string luaCode){ //加载lua代码 if(Lua.luaL_loadbuffer(L,luaCode,"")==0){ //执行栈顶的函数 if(Lua.lua_pcall(L,0,1,0)==0){ //函数执行完成后,返回值会依次依次押入栈 return true; }else{ Debug.LogError("pcall failed!"); return false; } }else{ Debug.LogError("load buffer failed"); return false; } } 假如我们有一段lua代码: return'hello,i am from lua' 这段lua仅仅返回一段字符串,那么利用DoLuaCode去执行就是: //lua代码 string luaCode="return'hello,i am from lua'"; if(DoLuaCode(L,luaCode)){ Debug.Log(Lua.lua_tostring(L,-1)); //lua_toXXX不会出栈,需要lua_pop才能出栈 Lua.lua_pop(L,1); } 由于此处lua代码返回的是字符串,因此使用lua_tostring(L,-1)来将栈顶的元素转为字符串并返回,相应的我们还能看到有lua_tonumber,lua_toboolean等等. 4.c#调用lua全局函数 接下来的例子将说明一下c#端如何执行lua中的全局函数。 假设现在我们有一段lua代码如下: function addSub(a,b) return a b,a-b; end 通过DoLuaCode来运行以上的lua代码,就得到了一个全局的addSub函数,这个函数会返回a,b相加和相减的结果。 为了在c#端执行以上的lua函数,需要按以下步骤进行: 将全局函数压入栈中,对应api-lua_getglobal 将函数所需的参数依次压入栈中,对应api-lua_pushnumber 执行栈中函数,对应api-lua_pcall 获取函数返回结果,对应api-lua_tonumber 完整c#代码如下: //从全局表里读取addSub函数,并压入栈 Lua.lua_getglobal(L,"addSub"); //压入参数a Lua.lua_pushnumber(L,101); //压入参数b Lua.lua_pushnumber(L,202); //2个参数,2个返回值 Lua.lua_pcall(L,2,2,0); //pcall会让参数和函数指针都出栈 //pcall执行完毕后,会将结果压入栈 Debug.Log(Lua.lua_tonumber(L,-2)); Debug.Log(Lua.lua_tonumber(L,-1)); Lua.lua_pop(L,2); 5.lua注册并调用c#静态函数 首先,想要被Lua调用的c#函数,都必须满足以下的格式: public delegate int LuaCSFunction(System.IntPtr luaState); 同时需要加上特性: MonoPInvokeCallback(typeof(LuaCSFunction)) 我们可以通过以下方式,将一个LuaCSFunction注册到lua中: static void RegisterCSFunctionGlobal(System.IntPtr L,string funcName,LuaCSFunction func){ //将LuaCSFunction压入栈中 Lua.lua_pushcfunction(L,func); //lua_setglobal会弹出栈顶元素,并按给定的名字作为key将其加入到全局表 Lua.lua_setglobal(L,funcName); } 那么,当我们在lua中执行c#注册的函数时,其交互过程如下: LuaVM会临时分配一个局部栈结构(这里要区分开始通过luaL_newstate创建的全局栈,两者是独立的) LuaVM会将lua侧的函数参数压入这个临时栈,然后将栈指针传给LuaCSFunction LuaCSFunction在实现上需要从这个栈中读取lua侧压入的参数,然后执行真正的相关逻辑,并将终结果压入栈中 LuaCSFunction需要返回一个int值,表示往栈中压入了多少个返回值 Lua从栈中获取C#侧压入的0/1/多个返回值 官方说明文档可以参考-Calling C from Lua 接下来要将演示如何将一个c#静态函数Print注入到lua中,实现lua中调用c#端的日志输出功能。 我们定义一个c#静态函数如下: [MonoPInvokeCallback(typeof(LuaCSFunction))] private static int Print(System.IntPtr localL){ //获取栈中元素个数 var count=Lua.lua_gettop(localL); System.Text.StringBuilder s=new System.Text.StringBuilder(); for(var i=1;i<=count;i ){ //依次读取print的每个参数,合并成一个string s.Append(Lua.lua_tostring(localL,i)); s.Append(''); } Debug.Log(s); //print函数没有返回值 return 0; } lua_gettop可以获取栈中的元素个数,此处代表了lua端压入栈中的函数参数个数 然后我们通过以下方式将这个c#侧的Print注册到lua中,命名为print。 //将LuaCSFunction压入栈中 Lua.lua_pushcfunction(L,Print); //lua_setglobal会弹出栈顶元素,并按给定的名字作为key将其加入到全局表 Lua.lua_setglobal(L,"print"); 接下来我们执行以下的lua代码: print('hello','csharp') 就能看到编辑器中输出 hello csharp 6.lua注册c#类型 通常我们使用lua中的table来模拟c#中的类。一般类的注册思路如下: 在lua中创建一个与c#类同名的表 将c#类的静态函数都注册到lua的这个同名表里 下面演示一下如何将Unity中的Debug类注册到lua中: Lua.lua_createtable(L,0,1); Lua.lua_setglobal(L,"Debug"); 其实很简单: lua_createtable会创建一个table,压入栈顶 lua_setglobal会弹出栈顶元素,并将其加到全局表里 这样我们在lua里就有了一个名为Debug的表可供全局访问。但目前这个表是空空如也的,我们还需要为其添加静态函数。(tips:实际上完整的设计中,还需要为class table设置metatable,增加一些限制性,但这里先不表) 6.1注入类的静态函数 首先我们定义一个符合LuaCSFunction形式的c#函数如下: [MonoPInvokeCallback(typeof(LuaCSFunction))] private static int Debug_Log(System.IntPtr L){ string msg=Lua.lua_tostring(L,1); Debug.Log(msg); return 0; } 这个c#函数是对Debug.Log的一个封装。 然后可以通过以下方式将这个c#函数注册到lua中的Debug表中: Lua.lua_createtable(L,0,1); //往栈中压入字符串'Log' Lua.lua_pushstring(L,"Log"); //往栈中压入函数Debug_Log Lua.lua_pushcfunction(L,Debug_Log); //从栈中弹出一个元素作为key,再弹出一个元素作为value,作为pair赋值到index指定的table Lua.lua_settable(L,1); Lua.lua_setglobal(L,"Debug");
联系人 | 罗聪 |
---|