During my work on GunPunks, I have created a class that wraps Lua, called LuaScript. While many many of such libraries exist, I find my class unique because it is simple. It doesn't add unnecessary things like trying to automatically wrap exact C++ interfaces or create a fake object-oriented environment inside Lua. It merely wraps all of the tedious Lua code that one has to write to embed Lua. I think that Lua could be used as an alternative to USL, since the scripting system in Globulation 2 allows the use of different languages (although the menu's do not yet allow for this, this can be easily changed).
I'm willing to take a break from my work on GunPunks to implement Lua scripting in Globulation 2 as an alternative to USL, but leaving USL as the default and de-facto language, if people agree with this decision.
The class I have created for GunPunks merely loads a lua script file, and allows for C++ tie ins by calling functions like this:
When Lua calls a function registered in C++, it calls T::recieveLuaFunctionCall(const std::string& name, std::vector<boost::any>& arguments, LuaScript* script) with the given object.
boost::any is used extensively in the interface to allow for easy
interoperability, although at the expense of type safety, but type safety
goes out the window when you deal with scripts anyhow. The Lua system does make sure that the arguments passed into C++
functions have the correct types (the ones given as template parameters
to the registerFunctionCall functions), so its not really lacking
type safety. There is a version of registerFunctionCall that simply
registers a function leaving it up to the user code to make sure the
number and types of arguments are correct. This is particularly useful
for functions that can accept different types.
The documentation specifies what values are acceptable and unacceptable for the boost::any values when calling Lua code from C++. Currently, you can send all of your basic POD typed to lua (int, unsigned int, long, unsigned char and all variations), as well as char* strings and std::string strings. I haven't found any need for more then this. You can register custom types (pointers only) via the following function:
This allows the Lua code to be able to handle custom types. In terms of what Lua returns from functions ( or gives as function arguments when called C++ code ), Lua only has a few native types, so it sends either bool, std::string, or float inside the boost::any (or the custom registered pointers), and this is also specified in the documentation.
Some people I have talked to suggested using boost::variant rather then boost::any, however this would not allow arbitrary user types to be added into the system.
I'm currently working on adding the ability to put the functions into modules, so you call them inside Lua like "GUI.runMessageBox" rather then compounding it into one function name like "gui_runMessageBox", along with various efficieny improvements, so the interface I discussed here is likely to be expanded somewhat.
The current convention is for every class that wants to interact with lua, it has a function called void prepareLuaForAccess(LuaScript& script), which calls all of the registerFunctionCall and setGlobalValues that it needs to, however this isn't a detail of the LuaScript class, just a convention I've been using in my own code.
In my experience, this class has been extremely useful. It was among the first things I created for Gun Punks, and it makes it very simple and direct to wrap Lua Scripts. You specifiy what functions are in the interface, and you add the code to responds to them. No troubling lua code or strange interfaces caused by things like tolua++.
-- Extra cheese comes at a cost. Bradley Arsenault.