lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Hello yall,

yesterday I was facing 3 problems here:
1) I wanted a C++ function to return a C++ object to the Lua world.
Example:      robot = Universe.newPlayer()

2) I wanted to use class.object:method()
Example:       robot.head:setColors('green', 'yellow', 'blue', 'white')

3) Because of 2) I needed to add selective garbage collection to my objects.

Clarifying the third item: my solution to the second item as setting the member 'object' of the instance table as an object. The problem is that Lua will try do free it during garbage collection (using stardard luna.h), and also will C++ on the class instance destruction. I cannot remove the garbage collection from the metatable because the same class (DPlayerHead) might be initialized by Lua directly like  newHead = DPlayerHead().

My solution for the first problem was creating a pushobject function in luna.h exactly like the constructor but using an already created object:
===BEGIN===
    static int pushobject(lua_State *L, T* obj) {
        lua_newtable(L);

        lua_pushnumber(L, 0);
        T** a = (T**)lua_newuserdata(L, sizeof(T*));
        obj->ud = (void**) a;
        *a = obj;
        luaL_getmetatable(L, T::className);
        lua_setmetatable(L, -2);
        lua_settable(L, -3); // table[0] = obj;

        for (int i = 0; T::Register[i].name; i++) {
            lua_pushstring(L, T::Register[i].name);
            lua_pushnumber(L, i);
            lua_pushcclosure(L, &Luna<T>::thunk, 1);
            lua_settable(L, -3);
        }
       
        return 1;
    }
===END==

For the second problem, on the DPlayer::DPlayer(lua_State *L) function I add the subclasses members manually:
===BEGIN===
    lua_pushstring(L, "head");
    Luna<DPlayerHead>::pushobject(L, &head);
    lua_settable(L, -3);
===END===

For the third I have an DObject class as everyone's parent with 2 attributes: void **ud and bool garbageCollect. When the object goes to Lua (like in pushobject above or luna.h's constructor), I set put the userdata pointer to ud. When the object is destroyed by C++ I set ud to NULL and check for this at luna.h's gc_obj(). To avoid the case where Lua tries to destroy it first I set garbageCollect to false and check for this on gc_obj():
==BEGIN==
    static int gc_obj(lua_State *L) {
        T** obj = static_cast<T**>(luaL_checkudata(L, -1, T::className));
       
        T* instancia = *obj;
        if (*obj == NULL) {
            return 0;
        }
       
        if ((*obj)->garbageCollect == false) {
            return 0;
        }
       
        delete (instancia);
        return 0;
    }
==END==

As I'm new to Lua (and scripting), I want to know what you think about this solution. Mine implied in modifying the C++ classes too much, but works and doesn't have an overhead in the Lua's execution.

PS: I'm not developing a game. DRobot, DPlayer and universe are just examples.

Thank you all!

Best regards,
Daniel Colchete