Jump to content

Celestia/Celx Scripting/CELX Lua Methods

From Wikibooks, open books for an open world

This summary describes the support for Lua/CELX-scripting in Celestia and consists mostly of the CELX API. This documents as well as the CELX-support in Celestia probably contain a number of errors or bugs. Please report any problems you find.

Introduction

[edit | edit source]

About this document

[edit | edit source]

It was started to document the available functionality during development celestia v1.3.1pre11, and was then extended as new functionality was contributed.

CELX uses the Lua Programming Language, so you are writing real programs. This is completely different than older CEL Celestia scripts, which are just sequences of fixed commands. So you probably should have a little experience in programming, otherwise this document won't help you much.

It's also a good idea to read at least the first sections of the Lua-Documentation, available here:

How CELX works in Celestia

[edit | edit source]

Celestia works roughly(!) by repeating this:

  • Check user input, change rendering settings accordingly (e.g. enable rendering of orbits, change observer position/orientation)
  • Update the simulation time
  • Update the observer's position if goto is active
  • Render all objects using the current settings (renderflags, time. positions)

If a CELX script has been started, it is executed just before rendering begins. Then Celestia gives control to the Lua interpreter, which continues to execute the script where it stopped the last time. When a CELX method is called in a script, e.g. celestia:print(), the Lua interpreter invokes a small C++ function which converts the arguments from Lua types to C++ types, calls the right Celestia-methods to perform the action, and, if necessary, converts the C++ return value back to a Lua value. Note that the Lua interpreter called this C++ function, so when the function returns, the script continues: there is never a chance to return control back to the Celestia loop. To do this, the script has to call the wait() function, which makes the Lua interpreter return control.

Forgetting to call wait() in Celestia 1.3.1 meant that Celestia never gained control again, and thus couldn't handle the command to stop or quit the script - it was completely blocked. Starting with version 1.3.2, Celestia periodically checks if the script has exceeded the maximum allowed time to execute (5 seconds), and if it has, it terminates the script.

It should be apparent that most actions don't really change anything immediately. Instead, scripts change a setting which is used later on during rendering, which from the point of view of the script happens while calling wait(). So if the position of the observer is changed ten times without calling wait() in between, this will have no effect - only the last position will actually be used in rendering.

Syntax

[edit | edit source]

For a complete description of the syntax of Lua, please read http://www.lua.org/manual/5.0/
Celestia version 1.5.0 uses Lua version 5.1, which differs slightly from version 5.0 of Lua, used in earlier Celestia releases.
The Lua 5.1 manual can be found at http://www.lua.org/manual/5.1/
For details about what changed between Lua versions 5.0 and 5.1, see http://www.lua.org/manual/5.1/manual.html#7

Some quick starting notes:

  1. Lua commands can be terminated either by a textual line terminator or by a semicolon. To include several Lua commands on a single line of text, separate them by semi-colons (;), but if there is only a single Lua command on a line of text, no semi-colon is needed.
  2. Write your CELX script by using a line editor like "Notepad", "Notepad++" or "Wordpad", without text formatting;
  3. Short (singleline) comments start with two hyphens "--";
  4. Long (multiline) comments use "--[[ comment ]]".
  5. When you use the comment "-- Title: string:text" in the first line of the CELX script, the string:text title will be displayed in the Celestia/File/Scripts drop down menu instead of the filename.

Example:

-- Title: Example script
-- This is a short comment line.
-- [[ This
      is
      a
      long
      comment
      line.]]
a = 5; b = 6 -- two Lua commands on a single line
c = 3        -- one Lua command on a line

Variables & Types

[edit | edit source]

Lua variables don't have to be declared and don't have a type, but the content has a type.

There are eight basic types in Lua:

  1. nil
    • Nil is the type of the value nil, whose main property is to be different from any other value; it usually represents the absence of a useful value.
  2. boolean
    • Boolean is the type of the values false and true.
      Both nil and false make a condition false; any other value makes it true.
  3. number
    • Number represents real (double-precision floating-point) numbers.
  4. string
    • String represents arrays of any 8-bit characters.
  5. table
    • Tables can be used as arrays that can be indexed not only with numbers, but with any value (except nil).
      Tables also can contain values of all types (except nil).
  6. userdata
    • The objects to control Celestia are of this special type userdata.
  7. function
    • The function type is an executable expression, compiled from a block of Lua and CELX code.
  8. thread
    • Not further explained here.

Example:
The same variable "a" can have content of different type.

a = 1                -- a is 1, an integer number
a = a / 2            -- a is now 0.5, changed into a floatingpoint number
a = "Hello World"    -- a contains a string now 
a = a / 3            -- ERROR, because a string is divided by a number! 
a = true             -- a is true, a boolean
a = not a            -- a is now false, a boolean

Example:
A table can be used like this.

t = {}                                  -- define Table t
t["key1"] = "value1"                    -- long form to store a string
t.key2 = "value2"                       -- short form to store a string
u = { key1="value1", key2="value2" }    -- u is now the same as t 
v = { 1,2,3,4,5 }                       -- v[1] is now 1, v[2] is 2, etc.

To operate on userdata, you can call methods for the objects. To use Lua for Celestia, you mostly need to know only about the available objects, the methods defined on them and how to call them - everybody who already knows Object-Oriented-Programming should feel right at home.

At the beginning of a script, the celestia object is automatically defined, holding a reference to the core-functionality of Celestia! To operate on this celestia object you can call methods which are defined on it by using the "celestia:" prefix, as shown in section celestia methods.

Example:

-- Get observer instance of the active view and store it in "obs"
obs = celestia:getobserver()

-- Find the celestial object representing Earth and store it in "earth"
earth = celestia:find("Sol/Earth")

-- Do something to confuse the reader, but possible in CELX
-- The object with name mars is made equal to the object with name earth
mars = earth
-- You can also use obs and earth like this.
obs:goto(earth)
-- This will start the goto-command, which moves the observer to Earth,
-- just as if you had pressed the [G] key in Celestia, after selecting Earth.

A function is an executable expression, compiled from a block of Lua and CELX code, whose value has type function.

A function can have arguments for input values and a function can also return zero, one or more values (see the Lua-documentation for details).

One or more functions can be defined at the beginning of your CELX script and they can be called once or several times from the main body of your CELX script.

Example:

-- Define function with name "add_one" and parameterlist "i" (a number).
function add_one(i) 
   -- use 'local' to declare variables local to function: 
   local j = i + 1 
   -- return the value of "j", a number.
   return j 
end
-- Define function with name "divide" and parameterlist "i, j" (two numbers).
function divide(i, j) 
   -- return the value of the division "i / j", a number.
   return i / j 
end
-- Start of the main body of your script
<... other script code ...>
-- and now call the functions: 
a = add_one(1) 
b = divide(a, 2)
<... other script code ...>

The function "wait(number:n)" is predefined in Celestia and waits number:n seconds. It is special because it returns control to Celestia, which you have to do to avoid blocking Celestia.

Many more functions are defined in Lua (see Lua-docs), such as mathematical functions or string operations.

Notes:

  1. Not all Lua-libraries are loaded, you don't have access to io and debug-functions (which greatly reduces the danger of security problems from "evil" scripts). See the method celestia:requestsystemaccess() for more information.

Control Structures

[edit | edit source]

Lua has the typical control structures, like for, while, repeat and if.

Examples:

-- Execute the block of codelines (...) 10 times after each other,
-- where "i" is incremented with 1 during each loop.
for i = 1, 10 do 
   ... 
end
-- Execute the block of codelines (...)
-- as long as "i" is smaller than or equal to 11.
i = 1 
while i <= 11 do 
   ... 
   i = i + 1 
end
-- Execute the block of codelines (...) 
-- until "i" is equal to "j".
i = 1
j = 22
repeat 
   ... 
   i = i + 1 
until i == j
-- Compare "i" and "j" with each other and execute a
-- certain block of codelines (...1, ...2 or ...3),
-- depending on the result of this comparison.
if i > j then 
   ...1
elseif i < j then 
   ...2 
else 
   ...3
end
-- To loop over the contents of a table "tbl", you can use this:
for key, value in pairs(tbl) do
   -- tbl[key] == value
   ...
end
-- Use this for tables used as arrays, i.e. indexed by numbers 1..n: 
for i, value in ipairs(tbl) do	
   -- tbl[i] == value
   ... 
end

Objects and Methods (The CELX API)

[edit | edit source]

This section documents the userdata classes (object types) available in CELX Lua scripting.

Besides the predefined celestia object, there are also other celestia related objects to control Celestia. You can't create an object (i.e. userdata) yourself, you must call some method to create one. As you only have the celestia object (ignoring methods which are not Celestia related) available when the script is starting, you must use it to create other objects.

The following celestia related objects can be used within a CELX script:

  1. Observer object:
    An observer object is used to access properties specific to a view, such as viewer position, viewer orientation, frame of reference, and tracking status. To operate on an observer objects, you can call observer methods which are defined on them, as shown in section observer methods.
  2. Object objects:
    An "object" object in CELX refers to a celestial object like a planet or a star. To operate on "object" objects, you can call "object" methods which are defined on them, as shown in section object methods.
  3. Position objects:
    A position object contains the exact coordinates of a point in space. To operate on position objects, you can call position methods which are defined on them, as shown in section position methods.
  4. Vector objects:
    A vector object is a geometric object that has both a length and direction [X,Y,Z] in a 3-dimensional Coordinate System. To operate on vector objects, you can call vector methods which are defined on them, as shown in section vector methods.
  5. Rotation objects:
    A rotation object is internally a Quaternion, which is one possibility to mathematically describe a rotation in 3 dimensions (i.e. it can be converted to a rotation matrix). A rotation can also be used to describe the orientation of objects or the observer (i.e. where the observer is looking to, and where "up" is). To operate on rotation objects, you can call rotation methods which are defined on them, as shown in section rotation methods.
  6. Frame objects:
    The frame object describes the celestia coordinate cystem and tells how the X, Y, and Z, axes of each 3-dimensional coordinate system are aligned. Coordinate systems are well documented in the available Celestia .Cel Scripting Guide v1-0g by Don Goyette, in the chapter: "Coordinate Systems". To operate on frame objects, you can call frame methods which are defined on them, as shown in section frame methods.
  7. Phase objects:
    The timeline of an object can be subdivided into one or more phases. Each phase object has its own trajectory, rotation model, orbit frame, and body frame. To operate on phase objects, you can call phase methods which are defined on them, as shown in section phase methods.
  8. CELscript objects:
    A CELscript object contains a string with a valid CEL script, which can be imbedded in a CELX script by using the "celestia:createcelscript()" method. To operate on CELscript objects, you can call CELscript methods which are defined on them, as shown in section CELscript methods.

Example:
To call the method getposition() of observer, you have to get an observer-instance from celestia first and then call getposition() on it:

obs = celestia:getobserver() 
pos = obs:getposition()

Notes:

  1. While using names for the various classes in this documentation, these names have no real meaning in a script. Even "celestia" is just a variable, holding an object of type celestia and is not really special.

In the following section, each method is listed with its signature:

return_value_type object:methodname(type:parameter, type:parameter [, type:optional parameter])

This is followed by:

  • A short description of what the method does;
  • A list of the arguments/parameters and what they are for;
  • Possibly some notes about how to use this method, what it does exactly, some concerns etc..
  • Finally an example about the usage of the method is given.

Object and method index

[edit | edit source]

1.6.0 Phases available only in Celestia 1.6.0 and later

Object and method index (alphabetical)

[edit | edit source]

1.6.0 Phases available only in Celestia 1.6.0 and later

Callbacks

[edit | edit source]

Callbacks are functions which are executed as a result of external events.

Right now there are two callbacks available in Celestia:

Note: Callbacks are limited in what you can do:

  • The callback must complete within 1 second, or it will be terminated;
  • You CANNOT use the wait() function in a callback !

CEL to CELX migration

[edit | edit source]

The following section contains an index of the available CEL commands. By clicking on a specific command, you will be routed to the explanation on its functionality and how that CEL command can be migrated to equivalent CELX objects and methods.

CEL command index

[edit | edit source]

The CEL commands below are organized following the sequence and explanation of CEL script commands in Celestia .Cel Scripting Guide v1-0g by Don Goyette. The explanations also contain many of Don's examples and syntax descriptions to aid in the migration from CEL to CELX.

Within this section, parameter values for CEL commands and CELX methods are printed like <type> or <name>. These parameter values need to be replaced when actually using these commands or methods.

Example:

<string>    "Sol/Earth"
<duration>  1.5
<distance>  20000

Since Celestia version 1.6.0 and 1.6.1 the original listing of only 35 Cel commands has been expanded to 52 Cel commands. The additional commands are indicated with 1.6.0 and 1.6.1.

  1. cancel
  2. 1.6.0 capture
  3. center
  4. changedistance
  5. chase
  6. cls
  7. 1.6.0 constellationcolor
  8. 1.6.0 constellations
  9. 1.6.0 deleteview
  10. 1.6.0 exit
  11. follow
  12. goto
  13. gotoloc
  14. gotolonglat
  15. labels
  16. lock
  17. lookback
  18. mark
  19. move
  20. orbit
  21. 1.6.0 orbitflags
  22. preloadtex
  23. print
  24. renderflags
  25. 1.6.0 renderpath
  26. rotate
  27. select
  28. set
  29. 1.6.0 setactiveview
  30. 1.6.0 setambientlight
  31. setfaintestautomag45deg
  32. setframe
  33. 1.6.0 setgalaxylightgain
  34. 1.6.0 setlabelcolor
  35. 1.6.0 setlinecolor
  36. setorientation
  37. setposition
  38. 1.6.0 setradius
  39. setsurface
  40. 1.6.1 settextcolor
  41. 1.6.0 settextureresolution
  42. seturl
  43. setvisibilitylimit
  44. 1.6.0 singleview
  45. 1.6.0 splitview
  46. synchronous
  47. time
  48. timerate
  49. track
  50. unmark
  51. unmarkall
  52. wait

Notes

[edit | edit source]

Typical Problems

[edit | edit source]
  • Lua scripts are executed between Celestia's rendering phases. So if you do some lengthy calculation (or an endless loop), Celestia won't be able to update the screen or even check for key presses (i.e. you can't stop the script by pressing [Esc] key). From the script's point of view, rendering and UI-handling only happen during calls to wait(). If the script doesn't return control to Celestia for more than 5 seconds, then the script is terminated.
  • If you want to move the observer smoothly, do this by setting its position and then call wait(). But watch out: if "track" is activated on a body this can override any observer:setorientation() in the script. A high time rate will change the position of planets significantly before they are rendered, which can result in a jerky movement. If necessary, check and reset time and timerate in your script.
  • On Windows wait() can return very quickly without doing any rendering, while on Linux it reliably enforces a rendering pass.
  • The user can change settings while a script is running, including which body is selected, position, orientation, speed, timerate, renderflags etc. Don't rely on these to stay constant, if necessary you have to continuously reset them.
  • Reference frames can be difficult to master at first. If you are trying to set the observer to a position within the Solar System, but get distances to the Sun of about 206 au instead, you probably got your reference-frame wrong. Before version 1.5.0, 206 AU is the distance between the point of origin [0,0,0] in universal coordinates and the position of the Sun. Starting with version 1.5.0, Celestia places the Solar System's barycenter at [0,0,0].
  • If your script turns your screen completely black or other weird effects occur, check for any usage of observer:setorientation() or observer:lookat(). You probably have your orientation set to an "invalid" quaternion (for example all zero), possibly by using observer:lookat() with your up-vector parallel to the direction of view. If this happens, you should get Celestia usable again by running a script which sets the orientation to some sensible value (or simply by restarting Celestia).