How to link a class variable to c++ in lua script?

Asked

Viewed 197 times

3

How do I access and set a class variable made in C++ passes to Lua?

// C++
#ifndef SCRIPTSTORAGE_H
#define SCRIPTSTORAGE_H

#include "HTest.h"

#include <luajit/lua.hpp>
#include <iostream>

struct HObject {
    unsigned int id;
    std::string name;
    float x, y, z;
    float sx, sy, sz;
    float u, v;

    HObject()
    {
        id = 1;
    }
};

static bool checkFunctionArgs(lua_State* ls, const char* fname, unsigned int nargs)
{
    int fnargs = lua_gettop(ls) - 1;

    if(fnargs < (int)nargs)
    {
        std::cout << "LuaScriptError: " << fname << "() need at least %d parameter(" << nargs << ")\n" << std::endl;;
        return true;
    }

    if(fnargs > (int)nargs)
    {
        std::cout << "LuaScriptError: " << fname << "() takes " << nargs << " positional arguments but " << fnargs << " were given" << std::endl;
        return true;
    }

    return false;
}

HObject* HObject_check(lua_State* ls, int index)
{
    void* ud = 0;

    luaL_checktype(ls, index, LUA_TTABLE);
    lua_getfield(ls, index, "__self");

    ud = luaL_checkudata(ls, index, "HObject:new");

    luaL_argcheck(ls, ud != 0, 0, "'HObject:new' expected");

    return *((HObject**)ud);
}

static int HObject_newHObject(lua_State* ls)
{
    if(checkFunctionArgs(ls, "HObjec:new", 0)){
        return 0;
    }

    luaL_checktype(ls, 1, LUA_TTABLE);
    lua_newtable(ls);

    lua_pushvalue(ls, 1);
    lua_setmetatable(ls, -2);

    lua_pushvalue(ls, 1);
    lua_setfield(ls, 1, "__index");

    HObject** obj = (HObject**)lua_newuserdata(ls, sizeof(HObject*));
    *obj = new HObject();

    luaL_getmetatable(ls, "HObject:new");
    lua_setmetatable(ls, -2);

    lua_setfield(ls, -2, "__self");

    return 1;
}

static int HObject_destructor(lua_State* ls)
{
    HObject* obj = HObject_check(ls, 1);
    delete obj;

    return 1;
}

void HTest_register(lua_State* ls)
{
    static const luaL_Reg hobjec_funcs[] = {
        {"new", HObject_newHObject},
        {"__gc", HObject_destructor},
        {NULL, NULL}
    };

    luaL_newmetatable(ls, "HObject:new");
    luaL_register(ls, 0, hobjec_funcs);
    lua_pushvalue(ls, -1);
    lua_setfield(ls, -2, "__index");

    luaL_register(ls, "HObject", hobjec_funcs);
}

#endif // SCRIPTSTORAGE_H


-- Lua
local obj = HObject:new() -- OK

obj.variavel = 10 -- Exemplo de escrever na variável
print(obj.variavel) -- Exemplo de acessar variável

I want to access and write in the variable, but I do not know how to lynch the same in Lua. I have already lynched the class HOBject along with its functions, only missing variables.

1 answer

2


There is no standard way to establish variable access in LUA. You have two options to circumvent this:

Getter and Setters

The first one is easier, but it can look kind of ugly. You can create getters and setters. So you would have to create a get and set pair for each variable you want to have accessible, for example:

static int getVariavel(lua_State* ls)
{
    //Obter seu objeto aqui
    lua_pushinteger(ls, obj->variavel);
    return 1;
}
static int setVariavel(lua_State* ls)
{
    //Obter seu objeto aqui
    obj->variavel = lua_tointeger(ls, -1);
    lua_pop(1);
    return 0;
}

You have to create a pair of these for each variable, but this can be simplified with the help of macros and/or templates. With this template you can access and change the variables as follows:

local obj = HObject:new() -- OK
obj:setVariavel(10) -- Exemplo de escrever na variável
print(obj:getVariavel()) -- Exemplo de acessar variável

Filtering by __index __newindex

The other way would be to put handlers to the events __index and __newindex in the object metatable. Thus, you could filter the variable names and return their values:

static int index(lua_State *ls)
{
    ///Obter objeto aqui.
    string s = lua_tostring(ls, 2);
    if(s == "variavel")
        lua_pushinteger(ls, obj->variavel);
    else if(s == "variavel2")
        lua_pushinteger(ls, obj->variavel2);
    // Outras variáveis aqui.
    else
    {
        //Chamar a table com as funções.
    }
    return 1;
}
static int newIndex(lua_State *ls)
{
    //Obter objeto aqui
    string s = lua_tostring(ls, 2);
    if(s == "variavel")
        obj->variavel = lua_tointeger(ls, -1);
    else if(s == "variavel2")
        obj->variavel2 = lua_tointeger(ls, -1);
    //..outras variáveis aqui.
    else
        //Mostrar msg de erro dizendo que tal variável não existe.
}

This model only needs these two functions, but comparing the strings one by one can be slow if it has a very large number of attributes and its class. On the other hand, the access in Lua becomes more beautiful, in my opinion:

-- Lua
local obj = HObject:new() -- OK

obj.variavel = 10 -- Exemplo de escrever na variável
print(obj.variavel) -- Exemplo de acessar variável
  • Talesm, thank you for the answer. I did it with getter and even Setter :/. But how is this done in Luabind for example?

  • I don’t know much about Luabind, but I know that it automates a lot using templates. But underneath it all he calls the Moon API, so he must implement one of these techniques underneath the scenes.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.