Iniciación al LSL para usuarios con conocimientos sobre programación. ¡Manual recomendado sólo para usuarios avanzados!
Creado por Fiona Spad para Creasl el 14 de Diciembre.
LSL DEFINICION
El Linden Scripting Language (LSL) es el lenguaje que se utiliza para crear contenido interactivo en Secondlife.
LSL es un simple, pero potente lenguaje utilizado para fijar los comportamientos de los objetos que se encuentran en Secondlife . Se ajusta a la sintaxis de los lenguajes C y Java, se maneja mediante eventos (events), características de los estados (states), utiliza variables tipo 3D ( vectores y quaternion), así como una variedad de funciones incorporadas para manipular la física y la interacción de los avatares . LSL carece de algunas características encontradas en esos lenguajes -- especialmente matrices (únicamente existen matrices de una dimensión) y constantes definidas por el usuario.
Pueden adjuntarse varios scripts a un mismo objeto, lo que permite tener un conjunto de pequeños scripts con funciones simples, que combinados permiten formar nuevos comportamientos mas complejos (por ej : hover etc..).
LSL EVENTOS
LSL es un lenguaje manejado por eventos (events). Literalmente, los scripts se dividen en bloques de código que se activan cuando ocurre un determinado evento. En los scripts se pueden codificar manejadores de eventos ( event-handlers) como por ejemplo: moving_end o touch_start.
Si en un script se codifica un event-handler, y un evento de este tipo ocurre, el simulador añadirá este evento a la cola de eventos del script. Los event-handlers del script serán entonces ejecutados en el orden en que han sido encolados ,en una cola tipo FIFO ( First In First Out). Según Cory Linden, la cola de eventos de un script puede almacenar hasta un máximo de 64 eventos. En caso de que la cola se llene, los nuevos eventos serán ignorados sin dar ningún mensaje de aviso.
LSL no permite múltiples subprocesos.
Los eventos se ejecutan de uno en uno.
Los eventos no pueden interrumpirse entre sí.
Simplemente son almacenados en una cola FIFO y ejecutados en orden.
No hay manera de interactuar en la cola de eventos directamente.
Cada vez que ocurre un cambio de estado, la cola de eventos se borra completamente . En cada estado se pueden codificar uno o varios event-handlers.
Téngase en cuenta que hay fallos en LSL (bugs).
Por ejemplo, cuando un event-handler es llamado a ejecución, todos los argumentos del event-handler se pasan por valor ( no por variable), y son almacenados en la pila ( stack) del script . Si un script tiene insuficiente memoria para guardar todos los argumentos, el script dará un error en ejecución del tipo : "pila / montón de colisión" sin dar mas información.
A diferencia de las funciones (functions) , los scripters o usuarios no podemos crear nuestros propios event-handler. Si se desea comprobar si un evento ha ocurrido o no, y no está contemplado dentro de la lista de event-handlers creada por Linden Labs , tendrá que hacerse mediante el evento timer ().
También la función llMinEventDelay puede ser de cierta utilidad en la coordinación de eventos.
La lista de los event-handlers definidos para LSL por Linden Labs:
(Se recomienda visitar http:/www.secondlife.com para obtener la lista actualizada ya que esto puede cambiar con los cambios de versiones)
- ¿Qué es una tarea ?
- en LSL una tarea es un avatar/agente o un objeto. Ambos pueden chocar con un objeto, aunque sólo los objetos pueden contener scripts. Se puede definir una "tarea" en el sentido de "el objeto que contiene la secuencia de comandos".
- ¿Qué es un agente ?
- Un agente es un cliente dentro de la presencia de un sim. Todos los usuarios conectarse a un sim como agente. Un agente no es un avatar, a pesar de que está representado en el cliente por uno. Un agente puede ser un objeto creador / propietario y / o un miembro del grupo. Un agente "ve" el mundo a través de una cámara y tiene un avatar. Un avatar es una representación visual de un agente dentro de Second Life;
LSL ESTADOS
LSL proporciona el concepto de "estados" que los scripts pueden definir de muchas maneras.
El principal estado es el default_state.
Todos los scripts deben tener definido el defaul_state al comienzo, que es el primer estado que se ejecuta cuando el script comienza.
Cuando un script es compilado, reseteado o cargado, entra al defaul_statet por defecto.
Si se define otro estado antes del default_state, el compilador dará un error de sintaxis.
Después de la definición del default_state , pueden definirse otros estados adicionales que determinan como se comportará el script en cada estado ante la llegada de eventos o entradas del exterior.
Cada estado contendrá sus event-handlers que son activados por la máquina virtual LSL.
Cada estado definido en el script debe contener por lo menos un event-handler -- en realidad no puede existir un state sin event-handlers. Si se declara un estado sin ningún event-handler el compilador dará un error de sintaxis.
En LSL, los scripts están en standby hasta que reciben alguna entrada, o detectan algún cambio del exterior. En todo momento el script está en un estado determinado y reaccionará a los eventos o entradas de acuerdo con un esquema definido por el programador.
Los estados se definen mediante la palabra clave state
(ejemplo: state foo {...})
Como excepción el default state se declara mediante el uso de la palabra clave default a secas
El cambio de estado dentro del script se hace mediante la directiva:
state nombre-del-estado-nuevo (ejemplo: state default;).
Cuando el intérprete llega a una declaración de cambio de estado (mediante la directiva state nombre-de-estado-nuevo):
- el event-handler que contiene dicha declaración es inmediatamente finalizado
- se ejecuta el state_exit del estado que se abandona
- se abandona el estado actual
- se cambia al nuevo estado
- se ejecuta el state_entry del estado nuevo
Cuando hay un cambio de estado, todos los eventos que estaban pendientes en cola se borran, y todos los eventos que requieran de setup (a través de una función) son deshabilitados (timer, sensor y listen events).
Nota: las versiones anteriores podían permitir que cuando un evento contenía un cambio de estado acabara hasta el final antes de cambiar al nuevo estado, pero ya no es así.
State_entry
El event-handler state_entry es llamado cada vez que se entra a un nuevo estado, y siempre es el primer event-handler tratado. No es posible pasar argumentos a este event-handler.
Es un error común asumir que la state_entry se llama cuando un objeto es rezzed desde el inventario. Cuando un objeto se añade al inventario, el estado actual del script se guarda, así que no se llamará al state_entry durante el rez.
Si se necesita el startup del codigo cada vez que se rezee un objeto, hay que crear una función global y llamarla desde state_entry y desde on_rez.
integer listenHandle; // llListen() handle holder.
// global initialization function.
init()
{ // Remove the old listen callback:
llListenRemove(listenHandle );
// Set up a listen callback for whoever owns this object.
key owner = llGetOwner ();
listenHandle = llListen( 0, "", owner, "");
}
default
{ state_entry()
{ init();
}
on_rez(integer start_param)
{ init();
}
listen(integer channel, string name, key id, string message)
{ llSay(0, "Hi " + name + "! You own me.");
}
}
State_exit
El event-handler state_exit es llamado cada vez que se abandona un estado, y es el último event-handler tratado.
Cada vez que se cambia de estado (mediante la directiva state nombre_de_estado_destino) sucede lo siguiente:
- el event-handler que contiene dicha declaración es inmediatamente finalizado
- se ejecuta el state_exit del estado que se abandona
- se abandona el estado actual
- se cambia al nuevo estado
- se ejecuta el state_entry del estado nuevo
Es útil codificar un state_exit cuando se desee hacer cualquier trabajo de reseteo antes de abandonar el estado actual.
// stupid stateful stopwatch
default { // stopped
touch_start( integer num_detected) {
state start; // go, go, go!
}
}
state start {
state_entry() {
llResetTime();
}
touch_start( integer num_detected) {
state default; // stop it
}
state_exit() {
llSay(0, "Stopped after " + (string )llGetTime() + " seconds." );
}
}
LSL FUNCIONES
Una función puede ser vista como una máquina en la que está prevista una entrada y que devuelve una salida. Mediante el uso de funciones, los mismos bloques de código se pueden usar una y otra vez, simplemente referenciándolo.
Existen dos tipos de funciones :
- Funciones de Linden Labs
LSL viene con más de 310 funciones incorporadas que permiten a los scripts y objetos interactuar con el medio exterior. Todas las funciones definidas en la librería Linden empiezan con "ll" -- son minúsculas' L's, que significan "Library Linden".
- Funciones definidas por el usuario :
El usuario puede definir funciones (con valores de retorno, si se quiere), siempre que el nombre de la función del usuario no esté en conflicto con una palabra reservada por Linden , una constante reservada por Linden, o una función incorporada de la librería Linden.
Este ejemplo llama a la función llSay que se utiliza para enviar un texto al canal especificado:
LlSay (0, "Hola mundo!");
Nota: Como SL ha evolucionado , algunas funciones están obsoletas. Asegúrese de usar la función correcta ya que las funciones en desuso, dejan de ser fiables y pueden ser eliminadas por completo en el futuro. Se recomienda visitar http://www.secondlife.com para obtener la lista de funciones actualizada.
Actualmente existen 337 funciones en la librería de LSL.
LSL VARIABLES
Una variable es un identificador o nombre de un sitio donde almacenar la información en un script. El proceso de creación de una variable se denomina "declaración de variable" o "la definición de una variable".
Una variable tiene un nombre, un tipo y un valor.
El nombre debe empezar por una letra y las normas para nombrar una variable son similares a C o Java. Se diferencian las mayúsculas de las minúsculas ( case sensitive).
Existen los siguientes tipos de variables :
· integer ,
· float,
· vector ,
· rotation,
· key,
· string ,
· list
| Type | Brief Description |
| integer | Numero entero desde -2,147,483,648 hasta 2,147,483,647 |
| float | Numero decimal desde 1.175494351E-38 hasta 3.402823466E+38 |
| vector | Tres floats de la forma < x , y , z >. normalmente para position, color, or Euler rotation |
| rotation | Un quaternion rotation, formado por 4 floats, < x , y , z , s > |
| key | Un UUID (string especial) usado para identificar algo SL, como pore j agent , object , sound , texture , other inventory item , or dataserver request |
| string | Una secuencia de caracteres , limitados unicamente por la cantidad de memoria libre en el script |
| list | Una lista heterogénea de datos |
El tipo de una variable limita qué tipo de valores se pueden almacenar en el mismo.
Las variables pueden ser locales o globales según donde sean declaradas dentro del script. Ver scope.
Para declarar una variable, utilice este formato general:
type name;
Donde:
· type es uno de los tipos de variable de LSL, y
· name es cualquier combinación de letras (mayúsculas o minúsculas), números, o bajos (_), que no empiece con un número.
Se puede declarar una variable asignando un valor inicial.
Ejemplos :
integer count = 2;
float measure = 1.2;
string chars = "Lee";
list words = ["This", "Is", "A", "List"];
list entries = ["A list may contain many types of values such as", 2, 1.2, <0.4, 0.8, 1.6>];
vector vec = <1,6,2>;
Ámbito de las variables (scope)
El nombre de la variable tiene de alcance (scope) desde el punto en el que se declara hasta el final del ámbito en el que está.
Las variables tienen un ámbito que puede ser local o global:
Una variable local es una variable que existe dentro de un bloque de código. (En un bloque definido por apertura y cierre de llaves -- {}) y sólo es accesible dentro del mismo área de script en que fue declarada.
Una variable global es una variable declarada antes del default state del script , y tiene un ámbito global. Estas variables son accesibles y modificables desde todas partes del script. Sin embargo, no son accesibles fuera del script, en otros scripts
Una variable no puede ser definida dos veces en el mismo ámbito de aplicación.
Un variable puede ser redefinido en un ámbito interior, en cuyo caso ocultará la misma variable en el ámbito exterior. Ver ejemplo.
Una vez más, la semántica es muy similar a la de C y Java.
En el siguiente ejemplo vemos que el siguiente código se compilará y se ejecutará sin problemas:
integer i = 50;
default { state_entry() { string i = "Hello there!"; //This WILL compile just fine, unlike in Java or C++.
llOwnerSay(i); //Will say "Hello there!". There is no way to get the global variable i.
}
}
LSL CONSTANTES
Constantes son valores predefinidos en LSL , que no cambian:
Por ej :TRUE siempre es 1.
Estas constantes tienen como finalidad simplificar el código y hacerlo más fácil de entender. Es buena práctica utilizar las constantes en nuestro código para hacerlo mas legible.
A continuación se enumeran las constantes generales:
· float
| PI | 3.1415926535897932384626433832795 (pi) |
| TWO_PI | 6.283185307179586476925286766559 (pi * 2) |
| PI_BY_TWO | 1.5707963267948966192313216916398 (pi / 2) |
| DEG_TO_RAD | Convierte de degrees a radians (multiply, example: radian = 90 * DEG_TO_RAD;) |
| RAD_TO_DEG | Convierte de radianes a degrees (multiply, example: degree = PI_BY_TWO * RAD_TO_DEG; ) |
| SQRT2 | 1.4142135623730950488016887242097 (square root of 2) |
· integer
| TRUE | 1, an integer constante para operaciones booleanas. |
| FALSE | 0, an integer constante para operaciones boolean. |
| DEBUG_CHANNEL | 2147483647, es un canal de chat especial usado para escribir los errors de script en una ventana. |
· string
NULL_KEY Indica una key vacia : "00000000-0000-0000-0000-000000000000".
EOF , "/n/n/n", Indica la ultima linea ( End of File)
| Substring | Replaced With |
| \t | four spaces |
| \n | nueva linea |
| \" | double quote |
| \\ | backslash |
· rotation
ZERO_ROTATION <0.0, 0.0, 0.0, 1.0>
(Notese que ZERO_ROTATION NO ES <0.0, 0.0, 0.0, 0.0>! ATENCION.)
· vector
ZERO_VECTOR <0.0, 0.0, 0.0>
LSL OPERADORES
Los operadores se utilizan para ejecutar operaciones sobre dos operandos.
Un ejemplo típico es 1 + 2, donde 1 y 2 son operandos, y el + es el operador.
Este concepto puede ampliarse mucho más lejos con LSL ya que los operandos pueden ser variables ,además del caso especial de los operadores de asignación que requieren que los operadores de la izquierda sean una variable.
| Operador | Descripcion | ejemplo |
| () [] . | Parentesis, Brackets, and Dot | do this second (do this first) |
| (type) | Tipo | message = "The result is:" + (string) result; |
| ! ~ ++ -- | NOT, One's Complement, Increment, Decrement | counter++; |
| * / % | Multiply/Dot-Product, Divide, Modulus/Cross-Product | rollover = (count + 1)%5; |
| - | Resta | one = 3 - 2; |
| + | Suma o unión de strings | two = 1+1; text = "Hello" + "World"; |
| + | Concatenation or joining Lists | myList = [1, 2, 3] + [4, 5]; newList = oldList + addList; |
| << >> | Left Shift, Right Shift | eight = 4 << 1; |
| < <= > >= | Menor que, menor o igual que, Mayor que, mayr o igual que | isFalse = (6 <= 4); |
| == != | Comparacion igual, comparacion distintol | isFalse = ("this" == "that"); |
| & | Bitwise AND | zero = 4 & 2; four = 4 & 4; |
| ^ | Bitwise XOR | zero = 4 ^ 4; six = 4 ^ 2; |
| | | Bitwise OR | four = 4 | 4; six = 4 | 2; |
| || | Comparison OR | isTrue = (FALSE || TRUE); |
| && | Comparison AND | isFalse = (FALSE && TRUE); |
| = += -= *= /= %= | Asignacion | four = 4; |
LSL CONTROL de FLUJO
· for
for( initializer; condition; increment ) loop
| • | initializer | – | Executed once just before checking condition. | |
| • | condition | – | If this executes as true then loop is executed. | |
| • | increment | – | Executed after loop, then condition is checked again. | |
| • | loop | – | Can be either a single statement, a block statement, or a null statement. | |
Any of the statements can be null statements.
· if
| • | condition | – | If this executes as true then branch is executed. | | | • | branch | – | Can be either a single statement, a block statement, or a null statement. | | |
if ( condition ) branch_true else branch_false | • | condition | – | If this executes as true then branch_true is executed otherwise branch_false is executed. | | | • | branch_true | – | Can be either a single statement, a block statement, or a null statement. | | | • | branch_false | – | Can be either a single statement, a block statement, or a null statement. | | |
| |
· while
| • | condition | – | If this executes as true then loop is executed. | |
| • | loop | – | Can be either a single statement, a block statement, or a null statement. | |
Any of the statements can be null statements.
· do while
do loop while (condition);
| • | loop | – | Executes once, then executes condition. | |
| • | condition | – | If condition executes true, it then loops back and executes loop again. | |
Any of the statements can be null statements. A do...while loop is slightly faster than a while or for loop, and requires fewer bytes of memory than a while or for loop.
· jump
| • label | target | – | Name of a label inside the same leg of the scope hierarchy tree | | |
| • label | target | – | A label that can be jumped to if the jump is in the same scope or child scope. | | |
· return
| • type | value | – | value or variable to be returned by the function, the type must be the same as that to be returned by the function. | |
Used to return execution to the previous scope along with a value.
Functions
Exits the function and continues script execution in the previous scope.
Events
Causes the script to crash. Events cannot return a value. Use the next form of this keyword instead
Used to prematurely return execution to the previous scope before reaching the end of the function/event. You do not need to use this at the end of an event or function, as it is assumed by the compiler.
Functions
Exits the function and continues script execution in the previous scope.
Events
Exits the event and removes it from the event queue. If there is another event in the queue, that event is triggered.
· state
| • event | events | – | one or more events | | The default state definition. |
| • label | target | – | state name | | | • event | events | – | one or more events | | target state definition. |
| • label | target | – | name of a state to run | | When a state target; is encountered at runtime, if the current state and the target state are different: 1. Trigger state_exit in the current state if it exists and clear the event queue. 2. Change state to target, any listens are unregistered. 3. Trigger state_entry in the target state if it exists. If target state is the same as the current state, no state change occurs nor do any of the side effects. |
| | |
LSL ERRORES
1 Mensajes de error en tiempo de ejecución (run-time):
2 Mensajes de error en compilación :
****************************************
Autora : Fiona Spad
Fecha: 14 diciembre 2007
Dedicado a Jabibi Zhichao
***************************************