I am currently working on my own videogame engine and I'm trying to implement support for lua scripts in order to code in game's behaviour. However, I'm currently struggling with C++ classes in Lua. I understand how to create a new instance of the class on heap by lua - but that's (probably) not what I want to do.
I rather need to pass an object that already exists in C++ into Lua and then work with it inside of the script. (Example: The engine has an instance of a monster and I'd like to run a script for the monster to see whether it sees the player - and if so, then the monster would attack the player).
The only solution I have found is this one: Passing existing C++ objects to Lua and calling the passed objects' member functions - however, the original poster is using luabind which requires boost (which I don't really want to use).
Thus, my questions are these:
How can I pass an object already allocated on heap in C++ to a Lua script? (without using luabind)
Is this approach even correct? Most of what I've found tends to answer the question "how to create an instance of a C++ class in Lua" rather than just passing it, which leads me to think whether is my idea even right or not.
Note: I do not mind using a tool such as luabind, I just don't want to use them in case they depend on external libraries such as boost. If there's any easy solution like this then I will gladly use it.
If you want truly independent binding, here is classic C-style boilerplate. Just replace "Object" with your class name and implement // { } blocks. Turning push_Object from static to public will give you universal existing Object pusher that also caches objects in metatable (otherwise multi-push would create many distinct userdata with all-obvious gc-trouble).
You may also C++ify or library-fy that if you want, but I personally do not do this, because adding e.g. __newindex-to-environment proxy and other quirks would not be so straightforward if it was library. Actually, all boilerplate is in push_mt, push_Object, forget_Object and check_Object, everything other is subject to fine-tuning.
Note that this only binds a single class, not all classes at once.
// { class Object { ... } }
static const char *tname = "Object";
static void push_Object(lua_State *L, Object *object);
static Object *check_Object(lua_State *L, int i);
static int
l_gc(lua_State *L)
{
Object **ud = luaL_checkudata(L, 1, tname);
if (*ud) {
// { delete *ud }
*ud = NULL;
}
return 0;
}
static int
l_tostring(lua_State *L)
{
Object **ud = luaL_checkudata(L, 1, tname);
lua_pushfstring(L, "%s: %p", tname, *ud);
return 1;
}
static int
l_new(lua_State *L)
{
Object *object = NULL; // { = new Object }
push_Object(L, object);
return 1;
}
static int
l_method(lua_State *L)
{
Object *object = check_Object(L, 1);
lua_Integer int_arg = luaL_checkinteger(L, 2);
const char *str_arg = luaL_checklstring(L, 3, NULL);
// { object->method(int_arg, str_arg) }
return 0;
}
static const luaL_Reg lib[] = {
// functions
{ "new", l_new }, // () -> object
// methods
{ "method", l_method }, // (object, int, string) -> none
{ NULL, NULL },
};
static lua_CFunction first_m = l_method;
static void
push_mt(lua_State *L)
{
if (luaL_newmetatable(L, tname)) {
size_t m = 0; while (first_m != lib[m].func) m++;
lua_createtable(L, 0, 0);
luaL_register(L, NULL, &lib[m]);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, l_tostring);
lua_setfield(L, -2, "__tostring");
lua_pushcfunction(L, l_gc);
lua_setfield(L, -2, "__gc");
lua_pushstring(L, tname);
lua_setfield(L, -2, "__metatable");
// mt.objects = setmetatable({ }, { __mode = "v" })
lua_createtable(L, 0, 0);
lua_createtable(L, 0, 1);
lua_pushstring(L, "v");
lua_setfield(L, -2, "__mode");
lua_setmetatable(L, -2);
lua_setfield(L, -2, "objects");
}
}
static void
push_Object(lua_State *L, Object *object)
{
int top = lua_gettop(L);
push_mt(L);
lua_getfield(L, -1, "objects");
// top+1 = mt
// top+2 = mt.objects
// ud = mt.objects[object]
lua_pushlightuserdata(L, object);
lua_gettable(L, top+2);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
Object **ud = lua_newuserdata(L, sizeof(*ud));
*ud = object;
// setmetatable(ud, mt)
lua_pushvalue(L, top+1);
lua_setmetatable(L, -2);
// mt.objects[object] = ud
lua_pushlightuserdata(L, object);
lua_pushvalue(L, -3);
lua_pushvalue(L, top+2);
}
// return ud
lua_replace(L, top+1);
lua_settop(L, top+1);
return; // ud at top
}
static void
forget_Object(lua_State *L, Object *object)
{
int top = lua_gettop(L);
push_mt(L);
lua_getfield(L, -1, "objects");
// top+1 = mt
// top+2 = mt.objects
// ud = mt.objects[object]
lua_pushlightuserdata(L, object);
lua_pushnil(L);
lua_settable(L, top+2);
lua_settop(L, top);
}
static Object *
check_Object(lua_State *L, int i)
{
Object **ud = luaL_checkudata(L, i, tname);
Object *object = *ud;
if (object == NULL)
luaL_error(L, "%s is finalized", tname);
return object;
}
int
luaopen_Object(lua_State *L)
{
push_mt(L); // register tname
lua_createtable(L, 0, sizeof(lib)-1);
luaL_register(L, NULL, lib);
return 1;
}
https://github.com/Rapptz/sol
Sol is the perfect example of a library that can support C++11+-like semantics, including the passing of class types using templates. If I were you, I'd look into Sol's source code and try to replicate its methods of object and data passing--much of Lua's "meta" functionality is probably build on its userdata structure, so I'd suggest you start looking there.
By the way, Sol is dependent on only Lua, and is header-inclusion only. It's quite possible to just use it out of the box, provided you're using Lua 5.2 (and not 5.3, which is a big gripe of the community but shouldn't matter, as LuaJIT is also on 5.2, I believe).
Most of what I've found tends to answer the question "how to create an instance of a C++ class in Lua" rather than just passing it, which leads me to think whether is my idea even right or not.
Those are answers to your problem, too. You can't create a C++ class in Lua. Any class construction is going to be done in the C++ code.
If you're not going to use a binding library, then you're going to need to be an export (no fear, it's not hard) on Lua's C API and metatables.
You expose the C++ object to Lua as a "userdata". You then supply a metatable with an __index metamethod which allows you to write C++ handlers for when the object is indexed, such as when a property is being accessed (e.g. pt.x) or when a method is being called (e.g. entity:attack(target)). You also need a __gc metamethod so you can delete the C++ object when the corresponding Lua userdata is garbage collected.
There can be quite a bit of boilerplate code, which is what many C++ binding libraries are supposed to take care of. I've never used one, so I can't recommend one. However, due to the Law of Leaky Abstractions, I would strongly recommend taking a stab at this on your own so that you understand how it works.
Related
I'm writing a Lua library in C++ that uses callbacks for certain functionalities. For testing I have 2 Lua functions, Register and Call. They are implemented in C++ like this:
int Lua_Register(lua_State* l){
int n = lua_gettop(l);
if(n==1){
if(lua_isfunction(l, -1)){
printf("Register\n")
lua_pushvalue(l, -1);
r = luaL_ref(l, LUA_REGISTRYINDEX);
}
}
return 1;
}
int Lua_Call(lua_State* l){
lua_rawseti(l, LUA_REGISTRYINDEX, r);
lua_call(l, 0, 0);
return 1;
}
and then in Lua:
Register(function()
Log("hi!")
end)
Call()
But all I see in the console is a lot of lines containing Register, followed by the message: C stack overflow. What I assume the problem is, is that I'm storing Register, rather than the anonymous function in the argument, which would create an infinite loop. How can I solve this?
Basically, You're trying to overwrite Lua registry with non-existant value instead of executing already set value.
What are You doing in short:
--calling Register()
lua_pushvalue(l, -1); -- now 2 copies of closure on top of stack
r = luaL_ref(l, LUA_REGISTRYINDEX); --one consumed, put into registry, 1 left
--calling Call()
--this C API call has got a new piece of stack
-- which does not contain that leftover of closure copy!
lua_rawseti(l, LUA_REGISTRYINDEX, r); --overwrite Lua registry entry with what?
lua_call(l, 0, 0); --What the heck are we calling now?
Thanks siffijoe and Etab Reisner for clarification about that new piece of stack.
What You should be doing:
I still don't really understand what actually are You trying to do, but in Your Lua code sample to execute properly (closure gets called by Call(), You should retrieve the closure before executing instead of overwriting with something which does not exist on top of the Lua stack. Something like this:
int Lua_Call(lua_State* l){
lua_rawgeti(l, LUA_REGISTRYINDEX, r); // <--- retrieve closure from registry!
lua_call(l, 0, 0); // <--- consider using lua_pcall()
return 0; // <--- the call does not leave anything useful on the stack.
}
NOTE: decide, which C API functions of Yours returns something, which ones does not. And change the return value to proper one.
Reference: luaL_ref(), lua_rawgeti(), lua_pcall() and misused lua_rawseti().
I want to how we can expose properties to lua library.
luaL_openlib( L, kName, kVTable, 1 ); // leave "library" on top of stack
With this, I am able to expose only functions as kVTable refers to luaL_Reg
typedef struct luaL_Reg {
const char *name;
lua_CFunction func;
} luaL_Reg;
Eg: With the above code. I can do following.
local myLib = require "plugin.myLib"
myLib.newFunc();
However, I want to expose Lua Table to the library as CONSTANTS variable.
myLib.CONSTANTS.SOME_CONST_1
myLib.CONSTANTS.SOME_CONST_2
etc. Please let me know how can I expose lua Table from my library as property.
As luaL_openlib leaves the library table on top on the stack, you can use regular C API to add new fields and subtables to it:
luaL_openlib( L, kName, kVTable, 1 ); // leaves "library" on top of stack
lua_pushstring(L, "CONSTANTS");
lua_newtable(L); // this will be CONSTANTS subtable
lua_pushstring(L, "SOME_CONST_1");
lua_pushnumber(L, 42); // SOME_CONST_1 value
lua_settable(L, -3); // sets SOME_CONST_1
lua_pushstring(L, "SOME_CONST_2");
lua_pushnumber(L, 12345); // SOME_CONST_2 value
lua_settable(L, -3); // sets SOME_CONST_2
lua_settable(L, -3); // sets CONSTANTS table as field of the library table
return 1;
If you use C++, you can use a binding library, such as the header-only luabridge to bind some data to named tables in Lua. Transforming your example into LuaBridge, call this function after you initialize your Lua state:
void register_constants (lua_State* L) {
luabridge::getGlobalNamespace(L)
.beginNamespace("myLib")
.beginNamespace("CONSTANTS")
.addVariable("SOME_CONST_1",&some_const_1,false/*read-only*/)
.addVariable("SOME_CONST_2",&some_const_2,false/*read-only*/)
.endNamespace()
.endNamespace()
;
}
...
lua_State* L=lua_open();
register_constants(L);
...
you can access the constants as your last code snippet
Caveat, lector, because Lua C API is, well, C API.
The whole burden with loadlib and friends was because functions are much harder to pass using C (C funcions aren't first class values). So my best bet would be to set all those constants using regular stack API.
In general, it is supposed to be used to exchange runtime data, of course, but there's no inherent reason why you shouldn't be able to fill your tables with that when loading the module.
I have some lua 'objects' that are wrappers to C++ objects, they hold a local reference to the c++ object and call it.
Now i want some functions in C++ return those wrappers, so i need to call this lua function and then set the C++ object on it.
I experience crashes and i suspect that i am not handling the lua stack right. For example, if i ask for lua_top before exiting a function that creates the wrapper + c++ object, i get 5 as result, shouldn't it be 1 if i return 1 object?
So here is what i do, maybe i am doing it wrong, maybe there is a better way to do this.
c++, .h:
#define gLuaGet(L, var, type) \
if (lua_istable(L, 1)) {\
lua_getfield(L, 1, "CObj");\
lua_replace(L, 1);\
}\
type& var = *(type*)lua_touserdata(L, 1);
#define gLuaCreate(L, type) new (lua_newuserdata(L, sizeof(type))) type();
class MyObject {
public:
MyObject();
int somefunc();
};
int MyObjectCreate(lua_State *L);
int MyObjectCallSomefunc(lua_State *L);
c++, .cpp:
int MyObject::somefunc() {
std::cerr << "in c++ function" << std::endl;
return 123;
}
int MyObjectCreate(lua_State *L) {
gLuaCreate(L, MyObject);
return 1;
}
int MyObjectCallSomefunc(lua_State *L) {
gLuaGet(L, obj, MyObject);
int r = obj.somefunc();
lua_checkstack(L, 1);
lua_pushnumber(L, r);
return 1;
}
lua wrapper:
function MyObject(donotinit)
self = {}
self.CObj = nil
if (donotinit == nil) then
self.CObj = MyObjectCreate()
end
self.setCObject = function(obj)
self.CObj = obj
end
self.somefunc = function()
return MyObjectCallSomeFunc(self)
end
return self
end
Now i want some other wrapper to return a MyObject that is created within c++, so here is the c++ code that is called from the new wrapper (for better readabiliy i removed the sanity checks on lua_pcall):
int returnLuaMyObject(lua_State *L) {
gLuaGet(L, obj, MyOtherObject);
MyObject *myObject = obj.getMyObject(); // get c++ part
lua_getglobal(L, "MyObject"); // create lua part
lua_pushnumber(L, 1); // and tell it not to initialize the self.CObj
lua_pcall(L, 1, 1, 0);
lua_getfield(L, -1, "setCObject"); // call the setCObject function
lua_pushlightuserdata(L, myObject); // give c++ object as param
lua_pcall(L, 1, 0, 0);
// at this point lua_gettop(L); returns 5, can this be correct?
return 1;
}
Well, if i call this function via a lua wrapper now a couple of times, everything seems fine, but if i call it lets say 50 times in a while loop, its crashing on random times (but always on the same c++ line)
Am i doing something wrong here? Is it OK for the lua stack top to be 5 at this point, where it only returns one object?
This is what your Lua stack will look like after each function/macro call, if I'm reading this correctly
int returnLuaMyObject(lua_State *L) {
// arg
gLuaGet(L, obj, MyOtherObject); // arg.CObj
MyObject *myObject = obj.getMyObject();
lua_getglobal(L, "MyObject"); // arg.CObj _G.MyObject
lua_pushnumber(L, 1); // arg.CObj _G.MyObject 1
lua_pcall(L, 1, 1, 0); // arg.CObj obj
lua_getfield(L, -1, "setCObject"); // arg.CObj obj obj.setCObject
lua_pushlightuserdata(L, myObject); // arg.CObj obj obj.setCObject myObject
lua_pcall(L, 1, 0, 0); // arg.CObj obj
// at this point lua_gettop(L); returns 2.
// If you end this function with return 1, only obj is returned
// to Lua, everything else is discarded.
return 1;
}
(For what it's worth, when writing Lua code I religiously put comments like that on every single line that messes with the Lua stack so I always know what I'm operating on. Once you memorize the side effects of Lua function it makes bug finding very easy)
This should be fine assuming that returnLuaMyObject is being called from Lua. If you're calling it in a loop in C++ your stack is going to get messed up since it's left with two things on the stack and some of your functions are hardcoded to operate on index 1.
A better way to do this is to do what Cubic suggested and use some templates rather than macros. You should also avoid using hardcoded indexes when possible so that you can reuse your functions in situations where the object you're interested in is in a difference spot on the stack. For example, your gLuaGet should take an index as an argument so that you can use it anywhere. (I'd also get rid of the obj argument and drop the entire last line of the macro, it makes it unclear where the the variable obj is being declared.
I wrote a library for myself (coincidentally called LuaWrapper, located here) which lets you do what you want without a lot of hassle. You can use luaW_to and luaW_push to push and get pointers from
Lua just like they were numbers or strings. I'm just throwing it out there because I like it better than the suggestion of Luabind or toLua++
The top of the stack in Lua is -1, not 1 (or lua_gettop(state)). Also, you should really use templates rather than macros for this. Or better yet, unless you have a reason not to, you could use luabind or tolua++. I'm currently writing something that works essentially the same as luabind, but uses C++11 features to drop the boost dependency, although it's nowhere near completion yet.
I want to make something like this:
1. Create object in Lua
2. Get this object to C++
3. Perform some method on this object passing it from C++
Now I have this in Lua:
Account = {balance = 0}
function Account.Create(name)
local a = Account:new(nil, name);
return a;
end
function Account:new (o, name)
o = o or {name=name}
setmetatable(o, self)
self.__index = self
return o
end
function Account:Info ()
return self.name;
end
Code in C++
//get Lua object
lua_getglobal (L, "Account");
lua_pushstring(L, "Create");
lua_gettable(L, -2);
lua_pushstring(L, "SomeName");
lua_pcall(L, 1, 1, 0);
const void* pointer = lua_topointer(L, -1);
lua_pop(L, 3);
//then I want to perform some method on object
lua_getglobal (L, "Account");
lua_pushstring(L, "Info");
lua_gettable(L, -2);
lua_pushlightuserdata(L,(void*) pointer );
lua_pcall(L, 0, 1, 0);
//NOW I GET "attempt to index local 'self' (a userdata value)'
const char* str = lua_tostring(L, -1);
...etc...
Do you what I made wrong ? How can I get this Lua object to C++ ?
const void* pointer = lua_topointer(L, -1);
Lua tables are not C objects. They're not void*s. The lua_topointer documentation says that the function is mainly for debugging purposes. You're not debugging anything.
Lua tables can only be accessed through the Lua API. You can't just get a pointer to a Lua table or something. Instead, what you need to do is store the Lua table in a place, and then retrieve it from that location when you want to access it. The typical place for storing this sort of data is the Lua registry. It's inaccessible from Lua code; only the C-API can talk to it.
Generally, you'll have some table stored in the registry that contains all of the Lua values that you are currently holding. That way, your use of the registry won't bash someone else's use of it.
I have a class called Entity, which has many functions like onPickup, onDrop, onUse etc. What I want to do is, write a script that defines all of these functions and make them callable from the C++ functions. So the functions defined in C++ would just be calling their corresponding Lua functions that have some functionality.
But here's the problem, I want every script that I write, for every Entity in the program to be working in it's own scope.
I'm using LuaBind, and I have no prior experience with Lua, so I'm a little lost here.
I don't use lua bind but this may help. The idea is to register the lua functions in your C++ class and keep a reference to the lua function in your C++ class.
To define a lua function that is callable from C/C++ I use luaL_ref to store a reference to the callback function in my C++ object.
// a little helper function
template <typename T>
T *Lua_getUserData(lua_State *L) {
assert(lua_isuserdata(L, 1) == 1);
T **v = (T **) lua_touserdata(L, 1);
assert(v != NULL);
return *v;
}
int lua_FormRegisterMethods(lua_State *L) {
Entity *f = Lua_getUserData<Entity>(L);
assert(lua_istable(L, 2) == 1); // check the next parameter is a table
lua_pushvalue(L,2); // dup the table
f->LuaTable = luaL_ref(L, LUA_REGISTRYINDEX); // keep a reference to the table
lua_getmetatable(L, 2); // get the metatable
lua_pushstring(L, "OnClick");
lua_rawget(L, -2); // get the OnClick Lua Function
f->LuaMethod = luaL_ref(L, LUA_REGISTRYINDEX); // save a reference to it
return 0;
}
and then you can get the lua method in your C++ event
lua_rawgeti( LuaInstance->L, LUA_REGISTRYINDEX, LuaMethod );
assert(lua_isfunction(LuaInstance->L, -1) == 1);
now you can call this function with self set to the table you saved earlier. hth
You can call a Lua function with, e.g.
int callLuaFunction(lua_State* lua_state) {
return luabind::call_function<int>(lua_state, "myluafunction", param1);
}
if the Lua function returns an int and takes 1 parameter.
I'm pretty sure you can make as many lua_State's as you want. Just pass the correct one for the entity into call_function.
To fully implement this the way you will probably want to will require digging around a bit in some of the more esoteric bits of Lua. It is well worth the time though. I'll show a very trimmed down version of how I have handled this. Be warned, there are a lot of little bits all working together here - mainly saving and calling saved functions and using c++ objects as Lua user data.
First we need a c++ class which will store events handlers (lua functions) as lua references which are simple ints. I am using an array here but you could use whatever makes sense. The main thing happening here is that you want to be able to call a lua function which is referred to by the int reference.
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include <string>
#include <iostream>
#include <assert.h>
using namespace std;
enum enum_event_types {
ON_USE, ON_DROP, ON_WHATEVER, EVENT_COUNT
};
class Entity {
private:
int events[EVENT_COUNT];
public:
lua_State* lua;
void setEventHandler(int event, int ref) {
assert(event < EVENT_COUNT);
events[event] = ref;
}
void callEventHandler(int event) {
int error;
assert(event < EVENT_COUNT);
// to call the function we need to get it from the registry index
lua_rawgeti(lua, LUA_REGISTRYINDEX, events[event]);
error = lua_pcall(lua, 0, 0, 0); // use protected call for errors
if (error) {
printf("error: %s", lua_tostring(lua, -1));
lua_pop(lua, 1);
}
}
};
Now you want to expose your Entity class to Lua. If you are not familiar with how this is done there is a good article here. Essentially what is going on is that we are setting the user data returned from Entity.new() to a pointer to a pointer. This is so Lua does not garbage collect your object. Then create a meta table for "Entity" which will
hold all of the methods exposed to Lua.
int L_newEntity(lua_State* L) {
Entity **e = (Entity **)lua_newuserdata(L, sizeof(Entity *));
*e = new Entity();
(*e)->lua = L;
lua_getglobal(L, "Entity");
lua_setmetatable(L, -2);
return 1;
}
int L_setOnUse(lua_State* L) {
Entity** e = (Entity**) lua_touserdata(L, 1);
lua_pushvalue(L, 2);
int ref = luaL_ref(L, LUA_REGISTRYINDEX);
(*e)->setEventHandler(ON_USE, ref);
return 0;
}
// this will be exposed to Lua as a table called Entity
static const luaL_Reg L_entityMethods[] = {
{"new", L_newEntity},{"setOnUse", L_setOnUse},{NULL, NULL}
};
Now set up the Lua state and create the Entity table and create a test. The test will create an Entity and set its event handler to a Lua function passed to it. Finally test that the Lua function is being called by the c++ object.
int main() {
Entity** e;
int error;
lua_State* L=lua_open();
luaL_openlibs(L);
luaL_register(L, "Entity", L_entityMethods);
lua_pushvalue(L,-1);
lua_setfield(L, -2, "__index");
lua_pop(L, 1);
luaL_loadstring(L,
"e = Entity.new(); "
"e:setOnUse(function()"
" print('Some of them want to use you')"
"end);");
error = lua_pcall(L, 0, 0, 0);
if (error) {
printf("error: %s", lua_tostring(L, -1));
lua_pop(L, 1); /* errors must be popped from stack */
}
lua_getglobal(L, "e");
if (lua_isuserdata(L, 1)) {
e = (Entity**) lua_touserdata(L, 1);
(*e)->callEventHandler(ON_USE);
}
return 0;
}
This is far from complete. First of all if you ever need to set an event handler twice you will need to use luaL_unref to clear out the old reference first. Second you will probably want to pass some data about the event which occurred to the event handler. The current event handler does not take any data so gives the user of the api very little to go on. It should probably at least pass a reference to the object which is calling the event. This can be used to create very powerful and usable Apis in Lua. Good luck!