7-30 1,194 views
要擅于去看lua文档,源码, 部分翻译来自云风, ps C#也开源了 :)
正数表示相对于栈底的位置,栈底是1 ,负数表示相对于栈顶的位置,栈顶是-1;
入栈
lua_getfield (lua_State *L, int index, const char *k);
将t[k] 的值压栈, 这里的 t 是栈索引
index 处的值, 可能触发__index
lua_getglobal (lua_State *L, const char *name)
#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, s)
把全局变量 name 里的值压栈
lua_getmetatable (lua_State *L, int index);
如果索引index处的值有元表,则将其元表压栈,返回 1 。 否则不会将任何东西入栈,返回 0
lua_gettable (lua_State *L, int index)
将t[k]值压栈, t是栈index处值, k是栈顶值,.这个函数会弹出栈顶的key值(把结果放在栈上相同位置)可能触发__index
lua_rawget (lua_State *L, int index)
同上,不会触发__index
lua_rawgeti (lua_State *L, int index, lua_Integer n)
把 t[n] 的值压栈, 这里的 t 是指给定索引 index 处的一个值, 不出发__index
lua_gettop (lua_State *L)
返回栈中元素的个数,同时也是栈顶元素的索引,0表示栈为空
lua_insert (lua_State *L, int index);
栈顶元素移动到指定的有效索引index处, 依次移动这个索引之上的元素
lua_newtable (lua_State *L)
创建空表压栈等价于 lua_createtable(L, 0, 0)
lua_pushnumber (lua_State *L, lua_Number n)
lua_pushstring (lua_State *L, const char *s)
浮点数n压栈
s指向的字符串压栈, 返回内部副本的指针, s为Null则将nil压栈返回Null
lua_pushvalue (lua_State *L, int index)
复制index位置的元素压入栈顶
lua_tostring (lua_State *L, int index)
把索引index处(字符串或数字)转换为C字符串, 否则返回NUll
出栈
lua_setfield (lua_State *L, int index, const char *k);
做 t[k] = v 的操作, t 是栈索引 index 处的值, 而 v 是栈顶的值,这个函数将把这个值弹出堆栈,可能触发__newindex
lua_setglobal (lua_State *L, const char *name)
从栈上弹出一个值作为全局变量name的新值
lua_setmetatable (lua_State *L, int index)
将表弹出栈设置为索引index处值的原表
lua_settable (lua_State *L, int index)
做t[k] = v 的操作, t是索引index处的值,v是栈顶的值, k是栈顶之下的值, 这个函数会将键值都从栈弹出, 可能会出发__newindex
lua_rawset (lua_State *L, int index)
同上, 不触发__newindex
lua_rawseti (lua_State *L, int index, lua_Integer i)
等价于 t[i] = v, 这里的 t 是指给定索引 index 处的一个值, 而 v 是栈顶的值。函数将把这个值弹出栈, 不会触发__newindex
lua_settop (lua_State *L, int index)
把栈顶设为这个索引index,如果新栈顶比原来大,超出部分填nil, index= 0时,清空栈
lua_pop (lua_State *L, int n)
从栈中弹出 n 个元素
lua_remove (lua_State *L, int index)
移除栈索引index处的值, 将此索引之上的向下移动填充
lua_call (lua_State *L, int nargs, int nresults)
nargs为参数个数, 先压入函数,再按顺序压入参数,调用时(会从栈弹出所有参数和函数),再按顺序压入返回值(最后的结果在栈顶)nresults 被设置成 LUA_MULTRET十所有返回值都被压栈
lua:
a = f("how", t.x, 14)
C:
lua_getglobal(L, "f");
lua_pushliteral(L, "how"); /* 1st argument */
lua_getglobal(L, "t");
lua_getfield(L, -1, "x"); /* push result of t.x (2nd arg) */
lua_remove(L, -2); /* remove 't' from the stack */
lua_pushinteger(L, 14); /* 3rd argument */
lua_call(L, 3, 1); /* call 'f' with 3 arguments and 1 result,push result to the stack*/
lua_setglobal(L, "a"); /* set global 'a' */
int lua_pcall (lua_State *L, int nargs, int nresults, int msgh)
如果有错误发生(返回值非0), lua_pcall 会捕获它, 然后把唯一的值(错误消息)压栈,然后返回错误码。 如果 msgh 是 0 ,返回在栈顶的错误消息就和原始错误消息完全一致。 否则, msgh 就被当成是 错误处理函数在栈上的索引位置.在发生运行时错误时, 这个函数会被调用而参数就是错误消息。错误处理函数的返回值将被 lua_pcall 作为错误消息返回在堆栈上。
Tolua为例, lua中调用gameobject.transform.position = pos流程简析
//从lua到C#基本流程:lua userdata->lua metatable->C# warp->lua id->C# translator->C#对象
//注册
L.BeginClass();//UnityEngine_GameObjectWrap
L.RegVar("transform", get_transform, null);//这些方法会被注册到对应metatable中
LuaDLL.tolua_variable(L, name, fget, fset);
//C tolua_variable RegVar调用,注册对应C方法到lua
LUALIB_API void tolua_variable(lua_State *L, const char *name, lua_CFunction get, lua_CFunction set)
{
...
lua_pushstring(L, name);
tolua_pushcfunction(L, get); //做metatable["transform"] = get操作
lua_rawset(L, -3);
...ga
}
//调用
gameobject.transform //访问userdata的metatable, 找到对应c方法
UnityEngine_GameObjectWrap .get_transform // 通过MonoPInvokeCallbackAttribute标签, 使C回调回C#
int udata = LuaDLL.tolua_rawnetobj(L, stackPos);
//C tolua_rawnetobj 把lua中的userdata变成c#可以辨认的id
LUALIB_API int tolua_rawnetobj(lua_State *L, int index)
{
int* udata = (int*)lua_touserdata(L, index);//如果index处值为int直接作为id返回
if (udata != NULL)
{
return *udata;
}
else if (lua_istable(L, index))
{
lua_pushvalue(L, index);
lua_pushlightuserdata(L, &vptr);//如果是个table, 找到userdata
lua_rawget(L, -2);
if (lua_isuserdata(L, -1))//把栈顶userdate替换到table位置
{
lua_replace(L, index);
udata = (int*)lua_touserdata(L, index);//转换userdata为id返回
if (udata != NULL)
{
return *udata;
}
}
else
{
lua_pop(L, 1);
}
}
return -1;
}
ObjectTranslator.TryGetValue(id) //用这个id,从ObjectTranslator中获取C#的gameobject对象
gameobject.transform //真正C#拿到transform
ObjectTranslator.AddObject //如果之前未保存过,给transform分配一个id,id这个id会在lua中用来代表这个transform,transform要保存到ObjectTranslator供未来查找
LuaDLL.tolua_pushnewudata(L, reference, index);
//C tolua_pushnewudata
LUALIB_API void tolua_pushnewudata(lua_State *L, int metaRef, int index)
{
lua_getref(L, LUA_RIDX_UBOX);//ubox表压栈, 值弱引用,存放userdata, 下次如果同样userdata直接从这里拿
tolua_newudata(L, index);//在lua分配一个userdata,把id存进去
lua_getref(L, metaRef);//拿到类型的metatable压栈
lua_setmetatable(L, -2);//userdata附上metatable,让你可以transform.position这样使用它
lua_pushvalue(L, -1);//栈顶放上transfrom返回
lua_rawseti(L, -3, index);//将userdata以index为id, 保存到ubox中
lua_remove(L, -2);
}
//赋值
UnityEngine_TransformWrap.set_position
LuaDLL.tolua_rawnetobj(L, stackPos)
ObjectTranslator.TryGetValue(id)
LuaDLL.tolua_getvec3 //得到pos
transform.position = new Vector3(x,y,z) //真正赋值
版权属于: CrazyStone Entertainment
原文地址: https://www.crazystonent.com/2020/07/30/lua%e5%a0%86%e6%a0%88%e6%93%8d%e4%bd%9c/
转载时必须以链接形式注明原始出处及本声明。