Sign in to follow this  
grumpymonkey

Manipulate C++ classes in Lua

Recommended Posts

grumpymonkey    126
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

Share this post


Link to post
Share on other sites
ddn3    1610
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

Share this post


Link to post
Share on other sites
Washu    7829
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.

Share this post


Link to post
Share on other sites
Drew_Benton    1861
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!

Share this post


Link to post
Share on other sites
ddn3    1610
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

Share this post


Link to post
Share on other sites
dmail    116
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 "+=" :(


Share this post


Link to post
Share on other sites
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 table
getmetatable(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 end
getmetatable(ud).__newindex = function(ud, ind, val) if ud[ind] and val ~= nil then getmetatable(ud).public[ind] = val end end
getmetatable(ud).__tostring = function(ud) return ud.Name end
getmetatable(ud).__eq = function(ud1, ud2) return ud1.Name == ud2.Name end


Google Lua metatables.

Share this post


Link to post
Share on other sites
Opps, typo. Sorry:

local ud = newproxy(true) -- Userdata is almost same as table
getmetatable(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 end
getmetatable(ud).__newindex = function(ud, ind, val) if ud[ind] and val ~= nil then getmetatable(ud).public[ind] = val end end
getmetatable(ud).__tostring = function(ud) return ud.Name end
getmetatable(ud).__eq = function(ud1, ud2) return ud1.Name == ud2.Name end

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this