LSL Pour les nuls: Sleep & Timer

Répondre
Partager Rechercher
Exemples d'application


Vous avez atteint un petit niveau en scripting et vous pouvez écrire facilement un petit script.

Les sleep et timer [ llSetTimerEvent (...) et llSleep(...) ] vous sont familiers désormais et vous décidez d'écrire un script simple correspondant au petit défi suivant.

Citation :
On désire avec une simple box réaliser un chronomètre donnant les secondes écoulées entre deux évènements.


Pour utiliser le chrono l'avatar devra être assis.

Le temps maximum possible est de 10 secondes.

Chaque clic lancera (relancera) OU stoppera le chrono.

Bien informer l'utilisateur sur toutes les actions.
La notion de temps vous dirige naturellement vers les deux instructions citées précédemment:

llSetTimerEvent (...) ou llSleep(...) ou les deux.

Le clic vers l'évènement touch_start

La détection du sit est moins évidente mais après recherche dans le wiki et/ou JOL évènement changed & CHANGED_LINK semble tout indiqué (utilisé dans les poses balls)


La structure du script s'établit ainsi:


Code PHP:

Counter (integer on)
{
  
// chrono 1s
}

default
{
    
state_entry() 
    {
        
// startup //
    
}

    
touch_start(integer num)
    {
        
// detection  start stop chrono
    
}
    
    
changed(integer change
    {
        
// assis / debout ?                                           }
    
)

    
timer()
    {  
        
// maximum 10 secondes.  
    
}

L'écriture du script est un jeu d'enfant :


Initialiser les données:

Code PHP:

    state_entry() 
    {
        
llSitTarget(<0.250.00.6>, ZERO_ROTATION); // préparons le siege...

        
llOwnerSay(Informations);   // informons le nouveau venu
        
Chrono_On FALSE;           // chrono prêt!  
    

Pour afficher les secondes:

Code PHP:

Counter (integer on)
{
    while (
on)
    {
        
llSleep(1);   // Affiche toutes les secondes         
        
llOwnerSay "Chrono ==> " + (string) (++Seconds) + " s"); // on affiche en incrementant le chrono...
    
}    

Gestions des clics:

Citation :
.Il faut être assis pour démarrer et stopper en alternance le chrono...

.Le start déclenche aussi la limite de 10 secondes
Code PHP:

 touch_start(integer num)
    {
        if (!
Sit// on a cliqué debout...  donc on refuse!!
        
{
            
llOwnerSay(Informations); // Ré-informons... 
            
return;
        }
        
        
Chrono_On =!Chrono_On;  // start <==> stop  etc...        
        
        
if (Chrono_On
        {   
// Chrono on
            
llOwnerSay "Chrono démarré pour 10 secondes!" ); // GO!
            
llSetTimerEvent (10);
            
Counter(TRUE);
        }
        else 
        {   
// Chrono off
            
llOwnerSay "Chrono arrété!" );  // STOP         
            
Counter(FALSE);            
        }
    } 

Gestion du timer

Citation :
qui stoppe tout après 10 secondes
Code PHP:

    timer()
    {
// get 10 seconds
        
llSetTimerEvent(0);
        
llOwnerSay "Les 10 secondes se sont écoulées!" ); // Fin du temps accordé //
    



Gestion assis / debout


Citation :
Si on se lève on stoppe le chrono...

Code PHP:

    changed(integer change
    {                                       
// quelque chose arrive mais quoi??
        
if (change CHANGED_LINK
        {                                   
// un link a changé!  quelqu'un vient de s'assoir??
            
key avatar llAvatarOnSitTarget();
            if (
avatar != NULL_KEY && !Sit
            {                               
// oui!! informons le 
                    
llOwnerSay("\nVous êtes assis...donc vous pouvez cliquez maintenant...");
                    
Sit TRUE// gardons cette information de quelqu'un est assis
            
}
            else
            {
                
Sit FALSE;
                
llOwnerSay "Chrono arrété!" );    // STOP       
                
Counter(FALSE);                  
            }
        }
    } 
Le script..
Ce qui donne en finalité le code suivant:

Code PHP:

//  Variables Globales //
integer Seconds;
integer Chrono_On;      // start/stop chrono
integer Sit;            // si assis ou pas..

string Informations =   "\nVeuillez vous assoir...\nCliquez pour lancer le chrono pour 10 seconds Maximum...\nPour le stopper..\n Cliquez de nouveau..\n ou bien lever vous tout simplement."// Message d(informations


//  Fonctions globales //

Counter (integer on)
{
    while (
on)
    {
        
llSleep(1);   // Affiche toutes les secondes         
        
llOwnerSay "Chrono ==> " + (string) (++Seconds) + " s"); // on affiche en incrementant le chrono...
    
}    
}


default
{
    
state_entry() 
    {
        
llSitTarget(<0.250.00.6>, ZERO_ROTATION); // préparons le siege...

        
llOwnerSay(Informations);   // informons le nouveau venu
        
Chrono_On FALSE;           // chrono prêt!  
    
}

    
touch_start(integer num)
    {
        if (!
Sit// on a cliqué debout...  donc on refuse!!
        
{
            
llOwnerSay(Informations); // Ré-informons... 
            
return;
        }
        
        
Chrono_On =!Chrono_On;  // start <==> stop  etc...        
        
        
if (Chrono_On
        {   
// Chrono on
            
llOwnerSay "Chrono démarré pour 10 secondes!" ); // GO!
            
llSetTimerEvent (10);
            
Counter(TRUE);
        }
        else 
        {   
// Chrono off
            
llOwnerSay "Chrono arrété!" );  // STOP         
            
Counter(FALSE);            
        }
    }
    
    
changed(integer change
    {                                       
// quelque chose arrive mais quoi??
        
if (change CHANGED_LINK
        {                                   
// un link a changé!  quelqu'un vient de s'assoir??
            
key avatar llAvatarOnSitTarget();
            if (
avatar != NULL_KEY && !Sit
            {                               
// oui!! informons le 
                    
llOwnerSay("\nVous êtes assis...donc vous pouvez cliquez maintenant...");
                    
Sit TRUE// gardons cette information de quelqu'un est assis
            
}
            else
            {
                
Sit FALSE;
                
llOwnerSay "Chrono arrété!" );    // STOP       
                
Counter(FALSE);                  
            }
        }
    }


    
timer()
    {
// get 10 seconds
        
llSetTimerEvent(0);
        
llOwnerSay "Les 10 secondes se sont écoulées!" ); // Fin du temps accordé //
    
}

Passons aux tests simples:

Compilation ==>OK

Startup à l'écran ==> OK

Citation :
Veuillez vous assoir...

Cliquez pour lancer le chrono pour 10 seconds Maximum...

Pour le stopper..

Cliquez de nouveau..

ou bien lever vous tout simplement.
Detection de l'avatar assis ==> OK

Citation :
Vous êtes assis...donc vous pouvez cliquez maintenant...

Lancement du chrono ==> OK


Citation :
[3:17] Object: Chrono démarré pour 10 secondes!
[3:17] Object: Chrono ==> 1 s
[3:17] Object: Chrono ==> 2 s
[3:17] Object: Chrono ==> 3 s
[3:17] Object: Chrono ==> 4 s

Tout est conforme au spécifications à ce stade.

Reste à tester les stop et restart.
Suite et fin des tests...
Le chrono est lancé

Citation :
llOwnerSay ( "Chrono démarré pour 10 secondes!" ); // GO!
llSetTimerEvent (10);
Counter(TRUE);
vérifions qu'il s'arrête à 10 secondes

Citation :
[3:21] Object: Chrono démarré pour 10 secondes!
[3:21] Object: Chrono ==> 1 s
[3:21] Object: Chrono ==> 2 s
[3:21] Object: Chrono ==> 3 s
[3:21] Object: Chrono ==> 4 s
[3:21] Object: Chrono ==> 5 s
[3:21] Object: Chrono ==> 6 s
[3:21] Object: Chrono ==> 7 s
[3:21] Object: Chrono ==> 8 s
[3:21] Object: Chrono ==> 9 s
[3:21] Object: ????
la seconde suivante confirmera sans doute l'arrèt du chrono .. et le script bien fait

Cliquez ce bouton ou survolez le contenu pour afficher le spoiler
Tester le script en 20 secondes pour connaitre la réponse..

Créer une box .. copier / coller ... assis...clic

[3:21] Object: Chrono ==> 9 s
[3:21] Object: ????
Oncontinue les tests...
Voyons un peu votre tête maintenant fasse aux résultats...

Cliquez ce bouton ou survolez le contenu pour afficher le spoiler
[3:21] Object: Chrono démarré pour 10 secondes!
[3:21] Object: Chrono ==> 1 s
[3:21] Object: Chrono ==> 2 s
[3:21] Object: Chrono ==> 3 s
[3:21] Object: Chrono ==> 4 s
[3:21] Object: Chrono ==> 5 s
[3:21] Object: Chrono ==> 6 s
[3:21] Object: Chrono ==> 7 s
[3:21] Object: Chrono ==> 8 s
[3:21] Object: Chrono ==> 9 s
[3:21] Object: Chrono ==> 10 s
[3:21] Object: Chrono ==> 11 s
[3:21] Object: Chrono ==> 12 s
[3:21] Object: Chrono ==> 13 s
Citation :
Quelque chose comme cela..




Bon cliquons sur la box pour stopper ce chrono... et regardons le résultat:


Cliquez ce bouton ou survolez le contenu pour afficher le spoiler

[7:41] Object: Chrono ==> 20 s
[7:41] Object: Chrono ==> 25 s
[7:41] Object: Chrono ==> 26 s
[7:41] Object: Chrono ==> 27 s
[7:41] Object: Chrono ==> 28 s
[7:42] Object: Chrono ==> 29 s
[7:42] Object: Chrono ==> 30 s
[7:42] Object: Chrono ==> 31 s
[7:42] Object: Chrono ==> 32 s
[7:42] Object: Chrono ==> 33 s
[7:42] Object: Chrono ==> 34 s
[7:42] Object: Chrono ==> 35 s
[7:42] Object: Chrono ==> 36 s
[7:42] Object: Chrono ==> 37 s
[7:42] Object: Chrono ==> 38 s
Citation :


Levons nous et constatons...l'étendue de notre problématique..

Cliquez ce bouton ou survolez le contenu pour afficher le spoiler
[7:42] Object: Chrono ==> 43 s
[7:42] Object: Chrono ==> 44 s
[7:42] Object: Chrono ==> 45 s
[7:42] Object: Chrono ==> 46 s
[7:42] Object: Chrono ==> 47 s
[7:42] Object: Chrono ==> 48 s
[7:42] Object: Chrono ==> 49 s
[7:42] Object: Chrono ==> 50 s
[7:42] Object: Chrono ==> 51 s
[7:42] Object: Chrono ==> 52 s
[7:42] Object: Chrono ==> 53 s
[7:42] Object: Chrono ==> 54 s
Citation :
Explications pour le sleep et timer
En lisant le wiki vous n'apprendrez pas grand chose de plus que vous ne connaissiez déjà...

llSleep:
Puts the script to sleep for sec seconds. The script will not do anything during this time

llSetTimerEvent:
Cause the timer event to be triggered a maximum of once every sec seconds. Passing in 0.0 stops further timer events.


Regardons le code:


Code PHP:

Counter (integer on)
{
    while (
on)
    {
        
llSleep(1);   // Affiche toutes les secondes         
        
llOwnerSay "Chrono ==> " + (string) (++Seconds) + " s"); // on affiche en incrementant le chrono...
    
}    

Code PHP:

    llSetTimerEvent (10);
    
Counter(TRUE); 
On lance le timer, réglé sur 10 secondes, et on appelle une procédure qui boucle sur elle même suspendant toute éxecution de code pendant 1 seconde et ensuite incrémente et affiche un compteur et ainsi de suite...

La première idée qui vient à l'esprit est que le timer est suspendu puisque que tout le code du script l'est.

En d'autres terme le timer ne sera actif et son temps décompté que pendant la durée de l'instruction (llOwnerSay).

La durée de l'instruction durant ~12 ms ... l'event timer se réveillera dans

10 / .001 = 1000 s.


Faisons un 3 tests très simples pour vérifier cette hypothèse...

Test1:

Code PHP:

default
{
    
state_entry()
    {
        
llResetTime();
        
llSetTimerEvent(5); // 5 secondes timer
        
llSleep(10);            // 10 secondes sleep 
        
llOwnerSay "Sleep " + (string) llGetAndResetTime());        
    }
    
timer()
    {
        
llOwnerSay "Timer: " + (string) llGetTime());
        
llSetTimerEvent(0); 
    }

Test2:

Code PHP:

default
{
    
state_entry()
    {
        
llResetTime();
        
llSetTimerEvent(5); // 5 secondes timer
        
llSleep(10);            // 10 secondes sleep 
        
llOwnerSay "Sleep " + (string) llGetAndResetTime());        
    }
    
timer()
    {
        
llOwnerSay "Timer: " + (string) llGetTime());
        
llSetTimerEvent(0); 
    }

Test3:
Code PHP:

default
{
    
state_entry()
    {
        
llResetTime();
        
llSetTimerEvent(5); // 5 secondes timer
        
llSleep(5);            // 5 secondes sleep 
        
llOwnerSay "Sleep " + (string) llGetAndResetTime());        
    }
    
timer()
    {
        
llOwnerSay "Timer: " + (string) llGetTime());
        
llSetTimerEvent(0); 
    }

Les résultat attendus est de :

Test 1 et Test 2 => ~15 secondes
Test 3 => ~ 10 secondes

Vérifions...

Citation :

Test1 :

Citation :
[9:02] Object: Sleep 10.036520
[9:02] Object: Timer: 0.022638
Test2:
Citation :
[9:03] Object: Sleep 5.051199
[9:03] Object: Timer: 5.358524
Soit environ 10 secondes et... non 15s!

Test3:

Citation :
[9:22] Object: Sleep 5.050892
[9:22] Object: Timer: 0.068091
5 secondes et non...10s

L'effet surprise passée... les conclusions s'imposent:
Citation :

1. Le timer est externe au code script. ( Il n'est pas suspendu)

2. Le code d'un script n'est pas préemptif ( Aucun évènement ne peut dérouter le code d'un script , même pas une évènement "système" et même un timer...
Explications pour le sleep et l'événement start_touch
Mais quid du touch_start??


Un petit script qui permettra de TOUT comprendre...

Code PHP:

default
{
    
state_entry()
    {
        
llResetTime();
        
llSetTimerEvent(1);
        
llSleep(15);
        
llOwnerSay "Sleep " + (string) llGetAndResetTime());        
    }
    
touch_start integer num)
    {
        
llOwnerSay "Touch " + (string) llGetTime());
    }
    
timer()
    {
        
llOwnerSay "Timer: " + (string) llGetTime());
        
llSetTimerEvent(0); 
    }

On lance un timer de 1 seconde
suivi d'un sleep de 15 secondes pendant lequel nous allons cliquez sur la box.. et attendre le résultat...

Citation :
[9:48] Object: Sleep 15.053680
[9:48] Object: Timer: 0.067811
[9:48] Object: Touch 0.134293
Quand le sleep est fini les 2 évènements qui sont survenus pendant sont déclenchés.

Citation :
Conclusions:

Le sleep suspend le code.

Les événements surviennent et sont postés dans la file d'attente et attendent tranquillement d'être gérés.. Ils ne préemptent jamais le code
Dans le script présenté la boucle ne permettait pas qu'ils le soient....tout simplement.
Un exemple de script ...
Un style de code qui répond à ce qui avait été demandé:


Code PHP:

integer Seconds;
integer Chrono_On;
integer Sit;

Counter (integer start)
{
    if (
start)
        
llSetTimerEvent (1); // déclenche des timers de 1s
    
else
        
llSetTimerEvent (0);
}

default
{
    
state_entry()
    {
        
llOwnerSay("\nVeuillez vous assoir...
                    \nCliquez pour lancer le chrono pour 10 seconds Maximum...
                    \nPour le stopper..
                    \n Cliquez de nouveau.. 
                    \n ou bien lever vous tout simplement."
);
    }


    
touch_start(integer num)
    {
        if (!
Sit// si pas assis Refus!
        
{
            
llOwnerSay "Asseyez vous avant de cliquez...");
            return;
        }
        
Chrono_On =!Chrono_On;  // set inverse.. start ==> stop ==> start etc...       
        
        
if (Chrono_On)
        {
            
llOwnerSay "Chrono démarré pour 10 secondes!" ); // on start!
            
Seconds 0;
            
Counter (Chrono_On);
        }
        else 
        {
            
llOwnerSay "Chrono arrété!" );   // on stoppe!         
            
Counter (Chrono_On);      
        }
    }
    
    
changed(integer change
    {                                       
// quelque chose arrive mais quoi??
        
if (change CHANGED_LINK
        {                                   
// un link a changé!  quelqu'un vient de s'assoir??
            
key av llAvatarOnSitTarget();
            if (
av != NULL_KEY && !Sit
            {                               
// oui!! informons le 
                    
llOwnerSay("\nVous êtes assis...donc vous pouvez cliquez maintenant...");
                    
Sit TRUE// gardons cette information
            
}
            else
            {
                
llOwnerSay "Chrono arrété!" );   
                
Sit FALSE;  // plus assis
                
Chrono_On FALSE;  
                
Counter (Chrono_On);   // chrono stoppé             
            
}
        }
    }

    
timer()
    {
        if ( 
Seconds 10 
            
llOwnerSay "Chrono ==> " + (string) (++Seconds) + " s"); // on affiche en incrementant le chrono...
        
else
        {
// get 10 seconds
            
llSetTimerEvent(0); // on stoppe 
            
llOwnerSay "Les 10 secondes se sont écoulées!" );
        }            
    }

Citation :
En résumé..

Si on doit continuer à bosser pendant la tempo on utilise llSetTimerEvent... si on a rien à faire alors le Sleep est parfait.
Seb,

NB: Beaucoup de scripts comporte ce type d'erreur... ce qui la plupart du temps passe inaperçu ... mais quand les scripts contiennent des messages linked ou listens les messages sont delayed ...ou perdus.
Wouahh,

Chapeau. c limpide.

Citation :
Publié par Seb_01
... mais quand les scripts contiennent des messages linked ou listens les messages sont delayed ...ou perdus.

delayed ou perdu ?
Est-il possible de savoir dans quels cas, les messages sont delayed et dans quels cas ils sont perdu ?
J'imagine que c trop aléatoire.
Citation :
Publié par Francky Habercom
Wouahh,

Chapeau. c limpide.




delayed ou perdu ?
Est-il possible de savoir dans quels cas, les messages sont delayed et dans quels cas ils sont perdu ?
J'imagine que c trop aléatoire.
Si un évènement est reçu alors que la file d'attente est pleine, ce nouvel évènement est jeté sans que l'on en soit averti.
Citation :
Publié par Francky Habercom
delayed ou perdu ?
Est-il possible de savoir dans quels cas, les messages sont delayed et dans quels cas ils sont perdu ?
J'imagine que c trop aléatoire.
Une envoyeur, un receveur, un tuyau, ca te rappel rien ? Et oui, pour s'assurer de la bonne reception d'un message il faut adapter son protocole d'envoi de données, à l'image des protocoles utilisés en réseau par exemple ... A toi de te monter le tien.

Generalement, si la sim ne lag pas trop et que ton système n'est pas trop gourmand, les link messages ne sont pas délaissés, pour la simple et bonne raison que la pile n'a pas le temps de se remplir (faible delais en jeu).

Maintenant, dans le cas incertain, tu peux mettre en place ce dont je t'ai parlé, une assurance de reception, c'est a dire un temoignage retour. Mais bon ca implique aussi de gerer l'eventuelle non reception du message retour ou de trouver une astuce pour rendre ca plus accessible.

Pour repondre a ta question tout de meme, il est impossible de connaitre le statut d'un message envoyé directement.
Citation :
Publié par Ahuri Serenity

Generalement, si la sim ne lag pas trop et que ton système n'est pas trop gourmand, les link messages ne sont pas délaissés, pour la simple et bonne raison que la pile n'a pas le temps de se remplir (faible delais en jeu).

Ben si dans les 2 cas justement...


Sans Sleep dans le récepteur


Si les messages sont adressés sans delai entre les messages.. la pile va saturer à 64 messages et les autres seront perdus.

Pourquoi?
Simplement parce que l'on dépile moins vite que l'on empile... ( 25 events/s Maxi à réception. Soit 40ms, temps bien supérieur à quelques ms pour l'envoi...

Si les messages sont adressés avec un petit delai (pour empêcher justement ce phénomène) on ne perd rien.


Avec Sleep dans le récepteur

Ce qui était dans mon NB ( ...les messages sont delayed ...ou perdus.)

La c'est simple:

2 secondes de sleep et on perd tous les messages après le 78 ème( nombre max dans la pratique certainement moins)

3 secondes de sleep on perd tous les messages après le 64 ème.
Citation :
Publié par falstaff
bjr, comment passer du code php en sl ? merci
Le code PHP concerne le developpement de scripts sur un serveur PHP. Second Life possède des serveurs HTML et des machines virtuelles (pour le LSL) mais pas de serveur PHP (à la disposition de l'utilisateur lambda).

Tu ne peux donc pas utiliser des scripts PHP directement dans SecondLife.

Maintenant, que veux tu faire avec ton code PHP ? Ne peux tu pas faire simplement sur un serveur web standard (possedant un serveur PHP) ?

Si ce n'est pas le cas, dis nous en plus, le PHP n'est peux etre pas necessaire.

Une remarque : Tu peux utiliser le Shared Media pour avoir l'impression de faire du PHP dans SL (hihi.. hum)

Et puis je crois que ce n'est pas le sujet de ce topic
Répondre

Connectés sur ce fil

 
1 connecté (0 membre et 1 invité) Afficher la liste détaillée des connectés