A simple method of interfacing cipher and lua
Overview
Author: bane
Date Submitted: 2004-07-07 20:57:11
Downloads: lua_interface.zip
Source Code
Screenshot

Description
Lua (http://www.lua.org) is a wonderful very small, very portable, very extensible, and very simple yet powerful scripting/data description/anything language that I'm using to great success in my own cipher project. By exposing engine functions and my own game functions, I can use Lua to drive just about any aspect of my project if I think it will be more convenient/efficient/whatever to do so. I thought I'd share the basic core of my C++ interface to the Lua API with you guys.
Include the two files in the attached zip file into your project, and link up with and include the headers of your local Lua installation (check out http://lua-users.org for windows binary distributions). You now have a simple but effective streams-based interface to the lua interpreter. If you use this in conjunction with some of the STL cipher streams I contributed earlier, you can do all sorts of things seamlessly - like run lua scripts residing within your pak file, or redirect the interpreter's output to the cipher console (this will require a little manual modification to lua's built-in library, so that the print function uses stl streams).
The following is an example of how you can use this together with my stl console stream contribution to make the cipher console an interactive lua scripting prompt. Just open and setup a new lua state using the interface provided by the attached files (the source is fairly well commented), then place something like the following in your console command handling function:
bool cg_ConsoleCommand( void )
{
static bool in_lua_prompt = false;
// see what the command is
wstring command = cmd_Argv(0);
if (in_lua_prompt && command == _T("exit_lua")) {
in_lua_prompt = false;
cphrout << "END LUA PROMPT" << endl;
return true;
}
// If we're in the lua prompt, interpret this command as
// a lua chunk
if (in_lua_prompt) {
wstring line = cmd_Args();
wstring s(command+_T(" ")+line);
string luacommand(s.begin(), s.end());
lua::run_stream(myLuaStateHandle, "console",
istringstream(luacommand), cphrout, cphrout);
}
else if (command == _T("enter_lua")) {
in_lua_prompt = true;
cphrout << "BEGIN LUA PROMPT" << endl;
}
else {
// Your regular command-handling code here
}
return true;
}
Now just run "enter_lua" at the cipher console prompt, and you're in business. "exit_lua" leaves the interpreter. Note that some commands which are handled by the engine before they get passed to your game code (e.g., "quit") get handled regardless of whether you're in the lua prompt. So don't define and try to use a lua function called "quit" :) .
From here you can start binding your own functions into lua, as well as wrapping the cipher engine with a lua interface. I use luabind (http://luabind.sf.net) for all that (and the attached interface has a luabind-related function that you may want to comment out if you don't use it), but there are various other tools around.
Good luck, and please let me know if you notice anything wrong with my code!
[Recent Contributions] [Recent Source Code]
User Contributed Comments
rikh 8th July, 2004 12:11
Great add-in. LUA is such a nice simple language.
Pickles 8th July, 2004 17:54
Thanks for these excellent contributions lately bane. They're totally useful and practical. I'm sure much of the community appreciates it. I know I do.
I was wondering, do you have an example of this using your ipakstream code to read a script file from the pak folder?
Also, how would you implement it to run? Would you make it process a single line of the lua script per frame or would you make it process the whole script per frame?
Thanks again.
JiuQ 8th July, 2004 19:04
Excellent stuff Bane, and nicely timed, since the Lua folks just released a free, online version of Programming In Lua, the best source of info on Lua :)
You can find it here : http://www.lua.org/pil/
And if you can, buy a paper copy :)
Edited 8th July, 2004 19:04
bane 8th July, 2004 19:25
Pickles - thanks for the kind word :)
Here's an example of how I setup my lua interpreter then run an init script during my game's initialization.
// Lua Setup
LOG(DEBUG, "Initializing Lua.");
EmporiaGlobals.luaState = lua::open_state(); // This is what i'll use to refer to this instance of the interpreter
lua::load_lualibs(EmporiaGlobals.luaState); // loads lua's standard libraries
lua::load_luabind(EmporiaGlobals.luaState); // initialize luabind (you might choose to use something else, though)
add_bindings(EmporiaGlobals.luaState); // this is my function which makes lua aware of whatever I want (e.g., cipher engine functions, my game stuff) through luabind
// Run main_init.lua
ipakstream main_init(_T("scripts/main_init.lua"));
lua::run_stream(EmporiaGlobals.luaState, "main_init.lua", main_init, cphrout, cphrout);
// So you see, you just send the ipakstream directly to the run_stream (or load_chunk) function. It will accept any wide input stream
To answer your second question... Here's what I do. Load all the scripts you'll need before hand using lua::load_chunk, and save the resulting chunk handles somewhere (that is, load the whole script file). This doesn't actually RUN the scripts, it just reads them in, and essentially creates a function within lua that, when executed, runs the contents of that script. Then, while processing each frame, run whichever of these chunks you need to.
But say you don't want to run one of the entire chunks every frame, just one of the functions defined within it. Then you just run the chunk once so that the function gets defined, then during each frame you can call just that lua function (either through the Lua C API or through Luabind or whatever).
Basically you have a whole lot of options on how and when to run your scripts and parts of your scripts. This is just how I do it. But running a single line per frame definitely wouldn't work. First of all, it's unnecessary, since Lua is VERY fast. Second, I assume by one line you mean one lua statement. Lua's syntax is very free so one line does not correspond to one statement - it would be very difficult and senseless to write (or cannibalize) a lexer to figure out the next complete syntactic chunk of lua script.
Hopefully this makes things clearer (I probably should have include this source example in the submission).
[Edit to Add: It would probably help a lot if you take a look at the reference manual on lua.org, especially the section on the C API and what exactly a "chunk" of lua code is.]
Edited 8th July, 2004 19:28
bane 8th July, 2004 19:30
JiuQ - Thanks, and yeah I just noticed yesterday that it's free online now. Pretty sweet - I was surprised at how well it's written.
seryu 8th July, 2004 20:30
nice code, ill try it :D
Pickles 8th July, 2004 22:53
Thanks again bane! That is great info!
mmelo 12th July, 2004 15:45
@Bane: you are using luabind? I played around with it a couple of months back, but since I needed threads I had to be in the head version which seemed to be irredimably broken all the time. I also found that debugging through those Boost template calls was nigh-on impossible.
I have since moved on to LuaPlus and find I am immensely more productive. While the interface is nowhere as neat as luabind (in a geeky OO sort of way) I just seem to be able to get things done for a change ;-)
Register and Sign In to discuss this article Copyright (c) 2003-2009 MBC Entertainment. All rights reserved
cipherengine.com and the Cipher game engine are wholly owned by MBC Entertainment.
All trademarks are the property of their respective owners.