在 tolua 和 xlua 中,调用 print 会直接在 Unity 控制台输出日志。而实际上 Lua 的源码中 print 只是输出日志,想要传递到 C# 需要额外做一些操作。
tolua的源码中,ToLua.cs文件里的构造函数和OpenLibs函数:
1 2 3 4 5 6 7 8 9 10 11 12
| L = LuaNewState(); ToLua.OpenLibs(L);
public static void OpenLibs(IntPtr L) { LuaDLL.tolua_pushcfunction(L, Print); LuaDLL.lua_setglobal(L, "print"); }
|
一开始构造函数中核心代码是两句,首先初始化lua状态机,然后打开lua标准库,将库中的函数放入全局变量。
lua标准库中是package、table、string、math等lua源码自带的函数,这些代码的加载在lua源码中的linit.c
文件里:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| static const luaL_Reg lualibs[] = { {"", luaopen_base}, {LUA_LOADLIBNAME, luaopen_package}, {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_DBLIBNAME, luaopen_debug}, {NULL, NULL} };
LUALIB_API void luaL_openlibs (lua_State *L) { const luaL_Reg *lib = lualibs; for (; lib->func; lib++) { lua_pushcfunction(L, lib->func); lua_pushstring(L, lib->name); lua_call(L, 1, 0); } }
|
LuaDLL.cs就是通过调用lua源码中的 luaL_openlibs
函数打开标准库。
接着 LuaDLL.tolua_pushcfunction
将 C# 的 Print 函数压入栈顶,lua源码中的lua_pushcfunction
是一个宏函数,不能直接通过dll调用,在LuaDll中是通过DLLImport导入这个函数然后封装实现调用的:
1 2 3 4 5 6
| [DllImport( LUADLL, CallingConvention = CallingConvention.Cdecl )] public static extern void lua_pushcclosure( IntPtr L, LuaCSFunction f, int n ); public static void lua_pushcfunction( IntPtr L, LuaCSFunction f ) { lua_pushcclosure( L, f, 0 ); }
|
LuaCSFuncton是一个参数为Intptr,返回值为int的委托。
tolua在 C# 层另外实现了一个 Print 方法,并且通过 lua_setglobal
把 lua 层的全局函数 print 替换掉:
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
| [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))] static int Print(IntPtr L) { try { int n = LuaDLL.lua_gettop(L);
using (CString.Block()) { CString sb = CString.Alloc(256); #if UNITY_EDITOR int line = LuaDLL.tolua_where(L, 1); string filename = LuaDLL.lua_tostring(L, -1); LuaDLL.lua_settop(L, n); int offset = filename[0] == '@' ? 1 : 0;
if (!filename.Contains(".")) { sb.Append('[').Append(filename, offset, filename.Length - offset).Append(".lua:").Append(line).Append("]:"); } else { sb.Append('[').Append(filename, offset, filename.Length - offset).Append(':').Append(line).Append("]:"); } #endif
for (int i = 1; i <= n; i++) { if (i > 1) sb.Append(" ");
if (LuaDLL.lua_isstring(L, i) == 1) { sb.Append(LuaDLL.lua_tostring(L, i)); } else if (LuaDLL.lua_isnil(L, i)) { sb.Append("nil"); } else if (LuaDLL.lua_isboolean(L, i)) { sb.Append(LuaDLL.lua_toboolean(L, i) ? "true" : "false"); } else { IntPtr p = LuaDLL.lua_topointer(L, i);
if (p == IntPtr.Zero) { sb.Append("nil"); } else { sb.Append(LuaDLL.luaL_typename(L, i)).Append(":0x").Append(p.ToString("X")); } } }
Debugger.Log(sb.ToString()); } return 0; } catch (Exception e) { return LuaDLL.toluaL_exception(L, e); } }
|