Search code examples
c++lua

How to add namespaces to Lua?


I'm using Lua in a game engine that I'm working on. I'd like to give Lua a way to get and set the position of the entity that the script is sitting on. The script is a component that contains a pointer to the entity that contains it. From Lua, I'd like to be able to type:

print(transform.position.x)
transform.position.x = 10

I've written a getter and setter for position, by I'd like them to be contained under transform.position, and preferably not be getter and setters at all but rather behave more like public members. My current getter and setter looks like this:

int getXPosition(lua_State* L) {
    lua_pushnumber(L, Script::currentEntity->get<Transform>().position.x);

    return 1;
}

So, how would this be done, if possible at all?


Solution

  • Short answer: it may be done with userdata and metatables.

    More details:

    1. Register metatable that will be a "class" for the position object and register "__index" and "__newindex" metamethods for it:

       luaL_newmetatable(L, "position_metatable");
       lua_pushcfunction(L, &position__index);
       lua_setfield(L, -2, "__index");
       lua_pushcfunction(L, &position__newindex);
       lua_setfield(L, -2, "__newindex");
       lua_pop(L, 1);
      
    2. Write function position__index (it is getter). This is regular C Api function, it takes 2 arguments: the position userdata and a field name. If the field name is "x", the function should return the value of the x field.

    3. Write function position__newindex (it is setter). This is regular C Api function, it takes 3 arguments: the position userdata, field name and a value to write. If the field is "x", teh function should write the value to the x field.

    4. To pass the position object from native code to script, create userdata and set the "position_metatable" as a metatable for the userdata, see 28.2 – Metatables for example.

    5. Access to the field as transform.position.x.