|
How to Use Lua 5.1 with the Dreamcast / KOS
Lua is perhaps the second-most miraculous discovery I've ever made in my life (the first was my wife). The fact that such a simple, powerful, easily-integratable and free scripting language exists is enough to alter a man's faith. If you don't think Lua is that great, then you probably don't know enough about it yet.
What's great about the Lua authors is that they've already given you everything you need, and I mean they just gave it to you, source code included. Besides the requirement to give Lua its props in your finished product, you can use Lua for whatever you want and even sell products containing Lua commercially.
The best part about Lua is you can just drop it into the vast majority of projects and it will compile instantly. From that point on you'll have all the portability and control advantages of working in C++, while still having access to a lightning fast scripting language.
The second great thing about Lua is the core basis of the language, like C, is very simple. Thus most functionality is gained by creating libraries for Lua. Since these libraries can be written in C, you can turn Lua into a language that will do anything you want it to.
KallistiOS and Lua 5.1
This article assumes you know how to do stuff with the Dreamcast. If you don't, the DC Dev ISO R3 is one hell of a place to start.
Assuming you know how to do make Dreamcast stuff compile, your first stop is Lua.org to download the programming language itself (and maybe purchase the wonderfully written yet dirt-cheap "Programming in Lua, Second Edition" and "Lua 5.1 Reference Manual" while you're there). IIRC Lua comes not just with the source but also some pre-compiled interpretors. If you're comfortable with C++ and are trying to add Lua as a scripting language for a Dreamcast project (and if not why would you be reading this?) just download the source and ignore the included sample scripts - for now.
Setting up the Tutorial
-
Create a new root directory for your project.
-
Download the tutoial c file "main.c" and put it in the root of the directory.
-
Download the lua script file "luascript.lua" and put it in the root of the directory.
-
Create a sub-directory within that directory called "Lua" and put all of Lua's source-files there.
-
Open up main.c. Line 152 changes the current directory (from the Dreamcast's perspective) to where the luascript file lives. You may need to change this to get the sample to work in your set-up. Google "+Dreamcast +fs_chdir" for more info if you get stuck.
-
Open up the Lua source file "lauxlib.c" and find this code:
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { (void)ud; (void)osize; if (nsize == 0) { free(ptr); return NULL; } else return realloc(ptr, nsize); }
Replace it with this code:
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { (void)ud; (void)osize; if (nsize == 0) { if (osize != 0) { free(ptr); } return NULL; } else { if (osize != 0) { return realloc(ptr, nsize); } else { return malloc(nsize);
} } }
Explanation of that one change
It turns out KOS has a small bug in it's free() function. The KOS guys might even tell you it's a bug in how Lua is calling free().
The Lua author's wisely choose to make Lua allocate and deallocate all of it's memory through one single function the user could easily change. That function is called l_alloc and it's what you need to change to make Lua work for the Dreamcast.
The l_alloc parameter "osize" means "original size" and "nsize" is new size. The idea is that if nsize=0 you need to free the memory and otherwise you're going to allocate new memory (if osize=0) or re-allocate exisiting memory to a bigger chunk.
Well, the first thing you have to do with Lua is create a lua_state object, and this object makes a few dozen calls all over the place eventually calling the l_alloc function where nsize=0 and osize=0. This is saying "call a free even though the size of what you're freeing is equal to zero," which really doesn't make that much sense.
KOS apparently interrprets it this way as well and thus hangs when free is called at this time. I'm not sure if the pointer (the parm "ptr") is bad or if Lua actually did want to free something that was somehow zero bytes but either way KOS won't have it and I can't blame it.
It's a little unnerving but the solution is to simply do nothing if nsize=0 and osize= 0. As far as I know there are no negative side-effects of doing this.
Explanation of Main.c
I've tried to keep this sample as short as possible. This code contains the only stuff I would have cared about seeing when I started to learn about Lua. It shows you how to create a single function that can be called from Lua - in this case the "Write" function which is a simple wrapper for printf(), and goes through the rigamorough of registering that function with Lua and showing how to "feed" Lua a file.
One flaw in this sample is that if it encounters a bad lua script, it crashes! I have no idea why this occurs and only discovered it when I was finishing up this tutorial. My own work with Lua cross-compiles to the PC and the method displayed here of checking the error code returned by lua_load works fine; normally, Lua will kindly show you the error of the script you're loading and not crash your program, which is incredibly useful. I have no idea why lua_load does not work here but it looks like it will be another fun error for someone to find the answer to.
* See update below.
For more fun, here's a second very simple Lua script.
If you want to know more you should seriously consider buying the two books listed on Lua's homepage. The reference manual is required if you're going to be serious about plugging Lua into your game, and "Programming in Lua 2nd Edition" is one of the clearest, most-concise texts I've ever read. The only problem with the later is it waits until the very end of the book to tell you about how to plug Lua into C, but I suggest that, since this tutorial shows you it can be done, you just take the time to read through the Lua book and gain a solid understanding of how the language works. Keep in mind you're basically going to have to make your own Lua libraries, so it would help to have a firm grasp of the language going in. And did I mention both books were cheap?
* Update
Sorry for appending this to the tutorial so late, but I only recently realized people were actually viewing it.
Thanks to BlackAura on the Dcemulation.com forums for finding the fix to the issue struck-out above.
Lua will correctly report script errors if you make another small change in the file "luaconf.h". Find this code:
#if defined(__cplusplus)
/* C++ exceptions */
#define LUAI_THROW(L,c) throw(c)
#define LUAI_TRY(L,c,a) try { a } catch(...) \
{ if ((c)->status == 0) (c)->status = -1; }
#define luai_jmpbuf int /* dummy variable */
#elif defined(LUA_USE_ULONGJMP)
/* in Unix, try _longjmp/_setjmp (more efficient) */
#define LUAI_THROW(L,c) _longjmp((c)->b, 1)
#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a }
#define luai_jmpbuf jmp_buf
#else
/* default handling with long jumps */
#define LUAI_THROW(L,c) longjmp((c)->b, 1)
#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a }
#define luai_jmpbuf jmp_buf
#endif
Change the "#if defined(__cplusplus)" to something like "#if defined(DONOTWANT__cplusplus)" (the point being that "DONOTWANT_cplusplus" is not defined).
This seems to allow Lua to handle scripts with errors (as well as other issues most likely) without problems.
-All material © 2007 Tim Simpson unless otherwise noted-
|