How to bind a variable from a class in c ++ to lua script?

3

How do I access and set a variable from a class made in C ++ 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 link the same in Lua. I have already managed to link the class HOBject along with its functions,     

asked by anonymous 29.03.2014 / 18:54

1 answer

2

There is no standard way of establishing variable access in LUA. You have two options to work around this:

Getter and Setters

The first one is easier, but it may seem 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 place handlers for the __index and __newindex events in the metatable of the objects. So 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 needs only these two functions, but comparing strings one by one can be slow if you have a very large number of attributes and your class. On the other hand, access on Lua looks 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
    
30.03.2014 / 17:49