简体   繁体   English

Lua C API代码不调用__newindex函数但调用其他函数

[英]Lua C API code not calling __newindex functions but calling other functions

I have written some code to separate registering custom functions and the __newindex and __index functions into 2 separate functions. 我编写了一些代码来将自定义函数和__newindex__index函数分别注册到2个单独的函数中。 The goal of my code is to have functions and variables visible to the Lua script writer that are organized based upon sublevels of specificity. 我的代码的目标是让Lua脚本编写器可以看到基于特异性子级组织的函数和变量。 For example, the user would have available the following commands: 例如,用户可以使用以下命令:

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

So basically a system with 2 tiers and then a function call or a variable. 所以基本上是一个有2层,然后是函数调用或变量的系统。 If I understand Lua correctly, that is a metatable in a table in a table. 如果我正确理解Lua,那就是表格中的表格。 When the user sets the variable, it should trip a __newindex call (not only to handle setting the value but to access a physical object that will animate through motors). 当用户设置变量时,它应该__newindex调用(不仅要处理设置值,还要访问将通过电机设置动画的物理对象)。 I also assume that the chief table in the table orc just sees lots of functions assigned to it regardless whether it is attack or __newindex . 我还假设表orc中的主表只是看到了很多分配给它的函数,无论它是attack还是__newindex To make it easier to add new variables and functions as the code develops, I have created 2 functions: one to create a function and one to create a variable. 为了便于在代码开发时添加新的变量和函数,我创建了两个函数:一个用于创建函数,另一个用于创建变量。 The function create just registers the functions and the variable create just makes a new table element and registers the functions for __newindex and __index . 函数create只是注册函数而变量create只是创建一个新的表元素并注册__newindex__index的函数。 Below is the code: 以下是代码:

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);
}

Then, in my main() I call the functions like this: 然后,在我的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);

When I run the code and pump in Lua scripts, orc.chief.attack() calls my OrcAttack() function but orc.chief.hp = 100 never calls my orcChief__newindex() function. 当我在Lua脚本中运行代码和泵时, orc.chief.attack()调用我的OrcAttack()函数,但orc.chief.hp = 100从不调用我的orcChief__newindex()函数。 I have even commented out the registerFunctions calls in case they were interfering somehow and just the registerIntegerVariable by itself still won't trigger the orcChief__newindex(). 我甚至已注释掉registerFunctions调用,以防它们以某种方式干扰,而registerIntegerVariable本身仍然不会触发orcChief__newindex(). Any ideas? 有任何想法吗?

__newindex is not called when you set a field in a table. 在表中设置字段时,不会调用__newindex It is called when you set a new field in a table. 在表中设置字段时调用它。 If the field already exists, __newindex will not be called. 如果该字段已存在,则不会调用__newindex

If you want __newindex to be called for every set operation on a table, you can't allow set operations to actually modify that table. 如果要为表上的每个集合操作调用__newindex ,则不能允许集合操作实际修改该表。 This is generally done by creating an empty table, called a proxy table, which the user uses. 这通常通过创建用户使用的称为代理表的空表来完成。 The proxy table is actually empty and must always remain so; 代理表实际上是空的,必须始终保持不变; you intercept all of the get and set calls, piping them to an internal table that the user never sees don't have access to. 您拦截所有get和set调用,将它们传递给用户从未看到过无法访问的内部表。

Or you use some userdata instead of a table. 或者您使用一些userdata而不是表。 __newindex is always called for them. 总是为它们调用__newindex

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM