Manipulate C++ classes in Lua

Started by
8 comments, last by Matthew Shockley 13 years, 12 months ago
I'm working on a game engine which so far has been coming out great. I'm currently in the process of adding scripting with lua, and I was able to send simple stuff like functions to lua. well heres the situation: my engine uses 'managers', like WorldManager,ObjectManager,ItemManager, etc. I want to be able to access all the members in all of the managers so that I can add objects, items, npcs, and everything else I need from a lua script. I've done quite a bit of googling and I came across a couple of pages that said you couldn't send whole classes, so this probably means that you can only send tables with members values, but I'm no lua expert so I might be wrong. Basically what I'm asking for is a way to send classes to lua so I can, for example, do something similar to:

--hello.lua
npc = NPCManager.addNPC("Alex");
npc.x+=3;
and get the same result as if I were to hard code it into my program
Advertisement
You'll need to use a binding library like LuaBind or MLuabind, which will create the Lua side wrappers for you. Then you can write the code just like you're example.

Here's the page for binding libraries available to Lua.

http://lua-users.org/wiki/BindingCodeToLua

You'll be interested in the C++ binding libraries, look for one 5.1 compatible.

I've used MLuabind and it works well enough for me.

Enjoy!

-ddn
Theres got to be a way to do it without a library.

I'd rather do it the hard way and learn since it will be better in the long run
Quote:Original post by grumpymonkey
Theres got to be a way to do it without a library.

I'd rather do it the hard way and learn since it will be better in the long run

As noted in the previous link, you can use the Lua C API... however, aside from learning purposes, there usually isn't a reason to avoid the prebuilt libraries such as LuaBind. Not only are they better written than you're likely to do yourself, but they've also had a lot more error and bug checking than your code will have.

In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.

Quote:Original post by grumpymonkey
Theres got to be a way to do it without a library.


I'd suggest taking a look at this article: Wrapping C++ classes in Lua. It covers over most of the basics for this task. It even shows some simple error checking you need to be aware of while doing it yourself.

You should also reference the official Lua Documentation for additional information concerning the use of metatables, garbage collection mechanics, and so on, but that article should be enough to get you started.

Once you get the basics down, you should be able to look at the source code of the libraries that already do this for you (ddn3 mentioned a link to them) to check against anything you might not have known about and need to account for in your own code. Then, you can decide if it'd be more practical to just use one of them for your project rather than doing it all yourself.

Good luck!
I recommend to use a library.

I've used tolua++ ( http://www.codenix.com/~tolua/ ) with great success. It's really quite simple.
There really isn't much to binding objects to Lua. Lua supports light and heavy user data types (which are just raw ptr data) which can be pushed onto the Lua stack. These objects are usually some native application specific object. They are tag with some type data so they can be upcast when passed into C function callbacks.

You create a series of Lua objects which have the same interface as your native
types and they hold references to the user data and call the appropriate native C function with appropriate user data passed in to operate on the C/C++ side.

It's alot of bean counting to keep track of all these types and creating the mirror Lua interface to the C/C++ objects. That's what most of these binding libraries do for you really, with some performance loss as they try to be generic as possible.

-ddn
Quote:Original post by ddn3,

...with some performance loss as they try to be generic as possible.

-ddn

It is not as simple as that. For example the hand rolled code from Game Programming Gems 6, written by one of the language creators, which does not use lightuserdata was the first piece of code which I profiled OOLua against. I found this to be pointless as the library blew it out of the water as did Luabind, this is why the profiling solution no longer is tested against it.
The main method of doing this is by only touching the Lua API when it is required.
As you can imagine it really depends on how you write your hand rolled code taking into account also the points stated by Washu of how long it takes to write this code and confirm it's trueness.

To the OP, any of the binding listed on the page will provide a method to complete your code listing although the syntax may differ slighty. One thing you will not be able to do in Lua, which is a personal pet hate of the language is use "+=" :(


Lua metatables are the closest thing Lua has to classes. They have basic operators, member variables, member functions, and member methods.

local ud = newproxy(true) -- Userdata is almost same as tablegetmetatable(ud).private = {Name = "Example", Value = 5}getmetatable(ud).__index = function(ud, ind) if rawget(getmetatable(ud).public, ind) then return getmetatable(ud).public[ind] else error("No member named " .. ind) end endgetmetatable(ud).__newindex = function(ud, ind, val) if ud[ind] and val ~= nil then getmetatable(ud).public[ind] = val end endgetmetatable(ud).__tostring = function(ud) return ud.Name endgetmetatable(ud).__eq = function(ud1, ud2) return ud1.Name == ud2.Name end


Google Lua metatables.
If I asked you for a hundred dollars would the answer to that question be the same as the answer to this question?
Opps, typo. Sorry:

local ud = newproxy(true) -- Userdata is almost same as tablegetmetatable(ud).public = {Name = "Example", Value = 5}getmetatable(ud).__index = function(ud, ind) if rawget(getmetatable(ud).public, ind) then return getmetatable(ud).public[ind] else error("No member named " .. ind) end endgetmetatable(ud).__newindex = function(ud, ind, val) if ud[ind] and val ~= nil then getmetatable(ud).public[ind] = val end endgetmetatable(ud).__tostring = function(ud) return ud.Name endgetmetatable(ud).__eq = function(ud1, ud2) return ud1.Name == ud2.Name end
If I asked you for a hundred dollars would the answer to that question be the same as the answer to this question?

This topic is closed to new replies.

Advertisement