继续Slua 的第二个Demo, 这个Demo 演示的主要是将 c# 函数注入到 lua 中并在 lua 中调用,不对的地方还望大佬们指正
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction)) ]static public int instanceCustom (IntPtr l ) { Custom self = (Custom)LuaObject.checkSelf(l); LuaObject.pushValue(l, true ); LuaDLL.lua_pushstring(l, "xiaoming" ); LuaDLL.lua_pushstring(l, "hanmeimei" ); LuaDLL.lua_pushinteger(l, self.v); return 4 ; } [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction)) ] [StaticExport ]static public int staticCustom (IntPtr l ) { LuaObject.pushValue(l, true ); LuaDLL.lua_pushstring(l, vs); LuaObject.pushObject(l, c); return 3 ; }public int this [string key] { get { if (key == "test" ) return v; return 0 ; } set { if (key == "test" ) { v = value ; } } }public string getTypeName (Type t ) { return t.Name; }
Demo 中展示了四个不一样的函数,前面两个就是标准的注册函数了,注释也给了解释,无需再生成注册用的函数代码,后面两个则没做处理,OK,我们一步一步来:
首先我们在 LuaGenCode.cs 中找到
[MenuItem("SLua/Custom/Make" ) ]static public void Custom ( )assembly = Assembly.Load("Assembly-CSharp" ); types = assembly.GetExportedTypes();foreach (Type t in types) { if (t.IsDefined(typeof (CustomLuaClassAttribute), false ) || namespaces.Contains(t.Namespace)) { fun(t, null ); } } CustomExport.OnAddCustomClass(fun);
这里一大堆判断逻辑我们先不去深究,根据注释提示我们可以看到它是遍历了所有带CustomLuaClassAttribute 修饰的类,然后按照模板去为这个类生成新的 cs 代码, 我们直接看新生成的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 public class Lua_Custom : LuaObject { [SLua.MonoPInvokeCallbackAttribute(typeof(LuaCSFunction)) ] [UnityEngine.Scripting.Preserve ] static public int getTypeName (IntPtr l ) { try { Custom self=(Custom)checkSelf(l); System.Type a1; checkType(l,2 ,out a1); var ret=self.getTypeName(a1); pushValue(l,true ); pushValue(l,ret); return 2 ; } catch (Exception e) { return error(l,e); } } [SLua.MonoPInvokeCallbackAttribute(typeof(LuaCSFunction)) ] [UnityEngine.Scripting.Preserve ] static public int getInterface (IntPtr l ) { try { Custom self=(Custom)checkSelf(l); var ret=self.getInterface(); pushValue(l,true ); pushInterface(l,ret, typeof (Custom.IFoo)); return 2 ; } catch (Exception e) { return error(l,e); } } [SLua.MonoPInvokeCallbackAttribute(typeof(LuaCSFunction)) ] [UnityEngine.Scripting.Preserve ] static public int getItem (IntPtr l ) { try { Custom self=(Custom)checkSelf(l); string v; checkType(l,2 ,out v); var ret = self[v]; pushValue(l,true ); pushValue(l,ret); return 2 ; } catch (Exception e) { return error(l,e); } } [SLua.MonoPInvokeCallbackAttribute(typeof(LuaCSFunction)) ] [UnityEngine.Scripting.Preserve ] static public int setItem (IntPtr l ) { try { Custom self=(Custom)checkSelf(l); string v; checkType(l,2 ,out v); int c; checkType(l,3 ,out c); self[v]=c; pushValue(l,true ); return 1 ; } catch (Exception e) { return error(l,e); } } [UnityEngine.Scripting.Preserve ] static public void reg (IntPtr l ) { getTypeTable(l,"Custom" ); addMember(l,getTypeName); addMember(l,getInterface); addMember(l,getItem); addMember(l,setItem); addMember(l,Custom.instanceCustom,true ); addMember(l,Custom.staticCustom,false ); createTypeMetatable(l,null , typeof (Custom),typeof (UnityEngine.MonoBehaviour)); } } ----------public static void getTypeTable (IntPtr l, string t ) { newTypeTable(l, t); LuaDLL.lua_newtable(l); LuaDLL.lua_newtable(l); }
正如前面的注释,有MonoPInvokeCallbackAttribute 修饰符的两个函数没有再生成代码,而是直接调用addMember 注册了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 protected static void addMember (IntPtr l, LuaCSFunction func, bool instance ) { checkMethodValid(func); pushValue(l, func); string name = func.Method.Name; LuaDLL.lua_setfield(l, instance ? -2 : -3 , name); }public static void pushValue (IntPtr l, LuaCSFunction f ) { LuaState.pushcsfunction (l, f); } ---------- LuaDLL.luaL_openlibs(L); string PCallCSFunction = @" local assert = assert local function check(ok,...) assert(ok, ...) return ... end return function(cs_func) return function(...) return check(cs_func(...)) end end " ; LuaDLL.lua_dostring(L, PCallCSFunction); PCallCSFunctionRef = LuaDLL.luaL_ref(L, LuaIndexes.LUA_REGISTRYINDEX); ----------static public void pushcsfunction (IntPtr L, LuaCSFunction function ) { LuaDLL.lua_getref(L, get (L).PCallCSFunctionRef); LuaDLL.lua_pushcclosure(L, function, 0 ); LuaDLL.lua_call(L, 1 , 1 ); }
其中lua_getref 和 lua_pushcclosure在Lua 5.1 中的源码定义如下(顺便分析下源码):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, (ref)) LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { StkId o; lua_lock(L); o = index2adr(L, idx); api_check(L, ttistable(o)); setobj2s(L, L->top, luaH_getnum(hvalue(o), n)); api_incr_top(L); lua_unlock(L); }LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { Closure *cl; lua_lock(L); luaC_checkGC(L); api_checknelems(L, n); cl = luaF_newCclosure(L, n, getcurrenv(L)); cl->c.f = fn; L->top -= n; while (n--) setobj2n(L, &cl->c.upvalue[n], L->top+n); setclvalue(L, L->top, cl); lua_assert(iswhite(obj2gco(cl))); api_incr_top(L); lua_unlock(L); }
闭包调用的具体分析可以参考这篇博客
此时,我们来分析下栈的结构:
-1 为 lua_call(L, 1, 1) 后压入的函数返回值
-2 为 for instance 函数的 table
-3 为 for static 函数的 table
昨天的 _s 函数的处理就是同理了
本文来自:https://blog.csdn.net/NotMz/article/details/79666208