LuaBind: How to bind specific instance of class to Lua? - c++

(sidenote: This is game programming)
Binding entire classes to Lua using LuaBind is easy:
class test
{
test()
{
std::cout<<"constructed!"<<std::endl;
}
void print()
{
std::cout<<"works!"<<std::endl;
}
}
//somewhere else
module[some_lua_state]
[
class_<test>("test")
.def(constructor<>())
.def("print",&test::print)
];
Now I can create instances of the class in Lua and use it:
lua_example.lua
foo = test() //will print "constructed!" on the console
foo:print() //will print "works!" on the console
However, now I'd like to bind a specific instance of test to Lua. This would enable me to pass objects down to Lua, e.g. an instance of the Player-class and do something like:
Player:SetPosition(200,300)
As opposed to going the hard way and having something like
SetPosition("Player",200,300)
where the corresponding C++ SetPosition function needs to look up a std::map to find the player.
Is this even possible and if so, how can I do it in LuaBind?

You don't bind instances of classes to Lua. Instances of classes are just data, and you can pass data to Lua via the usual means. C++ objects are special though; because they're registered through Luabind, you have to use Luabind methods to provide them to Lua scripts.
There are several ways to give data to Lua, and Luabind covers all of them. For example, if you have an object x, which is a pointer to class X that is registered with Luabind, there are several ways you can give Lua x.
You could set the value of x into a global variable. This is done through Luabind's object interface and the globals function:
luabind::globals(L)["NameOfVariable"] = x;
Obviously, you can put that in another table, which lives in another table, etc, which is accessible from the global state. But you'll need to make sure that the tables all exist.
Another way to pass this data to Lua is to call a Lua function and pass it as a parameter. You can use the luabind::object interface to get a function as an object, then use luabind::call_function to call it. You can then just pass x as a parameter to the function. Alternatively, if you prefer the lua_pcall-style syntax, you can wrap x in a luabind::object and push it into the stack with luabind::object::push.

Related

How to pass pass a bound method of a pointer as an argument?

If I am given a pointer to an object and I need to pass one of that object's methods as an argument to another function, is that possible?
A very simplified example would look like this:
void consumeAFunction(Function func) {
auto value = func();
// do some stuff //
}
void main(Object *pointerToObject) {
consumeAFunction(pointerToObject->someMethod)
}
I've tried the following, but I think my understanding of pointers and references is flawed. I'm 3 weeks old in my c++ journey.
​Object someObject = pointerToObject​ and Object someObject = *pointerToObject​
The specific context of the question is that I have a pointer to an object created by some other library and I need to use QtConcurrent::run on that object's methods.
Additional context
consumeAFunction is QtConcurrent::run
Function func is a method of an Engine that simply performs some logic. I am handed a pointer to Engine by a third party library.
I cannot avoid using a pointer to Engine, because it is all I am given to work with.
As much of the specific code as I am allowed to show:
// engine is the pointer to someObject:
auto engine = lui::QueryInterop<wise::Engine>(lui::GetLUI());
if (engine) {
connect(&m_modelsLoadedWatcher, &QFutureWatcher<bool>::finished, this, &ConfigDialog::onNNModelsLoaded);
// This is the call to consumeAFunction (qtconcurrent::run)
m_modelsLoadedFuture = QtConcurrent::run(engine->loadPytorchModels);
m_modelsLoadedWatcher.setFuture(m_modelsLoadedFuture);
Because this is a Qt question, I highly recommend you get an understanding of QObject and QMetaObject::invokeMethod().
Because QObject is pre-processing via the moc-compiler, a lot of public interfaces, such as properties, methods are exposed in such a way that the object's properties and methods can be inspected at runtime by another plugin and that it doesn't need to know or have access to the header files. This is why something like QMetaObject::invokeMethod() can work because it has access to the metadata.
Alternatively, if you are using Javascript a lot in QML, you may be interested in passing a Javascript callback function to C++. That function is accessible via QJSValue. QJSValue usually is used to hold simple types such as strings and numbers. When it holds more complex Javascript types such as arrays, objects, or functions you can use quite a few QJSValue methods to unlock their capabilities. In the case of Javascript functions you can verify if it is a Javascript function with QJSValue.isCallable() == true and can you can execute it with QJSValue.call(...).

Call C++ Functions in an active program from Lua

I'm not sure if my question makes any sense, but I certainly know it is near impossible to get the results from Google. Firstly, what I do not want. I don't want to call some function that prints "hello world" or adds two numbers together, I want to load a Lua script from a C++ program, but allow the script to modify variables of the C++ program, using functions. For example, imagine I have a C++ program like this:
class Foo
{
private:
int number = 0;
public:
void setNumber(const int& newNumber) {number = newNumber;}
}
int main()
{
Foo foo;
//Load and execute Lua script, with foo object
return 0;
}
How could I allow the Lua script to do foo.setNumber() (preferably without foo.)? This may be a very simple question, but as mentioned above, almost all information on Google when searching "Call C++ Function from Lua" assume there is no program, but just a .cpp/hpp file with some functions that you want to call.
I'm on Linux (Ubuntu), but the program needs to compile on all platforms (Windows and Mac)
This is asked here fairly regularly.
To roll your own binding you should:
Master Lua metatables completely.
Read the Programming in Lua stuff on the C API, particularly the part on classes. Alternatively you can read the manual, read the source (API headers especially), and do some googling, but the book will probably save you some time.
Broadly, you expose a C++ class instance to Lua by creating a Lua "userdata" containing a pointer to the class instance and passing this to the Lua script. A userdata is an opaque type; the Lua script can't actually do anything with it (other than pass it around) unless you give it a metatable. At the very least you must implement the __index metamethod on the userdata, which allows your C++ code to intercept attempts to index the userdata and return something meaningful, and the __gc metamethod, which allows your C++ code to delete the exposed C++ object when the corresponding Lua userdata is garbage collected.
For instance, you create a function called createFoo which creates a Foo instance, wraps the pointer as a userdata, applies a metatable implementing __index to it, and returns it to the Lua script.
When the user runs foo.setNumber, your C++ __index metamethod is called with the userdata and the string "setNumber". It's up to you what you return and this determines what foo.setNumber evaluates to in the Lua script. You want foo.setNumber to evaluate to a lua_CFunction which expects a Foo userdata as its first parameter, so that your class methods can be called idiomatically from Lua (i.e. foo:setNumber(12), which is syntax sugar for foo.setNumber(foo, 12)).
It's a very low level and manual process, and once you get the hang of it you're going to end up create a library/templates/macros whatever to do the boilerplate for you. At that point you may want to evaluate the myriad C++ binding libraries that exist. However, thanks to the Law of Leaky Abstractions it's a very good idea to learn to do this manually first.

How to create a C++ compatible function object in LUA?

I'm thinking about how to design my APIs, I plan to have a C++ application with a scripting layer in LUA .
For a couple of key points in my design I would like to give the ability to the user to create a function object that represents what he wants to do in LUA, than send this function object from LUA to C/C++ .
In pseudo code, in C++ I have a class T
class T {
...
int num1 = 0;
float num2 = 0.0f;
std::string str{"NONE"};
...
};
And I would like to manipulate an instance of T with a function object provided from LUA like so
void applyFunc(T t,F f){
f(t);
}
The problem is that I can't find nothing in LUA that creates a function object like a C++11 lambda or std::function or any other object that can be considered a function object.
Really my point is: how to define a C++ compatible function object in LUA ?
The problem is that I can't find nothing in LUA that creates a function object like a C++11 lambda or std::function or any other object that can be considered a function object.
That's what the function keyword does.
This is a lambda. It's easy enough to pass these to C++ and let the C++ code call them.
As for this:
void applyFunc(T t,F f){
f(t);
}
In principle it's easy: push the C++ object pointer onto the Lua stack as a userdata and call the Lua function. The problem is the Lua code can't do anything with a C++ pointer.
If you want the Lua code to be able to manipulate the object you pass it, you'll need to write manipulator methods in C++ and expose them to Lua. You usually do that by creating a metatable for the userdata.
There are libraries that this that automatically for C++. If you want to do it by hand (my preference), you should probably start here.
If you Google "C++ object Lua __index" that should net you numerous examples. I could code up an example later, but I'm at work at the moment.

Passing existing C++ objects to Lua and calling the passed objects' member functions

I'm working on a little simulation project which uses Lua to drive the behavior of individual units (ants) and using Luabind to glue the C++ and Lua sides together. Each individual ant (there are different types, derived from the base class Ant) has a Run() function, which calls the appropriate script; the script then carries out whatever actions need to be taken, calling the exposed class functions and possibly free functions. I've gotten the Run function (in C++) to successfully execute the matching Run function in the Lua script (which just prints some text at the moment).
void AntQueen::Run()
{
lua->GetObject("QueenRun")(GetID());
}
lua is just a manager class which retrieves the function from the script. The above is calling the following in a Lua file:
function QueenRun(ID)
print("The Queen is running!")
print(ID)
end
And Luabind registration looks like this for the AntQueen class:
void Register(lua_State *luaState)
{
using namespace luabind;
module(luaState)
[
class_<AntQueen, Ant>("AntQueen")
.def("Eat", &AntQueen::Eat)
.def("ExtractLarvae", &AntQueen::ExtractLarvae)
.def("GetMaxLarvaeProduced", &AntQueen::GetMaxLarvaeProduced)
.def("GetNumAvailLarvae", &AntQueen::GetNumAvailLarvae)
];
}
The way it's set up now, ants are created, removed, and found through a simple factory/manager. Each ant can be retrieved by calling static Ant* AntFactory::GetAntByID(const int ID) which just finds the ant in a hash map and returns a pointer to the ant. What I'm trying to do is get Lua to be able to do something like the following:
function QueenRun(ID)
ant = GetAntByID(ID)
larvae = ant:GetNumAvailLarvae()
print(larvae)
ant:Eat()
end
The above is just a made up example, but hopefully it shows what I'm trying to achieve. I don't want Lua to garbage collect the objects, because they are managed already on the C++ side. While testing everything out, any attempt to do the following:
ant = GetAntByID(ID)
in Lua resulted in abort() being called and the program crashing and burning.
R6010
-abort() has been called
I just seem to be missing something with how everything gets shuttled back and forth (this is my first foray into gluing Lua and C++ together beyond toy programs). I'm pretty sure passing a plain pointer isn't the way to do it; lightuserdata seems to be what I'm looking for, but it also has a bunch of restrictions.
So to sum up: What is going on here that causes abort to be called and how can I use Luabind/the Lua C API to get a pointer to a C++ object passed to Lua and call member functions on that pointer as if it were an object (without letting Lua garbage collect it)?
The solution to this problem seemed to be tied to the AntFactory class/member functions being static. As soon as I switched from registering and using this:
//C++
static int AntFactory::CreateAnt(foo, bar)
{}
//Lua
factory:CreateAnt(foo, bar)
to an instantiated object and regular member functions like this:
//C++
int AntFactory::CreateAnt(foo, bar)
{}
//Lua
factory:CreateAnt(foo, bar)
everything worked with no problems at all (after also pushing the factory to the global table). I think the reason for this is that trying to call static member functions on a non-instantiated C++ object fails due to Lua (or Luabind?) not being able to have an object to query for calls.

How would I go about sharing variables in a C++ class with Lua?

I'm fairly new to Lua, I've been working on trying to implement Lua scripting for logic in a Game Engine I'm putting together. I've had no trouble so far getting Lua up and running through the engine, and I'm able to call Lua functions from C and C functions from Lua.
The way the engine works now, each Object class contains a set of variables that the engine can quickly iterate over to draw or process for physics. While game objects all need to access and manipulate these variables in order for the Game Engine itself to see any changes, they are free to create their own variables, a Lua is exceedingly flexible about this so I don't forsee any issues.
Anyway, currently the Game Engine side of things are sitting in C land, and I really want them to stay there for performance reasons. So in an ideal world, when spawning a new game object, I'd need to be able to give Lua read/write access to this standard set of variables as part of the Lua object's base class, which its game logic could then proceed to run wild with.
So far, I'm keeping two separate tables of objects in place-- Lua spawns a new game object which adds itself to a numerically indexed global table of objects, and then proceeds to call a C++ function, which creates a new GameObject class and registers the Lua index (an int) with the class. So far so good, C++ functions can now see the Lua object and easily perform operations or call functions in Lua land using dostring.
What I need to do now is take the C++ variables, part of the GameObject class, and expose them to Lua, and this is where google is failing me. I've encountered a very nice method here which details the process using tags, but I've read that this method is deprecated in favor of metatables.
What is the ideal way to accomplish this? Is it worth the hassle of learning how to pass class definitions around using libBind or some equivalent method, or is there a simple way I can just register each variable (once, at spawn time) with the global lua object? What's the "current" best way to do this, as of Lua 5.1.4?
One approach is to use
a lightuserdata pointing to the C++ variable
a C function to access the C++ variable using the lightuserdata
keep the lightuserdata as an upvalue of the C function so one function suffices for all variables
use the number of arguments to the function to select between getting and setting the variable
For example:
int game_state_var_accessor (lua_State *L)
{
int *p = lua_topointer(L, lua_upvalueindex(1));
if (lua_gettop(L) == 0)
{ // stack empty, so get
lua_pushinteger(L, *p);
return 1;
}
else
{ // arg provided, so set
*p = lua_tointeger(L,1);
return 0;
}
}
When you make a new game state you can create accessors for each variable using:
lua_pushlightuserdata(L, (int *)p); // where p points to your variable
lua_pushcclosure(L, game_state_var_accessor, 1);
The accessor is now on the stack and can be bound to a global name, or to the name of a method in a Lua class. If your Lua class table is on the stack at index t this would be:
lua_setfield(L, t, "name_of_accessor");