Structure et système de communication interne

Répondre
Partager Rechercher
Je crée ce thread dans le but d'apporter un exemple (personnel) de structure de script que j'utilise tout le temps, bien que ça soit différent selon chaque scripteur, ça pourra également permettre de proposer les vôtres si vous avez envie de les partager.

Je vais également présenter le système de communications interne que j'utilise mais je pense que pour cette partie, beaucoup de personnes utilisent la même technique ou une très ressemblante.

Voilà la structure de départ que j'utilise quand je commence à écrire un script, je l'expliquerai par la suite :

Code PHP:


// ---------------------------------------------  NOTE  ------------------------------------------------------
// VERSION : 0.1
// DATE : 23/08/09
// AUTHOR : BLACKSHADE NIGHTFIRE
// ------------------------------------------------------------------------------------------------------------


//----------------------------------------------------------------------------------
//                            LIBRARY FUNCTIONS
//----------------------------------------------------------------------------------





//----------------------------------------------------------------------------------
//                               SCRIPT FUNCTIONS
//----------------------------------------------------------------------------------






//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------





//--------------------------------------------------------------------------------------
//                                          CONSTANTS
//--------------------------------------------------------------------------------------
//----------------------------------------------
//                INTERNAL COMM
//----------------------------------------------
//----------------
//      ME
//----------------

//----------------
//SCRIPT ADRESSES
//----------------

//----------------
//    GLOBAL
//----------------

//----------------------------------------------
//                     UTIL
//----------------------------------------------
string PRIM_SEP "|";
string SUB_SEP ":";

//--------------------------------------------------------------------------------------
//                           GLOBAL VARIABLES | State : Default
//--------------------------------------------------------------------------------------
//----------------------------------------------
//                     
//----------------------------------------------



default
{

    
state_entry() {
        
llSay0"Hi !" );
    }



Sans code ça parait un peu déroutant et incompréhensible je sais, mais il faut voir le résultat avec du code que je placerais après


Je vais commencer par expliquer ma façon de codifier les fonctions/variables/constantes etc...

[ Pour les fonctions ] :

Première lettre en majuscule pour chaque mot (y compris le premier)

Exemple :
Code PHP:

integer MaFonction() {
     return -
1;

[ Pour les variables globales ] :

La première lettre doit être un "g" en minuscule, suivit des mots qui ont leur première lettre en majuscule.

Exemple :
Code PHP:

list gKeyList
[ Pour les constantes ] :

Le nom doit être entièrement en majuscules et les mots séparés par un underscore.

Exemple :
Code PHP:

float MAX_OFFSET 12.3
[ Pour les variables locales ] :

La première lettre du premier mot doit être en minuscule et les premières lettres des mots qui suivent doivent être en majuscule.

Exemple :
Code PHP:

vector myPos llGetPos(); 

[ Pour les variables paramètres de fonctions ] :

Même principe que les variables locales.


[ Pour les states ] :

Toutes les lettres en minuscules.

Exemple :
Code PHP:

state readnotecard

Je vais commencer par le haut du script vide, c'est à dire :

Code PHP:

// ---------------------------------------------  NOTE  ------------------------------------------------------
// VERSION : 0.1
// DATE : 23/08/09
// AUTHOR : BLACKSHADE NIGHTFIRE
// ------------------------------------------------------------------------------------------------------------ 
Je met toujours en premier un bloc avec quelques notes comme la version du script, l'auteur et la date de la dernière modification. Ca me permet de faire la comparaison rapide pour savoir quel script identique est le plus récent (notamment quand mon inventaire est en bordel complet ).


Code PHP:

//----------------------------------------------------------------------------------
//                LIBRARY FUNCTIONS
//---------------------------------------------------------------------------------- 
Après ce bloc, je place des fonctions dites "library", c'est à dire des fonctions que j'utilise souvent et qui sont présentes dans plusieurs scripts.



Code PHP:

//----------------------------------------------------------------------------------
//                               SCRIPT FUNCTIONS
//---------------------------------------------------------------------------------- 
Après ce bloc je place des fonctions propres au script courant, c'est à dire des fonctions spécialement créées pour ce script.


Code PHP:

//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------- 
Cette partie sert à délimiter la section des fonctions de la section suivante.


La suite se compose en 2 grandes parties, c'est à dire les constantes et les variables globales.

Code PHP:

//--------------------------------------------------------------------------------------
//                                          CONSTANTS
//-------------------------------------------------------------------------------------- 
Indique la partie des constantes qui seront divisées en plusieurs sous-parties. La première est INTERNAL COMM. Cette partie sert à placer les adresses de scripts qu'on utilisera (je reviendrais sur le principe des adresses de script après). Nous avons 3 catégories : ME, SCRIPT ADRESSES et GLOBAL.

- ME : Sert à indiquer les adresses du script courant pour être contacté.
- SCRIPT ADRESSES : Sert à indiquer les adresses des autres scripts qu'on utilisera.
- GLOBAL : Sert à indiquer une adresse globale utilisée par plusieurs scripts à la fois.

J'ai également un principe d'écriture des adresses de scripts. Toutes les constantes représentant une adresse de script doivent avoir "IC_" (pour internal communication) en début de nom puis le nom (en raccourcit) du script et le nom (en raccourcit) de la fonction de cette adresse. Exemple : integer IC_SIMSCAN_ADDKEY = 484684; Le nom du script de destination est le simscan et la fonction est d'ajouter une key dans sa mémoire.

Pour les adresses globales c'est different, il faut mettre IC_GLOBAL_ en début de nom puis seulement la fonction de cette adresse. Exemple : integer IC_GLOBAL_ADDKEY = 1111;


Pour la suite de la partie CONSTANTS, on peut voir "UTIL", c'est des constantes que je me sert très souvent dont PRIM_SEP et SUB_SEP qui sont les séparateurs utilisés pour mes listes parsées, le premier est le séparateur primaire et l'autre secondaire pour faire des listes dans des listes: Exemple : test|1:2:3|test2|3:4:5

Les autres constantes sont affichées dans des bloc par thème comme pour UTIL et INTERNAL COMM, c'est un moyen simple pour les organiser.


Code PHP:

//--------------------------------------------------------------------------------------
//                           GLOBAL VARIABLES | State : Default
//-------------------------------------------------------------------------------------- 
On passe maintenant à la seconde partie, les variables globales. Elles sont représentées dans un bloc indiquant sur quelle state elles sont utilisées (là par exemple, c'est pour la state default). On les place ensuite dans des bloc plus petits qui sont des thèmes. Exemple on fait un bloc SIMSCAN STORAGE pour représenter les listes des avatars enregistrés.


Suite au prochain épisode...
Code PHP:

// ---------------------------------------------  NOTE  ------------------------------------------------------
// VERSION : 0.1
// DATE : 23/08/09
// AUTHOR : BLACKSHADE NIGHTFIRE
// ------------------------------------------------------------------------------------------------------------


//----------------------------------------------------------------------------------
//                                LIBRARY FUNCTIONS
//----------------------------------------------------------------------------------


integer GetRandomChannel() {
    
//random channel (negative)
    
return ~(integer)llFrand((float)DEBUG_CHANNEL);
}



integer IsKey(key in) {
    
// check if key is valid
    
if(in) return 2;
    return (
in == NULL_KEY);
}



integer Date2Dayinteger yyinteger mminteger dd ) {
   
// Made by Gary Katch, translated from C to LSL by Corto Maltese
   
integer m = (mm 9)%12// mar=0, feb=11 
   
integer y yy 1600 m/10;   // if Jan/Feb, year-- 
   
return y*365 y/y/100 y/400 + (m*306 5)/10 + (dd 1);

}


string Float2Stringfloat f ) {
    return (string)((integer)
f)+"."+(string)((integer)(f*10.0) - ((integer)f*10));
}


//----------------------------------------------------------------------------------
//                                    SCRIPT FUNCTIONS
//----------------------------------------------------------------------------------




AddKeykey k ) {

    
// [...]
    
llMessageLinkedLINK_THISIC_GLOBAL_SCANKEYS"");
}




AddListKey( list kList ) {

    
// [...]

}




//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------





//--------------------------------------------------------------------------------------
//                                          CONSTANTS
//--------------------------------------------------------------------------------------
//----------------------------------------------
//                INTERNAL COMM
//----------------------------------------------
//----------------
//      ME
//----------------
integer IC_SIMSCAN_ADDKEY 45457;
integer IC_SIMSCAN_CLEAR 214545;
//----------------
//SCRIPT ADRESSES
//----------------
integer IC_TEST_TESTFUNCTION 3333;
//----------------
//    GLOBAL
//----------------
integer IC_GLOBAL_SCANKEYS 32321;
//----------------------------------------------
//                     UTIL
//----------------------------------------------
string PRIM_SEP "|";
string SUB_SEP ":";
//----------------------------------------------
//                     TIMERS
//----------------------------------------------
float SHORT_TIMER 2.0;
float NORMAL_TIMER 10.0;
float LONG_TIMER 30.0;


//--------------------------------------------------------------------------------------
//                           GLOBAL VARIABLES | State : Default
//--------------------------------------------------------------------------------------
//----------------------------------------------
//               SIMSCAN STORAGE      
//----------------------------------------------
list gKeyList;
list 
gNameList;
//----------------------------------------------
//               ANOTHER BLOC      
//----------------------------------------------
string gVarTest;
integer gVarTest2;

//--------------------------------------------------------------------------------------
//                           GLOBAL VARIABLES | State : Test
//--------------------------------------------------------------------------------------
//----------------------------------------------
//               ANOTHER BLOC      
//----------------------------------------------
string gVarTest3;




default
{

    
state_entry() {
        
// [...]
    
}


    
link_messageinteger linkinteger adressstring datakey data2 ) {

        if( 
adress == IC_SIMSCAN_ADDKEY ) {

            
// [...]

        
}


        else if( 
adress == IC_SIMSCAN_CLEAR ) {

            
gKeyList = [];
            
gNameList = [];
        }

    }


}



state test
{

    
state_entry() {

        
gVarTest3 "test";
        
state default;
    }



Voilà à peu près ce que pourrait représenter un script sur ce principe de modèle. Je précise que ce script est totalement incohérent, c'est normal il est là à titre d'exemple.

On voit dans la partie CONSTANTS une catégorie rajoutée (TIMERS) qui pourrait servir à stocker des constantes de vitesse de rafraichissement de timers.

Dans la partie variable globale, on différencie bien les variables de la state default de la state test ainsi que les thèmes pour les organiser (SIMSCAN STORAGE, ANOTHER BLOC etc).


Je vais passer au système de communication interne qui est relativement simple, c'est par rapport aux adresses de script pour ceux qui se demandent. Une adresse de script n'existe pas en réalité, ce n'est qu'une technique pour contacter la fonction d'un autre script présent dans l'inventaire de l'objet grâce aux messages linked.

Je donne un exemple, si je veux utiliser la fonction GetRandomChannel de mon script B avec mon script A ? Certain diront que le fait de copier la fonction règle le problème mais si il s'agit d'une fonction qui utilise des variables globales et tout un processus propre à son script ? Là ça pose problème. La solution est les message linked.

On définit l'adresse de destination d'un script dans le second paramètre de la fonction llMessageLinked(); Voici un exemple pour nos scripts A et B :


[ Script A ]

Code PHP:


//...

touch_startinteger n ) {
     
      
llMessageLinkedLINK_THIS1002"""2002" );
}

link_messageinteger linkinteger adressstring datakey data2 ) {
        
        if( 
adress == 2002 ) {
              
// ici nous reçevons la valeur de retour
              
llSay0"random channel : " data );
        }
}

// ... 



[ Script B ]

Code PHP:


//...


link_messageinteger linkinteger adressstring datakey data2 ) {
        
        if( 
adress == 1002 ) {
              
// je renvois la valeur de GetRandomChannel à l'adresse de retour
              
llMessageLinkedlink, (integer)((string)data2), (string)GetRandomChannel(), NULL_KEY );
        }
}

// ... 
Pour le script A, on envoit un message linked en direction de l'adresse du script B qui est 1002. Ensuite pour le dernier paramètre nous mettons l'adresse sur laquelle on veut la réponse de la fonction qui est ici : 2002.



Voilà à peu près ma façon de faire question communication interne et modèle de script, si je n'ai pas été assez clair sur certain points n'hésitez pas à me demander de réexpliquer.
Citation :
Publié par Seb_01
Excellente initiative! On attend la suite : ))
Merci
Oufff quelle organisation !!

On sent la patte d'un pro là.

Moi je ne suis pas assez disciplinée pour appliquer ce genre de principe. Et je vais immanquablement m'emmêler les pinceaux (heu voyons on commence par une majuscule pour les variables locales - ha non zut c'est l'inverse - oh et pis je sais plus)
Je propose un autre exemple pour illustrer ce qui vient d'être expliqué, si je peux : ))

Imaginons un objet contenant plusieurs scripts ont la possibilité de parler sur un channel, mais que le message adressé sur ce channel doit être crypté avec une clef spécifique et aléatoire...

2 possibilités

1. Chaque script peut avoir la routine de cryptage et on doit veiller à bien communiqué la clef à utiliser au scripts concernés
ce qui suppose que chaque script doit être à l'écoute de cette information.

flow1.png

2. La routine de cryptage est externe à chaque script et située dans un seul et même script
avant d'émettre le message on demande alors son encodage.


flow2.png


L'avantage de la solution saute aux yeux, gain de code , maintenabilité + facile, pas de risque d'envoyé un message avec une mauvaise clef etc etc..
Merci Seb pour cette explication, par contre j'ai quelques petites questions la-dessus. Quand tu parles de messages cryptés c'est par rapport à une communication avec linked messages ? Et comment adresser un message à un seul script en particulier ? Si j'ai bien compris ils ont tous la même clée et le même channel? Si tu pouvais donner un petit exemple qui illustre cette explication, ça serait parfait .


Citation :
Oufff quelle organisation !!

On sent la patte d'un pro là.

Moi je ne suis pas assez disciplinée pour appliquer ce genre de principe. Et je vais immanquablement m'emmêler les pinceaux (heu voyons on commence par une majuscule pour les variables locales - ha non zut c'est l'inverse - oh et pis je sais plus)
C'est une question d'habitude en fait , c'est au fur et à mesure que j'ai crée ce modèle quand j'ai vu à quel point un code assez long pouvait devenir un bordel pas possible au niveau des variables, states etc...
Oui je vais tacher de m'y mettre. Merci de nous expliciter tout ça. Je m'était déjà demandée ce que voulais dire ce g ridicule devant les noms de variables maintenant je sais. Et c'est une bonne habitude à prendre je vais m'y appliquer.

Comme le jeu des majuscules. Excepté pour les constantes ou j'avais compris, je m'y emmêlait chaque fois les pinceaux. Donc tout en minuscule comme ça pas de souci. Parceque aussi je suis fainéante de presser shift. Mais les noms de variables sont plus parlant avec des majuscule. Je vais m'y mettre aussi.
C'est sur qu'avec le codage, de bonnes habitudes peuvent améliorer le travail du développeur ! Personnellement je m'habitue aussi, et c'est normal je trouve, à organiser mon code, ma présentation, ma synthaxe, etc.

Les conseils que nous donne ici BlackShade Nightfire sont bons à assimiler car ils permettent d'organiser un travail mais pas seulement :

Un organisation sur l' écriture du script permet d'offrir plus d' intéret sur
la pensée du script ( oui il faut penser son script ! lol ) ! Se débarasser des
soucis liés à la mise en forme par les habitudes permet de mieux réfléchir
à ce qu'on est en train de faire et ca, c'est vraiment bien !

Le LSL est cependant un langage très pauvre en possibilités pour les développeurs, la facon de rediger est donc quand meme moins capitale que dans d'autres langages comme le C/C++, le Java, .. En effet, on y trouve d'autres concepts qui mettent en place certaines autres conventions.

Personnellement j'adopte pas tout a fait les mêmes regles, mais bon après c'est chacun comme il veut hin Le tout c'est de se debarasser des contraintes d'ecriture pour mieux organiser et penser son travail.

Enfin, dites moi si je me trompe mais il n'a pas été question de l'indentation, c'est tres important de bien organiser son code grace aux indentations (décalages d'un multiple commun d'espaces du bord gauche) car grace a cela on sait où on en est, et le mieux dans tous ca c'est que la personne qui nous li le saura egalement plus facilement
__________________
--- Ahuri Serenity ---
Pense ton script !
C'est sur qu'au niveau des parenthéses moi j'ai une pratique que vous allez trouver peu orthodoxe : je colle toujours l'accolade ouvrante à l'instruction. J'indente bien sur et j'aligne la fermante avec la 1ére lettre de l'instruction.

par exempe les if ... else je code toujours comme ça :
Code:
state_entry(){
     if ( ....){
          ....
     }else if (....){
          ....
     }
}
Le but: gagner des lignes pour voir le maximum de lignes utiles de code. Et puis une ligne qui se termine par une accolade ouvrante c'est une ligne qui n'a pas besoin de ; .

Bon c'est moins aéré c'est sur mais je trouve que cela hache moins le code et que c'est plus compact et ainsi plus lisible.
Citation :
Publié par Ahuri Serenity
...
Je suis entièrement d'accord avec toi sur le fait que le LSL soit pauvre en possibilités, je suis également certain que si ce langage laissait un peu plus de liberté beaucoup de codes seraient moins laggy qu'a la base, je pense notamment au système de message linked.

Il y a également des délais énormes sur des fonctions qui nous forcent à utiliser plusieurs scripts je pense surtout au llSetPos. En plus d'être limitée en distance, elle possède un délais qui rend le mouvement d'un objet de façon saccadée.


Sinon oui j'ai pas parlé de l'indentation de code, je n'ai pas vraiment de règles la dessus, mis à part pour les accolades

[ Pour les states ]

Code PHP:

default
{


[ Pour les conditions et fonctions ]

Code PHP:


MaFonction
() {

}

if( 
test ) {


Je met souvent un espace à l'intérieur des parenthèses (au début et à la fin).
Citation :
Publié par BlackShade Nightfire
Merci Seb pour cette explication, par contre j'ai quelques petites questions la-dessus. Quand tu parles de messages cryptés c'est par rapport à une communication avec linked messages ? Et comment adresser un message à un seul script en particulier ? Si j'ai bien compris ils ont tous la même clée et le même channel? Si tu pouvais donner un petit exemple qui illustre cette explication, ça serait parfait .

Pour l'exemple donné les messages doivent être encryptés avant émission sur un channel quelconque.... donc il vont demander le cryptage à un script. Une fois le message crypté il sera envoyé.

j'ai écris vite fais deux scripts


Code PHP:

integer channel 0// le channel ou le script distant va recevoir le message crypté
default
{
    
touch_start(integer num)
    {
        
llMessageLinkedLINK_THIS1002"Ceci est le text à encoder""100" );
    }    

    
link_messageinteger numinteger adressstring messagekey data2 
    {
        if( 
adress == 100 
        {     
            
llSay channelmessage ); 
            
llMessageLinkedLINK_THIS1003, (string) data2 message "101" ); //  // juste pour tester le code
        
}     
        if( 
adress == 101 
             
llOwnerSay ("\nMessage décrypté:  " +message "\n"  "Clef utilisée: " + (string) data2 ); // juste pour tester le code
    
}


le message en clair est adressé à un script

Code PHP:

      llMessageLinkedLINK_THIS1002"Ceci est le text à encoder""100" ); 

l'adresse de retour est 100. Pour un autre script elle sera différente... 200 par exemple

le retour du message crypté se fait ici


Code PHP:

        if( adress == 100 
        {     
            
llSay channelmessage ); 
les lignes suivantes sont pour envoyer un message crypté et le décrypter ... cela n'a aucun intéret ici sinon pour vérifié mon cryptage.
C'est le script distant recevant le message crypté qui va devoir utiliser cette routine...


Le script de cryptage:

Code PHP:

list list_keys = [    "sebastien",
                    
"normalement les clefs sont plus longues",
                    
"et utilisent des caractère style ù^$*)àç_èeèe&",
                    
"pour compliquer un possible decryptage"
                 
];

integer keynumber
string  keypass;
string encrypt(string messagestring keyp )
{
    return 
llXorBase64StringsCorrectllStringToBase64(message),llStringToBase64keyp) );   
}

string decrypt(string messagestring keyp )
{
    return 
llBase64ToString(llXorBase64StringsCorrect(messagellStringToBase64(keyp)));  
}



default
{

    
link_messageinteger numinteger adressstring messagekey data2 
    {
        
        if( 
adress == 1002 // codage
        
{
            
integer keynumber = (integer)llFrandllGetListLength(list_keys) );
            
string  keypass llList2String list_keys ,keynumber ) ;
         
            
llMessageLinkedLINK_THIS, (integer)((string)data2),encrypt(message,keypass) , (string) keynumber );
        }
        else if( 
adress == 1003 // decodage juste pour verifier mon codage! :)
        
{
            
keynumber = (integer) llGetSubString (message,0,0);
            
message =  llGetSubString message1,-1);  
            
keypass llList2String list_keys ,keynumber ); 
            
llMessageLinkedLINK_THIS, (integer)((string)data2),decrypt(message,keypass) , (string) keypass );  
          
        }

    }


Le principe est simple:

il y a 4 clefs

une est prise au hasard et sert à l'encodage du texte et retour à l'envoyeur.

Code PHP:

        if( adress == 1002 // codage
        
{
            
integer keynumber = (integer)llFrandllGetListLength(list_keys) );
            
string  keypass llList2String list_keys ,keynumber ) ;
         
            
llMessageLinkedLINK_THIS, (integer)((string)data2),encrypt(message,keypass) , (string) keynumber );
        } 
le numero de clef est donnée en début du message pourquoi?

Parce le script distant (disposant des même clefs) recevant le message crypté devra connaitre la clef utilisée pour pouvoir décoder le message...

Voila un exemple simple qui met en avant les ++ que j'avais indiqué précédemment.

résultats

Code:
[11:07]  Object: MwoWGwAGHBlQAAxRAQAKVFWtgFAKHRAGBgkX
[11:07]  Object: 
Message décrypté:  Ceci est le text à encoder
Clef utilisée: pour compliquer un possible decryptage
PS et hors sujet... Pour parfaire le cryptage il faut de longues clefs et un nombre important de clefs,shifté les chaines etc pour se mettre à l'abri.. . C'était juste pour l'exemple.
C'est une très bonne idée Seb, j'avoue que question maintenabilité c'est au top et possibilité de changer de méthode de cryptage tout en conservant le reste. J'aime bien ton système de clée que tu as montré, les deux idées pourraient s'associer avec celle d'envoyer des messages linked externes par exemple.

Pour faire de l'adressage de script/link à distance. On peut également ajouter d'autre s supports que le listen comme l'email, l'http server etc Ca étendrait le champs de contact.
Répondre

Connectés sur ce fil

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