411 REFERENCE · Wikibooks
Celestia/Celx Scripting/Development Suggestions
Reference material by Wikibooks contributors. This retains its source identity and is not 411 news reporting.
Introduction
Once you've progressed beyond writing the simplest CELX "Hello World" scripts, development of your software can be a problem. Lua programming is just as complex as programming in any other language, and can be more challenging than many. Since Lua is an interpreted language with a runtime compiler, finding subtle bugs is often an issue. Here are a few suggestions to help make it easier to develop and debug Lua modules for Celestia.
Getting Started
Celestia is an amazing application in many ways, not the least of
which is its extensibility in the form of Lua, its built-in
programming language. Lua is fast and powerful and can augment the
Celestia experience in ways that are only limited by the
imagination. But as Uncle Ben once said to Peter Parker, with great
power comes responsibility. Celestia’s Lua doesn’t hold your hand.
It has an almost pathological adherence to letting you get away
with almost anything without complaining. It’s like having a girl
friend who’s so sweet she never complains about anything. Then one
day she’s gone and you find a nasty note about never picking up your
socks. Celestia’s Lua is like that. You can get away with almost
anything, but there’s a heavy price to pay. And Lua doesn’t even
leave a note. One day Lua will abandon you and you’ll have no idea
why. But it’s not like Lua won’t tell you her problems if you ask.
You just have to ask. (Good idea with your girlfriend too.)
The first thing you need to do is to get well acquainted with a Lua
function called "pcall" Like all of Lua’s functions you can get a
complete description in the "Lua Reference Manual" available either
as a book or online, available at http://www.lua.org/manual/5.0/
One of the first functions you should write is something like
error_pause = 20
result, error = pcall( f )
if(result == false) then
celestia:print(error, error_pause)
wait(error_pause)
end
where "f" is a function you’ve written. When you start programming
you should get in the habit of calling all of your functions with
pcall. Once your program is debugged, you can remove them if desired,
but you should probably keep a copy of the program with the pcall
statements in. Chances are, you’ll probably want to modify your baby.
What you’re essentially doing is duplicating the error reporting that
most other languages have built in. The advantage here is you can
remove the overhead of error detection when you’re through.
The next thing you should do, if you haven’t already, is to read
Harald Schmidt’s online description of Lua/CELX scripting at
http://celestia.h-schmidt.net/celx-summary-latest.html
This gives all the
available Celestia functionality with some tips on Lua, but I’d
recommend also reading the Lua manual in conjunction with Harold’s
description.
Programming Style
Extensible Programs
Programming Style is a matter of taste, of course, but if you going
to write anything large, I’d recommend taking advantage of Lua’s
ability to simply read in new code when it’s needed. For example,
dofile below is an example.
function dofile(filename)
s = assert(loadfile( filename ), "unable to load " .. filename)
return s
end
This function will compile the code in the file and issue an error if
it fails.
You can take advantage of Lua’s garbage collector in this case. Lua
does periodic garbage collection on any memory that your program no
longer has a link to. "dofile" above could overwrite links and Lua
would automatically (eventually) dispose of the memory, making your
code almost infinitely extensible if you desire. This also applies to
any text you might read in. Overwriting the links to strings frees
up the old memory.
Simplicity is King
Lua follows the KISS principle: "Keep it simple, stupid." There are
only eight types of data in Lua: nil, boolean, number, string,
function, userdata, thread and table where "userdata" is just a block
of undefined memory.
And, believe me, simplicity’s a good thing, for no other reason than
it’s so much easier to design than to remember. The data type you’ll
probably be using most is the table which is really an array that can
be indexed by almost anything except nil.
Macintosh Tip
If you’re programming on a Mac, be aware there are some subtle
differences from the PC version, the main one being how comments are
handled. The manual says comments can start with a "[[" but that
doesn’t work on a Mac. The comment form I use on my Mac is
--[[ this is a comment ]]
Note the "--" precedes the brackets. With multiline comments I use
--[[
The following code is the most magnificent piece of ...
--]]
Note: this seems to be caused by Mac text editors acting as word processors. They assume that when you type two dashes followed by a space you really want an em-dash (a single, double-wide dash), and replace those two dashes by the single binary code for a double-wide dash. Unfortunately, this breaks the Lua commenting convention, which requires two separate dash characters. Fortunately, if you follow two dashes by anything other than a space or tab, Mac editors don't make the substitution.
Crashing Celestia
Infinite Recursion
Celestia v1.5.0 cannot detect when a ScriptedOrbit or ScriptedRotation calls obj:getposition() or obj:getorientation() for an object which will have its position or orientation modified as a side effect of the ScriptedOrbit or ScriptedRotation.
As a result, one must not call obj:getposition() ( or obj:getorientation() ) from a Scripted function
if the position (or orientation) of "obj" is determined, even indirectly, by
that Scripted function. Doing so results in that getposition() calling
routines which call the Scripted function which calls getposition()... ad infinitum. This quickly exhausts the stack space and crashes Celestia.
Suggestion: the Scripted code might simply return the previous position or orientation rather than trying to calculate a new one.
It is hoped that this situation will be detected in a future major release of Celestia.
Requiring a lua file in a celx script
When using the Lua 'require' function in a celx script, Lua uses the celestia base directory to look for Lua files.
Then, one can define a different path in the celx script using:
package.path = "mypath/?.lua;"
To define the directory of the celx script as the default path, one just need to add the following line at the beginning of the script:
package.path = celestia:getscriptpath().."/../?.lua;"