c++lualuabind

Rather then create a object in lua, how let lua directly tall the C++ object to launch a method?


I'm using Luabind.

My title might be kind of unclear, I will try the best i can to explain what i want to ask.

My question is:
How do i directly tall C++ object's method that can access the object's values(especially pointers) rather then creating Another object in Luabind.

If you don't know what I'm asking, You can continue reading.

For example, i have three classes: Main, Test_Stage, Test_Class

the Lua is created only in Test_class.

I have a variable x ,created just for testing purpose. It is passed all the way from the Main to Test_Stage to Test_Class by their constructor. So that both Test_Class and Test_Stage have a global value which I'll need when I'm actually making the game.
More important thing is that Test_Class holds a pointer of Test_Stage, so that i can do such things as create_a_bullet or create_damage.

Learned from this Tutorial, I had tried to make The luaobject created in Test_Class call the method shoot_a_bullet which will tall 'Test_Stage' object to print "Runned " << 'the global value'. And without a syntax error in C++, IT didn't print anything. How can i fix this?

Codes are here(actually i had trouble working with forward including using class, so "Runned" << x is in Test_Class. At least I can test if it will read the global value had passed here.)

Edit: Just after few hours of doing nothing, I had though about another solution. Is there a way i can pass the pointer that can be used in the object that is created in lua, or maybe used in constructer?

Codes(you might considering skip the main and Test_Stage if you come for answering the question :

The main file start the program:

#include <iostream>
#include "test_stage.h"

using namespace std;

int x;

int main() {

    cin >> x;
    Test_Stage stage = Test_Stage(x);
}

And the Header of Test_Stage:

#ifndef TEST_STAGE_H
#define TEST_STAGE_H
#include <iostream>
class Test_Class;// to avoid circular include error, i used forward referancing
                 // i will include the file in the CPP file
                 // a class Test_Class which define the class is enough in header
using namespace std;

class Test_Stage
{
    public:
        int x;
        Test_Stage(int num);

        void create_bullet(int damage, string name, int x); /*This is currently useless 
            before i have understand how to include each other using foward referance*/
        void create_class(int num);

        Test_Class t_class;

        ~Test_Stage();
    private:

};

#endif

The cpp file of Test_Stage:

#include"test_stage.h"
#include "test_class.h"// and as you see i included both files(i just learned it few secs ago)

Test_Stage::Test_Stage()
{

}

Test_Stage::Test_Stage(int num)
{
    create_class(num);
}

void Test_Stage::create_bullet(int damage, string name, int x)
{
    cout << "created damage: " << damage << "to" << x ;
}

void Test_Stage::create_class(int num)
{
    Test_Class t_class = Test_Class(num, this);
}

Test_Stage::~Test_Stage()
{

}

The header of Test_Class:

#ifndef TEST_CLASS_H    
#define TEST_CLASS_H
extern "C"
{
#include <lua.h>
    #include <lualib.h>
    #include <lauxlib.h>
}
#include ".\luabind\luabind.hpp"
#include <iostream>
using namespace std;

class Test_Stage;

class Test_Class
{
    public:
        int x;
        Test_Class();
        Test_Class(int num, Test_Stage* stage);
        void shoot_a_bullet(Test_Class* o, int damage);

        Test_Stage *stage;
        ~Test_Class();
    private:

};

#endif TEST_CLASS_H

And finally the cpp of Test_Class(causing me lot's trouble):

#include "test_class.h"
#include"test_stage.h"

void Test_Class::shoot_a_bullet(Test_Class* o, int damage)
{
    cout << "Runned";
    stage->create_bullet(damage, "wowo", x);
}

Test_Class::Test_Class()
{

}

Test_Class::Test_Class(int num, Test_Stage* stg)
{
    stage = stg;
    x = num;
    // Create a new lua state
        lua_State *myLuaState = luaL_newstate();

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


    luabind::module(myLuaState)[
        luabind::class_<Test_Class>("Test_Class")
            .def("shoot_a_bullet", &Test_Class::shoot_a_bullet)
    ];

    /*followed the tutorial codes
    class_<A>("A")
        .def("plus", &plus)*/

    cout << "im here";//just to check how far did the program go
    luaL_dostring(
        myLuaState,
        "shoot_a_bullet(134)\n"
    );
    cout << "I passed it";
    cin.get();
    cin.get();//To pause the program before it closes
    // if you have the time, can you also explain 
    // why do i need two cin.get() to pause the program.
}

Test_Class::~Test_Class()
{

}    

Solution

  • After tons, and tons of researches, I had finally figured out an solution although I'm not sure about how efficient it is, it's actually working the way i wanted it to be.
    So the final solution is, to register an intptr_t converted from the pointer i needed to lua,(for more information about intptr_t, click here(mainly for safety reason, you can see it as a kind of int design just for pointers)) and pass it to the static function when I'm using it

    Here is the Code after modification:

    In Test_Class.cpp, after:

    luabind::module(myLuaState)[
        .def("shoot_a_bullet", &shoot_a_bullet)
    ];// since the functions are static now it will not need the namespace
    

    I had registered the intptr_t version of pointer:

    //first convert pointer to intptr_t
    intptr_t stage = (intptr_t)stg;//stg is the pointer
    
    //then register it to lua
    //if you try to register a pointer it will give you runtime error
    luabind::globals(myLuaState)["stage"] = stage;
    

    We also need to change the function a little bit:
    First, we need to make the function static, so in the header file:

    //change the line defined the function to
    void static shoot_a_bullet(intptr_t stg, int damage);
    

    Now we have to do things with the function it self:

    void Test_Class::shoot_a_bullet(intptr_t stg, int damage)
    {
        //we need to convert it back to pointer first, so
        Test_Stage* stage = (Test_Stage*)stg;//this is the part I'm not sure about efficiency 
        stage->create_bullet(damage, "wowo");
    }
    

    So now the Code with lua will be really simple: shoot_a_bullet(stage, 134);

    We are done! Life is good! This stuff has costed me 3 week.

    In chance you might not understanding what i said, here is the complete test code i had writen:

    main.cpp:

    #include <iostream>
    #include "test_stage.h"
    
    using namespace std;
    
    int x;
    
    int main() {
    
    cin >> x;
    cin.get();// clean the \n(when you press enter) after the number
    Test_Stage stage = Test_Stage(x);
    }
    

    Test_Stage.h:

    class Test_Class;
    #ifndef TEST_STAGE_H
    #define TEST_STAGE_H
    extern "C"
    {
        #include <lua.h>
        #include <lualib.h>
        #include <lauxlib.h>
    }
    #include ".\luabind\luabind.hpp"
    #include <iostream>
    #include "test_class.h"
    using namespace std;
    
    class Test_Stage
    {
        public:
            int x;
            Test_Stage();
            Test_Stage(int num);
    
            void create_bullet(int damage, string name); /*This is currently useless
            before i have understand how to include each other using foward referance*/
            void create_class(int num);
    
            Test_Class t_class;
    
            ~Test_Stage();
        private:
    
    };
    
    #endif
    

    Test_Stagecpp:

    #include"test_stage.h"
    #include "test_class.h"// and as you see i included both files
    
    Test_Stage::Test_Stage()
    {
    
    }
    
    Test_Stage::Test_Stage(int num)
    {
        x = num;// a variable specific in this object(to test pointer)
        create_class(num);
    }
    
    void Test_Stage::create_bullet(int damage, string name)
    {
        cout << "created damage: " << damage << " to " << x << endl;/*using the value
         created in this object to see if pointer is actually working*/
    }
    
    void Test_Stage::create_class(int num)
    {
        Test_Class t_class = Test_Class(this, num);
    }
    
    Test_Stage::~Test_Stage()
    {
    
    }
    

    Test_Class.h:

    #ifndef TEST_CLASS_H    
    #define TEST_CLASS_H
    extern "C"
    {
    #include <lua.h>
        #include <lualib.h>
        #include <lauxlib.h>
    }
    #include ".\luabind\luabind.hpp"
    #include <iostream>
    using namespace std;
    
    class Test_Stage;
    
    class Test_Class
    {
        public:
            int x;
            Test_Class();
            Test_Class(Test_Stage* stage, int num);
            void static shoot_a_bullet(intptr_t stg, int damage);
    
            ~Test_Class();
        private:
    
    };
    
    #endif TEST_CLASS_H
    

    And finally,Test_Class.cpp:

    #include "test_class.h"
    #include"test_stage.h"
    
    void Test_Class::shoot_a_bullet(intptr_t stg, int damage)
    {
        Test_Stage* stage = (Test_Stage*)stg; // intptr_t back to pointer
        stage->create_bullet(damage, "wowo"); // use pointer
    }
    
    Test_Class::Test_Class()
    {
    
    }
    
    Test_Class::Test_Class(Test_Stage* stg, int num)
    {
        intptr_t stage = (intptr_t)stg;
        // Create a new lua state
        lua_State *myLuaState = luaL_newstate();
    
        // Connect LuaBind to this lua state
        luabind::open(myLuaState);
        luaL_openlibs(myLuaState);
    
    
        luabind::module(myLuaState)[
        luabind::def("shoot_a_bullet", &shoot_a_bullet)//again this is static now
        ];
    
        luabind::globals(myLuaState)["stage"] = stage;
    
        cout << "I'm here " << endl;//just to check how far did the program go
    
        luaL_dostring(
            myLuaState,
            "shoot_a_bullet(stage, 134)\n"
        );
    
        cout << "I passed it"<< endl;
        cin.get();
    }
    
    Test_Class::~Test_Class()
    {
    
    }    
    

    Have fun!