Vous êtes sur la page 1sur 39

Lezione propedeutica.

Facciamo un riassunto delle informazioni minime che dovreste


già sapere per poter scriptare. E' una carrellata sulle cose
fondamentali:
(il simbolo § indica argomenti avanzati)

1. Gestione degli script

1.1 Come si crea uno script "New Script"


1.2 Come si edita uno script
1.3 Running/Reset degli script
1.4 Come si debugga uno script
1.5 Impostazione delle permissions
2. Sintassi del linguaggio lsl2

2.1 tipo variabili


2.2 variabili globali e locali
2.3 funzioni
2.4 struttura a stati
2.5 costrutti elementari (for, while, if, jump)

3. Libreria lsl

3.1 funzioni di gestione stringhe


3.2 funzioni di gestione matematica
3.3 funzioni di gestione liste
3.4 funzioni di gestione eventi listen
3.5 funzioni timer
3.6 funzioni touch
3.7 uso di lldialog
1.1 Come si crea uno script

Avete due sistemi:

a) lo create dall'inventory (create new script) e poi lo trascinate


nel content (questo è l'unico modo che funziona con opensim).

b) dal content di un oggetto fate "New Script" e vi verrà creato


uno script che poi andrete a rinominare

1.2. Come si edita uno script

Cliccate sullo script nell'inventory dell'oggetto (oppure tasto


destro/open) vi si apre un "editor" dove potete fare le cose
tipiche che si fanno in ambiente word:
* ctrl-c ctrl-v, funzionano
* shift-canc NON funziona, quindi dovete fare invece ctrl-c e poi
shift-canc altrimenti perdete il testo precedente.
* ctrl-z funziona

Potete fare ctrl-f per fare ricerca e sostituzioni. Ricordatevi di


mettere "case insensitive".

Syntax Highlighting ed help.


* Le funzioni speciali del linguaggio sono rappresentate in
"rosso". se ci passate sopra con il mouse avete un aiuto sulla
sintassi (moolto utile).
* in verde e blu i "verbi" del linguaggio. anche qui si passa sopra
per info
Quando salvate lo script vi segnala gli errori e la riga dove
andare per correggerli. Se vi sono errori lo script viene salvato lo
stesso ma NON è running (non fa niente!!).
1.3 Running reset degli script.

Potete in ogni momento sospendere uno script cliccando sul box


di "Running" e rimetterlo running successivamente. Utile per
stoppare uno script che sta dando di testa.

Analogamente per il reset. Il reset fa ripartire lo script da zero,


PERDENDO tutti i dati che stava usando. Utile per correggere
uno script che ha dato stack/collision.

Le stesse operazioni possono essere fatte da Tools->Set Script


running/not running in selection oppure Tools->Reset Scripts in
selection.
1.4. Come si debugga uno script

Ci sono virtualmente infiniti modi di verificare se uno script sta


facendo quello che deve, visto che la maggior parte del tempo
fa cose strane :(

* Mettete scritte di debug. La cosa più semplice è di usare


llOwnerSay(str), llSay(0, ""), oppure llSay(10,""). Da preferirsi la
terza perchè la potete utilizzare senza disturbare la chat
pubblica.

E' facile scriptare un oggetto perchè ascolti sulla porta 10 e ve la


rilanci come llOwnerSay.
§ 1.4.1 Debug avanzato
Altri sistemi sono meno semplici da strutturare e di solito non si
usano spesso:
* http di log su un sito esterno, (lo vedremo meglio nella lezione
su httprequest)
* colorazione di prim (utile per segnalare lo stato di busy)
* llSetText in cima all'oggetto
* Invio di IM
§ Visto che le chat possono essere difficili da consultare, ho
preparato un logging su un sito esterno (httplog) che potete
usare per i vostri test (si vedrà meglio nella lezione httprequest).

scrivete il seguente in cima al vostro script:


string
sURL="http://www.salahzar.info/lsl/httplog.php?pass=PA
SS";
debug(string k,string action,string str)
{
string
s=sURL+"&key="+llEscapeURL(k)+"&action="+action+"&text
="+llEscapeURL(str);
llOwnerSay(s);
llHTTPRequest(s,[],"");
}
Per consultarlo:
www.salahzar.info/lsl/data/log_k
(where k is the key you used)
1.5 IMPOSTAZIONE DELLE PERMISSIONS
Vi sono svariate tipologie di permissions per gli oggetti:
* COPY (potete avere diverse copie)
* MODIFY (potete modificare le caratteristiche)
* TRANSFER (potete trasferirlo, spesso sinonimo di venderlo ad
altri)

Per gli script:


* COPY lo script può essere ricopiato
* MODIFY lo script può essere visto
* TRANSFER venduto

Anche le texture hanno le loro permissions.

Permissions più diffuse:


Un oggetto "FULL-PERMISSIONS" può essere visto, aperto,
modificato, trasferito.
"COPY-MODIFY" è vostro lo potete modificare ma non trasferire
"MODIFY-TRANSFER" modificare, trasferire ma non copiare
Per gli script le combinazioni più diffuse sono:

* FULL-PERMISSIONS script "open source"

* COPY (no modify) i più diffusi se volete proteggere la proprietà


intellettuale

* NO-PERMISSIONS sconsigliato perchè impedisce anche il copy


degli oggetti in cui è contenuto
2 SINTASSI del linguaggio lsl2
2.1 Tipo delle variabili

* integer (numeri, canali, contatori, flag, handle, importi in L$).


§ 32bit con segno. da −2,147,483,648 a +2,147,483,647

* float (contiene valori in virgola mobile). Es. 3.1415 (o PI)


§ 32 bit, circa 10 cifre significative, da 10E-38 a 10E38 circa.

* string (array di "bytes" gestiti normalmente in una sorta di


UTF-8, simile all'ascii), dimensione massima normalmente 4000
bytes
§ (che possono essere anche molti meno se utf-8 di lingue
strane). Esempio "città" 5 caratteri utf-8, ma 6 bytes.
* key (rappresentano le UUID di oggetti, texture, avatar ecc),
sono "stringhe" lunghe 34 bytes esempio 39941cda-47c1-f928-
30e0-5cc9ce9632a7

* vector (sono 3 float, rappresenta posizioni, velocità, colori..),


esempio <x,y,z>, <r,g,b> dove r,g,b compresi fra 0 e 1 per i
colori.

* rotation (sono 4 float), anche rappresentabili con 3 float.


esempio <x,y,z,w>

* list. Liste eterogenee di dati. Esempio [ "Alpha", 5, <1,0,0> ]


2.2 variabili globali e locali

All'inizio di un programma si specificano le variabili viste


globalmente ovunque. Una variabile globale quando viene
modificata in un punto dello script appare modificata ovunque.
Le variabili globali vengono allocate in un'area chiamata
"statics".

Le variabili globali vanno dichiarate PRIMA della dichiarazione


degli stati

Ogni funzione / stato alloca le variabili locali sullo stack. Le


variabili locali usate all'interno di una funzione od evento
vengono rilasciate al termine dell'evento o della funzione.
E' importante distinguere fra variabili locali e globali.
Confonderle può condurre ai seguenti problemi:
* pensi di scrivere su una variabile globale ma invece scrivi su
una variabile locale che sparisce
* scrivi su una variabile globale pensando di scrivere su una
locale provocando il malfunzionamento di un altro pezzo di
programma

Per evitare confusioni, io suggerisco di usare una nomenclatura


chiara, prefissando le variabili gloabli con una lettera che indica
il loro tipo e mettendole tutte in maiuscolo.
iNOTECARD ad esempio, vPOS, lLISTA....
2.3 funzioni

Le funzioni vanno messe prima degli stati e possono essere


mischiate con le dichiarazioni di globals.

Servono a rendere facilmente utilizzabile pezzi di codice che si


ripete sempre uguale oppure per rendere "riciclabile" pezzi di
codice che avete già fatto in altri oggetti.

E' raccomandabile usare molte funzioni nel vostro codice, anche


se a causa della struttura primordiale di questo linguaggio le
funzioni possono rallentare e/o aumentare il consumo di
memoria.

In particolare ricordate che ogni volta che passate dei parametri


ad una funzione, questi parametri vengono ricopiati e quindi
occupano uno spazio almeno doppio. In quei casi anche se
brutto, è meglio ricorrere alle variabili globali. Questo vale in
particolare se avete bisogno di passare delle liste o delle
stringhe molto grosse.
2.4 struttura a stati e code di eventi

Il programma lsl quando entra in esecuzione è sempre in uno


stato, come minimo il default state. Tutti gli eventi sono associati
a quello stato se cambiate stato le code di eventi VENGONO
cancellate!

Per ogni evento c'è una "coda di eventi" per registrare le attività
che devono essere eseguite dall'oggetto (task). La coda di
eventi è limitata.
§ Notizia curiosa: se siete in una zona noscript il vostro
programma NON è in esecuzione, ma le code di eventi
continuano ad essere aggiornate (fino al loro limite).

Gli eventi più importanti sono:


- touch_start(integer count) (da non confondere con
touch(integer count)).
- on_rez(integer parm)
- state_entry()
- listen()
- timer()

2.5 costrutti elementari

- for(integer i=0;i<10;i++){}
- do {} while (<test>) ;
- while (<test> ) {}
- if(<test>) {}
- if(<test>) {} else {}
- @label ....... jump label
- chiamata di funzione
3. Libreria lsl
3.1 gestione stringhe
Fondamentali!!!

- x="string"
- llStringLength(x) per ottenere la sua lunghezza in caratteri
(non bytes!)
§ L'occupazione effettiva dipende dall'uso di caratteri UTF-8
estesi.
- llStringTrim(x,STRING_TRIM) per togliere spazi in testa e in
coda
- llGetSubString(x,start,end) per ottenere un pezzo di una
stringa. Nota l'uso di indici negativi per riferire agli ultimi
elementi della stringa. Nota la partenza da 0
- llDeleteSubString(x,start,end) per cancellare pezzi di stringa
- llSubStringIndex(src,pattern) cerca una stringa in un'altra
- llInsertString(dst,pos,src) inserisce una stringa dentro un'altra
§ - llMD5String(str,nonce) "firma" una stringa per sicurezza
§ - llXorBase64Strings(s1,s2) "cripta" una stringa con una
password
§ - llEscapeURL(s) trasforma una stringa in modo che sia
utilizzabile su internet
§ - llUnescapeURL(s) ritrasforma una stringa internet in formato
normale

Trucco: usate s=(s="")+s+x; invece di s+=x per ridurre l'uso di


memoria
3.2 funzioni matematiche

Le più importanti:

- llFrand(maxnum) per la generazione causale di canali,


password etc
- llFabs()
- llRound()
§ - llSin/llCos (in radianti) per la costruzione di strutture circolari

Rotazioni, visto che sono fra le più difficili :)

§- llEuler2Rot (converte un vettore euleriano in una rotazione) e


llRot2Euler
§- llAxes2Rot (fwd, left, fwd % left) dati due vettori determina la
rotazione implicita
3.3 funzioni di gestione liste

Ricordatevi che le funzioni di liste non modificano MAI la lista ma


ritornano sempre nel caso una lista modificata! (Questo
aumenta l'uso della memoria)

- llDeleteSubList(src,start,end) toglie un pezzo di lista

- llGetListLength(lst)
- llList2<Type>(lst,index) estrae un elemento tipato
§ attenzione se è un vettore conviene estrarlo in genere con
(vector)llList2String(lst,index)
- llList2List(src,start,end) estrae una sottolista
- llListFindList(src, lst) cerca un insieme di elementi nella lista
- llListInsertList(dst,src,pos) inserisce una lista
- llListRandomize(lst,stride) mette una lista in ordine casuale
- llListReplaceList(dst,src,start,end)

§ Funzioni avanzate

§- llGetListEntryType(lst,index) tipo dell'elemento della lista


§- llList2ListStrided(src,start,end,stride) estrae una "lista
intervallata"
§- llList2CSV(lst) salva una lista in una stringa
§- llDumpList2String(list,separator) salva una lista in una stringa
§- llCSV2List(string) ripristina una lista da una stringa
§- llListSort(src,stride,ascending)
§- llListStatistics
§- llParseString2List(src,sep,spacers)
§- llParseStringKeepNulls(src,sep,spacers)
§ Trucco: usate lst=(lst=[])+lst+x invece di lst+=x per ridurre
l'uso di memoria
3.4 Funzioni di gestione eventi listen

integer handle=llListen(channel,name,id,string) => apre


l'ascolto su un canale

channel:0 è quello dove gli avatar parlano


channel:>0 ogni avatar può parlare su quel canale facendo /x
parlo
§ channel:<0 solo gli oggetti possono parlare su quel canale
§ channel:DEBUG_CHANNEL usato dagli oggetti per segnalare
stati strani (script con triangolino giallo)

il canale è usato anche dalla funzione llDialog (che quindi non


funziona se parallelamente non è stato fatto un llListen)
NB: se non si fa la llListen, l'oggetto NON gestirà l'evento listen()
anche se definito!!
§ NB: i listeners creano lag, specie quelli sul canale 0
§ NB: listener su canali negativi generano MENO lag

§ In generale occorre limitare il numero di listeners al minimo


possibile e rimuovere l'handle non appena possibile con la
funzione llListenRemove(handle).

Usate sempre dei debug per essere sicuri di cosa state


ricevendo e di come avete impostato il listener. Molti oggetti
funzionano male perchè:

- non avete impostato il listener


- l'avete impostato male (sul canale sbagliato, specificando un id
sbagliato, di solito si imposta NULL_KEY, ma se state facendo un
llDialog potete mettere la key di chi vi ha toccato) ecc.
§ - è stato disattivato l'handle con una llListenRemove

§ La id può essere impostata a llGetOwner () in modo che


l'oggetto risponda solo all'owner. Per farla rispondere al gruppo
basta inserire un test nell'evento:
if(llSameGroup(id)) ....
3.5 funzioni timer

llSetTimerEvent(seconds) se 0 viene disabilitato

Si usa per moltissimi casi, fra cui:

* fare una cosa ogni tot secondi (es. cambiare foto)


§ * gestire un "timeout" esempio mantenere acceso un listener
solo per 30 secondi per ridurre il lag
§ * gestire timer multipli
§ * produrre un evento concordato (llSetTimerEvent(0.1) fa
scattare l'evento)

Ricordate che llSetTimerEvent imposta l'evento in modo


RIPETUTO, quindi se non lo spegnete l'evento si manifesta di
nuovo ogni tot secondi.
3.6 Funzioni di touch

touch_start(integer count)

Sono lo strumento principale per gestire l'interazione con gli


avatar (ce ne sono altri, mq il touch è quello che produce la
MINORE quantità di lag).

E' importante distinguere fra touch_start e touch. Il primo scatta


solo una volta quando l'oggetto viene toccato.
Touch invece continua a scattare per tutto l'intervallo di tempo
in cui l'avatar mantiene cliccato il tasto sinistro del mouse.

Cos'è il parametro count? Dice QUANTI avatar stanno toccando


l'oggetto.
In generale possiamo supporre per semplicità che ce ne sia uno
soltanto e per ottenerne l'identità scriviamo
key avkey=llDetectedKey(0)

§ ma se volessimo essere precisi dovremmo fare:


for(integer i=0;i<count;i++)
{
key avkey=llDetectedKey(i);
...
}
§ Altre interazioni possibili:

* la listen precedentemente citata (ma è considerata spesso


scomoda)
* le funzioni di collisione (ma l'avatar deve esplicitamente
andare addosso all'oggetto)
* sensor (l'avatar è vicino all'oggetto)

3.7 llDialog

funziona in pieno accordo con il touch: ecco il framework


indicativo per usarlo

integer iLISTEN=0;
integer iCHANNEL=-3000;
default
{
touch_start(integer count)
{
key avkey=llDetectedKey(0);
list options=[ "o1", "o2", "o3" ];
iLISTEN=llListen(iCHANNEL,"",avKey,"");
llSetTimerEvent(60); // deve rispondere entro 60 secondi
llDialog(avkey, "please say something",options,iCHANNEL);
}
timer()
{
llRemoveListener(iLISTEN);
llSay(0,"Timeout please touch me again for talking");
llSetTimerEvent(0);
}
listen(integer channel, string name, key id, string str)
{
llSay(0,"you told me "+str);
llSetTimerEvent(0);
llRemoveListener(iLISTEN);
}
}

Vous aimerez peut-être aussi