Lua for MUD development was Re: [vworld-tech] Modern MUD server design

Brian Hook hook_l at pyrogon.com
Fri Feb 20 11:37:57 PST 2004


First off, Jason Clow started work on a generic MUD server written in 
Lua a while ago, but I think he lost interest: 

http://lune.sourceforge.net/

Lua is a very dynamic language, and this is both good and bad.  I 
wrote up some general notes on scripting in games you can read here 
(feedback welcome and appreciated, send it directly to me):

http://www.bookofhook.com/Article/GameDevelopment/TheSecretLifeofGameS
cript.html

As mentioned here before, along with Pike and Lua, it sounds like 
JavaScript is a reasonable language as well (and Ruby and I'm sure a 
couple others, but I don't have experience with those).

Lua does not have user defined types, i.e. there are no "class" 
declarations a la C++, Java or Pike.  It's prototype based like 
JavaScript or Self, which means that you "derive" from another object 
by simply copying that object and adding new properties.

The fundamental type for most things in Lua is the table 
(dictionary/map/hash/associative array, whatever you want to call it). 
 You never have to declare variables, they're automatically created on 
use, same with properties.

f = {} -- new table
f[ "name" ] = "Dave"
print( f.name ) -- will print "Dave"

Something like:

foo.bar

Is syntactic sugar for:

foo[ "bar" ]

Lua uses a mark-and-sweep GC -- this means it can have hiccups, but 
5.1 is supposed to have an incremental GC incorporated.  Even so, many 
games use Lua successfully once they work around its hiccups.

Lua is small and very fast, however in many situations Pike is much 
faster.  Lua has a thriving community, and the language is trivial to 
embed (although I'm coming around to believing that writing everything 
in the script language and calling to C occasionally is preferable).

Calling Lua from C and C to Lua is very easy.  It's 100% ANSI C/C++ 
(it's C code, but it can be safely compiled as C++), and works on a 
ton of different platforms.

Over time I'm slowly migrating more and more stuff out of C/C++ and 
into Lua, primarily to minimize the amount of cross-talk between both 
sides.  For example, I just migrated all my database functionality out 
of C++ and into Lua, so whereas my Lua code used to trap into the 
kernel, e.g.:

pinfo = TRAP_getPlayerInfo( player_id ) -- call into C/C++

I now execute the queries in script.  It only took an hour or so to 
write the necessary wrappers around libpq.

The syntax is reasonably friendly, but I don't consider it as friendly 
as some Lua advocates do =)

There are many support libraries, however not nearly as much as Pike 
or Python or Ruby.  But if you just need SQL and sockets and basic 
things like that, those are all available.

The basic types are number (64-bit double), string, thread, function 
and userdata.  That's right, there are no integers, and don't even 
think about doing bit operations.

To dynamically load code, you just call loadfile() or loadstring() in 
Lua.  In fact, a common technique when you want to do something 
complex but don't want to write a function for it is to just put the 
code you'd normally execute into a string and execute it.

For example, say you want to get the function "A.B.C.foo" so you can 
bind it to a local function, but you don't know the specific function 
is going to be so it's a string.

function get_member( string )
  ...
end

You could parse the string, separated by periods, and descend into 
tables, kind of like this in pseudo code:

e = get_next_element( string )
t = _G[ e ] -- look up in _G, which is global env
while ( e = get_next_element( string ) ) ~= nil then
   t = t[ e ] -- look for t.e and make it current
end
return t

But then you're writing a parser, etc.  (Granted, trivial to do with 
regex, speaking of which, Lua does not come with stock POSIX regex out 
of the box, but there is an optional POSIX regex lib you can use).

Instead of doing all that, it would be nice if given a string you 
could just ask Lua to return that value, something like:

function get_member( string )
   return evaluate( string  );
end

And, in fact, you can do just that by simply:

function get_member( string )
   return loadstring( "return " .. string )()
end

loadstring returns a function that will evaluate that string, so you 
evaluate the return value.  You can then do a lot of complex crap 
without having to write a bunch of little miniparsers.

So to load code, you just load the .lua file.  Load it is many times 
as you want and it just replaces what exists.  No muss, no fuss, it's 
completely trivial.  The only thing to be careful of is that you're 
relying on looking things up by name, not by reference, so if you take 
a reference to a function directly and reload some code, that 
reference will still point to an old version.  Just like in C, if you 
take a pointer to a function in a shared object/DLL but then reload 
it, the pointer will still point to the old one.

Other things to be careful of is that you don't trash your variables 
inadvertently.  Say you have a file with your client definitions in 
it:

list_of_clients = {}

function Client.foo()
end
etc. etc.

If you reload that file, list_of_clients is reread and wham, the old 
one is toast.  To get around this, I separate data definitions from 
function definitions.  I don't reload data definitions, but I reload 
function definitions all the time.

I have a command in my MUD called "sudo_load" where I can give it the 
name of a file.  When I'm debugging a non-crash bug in some of my 
behaviour, I can easily edit the file and then do:

> sudo_load Gob_before
Gob_before loaded successfully!

And iteratively try things out.

The nightmarish side of all this is in my previously mentioned 
article, which is that the following things conspire against writing 
robust code:

- variables do not need to be declared
- table elements do not need to be declared
- variables are created on assignment, with default global scope

Minor typos can mask bugs for a long, long time unless you have really 
good code coverage analysis happening.

Whew, okay, that's all I can think of right now, if you have specific 
questions, let me know.




More information about the vworld-tech mailing list