Luabind and the "raw" policy

Posted by

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).

blog comments powered by Disqus