Siguiendo con la recuperación de manuales interesantes publicados en los Foros de Virtual Spain, hoy le toca el turno a la estupenda introducción al Linden Scripting Language (LSL) de Fiona Spad. Muy recomendable!
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 y el evento que los activa:
(Se recomienda visitar http:/www.secondlife.com para obtener la lista actualizada ya que esto puede cambiar con la actualización de versiones)
• at_rot_target --- Cuando el target de tipo rotational es alcanzado tras la ejecución de la función llRotTarget
• at_target --- Cuando el target set es alcanzado tras la ejecución de llTarget
• attach --- Cuando un objecto es attached or dettached a un agente o avatar
• changed --- Cuando cambian ciertos aspectos de un objeto (inventory, color, shape, scale, texture, link, ownership)
• collision --- durante la colisión o contacto de un prim (objeto… primitiva…)
• collision_end --- Cuando dos tareas (o prims) dejan de colisionar/contactar entre si
• collision_start --- Cuando dos tareas (o prims comienzan a colisionar/contactar entre si
• control --- Cuando uno de los controles tomados por la funcion llTakeControls es presionado/sostenido/ liberado
• dataserver --- Cuando un script recibe datos asíncronos
• email --- Cuando un prim recibe un email
• http_response --- Cuando un script recibe respuesta a la peticion hecha mediante llHTTPRequest
• land_collision --- mientras una tarea(objeto , prim con script) colisiona con tierra
• land_collision_end --- Cuando una tarea /prim deja de colisionar con tierra
• land_collision_start --- Cuando una tarea/prim con script comienza a colisionar con tierra
• link_message --- Cuando una tarea recibe un mensaje enviado mediante llMessageLinked
• listen --- Cuando un script esta a la escucha en un canal determinado por el criterio indicado en llListen
• money --- Cuando una tarea recibe dinero “detecta un pago al prim donde esta el script
• moving_end --- Cuando una tarea deja de moverse
• moving_start --- Cuando una tarea comienza a moverse
• no_sensor --- Cuando la llamada a las funciones llSensor / llSensorRepeat da como resultado nulo.
• not_at_rot_target --- Cuando un objetivo de tipo rotacional en la ejecución llRotTarget no ha sido alcanzado todavía
• not_at_target --- Cuando un destino en la ejecución de la funcion llTarget no ha sido alcanzado todavía
• object_rez --- Cuando una tarea crea ( rezzea ) otra tarea mediante la función llRezObject ( tarea = prim en todo u objeto)
• on_rez --- Cuando una tarea es creada ( rezzed) (desde el inventario o desde otra tarea)
• remote_data --- cualquier comunicacion del tipo XML-RPC
• run_time_permissions --- Cuando un agente concede permisos run-time a una tarea que fue requerido mediante la funcion llRequestPermissions
• sensor --- resultado de las funciones llSensor o llSensorRepeat
• state_entry --- en cualquier transición en el estado y en el arranque (startup)
• state_exit --- en cualquier transición de salida del estado
• timer --- en los intervalos determinados por la función llSetTimerEvent
• touch --- Cuando el agente hace click en la tarea
• touch_start --- Cuando un agente comienza a hacer click en una tarea
• touch_end --- Cuando un agente deja de hacer click en la tarea
- ¿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 nuevo;).
Cuando el intérprete llega a una declaración de cambio de estado (mediante la directiva state nombre-de-estado-nuevo):
1. el event-handler que contiene dicha declaración es inmediatamente finalizado
2. se ejecuta el state_exit del estado que se abandona
3. se abandona el estado actual
4. se cambia al nuevo estado
5. se ejecuta el state_entry del estado nuevo
state nuevo
{
state_entry()
{
….
}
}
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.
Si no se declara el state_entry , el script quedará en stand by para otros eventos que declaremos…como un link_message o un listen… etc.
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:
1. el event-handler que contiene dicha declaración es inmediatamente finalizado
2. se ejecuta el state_exit del estado que se abandona
3. se abandona el estado actual
4. se cambia al nuevo estado
5. se ejecuta el state_entry del estado nuevo , si existe.
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 :
1. 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".
2. 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
o Numero entero desde -2,147,483,648 hasta 2,147,483,647
• float
o Numero decimal desde 1.175494351E-38 hasta 3.402823466E+38
• vector
o Tres floats de la forma < x , y , z >. normalmente para position, color con valores entre 0 y 1, or Euler rotation (ángulos en radianes)
• rotation
o Un quaternion rotation, formado por 4 floats, < x , y , z , s > con valores desde -1 a 1
• key
o Un UUID (string especial) usado para identificar algo SL, como pore j agent, object, sound, texture, other inventory item, or dataserver request
• string
o Una secuencia de caracteres , limitados unicamente por la cantidad de memoria libre en el script
• list
o 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
o PI --- 3.1415926535897932384626433832795 (pi)
o TWO_PI--- 6.283185307179586476925286766559 (pi * 2)
o PI_BY_TWO --- 1.5707963267948966192313216916398 (pi / 2
o DEG_TO_RAD --- Convierte de degrees a radians (multiply, example: radian = 90 * DEG_TO_RAD;)
o RAD_TO_DEG --- Convierte de radianes a degrees (multiply, example: degree = PI_BY_TWO * RAD_TO_DEG;)
o SQRT2 --- 1.4142135623730950488016887242097 (square root of 2)
• integer
o TRUE -- 1, an integer constante para operaciones booleanas
o FALSE -- 0, an integer constante para operaciones bolean
o 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)
t -- four spaces
n -- nueva linea
" -- doble comilla
-- backslash
• rotation
o ZERO_ROTATION <0.0, 0.0, 0.0, 1.0>
(Atención: ZERO_ROTATION NO ES <0.0, 0.0, 0.0, 0.0>)
• vector
o ZERO_VECTOR <0.0, 0.0, 0.0>
o OBJETO -- TIPO
o AGENT -- 1
o ACTIVE -- 2
o PASSIVE -- 4
o SCRIPTED -- 8
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 Descripción
• () [] . Parentesis, Brackets, and Dot
• (type) Tipo
• ! ~ ++ -- NOT, One's Complement, Increment, Decrement
• * / % Multiply/Dot-Product, Divide, Modulus/Cross-Product
• - Resta
• + Suma o unión de strings, Concatenation or joining Lists
• << >> Menor que, menor o igual que, Mayor que, mayr o igual que
• == != Comparacion igual, comparacion distintol
• & Bitwise AND
• ^ Bitwise XOR
• | Bitwise OR
• || Comparison OR
• && Comparison AND
• = += -= *= /= %= Asignacion
LSL CONTROL de FLUJO
• for
for( initializer ; condition; increment ) loop
initializer -- ejecutado una vez antes de comprobar condición
condition -- si la condición es TRUE se ejecuta el loop
increment -- ejecutado después del loop, y a continuación la condicion se evalua de nuevo
loop -- puede ser una sentencia simple, un bloque de código o una sentencia nula
Cualquiera de las sentencias pueden ser sentencias nulas
• if
if ( condition ) branch
condition -- si la condición es TRUE se ejecuta el branch
branch -- puede ser una sentencia simple, un bloque de código o una sentencia nula
if ( condition ) branch_true else branch_false
condition -- si la condición es TRUE se ejecuta el branch
branch_true -- puede ser una sentencia simple, un bloque de código o una sentencia nula
branch_false -- puede ser una sentencia simple, un bloque de código o una sentencia nula
• while
while( condition ) loop
condition -- si la condición es TRUE se ejecuta el loop
loop -- puede ser una sentencia simple, un bloque de código o una sentencia nula
Cualquiera de las sentencias pueden ser sentencias nulas
• do while
do loop while (condition);
loop --ejecutado una vez, a continuación se evalua la condición
condition -- si la condición es TRUE, vuelve atrás y se ejecuta el loop otra vez
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
jump target
Etiqueta target – nombre de una etiqueta dentro del mismo ámbito
@target
Etiqueta target – nombre de una etiqueta a la que salta si esta en el mismoambito o en el ambito child
• return
return value
• value – valor o variable que devuelve la función, el tipo debe ser correcto
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
return
Se utiliza para volver de forma inmediata o prematura al ámbito superior antes de llegar al final de la funcion/event handler. No es necesario usar la sentencia return al final de la funcion/eventhandler , ya que es asumido por el compilador
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
default { events } definición del default state
state target { events}
definición del target state
target -- etiqueta de un state
state target;
target -- nombre del state a ejecutar
Cuando la directiva state target se encuentra en tiempo de ejecución, si el state actual y el state target son diferentes :
1. el eventhandler state_exit del estado en curso se ejecuta ( si existe) y se borra la cola de eventos
2. se pasa al estado target, no se registrará ningún listen
3. se ejecuta el eventhandler state_entry en el state target, si existe.
Si el state target es el mismo que el state en curso ,no habrá ningún cambio de state y no tiene ningún efecto.
LSL ERRORES
1 Mensajes de error en tiempo de ejecución (run-time):
Un script puede detenerse en ejecución, y mostrar un mensaje de error "Script error de tiempo de ejecución", seguido de otros mensajes, tales como:
• Script run-time error: Heap Error : Incoherencia. No se puede devolver una lista de una entrada a modo de resultado de una rutina que no devuelve nada.
• Script run-time error: Lists may not contain lists : No intente añadir una lista en una lista.
• Script run-time error: Math Error : Float dividido por cero, entero dividido por cero, etc
• Script run-time error: Stack-Heap Collision : El Stack ha entrado en conflicto con las Bytecode o el Heap. Cada script se ejecuta dentro de 16 KB de memoria dividido en Bytecode, Stack, y Heap.
Puede dar un error al compilar un script demasiado grande, que genere demasiado Bytecode. El script se compila y es guardado de forma correcta, pero cuando usted rezzea un objeto que contiene el script, el script falla, de inmediato o durante la ejecución. Ver llGetFreeMemory.
2 Mensajes de error en compilación : El GUI SL podrá rechazar código en tiempo de compilación, dando un ERROR seguido de otros mensajes tales como:
• Error : Type mismatch : Usted debe nombrar los componentes . X. Y. Z. S de un vector o rotación que está asignando, no se puede asignar todos los componentes a la vez a través de una lista, por ejemplo:
default
{
state_entry()
{
vector vec = (vector) [1, 2, 3]; // ERROR : Type mismatch
llOwnerSay((string) vec);
}
}
• Error : Byte code assembly failed -- out of memory : Usted debe hacer los scripts razonablemente pequeños.
¿Qué es un script demasiado grande?depende. Por ejemplo, los clientes SL 2007-08 Second Life variaban tanto como 30X, de una versián a la siguiente. En concreto, el cliente de SL para Windows aceptaba 22 else-if ´s y daba error con 23 else-if´s o más , mientras que los clientes de SL para Mac OS X aceptaba 692 else-if´s , y daba error con 693 else-if´s o mas .
Los límites en compilación varían en función del sistema operativo en el sentido de que trabaja como un mecanismo de restricción de copia. Cualquier usuario puede ejecutar un script compilado por el compilador menos limitado, pero los usuarios que tienen la limitación mayor en su compilador no pueden guardar cambios realizados en el código fuente.
Ver llGetFreeMemory, llMessageLinked.
• Error : Syntax error : Usted debe escribir el código de su script correctamente cumpliendo las normas de sintaxis dictadas por el compilador.
Además usted debe hacer cada script razonablemente pequeño. El compilador puede sorprendentemente dar un mensaje de error en "Syntax error" en lugar de quejarse más concretamente de un error “out of memory" o "byte code assembly failed" ", cuando el problema es simplemente que usted ha hecho un script demasiado grande.
Por ejemplo, el (2007-08) cliente de Second Life para windows se quejaba de un error de sintaxis si se codificaban muchos else-ifs en cascada . Los límites exactos pueden variar sorprendentemente. Por ejemplo, en el cliente de SL para Windows 2007-08 a veces se aceptan hasta 22 else-if´s en cascada, pero a veces también rechazaba tan sólo 19 else-if´s en cascada, en función de otros detalles del script. Los programadores de LSL que aprendieron a programar en un compilador ( en Mac OS X) pueden pensar que el compilador tiene límites razonables, por ejemplo, hasta quinientos else-if´s en cascada; mientras que los programadores entrenados en otro compilador ( en Windows) pueden creer que lo razonable es , por ejemplo, , no más de doce else-if´s en cascada.
INDICE
LSL DEFINICION 1
LSL EVENTOS 1
LSL ESTADOS 4
LSL FUNCIONES 7
LSL VARIABLES 7
• integer 7
• float 7
• vector 7
• rotation 8
• key 8
• string 8
• list 8
LSL CONSTANTES 9
• float 9
• integer 10
• string 10
• rotation 10
• vector 10
LSL OPERADORES 11
LSL CONTROL de FLUJO 11
• for 11
• if 12
• while 12
• do while 12
• jump 13
• return 13
• state 13
LSL ERRORES 14
By Fiona Spad
19 diciembre 2007

Crea aquí gratis tu avatar en Second Life y vive tu otra vida sin límites!


Está feo que lo diga pero estoy orgullosa del trabajo :-)
Me sirvió para aclarar conceptos de scripting.
Espero que sea útil para los interesados en el tema.
un saludo,
Fiona Spad