2012-11-28 45 views
0

我已经编写了一些代码来将注册自定义函数和__newindex__index函数分成2个独立的函数。我的代码的目标是让函数和变量对基于特殊子级的Lua脚本编写器可见。例如,用户将提供以下命令:Lua C API代码不调用__newindex函数,但调用其他函数

orc.chief.attack(); 
orc.chief.flee(); 
orc.chief.hp = 100; 
orc.pawn.attack(); 
elf.wood.attack(); 
elf.wood.hp = 200; 

因此,基本上使系统与2层,然后函数调用或一个变量。如果我正确理解Lua,那是表格中的表格中的元数据。当用户设置变量时,它应该跳过__newindex调用(不仅要处理设置值,而且要访问将通过电机动画的物理对象)。我还假设表orc中的主表只是看到很多分配给它的功能,不管它是attack还是__newindex。为了使代码更易于添加新的变量和函数,我创建了2个函数:一个给创建一个函数一个给创建一个变量。函数create只是注册函数,变量create只是创建一个新的表元素并注册了__newindex__index的函数。下面是代码:

int orcChiefhp; 

luaL_Reg Orc_Module[] = { 
    {"attack", OrcAttack}, 
    {"flee", OrcFlee}, 
    {NULL, NULL}}; 

const luaL_Reg orcChief_metareg[] = { 
    {"__index", orcChief__index}, 
    {"__newindex", orcChief__newindex}, 
    {NULL, NULL}}; 

int OrcAttack(lua_State *L) 
{ 
    //code to cause the motors to swing the weapon... 
    return 0;//0 parameters come back as the data 
} 

int orcChief__newindex(lua_State *L) 
{ 
const char *idx; 
    if(lua_isstring(L,2)) 
    { 
     idx = lua_tostring(L,2);//gets the string so we can get the variable of the struct 
     if(strcmp(idx, "hp")==0) 
     { 
      lua_pushnumber(L, orcChiefhp); 
     } 
     else 
      lua_pushnil(L); 
    } 
    return 1; 
} 

void registerFunctions(lua_State *L, const char *libname, const char *sublibname, const luaL_Reg *funcs) 
{ 
int isitnil; 

    lua_getglobal(L, libname); 
    isitnil = lua_isnil(L, -1); 
    if(isitnil) 
    { 
     lua_pop(L, 1); 
     lua_newtable(L); // create 'libname' table 
    } 
    // no sublib: just import our library functions directly into lib and we're done 
    if (sublibname == NULL) 
    { 
     luaL_setfuncs(L, funcs, 0); 
    } 
    // sublib: create a table for it, import functions to it, add to parent lib 
    else 
    { 
     lua_newtable(L); 
     luaL_setfuncs(L, funcs, 0); 
     lua_setfield(L, -2, sublibname); 
    } 
    if(isitnil) 
     lua_setglobal(L, libname);//this will pop off the global table. 
    else 
     lua_pop(L, 1);//the global table is still on the stack, pop it off 
} 

void registerIntegerVariable(lua_State *L, const char *libname, const char *sublibname, const char *variableName, 
    const char *metatableName, const luaL_Reg *metatableFuncs, int defaultValue) 
{ 
int isLibnameNil; 
int isSubnameNil; 
    lua_getglobal(L, libname);//get the libname 
    isLibnameNil = lua_isnil(L, -1);//check to see if it exists 
    if(isLibnameNil)//if it doesn't exist, create a new one 
    { 
     lua_pop(L, 1);//pop off the nil 
     lua_newtable(L); // create 'libname' table 
    } 

    // no sublib: just import our library functions directly into lib and we're done 
    if (sublibname == NULL)//if we want the functions at the lib level then just set the functions 
    { 
     lua_pushstring(L, variableName);//push the variable name 
     lua_pushnumber(L, defaultValue);//push the default value on the stack 
     lua_rawset(L, -3);//add the variable to the table (rawset is like settable but doesn't call __index) 
     luaL_newmetatable(L, metatableName);//create the metatable 
     luaL_setfuncs(L, metatableFuncs, 0);//set the metatable functions for __newindex and __index 
     lua_setmetatable(L, -2);//set the metatable to the libtable 
    } 
    // otherwise we need to create a table for the sublibname, import functions to it, add to parent lib. 
    else 
    { 
     lua_getfield(L, -1, sublibname);//see if the sublibname is under the global libname 
     isSubnameNil = lua_isnil(L, -1);//is it a nil 
     if(isSubnameNil)//if it is, then we need to create the sublibname 
     { 
      lua_pop(L, 1);//pop off the nil 
      lua_newtable(L);//creates the new sublibname table 
     } 
     lua_pushstring(L, variableName);//push the variable name 
     lua_pushnumber(L, defaultValue);//push the default value on the stack 
     lua_rawset(L, -3);//add the variable to the table and push it (rawset is like settable but doesn't call __index) 
     luaL_newmetatable(L, metatableName);//create the metatable 
     luaL_setfuncs(L, metatableFuncs, 0);//add the metamethods 
     lua_setmetatable(L, -2);//set the metatable to the sublibname 
     if(isSubnameNil) 
      lua_setfield(L, -2, sublibname);//now we need to add the sublibname to the libname 
    } 

    if(isLibnameNil) 
     lua_setglobal(L, libname);//set the global name if it was new 
    else 
     lua_pop(L, 1); 
} 

然后,在我的main()我调用的函数是这样的:

execContext = luaL_newstate(); 
//adding lua basic library 
luaL_openlibs(execContext); 

//now register all the functions with Lua 
registerFunctions(execContext, "orc", "chief", Orc_Module); 
registerFunctions(execContext, "orc", "pawn", Orc_Module); 
registerFunctions(execContext, "elf", "wood", Elf_Module); 
//now register all the variables with Lua 
registerIntegerVariable(execContext, "orc", "chief", "hp", "chief_meta", orcChief_metareg, 0); 

当我运行在Lua脚本代码和泵,orc.chief.attack()叫我OrcAttack()功能,但orc.chief.hp = 100从未调用我的orcChief__newindex()函数。我甚至在registerFunctions的电话中留下了注释,以防他们以某种方式干扰,而registerIntegerVariable本身仍然不会触发orcChief__newindex().任何想法?

回答

2

__newindex在您设置表中的字段时未被调用。当您在表格中设置新的字段时会调用它。如果该字段已存在,则不会调用__newindex

如果您希望__newindex针对表上的每个设置操作进行调用,则不能允许设置操作实际修改该表。这通常通过创建一个名为代理表的用户使用的空表来完成。代理表实际上是空的,必须总是仍然如此;你拦截所有get和set调用,将它们传递给一个内部表,用户永远不会看到它没有访问权限。

或者您使用一些userdata而不是表。总是为他们调用__newindex

+0

这个虚拟表总是保持为空,这就是为什么__newindex会被调用? –

+0

我是Lua的新手,整个userdata事情让我感到困惑。我认为这将是完整的用户数据,因为我读了light userdata只有一个全局__newindex所有的权利?如果我使用完整的用户数据,我该如何保持它看起来像上面那样?我失去了阵列结构吗?我会创建一个用户数据,然后做一个userdata到一个表的setfield,以便我有一个userdatas表? –

+0

“*这个虚拟桌子总是保持空白*”是的。 –