Difference between revisions of "User:Michel Lemmon/Script Propedeutico"

From Second Life Wiki
Jump to navigation Jump to search
(New page: {| width="100%" |- |valign="top"| <div id="box"> ==Script Lezione Propedeutica == <div style="padding: 0.5em"> '''Descrizione:''' Si tratta di una lezione Propedeutica Script '''Pre-Requi...)
 
m (added to category)
 
(6 intermediate revisions by one other user not shown)
Line 5: Line 5:
==Script Lezione Propedeutica ==
==Script Lezione Propedeutica ==
<div style="padding: 0.5em">
<div style="padding: 0.5em">
'''Descrizione:''' Si tratta di una lezione Propedeutica Script
'''Descrizione:''' Si tratta di una lezione Propedeutica Script avanzati


'''Pre-Requisiti:''' Conoscenza base di script
'''Pre-Requisiti:''' Una conoscenza base di Script


'''Durata Stimata:''' 60 minuti
'''Durata Stimata:''' 90 minuti


'''Nota:''' Trovate qui di seguito le slide della formazione.
'''Nota:''' Trovate qui di seguito le slide della formazione.
Line 15: Line 15:
</div>
</div>
<div id="box">
<div id="box">
==Slide 1 Lezione Propedeutica==
==Introduzione Lezione Propedeutica==
<div style="padding: 0.5em">
<div style="padding: 0.5em">
Lezione propedeutica.
Facciamo un riassunto delle informazioni minime che dovreste già sapere per poter scriptare. E' una carrellata sulle cose fondamentali:
Facciamo un riassunto delle informazioni minime che dovreste già sapere per poter scriptare. E' una carrellata sulle cose fondamentali:
(il simbolo § indica argomenti avanzati)
(il simbolo § indica argomenti avanzati)
Line 50: Line 48:
</div>
</div>
<div id="box">
<div id="box">
==Come si crea uno script "New Script"==
==Come si crea uno script==
<div style="padding: 0.5em">
<div style="padding: 0.5em">
Avete due sistemi:
Avete due sistemi:
 
*lo create dall'inventory (create new script) e poi lo trascinate nel content (questo è l'unico modo che funziona con opensim).
*a) lo create dall'inventory (create new script) e poi lo trascinate nel content (questo è l'unico modo che funziona con opensim).
*dal content di un oggetto fate "New Script" e vi verrà creato uno script che poi andrete a rinominare
*b) dal content di un oggetto fate "New Script" e vi verrà creato uno script che poi andrete a rinominare
 
</div>
</div>
</div>
</div>
Line 95: Line 91:


E' facile scriptare un oggetto perchè ascolti sulla porta 10 e ve la rilanci come llOwnerSay.
E' facile scriptare un oggetto perchè ascolti sulla porta 10 e ve la rilanci come llOwnerSay.
</div>
*§ Debug avanzato
</div>
<div id="box">
==§ Debug avanzato ==
<div style="padding: 0.5em">
Altri sistemi sono meno semplici da strutturare e di solito non si usano spesso:
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)
* http di log su un sito esterno, (lo vedremo meglio nella lezione su httprequest)
Line 105: Line 97:
* llSetText in cima all'oggetto
* llSetText in cima all'oggetto
* Invio di IM
* 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).
§ 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:
*scrivete il seguente in cima al vostro script:
string sURL="http://www.salahzar.info/lsl/httplog.php?pass=PASS";
 
debug(string k,string action,string str)
  string sURL="http://www.salahzar.info/lsl/httplog.php?pass=PASS";
{
  debug(string k,string action,string str)
  {
     string s=sURL+"&key="+llEscapeURL(k)+"&action="+action+"&text="+llEscapeURL(str);
     string s=sURL+"&key="+llEscapeURL(k)+"&action="+action+"&text="+llEscapeURL(str);
     llOwnerSay(s);
     llOwnerSay(s);
     llHTTPRequest(s,[],"");
     llHTTPRequest(s,[],"");
}
  }


Per consultarlo:
'''Per consultarlo:'''
www.salahzar.info/lsl/data/log_k
www.salahzar.info/lsl/data/log_k
(where k is the key you used)  
(where k is the key you used)  
Line 123: Line 116:
</div>
</div>
<div id="box">
<div id="box">
==Impostazioni delle permission==
==Permissions==
<div style="padding: 0.5em">  
<div style="padding: 0.5em">
Vi sono svariate tipologie di permissions per gli oggetti:
Vi sono svariate tipologie di permissions per gli oggetti:
* COPY (potete avere diverse copie)
* COPY (potete avere diverse copie)
Line 138: Line 131:


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


Line 151: Line 144:
</div>
</div>
<div id="box">
<div id="box">
=='''SINTASSI del linguaggio lsl2'''==
==SINTASSI del linguaggio lsl2==
<div style="padding: 0.5em">  
<div style="padding: 0.5em">
</div>
</div>
</div>
</div>
<div id="box">
<div id="box">
==Tipo delle variabili==
==Tipo delle variabili==
<div style="padding: 0.5em">  
<div style="padding: 0.5em">
* integer (numeri, canali, contatori, flag, handle, importi in L$).  
* integer (numeri, canali, contatori, flag, handle, importi in L$).  
§ 32bit con segno. da -2,147,483,648 a +2,147,483,647
§ 32bit con segno. da -2,147,483,648 a +2,147,483,647
Line 177: Line 170:
</div>
</div>
<div id="box">
<div id="box">
==Variabili globali e locali==
==variabili globali e locali==
<div style="padding: 0.5em">
<div style="padding: 0.5em">
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".
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".
Line 194: Line 187:
</div>
</div>
<div id="box">
<div id="box">
==Funzioni==
==funzioni==
<div style="padding: 0.5em">
<div style="padding: 0.5em">
Le funzioni vanno messe prima degli stati e possono essere mischiate con le dichiarazioni di globals.
Le funzioni vanno messe prima degli stati e possono essere mischiate con le dichiarazioni di globals.
Line 206: Line 199:
</div>
</div>
<div id="box">
<div id="box">
==Struttura a stati e code di eventi==
==struttura a stati e code di eventi==
<div style="padding: 0.5em">
<div style="padding: 0.5em">
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!
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.  
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).
*§ 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:
'''Gli eventi più importanti sono:'''
* touch_start(integer count)  (da non confondere con touch(integer count)).
*touch_start(integer count)  (da non confondere con touch(integer count)).
* on_rez(integer parm)
*on_rez(integer parm)
* state_entry()
*state_entry()
* listen()
*listen()
* timer()
*timer()
</div>
</div>
</div>
</div>
<div id="box">
<div id="box">
==Costrutti elementari==
==costrutti elementari==
<div style="padding: 0.5em">
<div style="padding: 0.5em">
* for(integer i=0;i<10;i++){}
*for(integer i=0;i<10;i++){}
* do {} while (<test>) ;
*do {} while (<test>) ;
* while (<test> ) {}
*while (<test> ) {}
* if(<test>) {}
*if(<test>) {}
* if(<test>) {} else {}
*if(<test>) {} else {}
* @label ....... jump label
*@label ....... jump label
* chiamata di funzione
*chiamata di funzione
</div>
</div>
</div>
</div>
<div id="box">
<div id="box">
=='''Libreria lsl'''==
==Libreria lsl==
<div style="padding: 0.5em">
<div style="padding: 0.5em">
</div>
</div>
</div>
</div>
<div id="box">
<div id="box">
==Gestione stringhe==
==gestione stringhe==
<div style="padding: 0.5em">
<div style="padding: 0.5em">
Fondamentali!!!
'''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'''


*  x="string"
'''§ - llUnescapeURL(s) ritrasforma una stringa internet in formato normale'''
*  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
Trucco: usate s=(s="")+s+x; invece di s+=x per ridurre l'uso di memoria
Line 260: Line 256:
</div>
</div>
<div id="box">
<div id="box">
==Funzioni matematiche==
==funzioni matematiche==
<div style="padding: 0.5em">
<div style="padding: 0.5em">
Le più importanti:
'''Le più importanti:'''
 
* llFrand(maxnum) per la generazione causale di canali, password etc
* llFabs()
* llRound()


*  llFrand(maxnum) per la generazione causale di canali, password etc
'''§ - llSin/llCos (in radianti) per la costruzione di strutture circolari'''
*  llFabs()
*  llRound()
*§ llSin/llCos (in radianti) per la costruzione di strutture circolari


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


*§ llEuler2Rot (converte un vettore euleriano in una rotazione) e llRot2Euler
'''§- llEuler2Rot (converte un vettore euleriano in una rotazione) e llRot2Euler'''
*§ llAxes2Rot (fwd, left, fwd % left) dati due vettori  determina la rotazione implicita
 
'''§- llAxes2Rot (fwd, left, fwd % left) dati due vettori  determina la rotazione implicita'''
</div>
</div>
</div>
</div>
<div id="box">
<div id="box">
==Funzioni di gestione liste==
==funzioni di gestione liste==
<div style="padding: 0.5em">
<div style="padding: 0.5em">
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)
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
* llDeleteSubList(src,start,end) toglie un pezzo di lista
* llGetListLength(lst)  
* llGetListLength(lst)  
* llList2<Type>(lst,index) estrae un elemento tipato
* llList2<Type>(lst,index) estrae un elemento tipato
*§ attenzione se è un vettore conviene estrarlo in genere con       
 
   (vector)llList2String(lst,index)
'''§ attenzione se è un vettore conviene estrarlo in genere con       
   (vector)llList2String(lst,index)'''
 
* llList2List(src,start,end) estrae una sottolista
* llList2List(src,start,end) estrae una sottolista
* llListFindList(src, lst) cerca un insieme di elementi nella lista
* llListFindList(src, lst) cerca un insieme di elementi nella lista
Line 292: Line 291:
* llListReplaceList(dst,src,start,end)
* llListReplaceList(dst,src,start,end)


§ Funzioni avanzate
'''§ 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'''


*§ llGetListEntryType(lst,index) tipo dell'elemento della lista
'''§- llListSort(src,stride,ascending)'''
*§ 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
'''§- 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'''
</div>
</div>
</div>
</div>
Line 312: Line 319:
integer handle=llListen(channel,name,id,string) => apre l'ascolto su un canale
integer handle=llListen(channel,name,id,string) => apre l'ascolto su un canale


* channel:0  è quello dove gli avatar parlano
*channel:0  è quello dove gli avatar parlano
* channel:>0 ogni avatar può parlare su quel canale facendo /x parlo
*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)
'''§ 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)
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: 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).
'''§ 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è:
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
* 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.
* 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:
'''§ - è stato disattivato l'handle con una llListenRemove'''
if(llSameGroup(id)) ....
 
'''§ 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)) ....'''
</div>
</div>
</div>
</div>
<div id="box">
<div id="box">
==Funzioni timer==
==funzioni timer==
<div style="padding: 0.5em">
<div style="padding: 0.5em">
llSetTimerEvent(seconds)    se 0 viene disabilitato
llSetTimerEvent(seconds)    se 0 viene disabilitato


Si usa per moltissimi casi, fra cui:
'''Si usa per moltissimi casi, fra cui:'''


* fare una cosa ogni tot secondi (es. cambiare foto)
* 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
'''§ * gestire un "timeout" esempio mantenere acceso un listener solo per 30 secondi per ridurre il lag'''
*§ produrre un evento concordato (llSetTimerEvent(0.1) fa scattare l'evento)
 
'''§ * 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.
Ricordate che llSetTimerEvent imposta l'evento in modo RIPETUTO, quindi se non lo spegnete l'evento si manifesta di nuovo ogni tot secondi.
Line 365: Line 379:
key avkey=llDetectedKey(0)
key avkey=llDetectedKey(0)


§ ma se volessimo essere precisi dovremmo fare:
'''§ ma se volessimo essere precisi dovremmo fare:'''
for(integer i=0;i<count;i++)


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


* la listen precedentemente citata (ma è considerata spesso scomoda)
* la listen precedentemente citata (ma è considerata spesso scomoda)
Line 381: Line 396:
</div>
</div>
<div id="box">
<div id="box">
==llDialog==
==llDialog ==
<div style="padding: 0.5em">
<div style="padding: 0.5em">
funziona in pieno accordo con il touch: ecco il framework indicativo per usarlo
funziona in pieno accordo con il touch: ecco il framework indicativo per usarlo


integer iLISTEN=0;
  integer iLISTEN=0;
integer iCHANNEL=-3000;
  integer iCHANNEL=-3000;
 
  default  
 
  {
default  
  touch_start(integer count)
{
  {
touch_start(integer count)
{
     key avkey=llDetectedKey(0);
     key avkey=llDetectedKey(0);
     list options=[ "o1", "o2", "o3" ];
     list options=[ "o1", "o2", "o3" ];
Line 398: Line 411:
     llSetTimerEvent(60); // deve rispondere entro 60 secondi
     llSetTimerEvent(60); // deve rispondere entro 60 secondi
     llDialog(avkey, "please say something",options,iCHANNEL);     
     llDialog(avkey, "please say something",options,iCHANNEL);     
}
  }
timer()
  timer()
{
  {
     llRemoveListener(iLISTEN);
     llRemoveListener(iLISTEN);
     llSay(0,"Timeout please touch me again for talking");
     llSay(0,"Timeout please touch me again for talking");
     llSetTimerEvent(0);
     llSetTimerEvent(0);
}
  }
listen(integer channel, string name, key id, string str)
  listen(integer channel, string name, key id, string str)
{
  {
     llSay(0,"you told me "+str);
     llSay(0,"you told me "+str);
     llSetTimerEvent(0);
     llSetTimerEvent(0);
     llRemoveListener(iLISTEN);
     llRemoveListener(iLISTEN);
}
  }
}
  }
 
</div>
</div>
</div>
</div>
Line 418: Line 430:
==Ringraziamenti==
==Ringraziamenti==
<div style="padding: 0.5em">
<div style="padding: 0.5em">
[[User:Salahzar Stenvaag|Salahzar Stenvaag]]
[[User:Salahzar Stenvaag|Coach:Salahzar Stenvaag]]  
</div>
</div>
</div>
</div>
Line 425: Line 437:
{{User:Michel_Lemmon/Michel_Quik_links_it}}
{{User:Michel_Lemmon/Michel_Quik_links_it}}
|}
|}
[[User:Michel Lemmon|Michel Lemmon]] 22:00, 6 march 2008(PST)
[[User:Michel Lemmon|Michel Lemmon]] 3:30pm, 18 march 2008(PST)
 
[[category:Pagine italiane da wikificare]]

Latest revision as of 13:07, 1 November 2009

Introduzione 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)

Gestione degli script

  1. Come si crea uno script "New Script"
  2. Come si edita uno script
  3. Running/Reset degli script
  4. Come si debugga uno script
  5. Impostazione delle permissions

Sintassi del linguaggio lsl2

  1. tipo variabili
  2. variabili globali e locali
  3. funzioni
  4. struttura a stati
  5. costrutti elementari (for, while, if, jump)

Libreria lsl

  1. funzioni di gestione stringhe
  2. funzioni di gestione matematica
  3. funzioni di gestione liste
  4. funzioni di gestione eventi listen
  5. funzioni timer
  6. funzioni touch
  7. uso di lldialog

Come si crea uno script

Avete due sistemi:

  • lo create dall'inventory (create new script) e poi lo trascinate nel content (questo è l'unico modo che funziona con opensim).
  • dal content di un oggetto fate "New Script" e vi verrà creato uno script che poi andrete a rinominare

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!!).

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.

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.

  • § 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=PASS";
 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)

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

SINTASSI del linguaggio lsl2

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> ]

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....

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.

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()

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

Libreria lsl

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

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

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

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)) ....

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.

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)

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);
 }
 }

Ringraziamenti

Michel's Informazioni
Michel Lemmon2.jpg
Click per Ingrandire


Link VTeam

Michel Lemmon 3:30pm, 18 march 2008(PST)