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

StackOverflow https://stackoverflow.com/questions/21213495

  •  29-09-2022
  •  | 
  •  

Question

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()
{

}    
Was it helpful?

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!

OTHER TIPS

I know this is late but why didnt you simple do

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

luabind::globals(myLuaState)["stage"] = stage;

luaL_dostring(
        myLuaState,
        "stage::shoot_a_bullet(134)\n"
    );

You did everything right, if you want to call a member function of an exposed C++ object you first need to bind it (which you did) then you put your object into some lua scope (you used the global) and then you simple reference the object stage and call a function with ::myfunction

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top