What is this?
The below is a document that was included with the Second Life client and is kept here for historical documentation. For a more accurate and updated LSL reference see http://lslwiki.net.
Linden Scripting Language Reference
Table of Contents
touch_start(integer total_number)
touch_end(integer total_number)
collision_start(integer total_number)
collision(integer total_number)
collision_end(integer total_number)
land_collision_start(vector position)
land_collision(vector position)
land_collision_end(vector position)
listen(integer channel, string name, key id, string message)
control(key name, integer levels, integer edges)
at_target(integer number, vector targetpos, vector ourpos)
at_rot_target(integer number, rotation targetrot, rotation ourrot)
money(key giver, integer amount)
email(string time, string address, string subject, string body, integer remaining)
run_time_permissions(integer permissions)
link_message(integer sender_num, integer num, string str, key id)
This document is broken down into three major sections: Introduction, User’s Manual, and Reference Manual. The Introduction provides a high level review of the Linden Scripting Language (LSL) and how it is used within Linden World. The User’s Manual provides a more detailed review of the syntax and functionality of LSL and provides sample code. The Reference Manual provides detailed information on the underlying code and data structures, byte code format, and execution model. This document assumes that the reader has a working knowledge of programming and is familiar with a high level language like Java or C.
LSL was designed with the following goals in mind:
·Provide a robust method for users to add behavior to objects in Linden World
·Provide a simple interface to exchange scripts and to modify tuning values
·Provide a powerful language for advanced users
·Ensure that user scripts cannot crash a simulator or greatly reduce simulator performance
LSL is a Java-like language incorporating several extensions. It sticks to the well known C/Java syntactic style, but allows tuning variables to be exposed via a GUI to allow users with no programming knowledge to modify scripts. Much like faces or textures, this will allow an economy to evolve around well written scripts.
Multiple scripts may also be attached to the same object, allowing a style of small, single-function scripts to evolve. This leads to scripts that perform specific functions (“hover”, “follow”, etc.) and allows them to be combined to form new behaviors.
The text of the script is compiled into an executable byte code, much like Java. This byte code is then run within a virtual machine on the simulator. Each script receives a time slice of the total simulator time allocated to scripts, so a simulator with many scripts would allow each individual script less time rather than degrading its own performance. In addition, each script executes within its own chunk of memory, preventing scripts from writing into protected simulator memory or into other scripts, making it much harder for scripts to crash the simulator.
The following LSL code opens a door when the user speaks the magic word. It handles the concepts of user chats, exposure of global tuning variables, and calls library functions.
// exposed global variables accessible via GUI
// the phrase the user will use
string gMagicPhrase = "Shazamm!";
// how fast the door opens
float gOpenTime = 1.0;
// global variables that aren’t exposed
integer gSteps = 20; // the door moves through 20 steps
vector gOffset = <0.0, 0.0, 0.10>; // 2 meters of total motion
// states the script can be in
// all scripts start in the default state
default
{
// setup to listen only for magic phrase
state_entry()
{
llSay(0, "To open me, say " + gMagicPhrase);
// listen on chat channel 0 for the magic phrase from anyone
llListen(0, "", "", gMagicPhrase);
}
// handle chat messages that we’re listening for
listen(integer channel, string name, key id, string message)
{
integer i;
vector basepos = llGetPos();
// loop through the steps, adjusting the door
for (i = 0; i < gSteps; i++)
{
// set the object's position
llSetPos(basepos + i*gOffset);
llSleep(0.1);
}
// now, flip the offset vector to move us back down
gOffset *= -1;
}
}
The key elements of this example are:
·The default state. All scripts must have a default state, which is the state that scripts start out in.
·The state_entry and chat event handlers. LSL uses an event execution model, meaning that events cause specific pieces of code to execute. In this script, the state_entry event is executed at script start when we enter the default state.
·Library function calls. Any function that begins with “ll” is a library function call. In this example, llListen tells the script to listen for the magic words. If those words are heard, the chat event is executed.
·The overall syntax (bracing and keywords) is
very similar to Java/C.
User’s Manual
LSL is loosely based on Java/C syntax with significant changes as detailed below.
Below is an example LSL script:
// global variable that isn’t exposed
vector gStartPosition;
// global functions that can be called from any state
make_physical_and_spin(vector torque)
{
// double the torque because we want to
vector double_torque = 2.0*torque;
llSetTorque(double_torque, FALSE);
}
// state sections
// default state – all scripts must have a default state
default
{
// when a state is transitioned to, the state_entry event is raised
state_entry()
{
// Make physical so it can move
llSetStatus(STATUS_PHYSICS, TRUE);
// get the base stating position
gStartPosition = llGetPos();
// Move to 2 meters above the start position
gStartPosition.z += 2.0;
llMoveToTarget(gStartPosition, 0.5);
// transition to spin state
state SpinState;
}
// when a state is transitioned out of, the state_exit event is raised
state_exit()
{
// set critical damping to keep us on our stating location, with time constant of 0.5 seconds
llMoveToTarget(gStartPosition, 0.5);
}
}
// SpinState is a user defined state
state SpinState
{
state_entry()
{
// say hello on channel 0
llSay(0, "Starting to spin");
// call global function
make_physical_and_spin(<0.1, 0.1, 0.0>);
}
}
The LSL file is broken up as follows:
LSL variables are case sensitive, made up of letters, numbers, and underscores, and must start with a letter or underscore.
Global variables and functions are accessible from anywhere in the file. Global variables are declared much like Java or C, although only one declaration may be made per line:
vector gStartPosition;
Global variables may also be initialized if desired, although uninitialized global and local variables are initialized to legal zero values:
vector gStartPosition = <10.0,10.0,10.0>;
Global functions are also declared much like Java/C, with the exception that no “void” return value exists. Instead, if no return value is needed, just don’t specify one:
make_physical_and_spin(vector torque)
{
// double the torque because we want to
vector double_torque = 2.0*torque;
llSetState(STATUS_PHYSICS, TRUE);
llApplyTorque(double _torque);
}
Local variables are scoped below their declaration within the block of code they are declared in and may be declared within any block of code. Thus the following code is legal and will work like C:
Integer test_function()
{
// Test vector that we can use anywhere in the function
vector test = <1,2,3>;
integer j;
for (j = 0; j < 10; j++)
{
// This vector is a different variable than the one declared above
// This IS NOT good coding practice
vector test = <j, j, j>;
}
// this test fails
if (test == <9,9,9>)
{
// never reached
}
}
All scripts must have a default state, which is the state the script starts in. States contain event handlers that are triggered by the LSL virtual machine. States must have at least one event handler, but can choose which handlers to use. Some handlers, like listen, require that the script call a library function to setup information that determines when the event happens.
The example code sets the global variable gStartPosition within the state_entry event handler, which is set when the script begins execution.
default
{
// when a state is transitioned to, the state_entry event is raised
state_entry()
{
// get the base stating position
gStartPosition = llGetPos();
// transition to spin state
state SpinState;
}
// when a state is transitioned out of, the state_exit event is raised
state_exit()
{
// set critical damping to keep us on our stating location, with time constant of 0.5 seconds
llMoveToTarget(gStartPosition, 0.5);
}
}
The command state SpinState changes the state to the SpinState state and raises the state_exit event, causing that handler to be called.
The user state SpinState works like the default state.
state SpinState
{
state_entry()
{
// say hello on channel 0
llSay(0, gHello);
// call global function
make_physical_and_spin(<10.0, 10.0, 0.0>);
}
}
LSL uses Java/C++ style single line comments:
// Name and Description
LSL supports the following basic types:
·integer
Signed, 32-bit integer value
·float
32-bit floating point value
·string
A sequence of characters
“\” functions as an escape character, so use “\n” to enter a carriage return into a string, “\t” to enter a 4 space tab, “\\” to enter a backslash, “\”” to enter a double quote, and “\” followed by any other character to enter that character. Note that the C conventions of \ooo and \xhh are not supported.
·key
A unique identifier that can used to reference objects in Linden World
·vector
3 floats that can be acted on together
Members are accessed via .x, .y. or .z.
4 floats that represent a rotation
Members are accessed via .x, .y., .z, or .w.
·list
A heterogeneous list of the other data types
Lists are created via comma separated lists of the other data types enclosed by “[“ and “]”.
string StringVar = "Hello, Carbon Unit";
list MyList = [ 1234, ZERO_ROTATION, StringVar ];
Give this list:
[ 1234, <0,0,0,1>, "Hello, Carbon Unit" ]
Lists may be combined with other lists or variables to form larger lists:
MyList = 3.14159 + MyList;
This would give the list:
[ 3.14159, 1234, <0,0,0,1>, "Hello, Carbon Unit" ]
MyList = MyList + MyList ;
[ 3.14159, 1234, <0,0,0,1>, "Hello, Carbon Unit", 3.14159, 1234, <0,0,0,1>, "Hello, Carbon Unit" ]
Library function are used to copy data from lists, sort lists, copy/remove sublists.
LSL supports a wide range of arithmetic operations between its basic types using Java/C syntax.
float foo_float = 4.0;
integer foo_int = 4;
vector foo_vector = <1,1,1>;
rotation foo_rotation = <1,0,0,0>;
// scale up vector
foo_vector = foo_int * foo_vector;
// rotate vector by rotation
foo_vector = foo_vector * foo_rotation;
// mix integer and floats
foo_float = foo_float * foo_int;
Type conversion can either occur implicitly or explicitly. Explicit type casts are accomplished using C syntax:
float foo_float = 1.0;
integer foo_int =(integer)foo_float;
LSL only supports two implicit type casts: integer to float and string to key.
LSL supports the following explicit casts:
·Integer to String
·Float to Integer
·Float to String
·Vector to String
·Rotation to String
·Integer to List
·Float to List
·Key to List
·String to List
·Vector to List
·Rotation to List
·String to Integer
·String to Float
·String to Vector
·String to Rotation
LSL supports several C/Java loop structures.
The LSL for loop operates like the Java/C loop structure except that variables may not be declared within the for command:
integer j;
integer count = 10;
for (j = 0; j < count; j++)
{
// do stuff here
}
The LSL do-while loop operates like the Java/C loop structure:
integer j;
integer count = 10;
do
{
// do stuff here and increment j
} while (j < count);
The LSL while loop operates like the Java/C loop structure:
integer j;
integer count = 10;
while (j < count)
{
// do stuff here and increment j
}
LSL supports if and if-else conditional statements.
The LSL if statements operates just like the Java/C versions:
integer small = 1;
integer big = 10;
if (small < big)
{
// we get here!
}
The LSL if-else statements operates just like the Java/C versions:
integer small = 1;
integer big = 10;
if (small < big)
{
// we get here!
}
else
{
// we don’t get here
}
LSL supports a jump statement within functions or event handlers.
@Label;