Opps...need help on how to manage c++ objects from Lua

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Opps...need help on how to manage c++ objects from Lua

voodooRod
This post has NOT been accepted by the mailing list yet.
Opps...my previous post I sent accidently before finishing.

I know how to bind C++ classes and expose to Lua so that Lua script can instantiate class and call member functions.

What I'd like to is manage c++ objects from lua script. Not instantiate objects in lua and then call member functions but, objects created on the C++ side that I can then manage from script, i.e.,

C++ side

class FooManager
{
public:
    FooManager();
    ~FooManager();

      void doSomething() {}
      FooObjects* getObject(someID) { // return object from list}
      void start() { // call lua function }

private:
     std:list<FooObjects*> m_fooObjsList;
}      

LUA side

function start()

    pFoo = getObjects(someID)
    pFoo.bar() -- some method in the returned object

end

I need help in how to achieve this using Luabind.

Thank you,
Rod
Reply | Threaded
Open this post in threaded view
|

Re: Opps...need help on how to manage c++ objects from Lua

voodooRod
So, I started to try to answer my own question. I wrote the following code as a test case. Some things are a bit sloppy, just test code.

I have an abstract class and then derive classes. I also have a class, FooManager that will hold those classes. The Foo class has a function "Awake" that it calls in the Lua script. Inside the script I want to grab the appropriate component and call its methods.

I've used the luabind::globals to give the FooManager class to the script. When I try to call the "sayName" method of Foo class I'm getting an error message, "No matching overload found, candidates: void sayName(Foo&)"

Here's the C++ code: (see after for Lua script)

template <typename T> 
void registrate(lua_State *pLuaState) {
        T::registrate(pLuaState);
}

class IFoo
{
public:
        virtual ~IFoo() {}
        virtual void sayName(void) = 0;
        virtual void doAwake(void) = 0;
        virtual void update(void) = 0;
};

class Foo : public IFoo
{
public:
        Foo() { m_sName = "Blank"; }
        Foo(std::string sName, lua_State* pLuaState) :
          m_sName(sName), m_pLuaState(pLuaState) {}

        void sayName(void) { printf("FOO: the name is: %s\n", m_sName.c_str()); }
        void changeName(const std::string &sName) { m_sName = sName; }
        void update(void){};
        void doAwake(void)
        {
                // do the script
                if(luaL_dofile(m_pLuaState, "myscript1.lua"))
                {
                        printf("Lua engine error: %s",lua_tostring(m_pLuaState, 1));
                        return;
                }

                try {

                        // call the lua function
                        luabind::call_function<void>(m_pLuaState, "Awake");

                } catch (luabind::error& e)

                {
                        std::string error = lua_tostring( e.state(), -1 );
                        std::cout << error << "\n";
                }
        }

        static void registrate(lua_State *pLuaState)
        {
                // export our class with LuaBind
                luabind::module(pLuaState) [
                        luabind::class_<Foo>("Foo")
                                .def(luabind::constructor<>())
                                .def(luabind::constructor<std::string, lua_State*>())
                                .def("sayName", (void(Foo::*) (void)) &Foo::sayName)
                                .def("changeName", (void(Foo::*) (const std::string &)) &Foo::changeName)
                ];
        }

private:
        std::string m_sName;
        lua_State *m_pLuaState;
};

class Foo2 : public Foo
{
public:
        Foo2() {}
        Foo2(std::string sName) :
                Foo(sName, NULL) { m_sName = sName; }

        void sayNothing(void) { printf("FOO2: saying nothing %s\n", m_sName.c_str()); }
        void update(void) {}
        void doAwake(void) {}
        void sayFooName(void) { printf("FOO2: saying FOO's name = "); Foo::sayName(); }

        static void registrate(lua_State *pLuaState)
        {
                luabind::module(pLuaState) [
                        luabind::class_<Foo2, Foo>("Foo2")
                                .def(luabind::constructor<std::string>())
                                .def("sayNothing", (void(Foo2::*) (void)) &Foo2::sayNothing)
                ];
        }

private:
        std::string m_sName;
};

class FooManager
{
public:
        FooManager() {};
        ~FooManager() {};

        void addComponent(IFoo* pFoo) { m_iFooVector.push_back(pFoo); }
        IFoo* getComponent(int nIndex) { return m_iFooVector[nIndex]; }

        static void registrate(lua_State *pLuaState)
        {
                luabind::module(pLuaState) [
                        luabind::class_<FooManager>("FooManager")
                                .def(luabind::constructor<>())
                                .def("getComponent", (IFoo*(FooManager::*) (int)) &FooManager::getComponent)
                ];
        }

private:
        std::vector<IFoo*> m_iFooVector;
};

int main()
{
        lua_State *myLuaState = luaL_newstate();

        // Connect LuaBind to this lua state
        luabind::open(myLuaState);

        // register the luaBind classes
        registrate<Foo>(myLuaState);
        registrate<Foo2>(myLuaState);
        registrate<FooManager>(myLuaState);

        // create all the objects
        Foo *pFoo = new Foo("Test: 1-2-3!", myLuaState);
        Foo2 *pFoo2 = new Foo2("Zimba");
        FooManager fooManager;

        fooManager.addComponent(pFoo);
        fooManager.addComponent(pFoo2);
       
        // set object manager global
        luabind::globals(myLuaState)["FooManager"] = &fooManager;

        pFoo->doAwake();

        lua_close(myLuaState);
 
        // clean up
        delete pFoo;
        delete pFoo2;

        return 0;
}

Here's the Lua script...

function Awake()

        pFooObj = FooManager:getComponent(0)
        pFooObj:sayName();

end

I hope some folks are still on this site...I saw I only 3 views originally and 1 was mine. ;)

Thank you
Reply | Threaded
Open this post in threaded view
|

Re: Opps...need help on how to manage c++ objects from Lua

voodooRod
In reply to this post by voodooRod
I solved my own problem.

I needed to first bind my abstract class "IFoo." And, in my class Foo I needed to bind the constructor with the derived IFoo. So now, all works. I will post the working code below in case anyone else needs to know how to do.

All the samples online seem to show how to bind C++ to Lua and then construct the objects from Lua. However, if you wish to do "declarative" programming, creating and managing the objects on the C++ side and then allowing Lua to manipulate those objects, I hadn't found any clear samples. So, here's a sample...

// C++ CODE

template <typename T> 
void registrate(lua_State *pLuaState) {
        T::registrate(pLuaState);
}

class IFoo
{
public:
        virtual ~IFoo() {}
        virtual void sayName(void) = 0;
        virtual void doAwake(void) = 0;
        virtual void update(void) = 0;

        static void registrate(lua_State *pLuaState)
        {
                // export our class with LuaBind
                luabind::module(pLuaState) [
                        luabind::class_<IFoo>("IFoo")
                                .def("sayName", (void(IFoo::*) (void)) &IFoo::sayName)
                ];
        }

};

class Foo : public IFoo
{
public:
        Foo() { m_sName = "Blank"; }
        Foo(std::string sName, lua_State* pLuaState) :
          m_sName(sName), m_pLuaState(pLuaState) {}

        void sayName(void) { printf("FOO: the name is: %s\n", m_sName.c_str()); }
        void changeName(const std::string &sName) { m_sName = sName; }
        void update(void){};
        void doAwake(void)
        {
                // do the script
                if(luaL_dofile(m_pLuaState, "myscript1.lua"))
                {
                        printf("Lua engine error: %s",lua_tostring(m_pLuaState, 1));
                        return;
                }

                try {

                        // call the lua function
                        luabind::call_function<void>(m_pLuaState, "Awake");

                } catch (luabind::error& e)

                {
                        std::string error = lua_tostring( e.state(), -1 );
                        std::cout << error << "\n";
                }
        }

        static void registrate(lua_State *pLuaState)
        {
                // export our class with LuaBind
                luabind::module(pLuaState) [
                        luabind::class_<Foo, IFoo>("Foo")
                                .def(luabind::constructor<>())
                                .def(luabind::constructor<std::string, lua_State*>())
                                .def("sayName", (void(Foo::*) (void)) &Foo::sayName)
                                .def("changeName", (void(Foo::*) (const std::string &)) &Foo::changeName)
                ];
        }

private:
        std::string m_sName;
        lua_State *m_pLuaState;
};

class Foo2 : public Foo
{
public:
        Foo2() {}
        Foo2(std::string sName) :
                Foo(sName, NULL) { m_sName = sName; }

        void sayName(void) { printf("FOO2: the name is: %s\n", m_sName.c_str()); }
        void sayNothing(void) { printf("FOO2: saying nothing %s\n", m_sName.c_str()); }
        void update(void) {}
        void doAwake(void) {}
        void sayFooName(void) { printf("FOO2: saying FOO's name = "); Foo::sayName(); }

        static void registrate(lua_State *pLuaState)
        {
                luabind::module(pLuaState) [
                        luabind::class_<Foo2, Foo>("Foo2")
                                .def(luabind::constructor<std::string>())
                                .def("sayName", (void(Foo2::*) (void)) &Foo2::sayName)
                                .def("sayNothing", (void(Foo2::*) (void)) &Foo2::sayNothing)
                ];
        }

private:
        std::string m_sName;
};

class FooManager
{
public:
        FooManager() {};
        ~FooManager() {};

        void addComponent(IFoo* pFoo) { m_iFooVector.push_back(pFoo); }
        IFoo* getComponent(int nIndex) { return m_iFooVector[nIndex]; }

        static void registrate(lua_State *pLuaState)
        {
                luabind::module(pLuaState) [
                        luabind::class_<FooManager>("FooManager")
                                .def(luabind::constructor<>())
                                .def("getComponent", (IFoo*(FooManager::*) (int)) &FooManager::getComponent)
                ];
        }

private:
        std::vector<IFoo*> m_iFooVector;
};

int main()
{
        lua_State *myLuaState = luaL_newstate();

        // Connect LuaBind to this lua state
        luabind::open(myLuaState);

        // open the lua libraries
        luaL_openlibs(myLuaState);

        // register the luaBind classes
        registrate<IFoo>(myLuaState);
        registrate<Foo>(myLuaState);
        registrate<Foo2>(myLuaState);
        registrate<FooManager>(myLuaState);

        // create all the objects
        Foo *pFoo = new Foo("Test: 1-2-3!", myLuaState);
        Foo2 *pFoo2 = new Foo2("Zimba");
        FooManager* pfooManager = new FooManager();

        pfooManager->addComponent(pFoo);
        pfooManager->addComponent(pFoo2);
       
        // set object manager global
        luabind::globals(myLuaState)["fooManager"] = boost::ref(pfooManager);

        pFoo->doAwake();

        lua_close(myLuaState);
 
        // clean up
        delete pFoo;
        delete pFoo2;

        return 0;
}


// LUA SCRIPT

function Awake()

        print("In Awake!")

        local pFooObj = fooManager:getComponent(0)

        pFooObj:sayName();

end

Cheers!