1

I am pulling my hair out here, I can share an array between Lua and c++, I can even create an array of objects in Lua (using the code below) and access their member functions (eg obj[10]:setPosition(0,0,0) ). What I can't do is send c++ objects to Lua that already exist and have Lua call their respective member functions. For example:

objects = Scene.getAllObjects()
objects[5]:setPosition(0,0,0)

...doesn't work, however, The code below works

for i=1,10 do
  objects[i] = Object.new("Box")
  objects[i]:setPosition(0,0,0)
end

...which calls the c++ function below

int luaAddNewEditableObject(lua_State * L)
{
    const char * name = luaL_checkstring(L, 1);

    EditableObject ** udata = (EditableObject **)lua_newuserdata(L, sizeof(void*));
    EditableObject *obj = scene->addNewEditableObject(name);
    *udata = obj;

    luaL_getmetatable(L, "luaL_EditableObject");

    lua_setmetatable(L, -2);

    return 1;
}

So basically, if it's created in Lua then no problems, but if there are objects that already exist in c++ then I need to get it into a Lua table/array so Lua can do magic to them

Please Help

struct ObjectArray 
{
    int size;
    EditableObject *objects;  /* The cpp objects */
};

static int getAllObjects (lua_State *L) 
{
    //This creates the metatable for array notation
    size_t nbytes = sizeof(ObjectArray) + numObjects * sizeof(ObjectArray*);
    ObjectArray *objectArray = (ObjectArray*)lua_newuserdata(L, nbytes);
    objectArray->size = numObjects;

    for (int i = 0; i < numFoos; i++)
    {
            //This sets the c++ pointers to the lua_newuserdata 
                objectArray->objects[i] = objects[i];

        //So maybe here I need to assign the 'luaL_EditableObject' metatable for each object
        //so I can call it's member functions ??
    }
    luaL_getmetatable(L, "ObjectArray");
    lua_setmetatable(L, -2);

    return 1; 
}
7
  • 2
    Can you clarify how it doesn't work? Do you get an error? Does it crash? What happens? What does Scene.getAllObjects return? Are you sure it's returning a table of your objects (eg. if you compare metatable of the udata returned by Scene.getAllObjects is it the same as Object.new "Box")? Commented Dec 31, 2013 at 8:57
  • The metatable is as follows void registerEditableObject() { luaL_Reg regs[] = { { "new", luaAddNewEditableObject }, { "setPosition", luaSetObjectPosition }, { NULL, NULL } }; luaL_newmetatable(L, "luaL_EditableObject"); luaL_register(L, NULL, regs); lua_pushvalue(L, -1); lua_setfield(L, -1, "__index"); lua_setglobal(L, "Object"); } Commented Jan 1, 2014 at 0:58
  • getAllObjects() should return a table/array of what Object.new("Box") returns, but of already existing objects. But I have no idea of how to go about it. Thanks in advance Commented Jan 1, 2014 at 1:08
  • To clarify further, Object.new("Box") returns a metatable of a single object but what I need for getAllObjects() is a metatable of object metatables... if that makes sense Commented Jan 1, 2014 at 1:14
  • Can you add the C++ snippet for Scene.getAllobjects to your question? Commented Jan 1, 2014 at 3:20

1 Answer 1

1

Ok I figured it out and will answer my own question in case anyone else has had this problem

extern "C"
{
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}

#include <map>

class Object 
{
public:
    Object()
    {
        x = 0;
        y = 0;
    }
    Object(int x, int y)
    {
        this->x = x;
        this->y = y;
    }
    int x, y;
};


std::map<std::string,Object> objects;

static int luaGetObjects(lua_State *L)
{
    lua_newtable(L);
    int i=0;
    for (auto it = objects.begin(); it != objects.end(); it++, i++) 
    {

        lua_pushstring(L, it->first.c_str());

        luaL_getmetatable(L, "luaL_Object");
        lua_setmetatable(L, -2);

        lua_rawseti(L, -2, i+1);
        stackDump(L);
    }

    return 1;   
}

static int luaSetPosition(lua_State* L) 
{
    const char* key = luaL_checkstring(L,1);

    int x = luaL_checknumber(L,2);
    int y = luaL_checknumber(L,3);

    objects[key].x = x;
    objects[key].y = y;

    return 0; 
}

static int luaGetPosition(lua_State* L) 
{
    const char* key = luaL_checkstring(L,1);

    lua_pushnumber(L, objects[key].x);
    lua_pushnumber(L, objects[key].y);

    return 2; 
}

void registerObject(lua_State *L)
{
    luaL_Reg regs[] =
    {
        { "setPosition", luaSetPosition },
        { "getPosition", luaGetPosition },
        { NULL, NULL }
    };

    luaL_newmetatable(L, "luaL_Object");
    luaL_register(L, NULL, regs);
    lua_pushvalue(L, -1);
    lua_setfield(L, -1, "__index");
}

int main()
{
    lua_State * L = luaL_newstate();
    luaL_openlibs(L);

    lua_pushcfunction(L, luaGetObjects);
    lua_setglobal(L, "getObjects");

    registerObject(L);

    objects["id001"] = Object(1,2);
    objects["id002"] = Object(3,4);
    objects["id003"] = Object(5,6);

    int erred = luaL_dofile(L, "hello.lua");
    if(erred)
        std::cout << "Lua error: " << luaL_checkstring(L, -1) << std::endl;

    lua_close(L); 

    return 0;
}

The 'hello.lua' code:

objects = getObjects()

for i=1,#objects do
   x,y = objects[i]:getPosition();
   print(string.format("object[%d] x = %d y = %d",i,x,y))

   objects[i]:setPosition(x*100, y*100);

   x,y = objects[i]:getPosition();
   print(string.format("object[%d] x = %d y = %d after mul",i,x,y))
end
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.