I've been working on integrating Lua into War Worlds for programming the AI player and so far, it's been going really well. I've been using Luabind to help me bind C++ classes and methods to Lua tables and functions and it's mostly been really easy.
I've never really use Lua before about a week and a half ago when I started, but it's such a well-designed and logical language that I've managed to pick up quite a bit of it. I haven't really looked into some of the more advanced stuff, yet, though (like object inheritance, threads and so on) but maybe I'll look into that in the future...
But I hit my first major stumbling block yesterday when I was trying to define a method in C++ that returned an array of C++ objects to the Lua code (I'll give some more details of exactly what I'm doing in another post, perhaps). Without further ado, I'll give you an example of the function I was trying to expose to Lua:
struct find_options { /* ... */ };
class player
{
private:
std::vector<entity> findunits(find_options options);
};
Now let's say we want to expose this method to Lua. It took me a while to figure out the exact syntax, and I won't bother you will all the trouble I was having. Instead I'll just skip straight to the answer (it makes a lot of sense once you know how to do it, actually):
class player
{
private:
std::vector<entity> findunits(find_options options);
luabind::object lua_findunits(luabind::object options, lua_State *L);
public:
void init();
};
void player::init()
{
luabind::module(L)
[
luabind::class_<player>("player")
.def("findunits", &player::lua_findunits, luabind::raw(_3))
];
luabind::globals(L)["self"] = this;
}
luabind::object player::lua_findunits(luabind::object options, lua_State *L)
{
// create the response object - we'll populate it as an array
luabind::object result = luabind::maketable(L);
// do the "real" findunits
std::vector<entity> entities = findunits(find_options(options));
int index = 1;
BOOST_FOREACH(entity ent, entities)
{
result[index++] = entity_wrapper(ent);
}
return result;
}
And on the Lua side,
local units = self:findunits({ unit_type="factory" })
for _,u in ipairs(units) do
log.write(u:kind())
end
And that's it! Now, the important part is the use of luabind::raw(_3) on line 17. That instructs luabind to pass the lua_State as the third parameter (that's what the _3 means) - remember that the first parameter to member function is always the "this" pointer, and in this case the second parameter is our "options" parameter.
We need the lua_State because we want to return a new luabind::object (which we do in this case, so we can return an array to a Lua-managed set of objects).