Which scripting language?

Started by
22 comments, last by WMCoolmon 18 years, 5 months ago
I've been looking into implementing a scripting language into fs2_open, which is the engine of the game Freespace 2 (now open-source.) FS2 uses table files like this:
#Section
$Name: Object name
$Variable 1: 10
$Variable 2: moo
;;etc etc...
#End
Now, what I'd like to do is make it possible to use a scripting language, using one of those variables. EG with Python:
#Section
$Name: Object name
$Variable 1: cmath.cos(35)
$Trigger: {
     if conditional:
          do_something()
}
#End
The preference of the modding community, however, is Lua. Which is where I run into a problem; Lua doesn't seem to let you precompile code chunks on runtime. Since some of the code chunks may be executed per frame, obviously I don't want it to be parsing the file or some text buffer in memory. In addition, I understand that Python has large memory requirements. So, wish list here for a scripting language (in no particular order): - Precompile code chunks - Allow for object-oriented programming - Small and fast - EASY TO LEARN for non-coders - Lets you use named arrays, eg Array['element'] - Lets you extend variables, functions, classes from C/++ - Is cross-platform (fs2_open runs on Win32, OSX, Linux, and Linux64) - JIT compile to machine code, as long as it doesn't interfere with cross-platformability Thanks. :)
Advertisement
Of course lua lets you precompile at runtime. Consider this code fragment:

ontrigger = function()     if active then print "I'm triggering" endendontrigger()ontrigger()ontrigger()ontrigger()ontrigger()

In that fragment, the ontrigger command is compiled exactly once. If Lua doesn't seem to precompile stuff, it's only because the precompilation is completely transparent.
Indeed. Getting Lua to run a script happens in two stages. First, you load the script, at which point it will be compiled into a function, and second, you run that function. As long as you keep the function around to re-use, you won't have to compile it again.

Secondly, for JIT compilation, you could take a look at LuaJIT. It may or may not speed things up though, depending on what type of code you're running (there are some statistics on the LuaJIT site - take a look and see if it's appropriate).

For JIT compilation in Python, look at Psyco. I don't know how easy it is to set that up when you're got Python embedded in something though.

Python is beefier than Lua, and includes more language features, eg support for classes and so on - you can write Object Oriented code in Lua, but you have a bit more framework to write yourself, since Lua doesn't provide 'classes' as such built-in; it just provides tables and metatables, and you build everything up from those.

Lua and Python aren't the only options of course - you could check out Squirrel (a lot like Lua), AngelScript, Small, GameMonkey, or even something like Guile.

John B
The best thing about the internet is the way people with no experience or qualifications can pretend to be completely superior to other people who have no experience or qualifications.
That's not exacly what I mean...I mean that, given a chunk of code, it may be executed at different places within the C code, or simply once a frame, or maybe multiple times per frame.

AFAIK the Lua API only provides functions that will run script from a text file, or buffer.

EG:
$Name: Homing Rocket$Damage: 25 * current_speed


Where "current_speed" is the speed that frame. It's not technically a function; but it still needs to be executed every frame that the weapon damage is needed.
Quote:Original post by WMCoolmon
That's not exacly what I mean...I mean that, given a chunk of code, it may be executed at different places within the C code, or simply once a frame, or maybe multiple times per frame.

AFAIK the Lua API only provides functions that will run script from a text file, or buffer.

No, as I said, the process happens in two stages. First you load from a text file or buffer (with lua_load), at which point it gets compiled into a function. Then, you call that function with lua_call (or one of the other call functions like lua_pcall). As long as you keep a copy of the function somewhere, you can keep calling it whenever you need it, without having to recompile everything.

John B
The best thing about the internet is the way people with no experience or qualifications can pretend to be completely superior to other people who have no experience or qualifications.
In my inexperience with scripting languages, I see lua having the easiest syntax even for non coders. Squirrel, however, has native support for classes, and was made with lua's problems in minds. It, however, has a more C++'y syntax, though it's still easy to learn. Python is, like you've heard, very beefy with a lot of features, but very difficult to get going. In my opinion, squirrel is the best of both worlds. Like they said, you could check out other scripting languages, though I recommend squirrel.
See lua_loadfile() (loads chunk from disk as function onto the stack: can be set to a table and called later at will) and lua_dofile() (executes a chunk from disk (elements defined on root table will be available for later use)):

See: Lua 5.0 Manual

If your fellow programmers are set on using Lua, you should have no problem given your requirements (not clear whether Lua will work OK in a 64 bit environment (support appears to be coming in Lua 5.1)).

However (IMO), Squirrel is easier to use (both script side and C/C++ side (binding/class handling)), and was developed as an improvement to Lua specifically for use in commercial game applications. Those with experience with Lua will have no problem using Squirrel. Lua compared to Squirrel.

Both Squirrel and SqPlus compile and run with gcc. There is an ongoing effort to get Squirrel 100% compatible with 64 bit environments (see the Squirrel forum): it appears a few base typedefs must be changed and Squirrel and SqPlus will compile and run OK in 64 bit.


[Edited by - John Schultz on October 29, 2005 1:12:22 PM]
(I apologize in advance if this post is hideous, I'm trying to finish quickly)

I'm considering Lua 5.1 at the moment (just to learn, don't have any projects going).

I liked Python a lot but, as you've definitely heard, it's *beefy*. But so far it seems that it's already "prettified" a lot of the solutions to problems I'm already starting to see in Lua (for instance, I much prefer Python strings to Lua strings, because there's quite a lot more functionality as soon as the builtins are imported).

An advantage of Lua is that, if a feature you want doesn't exist (read: it exists, but you haven't found it yet), you can build it yourself. Python (I'll assume) is the same way, but is quite a bit more to read before you're really comfortable.

I think Python looks prettier, as well, and, if you're trying to embed it, boost.python makes it much easier than with the native embedding API (?).

Someone above mentioned LuaJIT, which I hadn't even heard of until a month or so ago, so I suppose you can look into that for JIT compiling.

...Did I mention that I think Lua is ugly? In a way, though, I like that Lua doesn't look too much like C/++ -- Python is a little harder to work with for me sometimes (but not by much) because of carry-over C-isms, which Lua's sometimes-foreign syntax avoids.

Python has much better documentation, and it seems like builtin commands connotate well (the words that I would think to use for a situation often are, and I like that).

Embedding python with boost.python is actually a little bit *more* enjoyable than embedding lua, because you avoid the "stack" idea. It's not a huge problem, though, because much of the work is done through the scripts regardless (both languages).

And then, I never did find a good Python debugger. Admittedly, I didn't look very hard, and my code problems came from syntactical errors (again, the C-isms), which were easily solved with the interpreter's help.

This post came out differently than I'd planned -- but I guess a personal comparison won't hurt *too much*.
Things change.
To either of the two Johns: I understand the lua_load* functions, but how do I get something off the stack, or keep the stack from getting extremely large from loading minor chunks from everywhere?

Edit: And the current status is that three of the principal coders are against it, but a number of modders seem interested, and the project head (who actually runs a game dev company) is definitely for it.

The reasons being that there's a scripting language (SEXPs) implemented for mission scripting, which could conceivably be expanded to support floats and strings. But, it doesn't allow you to define new functions, doesn't support functions that both change something and return a value, doesn't allow classes, and doesn't support floating point values, as well as being a PITA to code for as it requires you to add code in 6 different places to add a function for it. It's also LISP-based, which at least one strongly feels is a better syntax than Lua. (I'd never heard of LISP until it was mentioned in passing ~3-4 months ago)

But the biggest reason for their disagreement that they feel that any scripting language will be much slower and cause massive memory overhead or leaks than what reworking the SEXP system would do.

The 'debate thread' is here: http://dynamic.gamespy.com/~freespace/forums/showthread.php?s=&threadid=35860

The 'vote thread' is here:
http://dynamic.gamespy.com/~freespace/forums/showthread.php?s=&threadid=35914

The SEXP source code files can be found here (.cpp, .h):
http://fs2source.warpcore.org/cgi-bin/cvsweb/cvsweb.cgi/fs2_open/code/parse/sexp.cpp?rev=2.179&content-type=text/x-cvsweb-markup
http://fs2source.warpcore.org/cgi-bin/cvsweb/cvsweb.cgi/fs2_open/code/parse/sexp.h?rev=2.98&content-type=text/x-cvsweb-markup
Quote:Original post by WMCoolmon
To either of the two Johns: I understand the lua_load* functions, but how do I get something off the stack, or keep the stack from getting extremely large from loading minor chunks from everywhere?


The entire contents of the file are returned as a single function (closure) on the stack. The closure (effectively a pointer; does not take up much "stack space"; the stack won't grow, as you'll store the result in a table somewhere, then pop the stack) can be called/saved, etc. I use this methodology in Squirrel to compile and load a script for later execution (and done in such a way to to put everything declared in the script file in a specific table (not the root table)):

// Squirrel script:// ...  try {    game.init <- loadfile("levels/game.nut",true);  } catch (e) {     return 0;  } // catch  game.init(); // Everything in game.nut is defined in the table 'game'// ...  game.update(); // Calls update(), defined in game.nut.// Or called from C/C++:// gameObject is a SquirrelObject (the 'game' table)  res = SquirrelFunction<int>(gameObject,"update")();


You can do similar operations with Lua (see the Lua docs, perhaps google for Lua examples).

This topic is closed to new replies.

Advertisement