Créer des scripts pour Second Life
SOMMAIRE
Créer des scripts pour Second Life
• Linden Scripting Language (LSL) : devenez le maître du jeu ! | 2 • Dotez vos objets de comportements particuliers | 10
De Jean-Marc Delprato
• Détecter la présence d’un avatar ou d’un objet et agir en conséquence | 16
© Editions O’Reilly ISBN 13 : 978-2-35402-061-3 — Prix : 8 euros
• Créer des objets qui s’entretiennent entre eux | 22
Quels que soient votre profil et vos intentions, la création d’objets personnels dans Second Life a tout intérêt à s’enrichir de comportements particuliers – non seulement pour les améliorer et proposer quelque chose de neuf aux utilisateurs, mais également pour les démarquer considérablement des autres créations. C’est précisément là qu’intervient LSL (Linden Scripting Language), le langage de programmation en vigueur dans Second Life. Proche de Java ou de C, il est le seul véritable outil à votre disposition pour enrichir vos créations et leur accorder une réelle valeur ajoutée. Programmation ludique, graphique, comportementale ou événementielle : LSL permet d’aller dans toutes les directions et d’emmener l’univers virtuel là où on ne l’attendait pas encore. Nous allons nous intéresser en particulier au développement lié à la communication – il offre de fantastiques possibilités d’ouverture à Second Life et s’inscrit pleinement dans la nouvelle tendance du Web 2.0.
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
• Créer un objet qui vous écoute et qui vous répond | 27 • Envoyer dynamiquement un e-mail à travers un objet | 34 • Faire appel à l’API du service web de Flickr | 39 • Créer un téléporteur à l’aide de coordonnées récupérées en XML-RPC | 44
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Linden Scripting Language (LSL) : devenez le maître du jeu ! Sorti en 2003, Second Life a rapidement gagné en popularité au point de s’imposer comme un nouveau média, évoluant en marge du Web. Commerce électronique, « vitrine en ligne » de véritables boutiques ou de fabricants mais aussi simple moyen d’échange entre passionnés : l’univers virtuel n’obéit qu’aux lois fixées par la communauté de ses utilisateurs. Mais en quoi Second Life répond-il à des besoins spécifiques des utilisateurs, prêts à y consacrer de nombreuses heures et parfois un budget conséquent ? Tout d’abord, après un développement un peu anarchique s’appuyant en partie sur une série d’initiatives et de « tâtonnements », Second Life apparaît aujourd’hui comme un complément nécessaire au Web. Si les pages HTML visent à rassembler l’étendue des connaissances humaines, Second Life, avec l’interaction entre des avatars dans un univers en 3D, rend compte des activités humaines. Les deux approches évoluent en parallèle et se nourrissent l’une de l’autre. Ensuite, Second Life met entre les mains de ses utilisateurs d’étonnantes possibilités de création et de personnalisation. Là encore, le parallèle avec le Web nous éclaire sur le fonctionnement de Second Life. S’il est aujourd’hui possible de réaliser simplement un site web ou un blog à l’aide d’une poignée d’outils intuitifs, la conception de larges sites dynamiques bardés de technologies nécessite toujours un grand savoir-faire technique. Second Life obéit au même principe et l’on est aussi bien en mesure de bâtir des objets simples en quelques minutes, sans connaissances particulières, que d’ambitieux projets interactifs qui s’articulent autour d’un cycle de développement de plusieurs mois. Vous pouvez ainsi envisager tout type d’échelle dans le développement de vos projets. Car c’est bien l’aspect le plus séduisant et novateur de Second Life : au-delà du dialogue permanent avec une communauté
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Linden Scripting Language (LSL) : devenez le maître du jeu !
riche de plus de 10 millions d’utilisateurs, vous êtes réellement le maître du jeu et vous pouvez imaginer tout type « d’extensions » au sein de l’univers virtuel. Plus de 90% des objets présents dans Second Life ont été créés par des passionnés. Mais le succès de cette plate-forme vous oblige à vous démarquer radicalement des créations des autres utilisateurs – que vous nourrissiez des ambitions commerciales en vendant vos produits ou que vous programmiez des objets par pur plaisir, afin d’élargir les possibilités de l’univers virtuel. Vous avez ainsi tout intérêt à maîtriser LSL (Linden Scripting Language), le langage de programmation au cœur de Second Life. C’est la seule solution pour accroître vos possibilités au-delà de la simple modélisation d’éléments et pour offrir aux utilisateurs des comportements originaux et de nouvelles activités. En associant des scripts développés dans ce langage aux objets que vous aurez modélisés, vous leur conférerez une véritable valeur ajoutée et vous les rendrez interactifs. LSL offre en effet de formidables possibilités d’extensions aux objets : effets visuels, programmation de jeux, interactions avec des services web, programmation comportementale en fonction du contexte ou des utilisateurs… En maîtrisant le langage, vous décuplez vos possibilités et vous avez l’assurance de créer des objets originaux et « intelligents » qui susciteront l’intérêt. Parmi tous ces aspects nouveaux qu’offre LSL, nous avons choisi de nous concentrer en particulier sur la notion de « communication » au sens large qui illustre parfaitement les différentes facettes du langage. C’est uniquement à travers la programmation de comportements originaux que vous rendrez les objets de Second Life interactifs. Nous aborderons tout d’abord la communication entre les objets en eux-mêmes, au sein d’un véritable dispositif interactif qui détecte la présence des avatars et qui s’entretient automatiquement avec eux. Nous pourrons ensuite envisager de nom-
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
breuses déclinaisons de ce principe à des applications ambitieuses ou à de modestes gadgets qui enrichiront votre boutique ou votre domicile virtuel. Nous évoquerons également la possibilité de dialoguer avec un objet : la zone de chat est l’un des seuls moyens d’envoyer des commandes à un objet, pour qu’il agisse en conséquence. Mais la communication peut aussi s’effectuer à travers des services externes, notamment le courrier électronique et les services web proposés par des éditeurs de sites. Là encore, LSL répond présent et dispose de nombreuses fonctions liées à l’accès distant à ce type de services.
Figure 1. La programmation en LSL est devenue une activité lucrative pour de nombreux développeurs, qui proposent leurs services au plus offrant.
À la découverte de LSL LSL étant un langage propre à Second Life, il est relativement neuf et ne bénéficie pas encore d’implémentations dans d’autres applications. Cette simple constatation met sur un plan d’égalité
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Linden Scripting Language (LSL) : devenez le maître du jeu !
les nouveaux développeurs, qui n’ont pas d’expérience antérieure en programmation, et les programmeurs plus aguerris, rompus au C, Java ou PHP. Comme nous le verrons par la suite, le langage est tout à fait accessible aux débutants. Les utilisateurs confirmés prendront en revanche un malin plaisir à progresser malgré les restrictions du langage : même si LSL emprunte une partie de sa nomenclature et de ses principes à JavaScript, C et Java, la gestion de la mémoire et le passage de variables d’un script à l’autre se démarquent fortement et méritent toute votre attention. Nous y reviendrons.
Figure 2. Le wiki semi-officiel consacré au LSL regorge d’informations et correspond à un excellent point d’entrée pour découvrir le langage et approfondir ses connaissances.
Dans la suite de cet ouvrage, nous partons du principe que vous connaissez déjà Second Life, que vous disposez d’un compte (sans nécessairement détenir un compte Premium ou disposer de nombreux Linden dollars) et que vous maîtrisez la modélisation d’objets. Second Life a mis en place un écosystème permettant
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Linden Scripting Language (LSL) : devenez le maître du jeu !
de réaliser des bénéfices autour de la vente de vos propres objets : nous verrons que l’ajout de scripts LSL est la seule gageure permettant de rendre ces objets « intelligents » et d’articuler de véritables applications dans l’univers virtuel. Nous n’aborderons pas en détails la vente de vos propres objets dotés de comportements définis dans des scripts : libre à vous de fixer vos tarifs et de mettre en vente vos créations. Sachez toutefois que la programmation en LSL est avant tout ludique : vous pouvez parfaitement tester tous les exemples de cet ouvrage et développer vos propres projets sans débourser le moindre centime ! À ce titre, la programmation en LSL est l’un des meilleurs moyens d’étendre son immersion dans l’univers de Second Life à moindres frais. Découvrez la modélisation d’objets Si vous débutez dans l’univers de Second Life ou si vous souhaitez parfaire vos connaissances en matière de modélisation d’objets, nous vous conseillons de vous reporter au focus de Stéphane Pilet, « Créez des objets dans Second Life » (http:// www.oreilly.fr/catalogue/2354020236). Cet ouvrage est disponible en téléchargement sur le site d’O’Reilly. Par ailleurs, si la modélisation d’objets avec l’éditeur intégré à Second Life vous paraît rébarbative, n’hésitez pas à exploiter des outils alternatifs. Google SketchUp (http://sketchup.google. fr) est un utilitaire gratuit très intuitif qui permet de réaliser des bâtiments en 3D à intégrer dans Google Earth. Si vous avez déjà goûté à cet excellent outil, sachez qu’Andrew Reynolds a développé en septembre 2007 un plug-in visant à exporter des modèles depuis SketchUp. Encore à l’état de beta-test, ce plug-in est disponible à l’adresse http://eightbar.co.uk/2006/09/ 29/google-sketchup-second-life-export/. Il devrait vous faire gagner un temps précieux et vous éviter de manipuler l’éditeur intégré à Second Life, qui n’est pas toujours commode pour les objets les plus complexes. Surveillez le développement de ce plug-in ! [07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Figure 3. Google SketchUp est une application de modélisation
gratuite, particulièrement intuitive. Apprenez à l’utiliser : elle devrait s’intégrer de plus en plus à Second Life au cours des prochains mois. Avant d’aller plus loin, sachez que la création de vos propres modèles et l’ajout de scripts en LSL ne peuvent pas s’effectuer à n’importe quel endroit du métavers. En effet, chaque zone permet d’afficher un nombre limité de prims (les objets 3D) en fonction de sa superficie. Cette limite est d’ordre technique : Linden Lab veille à ce qu’on ne surcharge pas les zones très populaires avec des dizaines de milliers d’objets 3D, lourds à charger. Dans la mesure où vos scripts « s’attachent » à des objets concrets, vous devez donc avoir le droit de déposer des prims au sol. Si vous possédez votre propre zone, pas de problèmes : vous êtes le seul maître à bord et vous avez tout le loisir de tester vos créations et de jouer avec l’éditeur intégré. Si vous ne consacrez pas un budget spécifique à votre immersion dans Second Life, pas de panique : de nombreuses « Sandbox » permettent d’héberger vos
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
créations l’espace d’un instant. Signifiant littéralement « bacs à sable », ces zones vous donnent un droit de création absolu (dans la limite du nombre de prims maximum autorisés, comme nous venons de le voir). Vous créerez vos modèles, vous leur associerez des scripts et vous rangerez le résultat dans votre inventaire, pour le réutiliser à n’importe quel moment. Par ailleurs, les Sandbox représentent un lieu idéal pour trouver de l’aide et dialoguer avec d’autres développeurs. Certaines zones sont administrées par des groupes de programmeurs, qui donnent régulièrement rendez-vous à la communauté pour de petits cours ou des aides personnalisées. Ouvrez le moteur de recherche de Second Life et saisissez « sandbox » dans le champ de recherche. L’onglet « Places » recense plusieurs centaines de zones de ce type. Cliquez sur l’une d’entre elles puis sur le bouton Teleport pour vous y rendre instantanément et entamer vos développements.
Linden Scripting Language (LSL) : devenez le maître du jeu !
Quelques Sandbox recommandées Parfois lugubres avec leurs couleurs sombres, leurs oriflammes menaçants et leurs brûloirs incandescents, parfois enfantins avec leurs teintes pastels et des paysages acidulés, les Sandbox ne se ressemblent pas toujours et servent pourtant un objectif commun : vous permettre de tester vos créations en toute liberté. Toutefois, l’accueil n’est pas systématiquement hospitalier et certaines zones sont aux mains de pillards et de bandits qui n’hésiteront pas à vous piéger. Ils ne peuvent pas vous faire beaucoup de tort, mais vous pouvez éventuellement être la proie de leurs scripts malicieux. Il n’y a rien de plus pénible, lorsque vous êtes en pleine concentration lors d’un développement ambitieux ! Les Sandbox suivantes ont donc été largement testées par nos soins et sont connues pour leur sérieux et leur bon accueil : • Heron Island (http://slurl.com/secondlife/Heron%20Island/203/207/22) • Bac à sable francophone (http://slurl.com/secondlife/aide%20francophone/148/99/24) • SkyBeam Sandbox (http://slurl.com/secondlife/SkyBeam/82/83/38) • EDTech Island Sandbox (http://slurl.com/secondlife/EdTech/130/125/25) • Sun Microsystems Public Sandbox (http://slurl.com/secondlife/SMI/88/151/24) • Turbo Sandbox (http://slurl.com/secondlife/Turbo/185/111/27), qui organise régulièrement des concours de programmation
Figure 4. Après avoir posé le pied dans une Sandbox, modélisez
votre objet grâce à l’éditeur intégré : vous lui associerez un script LSL dans un second temps.
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Créer des scripts pour Second Life
➔ Sommaire
Linden Scripting Language (LSL) : devenez le maître du jeu !
Créer des scripts pour Second Life
Maîtriser l’interface de développement Après avoir foulé le sol d’une Sandbox, effectuez un clic droit sur le sol, à l’endroit où vous désirez créer votre objet et cliquez sur « Create ». Les différents onglets de l’interface vous permettent d’ajouter des formes de base, de les étirer à loisir, de leur appliquer des textures et de les regrouper. Nous n’aborderons pas ces étapes dans ce focus ; en revanche, l’onglet « Content » nous intéresse au plus haut point : il permet d’associer des scripts à votre objet. Commencez par déposer une forme de base au sol puis cliquez sur le bouton « More ». Cliquez ensuite sur « Content » puis sur le bouton « New Script ». Une nouvelle entrée apparaît dans la liste au-dessous ; vous comprenez ainsi qu’on peut associer plusieurs scripts à un seul objet afin d’isoler les comportements et les fonctions.
Lorsque vous modifiez un objet de cette manière, Second Life le dote d’un script par défaut. Très simple, celui-ci affiche « Hello, Avatar ! » puis « Touched » lorsqu’on touche l’objet. Effectuez un double-clic sur « New Script » pour en afficher le contenu. Le voici en intégralité : Exemple 1. Le script associé par défaut aux objets. default { state_entry() { llSay(0, "Hello, Avatar!"); } touch_start(integer total_number) { llSay(0, "Touched."); } }
Figure 5. L’éditeur de script intégré à Second Life
vous permet d’associer en quelques secondes des scripts ambitieux à vos objets.
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Ce script de base met en place un état, deux événements et deux fonctions. Un « état » correspond à un comportement spécifique de votre script, que vous isolez ainsi dans un bloc de code. Si vous développez un jukebox interactif, par exemple, vous pouvez envisager un premier état pour la sélection d’une piste audio (il s’agira vraisemblablement de votre état par défaut, qui s’exécutera dès qu’on interagit avec votre objet), un deuxième état pour le lancement du morceau et un troisième pour l’arrêt de la musique. Chaque script ne peut se trouver que dans un état à la fois : vous définissez ainsi les différents comportements de votre objet (en les encadrant avec des accolades, comme dans l’exemple précédent) et votre script va basculer de l’un à l’autre en fonction des choix de l’utilisateur. C’est l’un des concepts essentiels de LSL et nous y reviendrons régulièrement. Vos scripts doivent impérativement disposer d’au moins un état, default .
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Les « événements » correspondent à des « cas de figure » que vous prévoyez et que vous intégrez aux différents états. Dans l’exemple précédent, state_entry() et touch_start() sont deux événements : le premier correspond à un événement qui est déclenché automatiquement dès qu’on accède à un état et le second se déclenche lorsque l’utilisateur touche l’objet. Enfin, les « fonctions » définissent les réactions de votre script. Ici, la fonction llSay() affiche un message sur le canal de discussion. On comprend mieux le fonctionnement de ce premier script : dès qu’on ouvre l’objet, on accède à l’état « par défaut » qui affiche immédiatement le message « Hello, Avatar ! ». Si l’on touche l’objet, on lance le second événement et le message « Touched. » apparaît sur le canal de discussion. Toutes les fonctions prédéfinies en LSL débutent par deux « l » d’affilée, à l’instar de llSay() .
Figure 6. Touchez l’objet pour déclencher l’événement associé
et laisser l’objet vous parler à travers le canal de discussion.
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Linden Scripting Language (LSL) : devenez le maître du jeu !
L’éditeur / compilateur intégré à LSL offre plusieurs possibilités visant à simplifier le développement de vos projets. Tout d’abord, il utilise par défaut une coloration syntaxique qui permet d’identifier au premier coup d’œil les états, les événements, les fonctions et les arguments (on passe ces derniers à des fonctions entre les parenthèses qui suivent leur appel). Ensuite, il dresse la liste de toutes les fonctions, états, variables événements prédéfinis en LSL. Utilisez le menu déroulant en bas de la fenêtre pour insérer automatiquement un nouvel élément. Enfin, cet éditeur vous indique la nomenclature attendue de chaque élément de votre script. Passez la souris quelques secondes au-dessus de la moindre ligne de code : une infobulle vous indique les arguments nécessaires à chaque fonction. Le développement dans un éditeur tiers Mais pour les projets les plus ambitieux, il peut paraître rébarbatif d’écrire des centaines voire des milliers de lignes dans cet éditeur intégré. Heureusement, la communauté des développeurs s’est largement organisée et propose désormais de nombreux plug-ins pour des éditeurs de texte très populaires. Vous en trouverez la liste complète sur le LSL Wiki (http://lslwiki.net/lslwiki/ wakka.php?wakka=AlternativeEditors). Si vous avez déjà l’habitude de programmer dans d’autres langages à l’aide de GEdit, UltraEdit ou vim, téléchargez les plug-ins correspondants afin de profiter de la coloration syntaxique. Nos préférences vont à LSLEditor, un luxueux éditeur spécifiquement dédié au LSL, et au plug-in ByronStar SL pour Eclipse. Vous téléchargerez ce dernier à l’adresse http://byronstar-sl.sourceforge.net/. Outre la coloration syntaxique, il complète automatiquement votre saisie : indiquez les premières lettres d’une fonction, par exemple, afin de laisser l’éditeur poursuivre la saisie. Si vous préférez une solution moins technique mais tout aussi intéressante, optez sans hésiter pour LSLEditor. Vous le téléchargerez à l’adresse http://www.lsleditor.org/. Ne nécessitant pas la moin-
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
dre installation, cet éditeur dispose de la coloration syntaxique, de l’auto-complétion des instructions que vous saisissez, d’un navigateur web intégré pour parcourir la liste des fonctions ou bénéficier de tutoriels en ligne et surtout d’un puissant débogueur.
Linden Scripting Language (LSL) : devenez le maître du jeu !
basculer d’un état à un autre et simuler les différents événements. Lorsque vous êtes pleinement satisfait du résultat, vous pouvez effectuer un simple copier / coller de l’intégralité de votre code source vers la fenêtre d’édition intégrée à Second Life. En cliquant sur le bouton Save de celle-ci, vous compilerez votre code (qui sera donc à nouveau parcouru afin d’éliminer la moindre erreur) et il sera prêt à être exécuté. Quittez enfin l’éditeur pour tester votre objet dans les conditions réelles.
Figure 7 . LSLEditor, développé par Alphons van der Heijden, est
un puissant éditeur spécifiquement dédié au LSL. Après avoir développé votre code source, pressez la touche F5 de votre clavier : le code sera parcouru et les éventuelles erreurs apparaîtront en clair, dans le bas de la fenêtre, avec des suggestions de correction. Si tout fonctionne correctement, vous disposez d’une console au sein de LSLEditor qui vous permet d’interagir avec votre script. Sur la droite du débogueur, vous pouvez
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Figure 8. Le débogueur de LSLEditor vous permet de vérifier
l’état de vos variables et de simuler les interactions de l’utilisateur. Idéal pour s’assurer de la qualité de votre script !
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Le développement sous Windows Vista Si vous disposez de la dernière version du système d’exploitation de Microsoft, sachez que votre cycle de développement risque d’être interrompu par une série de comportements erratiques de la part de Second Life. En effet, à l’heure où nous écrivons ces lignes, le métavers n’est toujours pas officiellement compatible avec Windows Vista. Sans entrer dans des considérations techniques, la faute incombe en partie au support des cartes graphiques dans le dernier système d’exploitation de Microsoft. D’après nos propres essais, certains modèles de cartes graphiques ATI ne fonctionnent pas du tout avec Second Life, qui ne parvient pas à se lancer, tandis que la situation est beaucoup plus stable avec les cartes nVidia. Dans tous les cas, prenez garde : au bout d’une certaine période d’activité, Second Life peut planter – vous perdez ainsi tout le fruit de votre travail si vous développez directement dans l’éditeur intégré de l’univers virtuel. Pour toutes ces raisons, il est très intéressant de passer par un éditeur-tiers comme LSLEditor, quelle que soit la complexité de votre projet. Vous limiterez les risques de plantage et vous n’accéderez à Second Life qu’en dernier lieu, pour associer des scripts que vous aurez déjà testés sous toutes les coutures à vos objets. Les possibilités offertes par LSL En jouant avec les états, les événements et les quelques 200 fonctions prédéfinies, vous élargissez considérablement vos possibilités au sein de Second Life. La programmation en LSL vous permet ainsi de modifier l’objet associé à votre script (changements de couleurs, de forme, ajout d’effets spéciaux avec le système de particules…), mais également d’interagir avec l’utilisateur, à travers la fenêtre de discussion ou un menu qui apparaît en surimpression à l’écran, de lancer des animations et d’invoquer des ressources externes, notamment des services web. [07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Linden Scripting Language (LSL) : devenez le maître du jeu !
La communication, le sujet sur lequel nous nous penchons aujourd’hui, apparaît alors comme la pierre angulaire de ces différentes familles de scripts. En effet, la quasi-totalité des scripts que vous serez susceptible de développer s’appuient dans une large mesure sur cette notion de communication et d’échange entre les objets ou vis-à-vis des utilisateurs. C’est également la facette du langage qui est la plus appelée à évoluer au cours des prochains mois et qui devrait étendre les fonctions de Second Life bien au-delà du cadre envisagé par Linden Lab. Aussi, avant d’aborder des exemples plus complexes et davantage tournés vers ce type de comportement, vous devez prendre le temps de maîtriser la syntaxe de LSL. Si vous avez déjà l’habitude du typage, des opérateurs et des structures conditionnelles des autres langages, notamment C ou Java, vous devriez être en terrain connu. LSL reprend en effet la plupart des éléments les plus courants qui bercent la programmation depuis ses balbutiements. En revanche, si le développement est une activité totalement nouvelle pour vous, prenez le temps de consulter le guide officiel des fonctions en LSL. Il est installé par défaut avec Second Life et vous le parcourrez avec votre navigateur Internet (depuis C:\Program Files\SecondLife\lsl_guide.html). Plus limité pour les scripts ambitieux, ce guide constitue une bonne introduction générale à la programmation. En particulier, LSL reconnaît sept types de variables : des entiers ( integer ), des nombres à virgule flottante ( float ), des chaînes de caractères ( string ), des identifiants représentant des objets ou des agents dans Second Life ( key ), des vecteurs regroupant trois nombres à virgule flottante ( vector ), des rotations définies par quatre valeurs ( rotation ) et des listes ( list ). Nous passerons en revue ces différents types à travers des exemples concrets, mais sachez que le typage est fort en LSL : vous devez indiquer le type de vos variables lorsque vous les définissez. Mis à part les vecteurs, les variables de type key et les rotations, LSL n’exploite pas
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
de spécificités particulières. Comme nous le verrons par la suite, c’est plutôt dans l’usage et la mise en place de votre code source que des comportements inédits apparaîtront. Lorsque vous vous heurtez à un problème ou lorsque le manque d’informations se fait cruellement sentir, ne restez pas seul ! La Toile comme le monde virtuel de Second Life regorgent de ressources utiles pour vous aider. En participant aux discussions, vous suivrez l’évolution du LSL et vous serez les premiers informés de certaines techniques de programmation ou de l’apparition de nouvelles fonctions intégrées. Une immersion dans Second Life Dans la suite de cet ouvrage, des notes ponctuent régulièrement les exemples de scripts et les détails sur les fonctions utilisées. Elles visent à décrire une implémentation concrète du procédé que nous étudions, glanée dans les méandres du métavers. N’oubliez pas que Second Life est avant tout entre les mains des avatars, qui regorgent d’idées et d’inventivité ! Plongez dans les créations les plus originales, entretenez-vous avec les développeurs et mimez leurs procédures pour développer vos propres projets.
Dotez vos objets de comportements particuliers Vous connaissez à présent les règles d’or de la création et de l’édition de scripts en LSL. Retroussons-nous les manches pour nous atteler à un premier exemple d’envergure. Dans un premier temps, nous allons explorer la notion d’états et les différents types de variables afin d’aborder des sujets plus ambitieux par la suite. Ouvrez LSLEditor et saisissez le listing suivant :
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Linden Scripting Language (LSL) : devenez le maître du jeu !
10
Exemple 2. Illustration
des états avec la création d’un interrupteur.
vector pleine_lumiere = <1,1,0>; vector noir_complet = <0,0,0>; // L'état par défaut ("default") est obligatoire default { // les instructions suivantes s'exécutent // automatiquement à chaque fois qu'on // entre dans cet état. state_entry() { // l'objet parle dans le canal 0 llSay(0, "Que la lumiere soit !"); // chaque face de l'objet est éclairée au max. llSetColor(pleine_lumiere, ALL_SIDES); } // événement déclenché lorsqu'on touche l'objet touch_start(integer total_number) { // On change d'état : // on appelle l'état "extinction" // notez qu’il s'agit ici d'un appel // et non d'une définition state extinction; } } // fin de l'état par défaut // Second état state extinction { state_entry() // instructions exécutées automatiquement { llSay(0, "Extinction des lumieres !"); // chaque face de l'objet est assombrie au max. llSetColor(noir_complet, ALL_SIDES); }
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Linden Scripting Language (LSL) : devenez le maître du jeu !
11
// Lorsqu'on touche l'objet, // on revient à l'état par défaut touch_start(integer total_number) { state default; } }
5. Cliquez sur le bouton « More » de la fenêtre flottante, puis sur l’onglet « Content ». Comme nous l’avons déjà vu, c’est derrière cet onglet que se cachent les scripts que vous associez à vos objets.
Suivez ces quelques étapes pour intégrer le script dans Second Life :
7. Supprimez le code proposé par défaut (que nous avons d’ailleurs parcouru précédemment) et collez le script que vous avez préparé.
6. Cliquez sur le bouton « New Script » puis effectuez un doubleclic sur « New Script » qui apparaît dans la liste. Vous ouvrez ainsi l’éditeur/compilateur de script.
1. Après avoir saisi le code dans LSLEditor, appuyez ensuite sur la touche F5 de votre clavier afin de lancer le débogueur. Un nouvel onglet apparaît (« Debug ») et vous pouvez ainsi tester les deux états et simuler un utilisateur en train de toucher votre création. Vous ne visualisez pas à proprement parler le résultat, mais la console vous renvoie les modifications apportées à l’objet et les messages renvoyés à l’utilisateur apparaissent en bas de l’écran. La moindre erreur de compilation aurait été signalée : votre code paraît donc correct et vous pouvez le tester dans le métavers.
8. 8. Cliquez sur le bouton « Save » : le compilateur de Second Life entre en action et convertit votre script en données brutes. Fermez les deux fenêtres et cliquez sur votre objet. Vous basculez ainsi d’un état à un autre et votre objet s’éclaire ou s’éteint alternativement.
2. Cliquez à présent sur l’onglet « Script » et copiez l’intégralité du code source (sous Windows, vous sélectionnez l’ensemble du listing en pressant simultanément CTRL + A et vous le copiez avec CTRL + C). 3. Rendez-vous dans Second Life, dans votre Sandbox de prédilection. 4. Effectuez un clic droit sur le terrain et choisissez l’option « Create ». Par défaut, l’ensemble des figures géométriques de base apparaît dans la fenêtre principale (cliquez sur Create si ce n’est pas le cas). Déposez une première forme sur le terrain afin de bâtir un objet. À ce stade, vous pouvez également exploiter un modèle que vous aurez déjà préparé (par exemple, une lampe dont le modèle regroupe plusieurs prims).
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Figure 9. Associez le script à votre objet en effectuant un copier
/ coller depuis LSLEditor vers l’éditeur intégré à Second Life.
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Linden Scripting Language (LSL) : devenez le maître du jeu !
12
Variables globales, vecteurs, états et événements Regardons de plus près le listing précédent. Remarquez tout d’abord qu’il est constellé de commentaires, précédés de deux slashes (« // ») comme dans la plupart des langages de programmation. Si vous effectuez vos premiers pas en programmation, adoptez sans plus tarder cette habitude : LSL n’est pas particulièrement adapté au développement collaboratif, mais vous exposerez ainsi quelques explications supplémentaires à l’attention d’autres développeurs ou … de vous-mêmes, si vous revenez vers ce script dans quelques mois ! Le script s’ouvre par la définition de deux variables globales, qui sont des vecteurs. Définies en-dehors du moindre état, ces deux variables globales sont ainsi accessibles à tout moment dans votre code source. Comme vous pouvez le voir, les vecteurs regroupent trois flottants en les séparant par une virgule. Nous les utilisons ici pour définir des couleurs selon la nomenclature <rouge, vert, bleu> ; le premier vecteur correspond ainsi à du jaune très clair et le second à du noir.
Figure 10. On touche l’objet une première fois : il s’éclaire
instantanément.
Nous entrons ensuite dans l’état default . L’événement state_ entry() s’exécute automatiquement quel que soit l’état dans lequel vous vous trouvez. Nous commençons par laisser la parole à l’objet, qui vous indique sur le canal de discussion qu’on s’apprête à « l’allumer ». La fonction llSetColor() modifie la couleur de l’objet selon le vecteur qu’on lui passe en argument et la face concernée. Dans cet exemple, nous utilisons la constante ALL_ SIDES (comme toutes les constantes dans la plupart des langages de programmation, elle s’écrit en majuscules) qui applique la teinte à toutes les faces de votre objet.
Figure 11. Exploitez le débogueur intégré à Second Life pour vous
assurer d’appliquer une modification à une face en particulier ! [07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Limiter le changement à une ou plusieurs faces en particulier Avec la constante ALL_SIDES , toutes les faces de votre objet sont concernées par la modification. Selon la complexité de votre modèle, vous aurez parfois envie de restreindre les changements à une ou plusieurs faces, pour obtenir le meilleur rendu possible. C’est tout à fait possible : les faces sont numérotées de 0 à 5 sur un cube et même au-delà pour les formes plus complexes. La numérotation obéit à des lois très strictes – on alloue respectivement aux faces supérieure et inférieure les numéros 0 et 5 puis de 1 à 4 pour les autres faces en fonction de leurs coordonnées. La meilleure méthode consiste à exploiter le débogueur de Second Life pour connaître ces numéros. Pressez Ctrl + Alt + D simultanément afin d’afficher les menus « Client » et « Server » dans la barre d’outils. Cliquez sur votre objet puis cochez la case « Select Texture ». Vous pouvez alors sélectionner chaque face de manière individuelle. Appuyez ensuite sur Ctrl + Alt + Maj + T pour faire apparaître le débogueur de textures, qui indique clairement le numéro des faces sur lesquelles vous cliquez. Vous pouvez alors remplacer la constante ALL_SIDES par le numéro concerné, dans l’appel de la fonction llSetColor() . Après avoir « éclairé » l’objet, le script entre en pause jusqu’à ce que l’utilisateur touche le modèle. C’est le rôle de l’événement touch_start() qui poursuit l’exécution du script en basculant dans l’état « extinction ». Il s’agit d’un second état personnalisé, que l’on a créé grâce au mot-clé « state ». Un nouveau message parvient à l’utilisateur puis la fonction llSetColor() exploite le second vecteur pour « éteindre » l’objet en recouvrant sa texture de noir. Là encore, il faut toucher le modèle pour revenir à l’état par défaut. Les deux états s’apparentent ainsi à un interrupteur qu’on presse pour provoquer une réaction.
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Linden Scripting Language (LSL) : devenez le maître du jeu !
13
Figure 12. On touche l’objet à nouveau : nous sommes dans le second état, « extinction », et l’objet s’éteint automatiquement.
La définition des couleurs à travers des vecteurs est commode : les trois valeurs sont de type float et correspondent au pourcentage de rouge, vert et bleu au sein de la teinte. Ainsi, <0.75, 1, 0.25> définit une teinte composée de 75% de rouge, 100% de vert et 0.25% de bleu. La plupart des éditeurs graphiques (y compris l’éditeur de textures et de couleurs intégré à Second Life) indique ces valeurs selon une échelle allant de 0 à 255. Vous pouvez ainsi diviser ces valeurs par 255 pour les convertir en pourcentage. Si vous réalisez régulièrement ce type de calculs, optez sans hésiter pour Color Picker. Il s’agit d’un petit utilitaire développé par un fan, que vous trouverez à l’adresse http://byte3d. phpwebhosting.com/aw/. Il convertit toutes les couleurs que vous serez susceptible d’utiliser dans la nomenclature de Second Life et vice-versa.
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Au bal des lumières 19h23. Le soleil commence déjà à disparaître derrière l’horizon de Sunset Island. La galerie marchande est toujours noire de monde et les avatars déambulent de boutique en boutique à pas pressés. À quelques pas de la fontaine, une voix nous tire de nos pensées. « Bonjour ! Vous voulez entrer ? ». On lève les yeux : la propriétaire des lieux, Alyssa Yap, est montée sur un escabeau et nettoie soigneusement les vitres de son échoppe. « Je ferme dans quelques minutes, vous avez le temps de faire le tour », nous lance-t-elle avec un clin d’œil. On pénètre dans la boutique : des dizaines de luminaires remplissent les étals. Spots, lampes halogènes, néons, lampes de chevet… Des dizaines de modèles sont disponibles. « La clé de mon succès ? » nous demande Alyssa, un seau et une éponge à la main. « Chaque lampe est un modèle unique qui émet une lumière particulière. C’est un script LSL qui gère l’interrupteur et qui définit les couleurs. Les clients se les arrachent ! ». Intéressé par un petit modèle qui ira à ravir sur la table de notre salon, nous effectuons la transaction et nous quittons notre artisane. Rendez-lui visite à l’adresse http://slurl.com/secondlife/Sunset%20 Arts%20II/240/91/22. Aller plus loin dans la modification de comportements avec les timers Pour l’instant, nous avons associé à notre objet un script qui répond aux interactions de l’utilisateur. Il est toutefois possible de définir des objets « intelligents » en LSL grâce aux timers (littéralement, des « chronomètres » ou des « minuteurs »). Les changements vont s’effectuer automatiquement, sans l’intervention d’un avatar. Recopiez le listing suivant dans LSLEditor et lancez le débogueur afin de vérifier qu’aucune erreur ne ponctue le script.
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Linden Scripting Language (LSL) : devenez le maître du jeu !
14
Exemple 3. Modifications automatiques d un objet grâce aux
timers integer compteur; integer secondes; default { state_entry() { llSay( 0, "Bienvenue dans cet exemple ! Touchez la sphere pour changer sa couleur et sa taille."); compteur = 0; } touch_start(integer total_number) { compteur = compteur + 1; llSay( 0, “Touche pour la “ + (string)compteur + " fois."); // On déclenche un événement de type “timer” // toutes les trois secondes. llSetTimerEvent(3); } // ce bloc est appelé toutes les trois secondes, // à chaque fois que l’événement Timer se déclenche timer() { secondes++; // on définit aléatoirement // trois valeurs de rouge, vert et bleu float rouge = llFrand( 1.0 ); float vert = llFrand( 1.0 ); float bleu = llFrand( 1.0 ); // on regroupe les trois valeurs
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Linden Scripting Language (LSL) : devenez le maître du jeu !
15
// déterminées automatiquement // au sein d’un vecteur unique. vector prim_color = < rouge, vert, bleu >; llSetColor( prim_color, ALL_SIDES ); // on assigne la nouvelle couleur à l’objet // on définit aléatoirement // une nouvelle échelle entre 0 et 10 float echelle = llFrand( 10.0 ); llSetScale(< echelle, echelle, echelle > ); // on réassigne l’échelle de l’objet if ( secondes > 30 ) // Au bout de 30 secondes, on réinitialise l'objet { // on éteint alors l'objet llSetColor( < 0, 0, 0 >, ALL_SIDES ); llSay( 0, "L'objet revient a son etat initial" ); llResetScript(); // réinitialise le script pour faire // revenir l’objet à son état initial } } }
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Figure 13. On associe le script à notre objet et on le lance en
touchant notre modèle une première fois. Ici, nous n’avons défini qu’un seul état – mais le chronomètre permet de parcourir plusieurs fois la même boucle. On définit cet événement à l’aide de la fonction llSetTimerEvent() . La valeur passée en argument correspond à un nombre de secondes : à intervalles réguliers, un événement de type « timer » est déclenché. À chaque fois, on bascule ainsi dans la boucle timer() { … }. On y définit aléatoirement quatre valeurs : trois composantes de couleurs (de 0 à 1.0, donc) et une échelle, de 0 à 10. On applique alors cette nouvelle teinte à l’objet à l’aide de la fonction llSetColor() et on modifie l’échelle avec la fonction llSetScale() . Au bout de trente secondes (soit dix modifications puisque l’événement timer intervient toutes les trois secondes), l’objet retrouve son état d’origine à l’aide de la fonction llResetScript() .
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Détecter la présence d’un avatar ou d’un objet et agir en conséquence
16
habitants de Second Life et pour accorder une réelle valeur ajoutée à vos créations.
Figure 14. Dix changements de couleurs et d’échelle vont
s’opérer automatiquement, jusqu’à revenir à l’état initial.
Détecter la présence d’un avatar ou d’un objet et agir en conséquence Jusqu’à présent, nous n’avons abordé qu’une infime partie des possibilités d’interaction en LSL : nos objets modifient leur comportement lorsqu’un avatar les effleure, ce qui se traduit en LSL par l’événement touch_start() comme nous l’avons déjà vu à plusieurs reprises. Il s’agit donc du résultat d’une action volontaire de la part d’un avatar ; les objets ne présentent pas encore de réelle intelligence et ne font pas preuve de la moindre autonomie. Pour y remédier, nous allons découvrir l’une des notions les plus importantes de la programmation en LSL : les sensors. En paramétrant précisément ces « radars », vous serez en mesure de personnaliser la réaction de vos objets en fonction de la présence d’avatars ou d’autres objets dans les environs. Il s’agit d’une technique essentielle pour attirer l’attention des autres [07/02/08]
Xavier Cazin <xavier@oreilly.fr>
La création d’un premier radar Afin d’illustrer cette technique, nous allons mettre en place un « point de rencontre » à disposer dans votre propre sim ou dans votre galerie marchande. Tous les avatars situés dans un rayon de 96 mètres (la limite imposée en LSL, soit environ un quart de sim) apparaîtront sous la forme d’une liste et le script calculera automatiquement la distance exacte qui sépare tous ces personnages de notre prim, qui représente le point de rencontre en luimême. La limite imposée par Linden Lab évite de surcharger les serveurs et d’accentuer les temps d’attente. Imaginez le résultat si des milliers d’objets scannaient plusieurs fois par seconde l’ensemble du multivers, en lançant des actions spécifiques à chaque détection d’objet ou d’avatar ! À ce titre, un tel radar ne permet de détecter que seize objets ou avatars différents. Nous verrons toutefois qu’il est possible de contourner ces deux limites à l’aide de méthodes de triangulation. Avant d’aller plus loin, il est nécessaire de comprendre la notion d’agents. Contrairement à ce qu’un abus de langage largement répandu laisse à penser, les agents ne sont pas exactement des avatars ; il s’agit plus généralement des utilisateurs qui se connectent à une sim. Dans le client, les agents sont donc représentés par des avatars, tributaires des lois de la physique et capables de porter des éléments. La distinction peut paraître anecdotique, mais vous devez garder à l’esprit qu’il existe des méthodes et des événements spécifiquement applicables à des agents ou des avatars. Ainsi, lorsque l’on cherche à détecter la présence d’un avatar, on crée plus précisément un sensor d’agent. La notion est plus générale et permet d’interagir dans la foulée avec un véritable utilisateur (pour renflouer son compte en banque, par exemple) et non sa seule représentation visuelle.
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Dans un premier temps, ouvrez LSLEditor et saisissez le listing suivant : Exemple 4. Le code LSL associé à notre point de rencontre // Variables globales float g_rayon = 96.0; float g_angle = PI; float g_delai = 1.0; vector g_couleur_texte = <1,0,0>;
17
Pour tester votre script, procédez comme suit : 1. Créez un objet dans votre boutique ou dans une Sandbox. Dans notre exemple, il s’agit d’un modeste poteau auquel nous avons ajouté une demi-sphère sur le dessus afin de lui conférer l’allure d’une borne. 2. Passez en mode d’édition en cliquant sur le bouton Edit puis cliquez sur l’onglet Content (pressez éventuellement le bouton More afin de faire apparaître le menu complet). 3. Cliquez sur le bouton New Script puis effectuez un double clic sur l’icône « New Script » qui apparaît dans l’arborescence.
// Evénements default { state_entry() { llSetText("", g_couleur_texte, TRUE);
4. Remplacez le script d’exemple par le listing que vous avez saisi dans LSLEditor. Cliquez sur le bouton Save puis fermez la boîte de dialogue. Veillez à cocher la case « Running ».
llSensorRepeat(«», NULL_KEY, AGENT, g_rayon, g_angle, g_delai); } sensor(integer nbr_detectes) { string message; integer i; for(i = 0 ; i < nbr_detectes ; i++) { integer distance = (integer)llVecDist(llGetPos(), llDetectedPos(i)); message += llDetectedName(i) + " (" + (string)distance + "m)\n"; } llSetText(message, g_couleur_texte, TRUE); } }
[07/02/08]
Détecter la présence d’un avatar ou d’un objet et agir en conséquence
Xavier Cazin <xavier@oreilly.fr>
Le résultat ne se fait pas attendre : le nom de tous les agents situés dans un rayon de 96 mètres de la borne de rendez-vous apparaît au-dessus de cet objet, vous y compris. La distance qui les sépare du prim figure également parmi les informations. Faites quelques pas en arrière : la distance est remise à jour automatiquement toutes les secondes.
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Figure 15. Notre poteau dresse la liste de tous les agents situés
dans un rayon de 96 mètres. La mise en place du radar et la récupération des informations sur les agents Quelques explications s’imposent. Nous commençons tout d’abord par définir quatre variables globales en début de script, avant de déclarer le moindre état. Vous noterez d’ailleurs que nous avons choisi de mettre en relief ces variables globales en les faisant précéder de la lettre « g ». Prenez l’habitude d’opter pour cette nomenclature : c’est un excellent moyen d’identifier les paramètres essentiels de votre script, que vous pourrez ainsi modifier en quelques secondes. Ces quatre variables globales définissent respectivement un rayon (96 mètres), un arc de cercle exprimé en radians (pi), un délai de recherche (une seconde) et un vecteur qui déclare la couleur du texte (le rouge). Notre script ne met en place qu’un seul état, default . Dès le lancement du script, nous entrons dans
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Détecter la présence d’un avatar ou d’un objet et agir en conséquence
18
l’événement state_entry() : nous commençons par supprimer tout texte éventuel au-dessus de la borne de rendez-vous à l’aide de la méthode llSetText() à laquelle nous passons une chaîne de caractères vide. Nous faisons ensuite appel à la fonction llSensorRepeat() . Celle-ci met en place un radar qui va scanner les environs à intervalles réguliers, à la recherche d’agents définis par n’importe quelle valeur key dans le rayon décrit par nos variables globales. La recherche s’effectue de part et d’autre d’un vecteur en ligne droite par rapport à l’objet : en définissant un arc de cercle de « pi radians », on scanne ainsi tout autour de notre objet. Dans notre script, nous n’avons pas précisé de critères particuliers : notre sensor va détecter l’ensemble des éléments tant qu’il s’agit d’agents. Vous pouvez remplacer le paramètre AGENT par ACTIVE (pour détecter les objets qui obéissent à la physique et qui se déplacent ou les objets contenant un script en cours d’exécution), PASSIVE (pour les objets ne s’articulant pas autour d’un script) ou SCRIPTED (pour tous les éléments scriptés, que ces derniers soient actifs ou non). Dès que ce critère est rencontré, un événement de type sensor est lancé. On se rapproche ici du principe des timers que nous avons étudiés précédemment. L’événement sensor() ne renvoie qu’une seule valeur : le nombre d’éléments détectés ( nbr_detectes ). Nous exploitons immédiatement cette variable locale pour parcourir une boucle for() qui va lancer un traitement pour chaque agent détecté. Comme nous l’avons vu précédemment, il existe plusieurs fonctions liées à la détection des agents. Nous utilisons ici llDetectedName() pour récupérer le nom de l’agent et llDetectedPos() pour connaître sa position exacte. Dès lors, il est possible de créer une chaîne de caractères au sein de la boucle for() contenant le nom de chaque agent puis la distance qui les sépare de notre prim. (integer)llVecDist(llGetPos(), llDetectedPos(i))
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Grâce à cette instruction, nous calculons la distance entre le prim (repéré par la fonction llGetPos() ) et l’agent détecté, puis nous arrondissons la valeur sous la forme d’un entier. La forme message += ... revient à écrire message = message + ... : nous construisons une chaîne de caractères qui se complète ainsi au fur et à mesure. Notez également que « \n » correspond au retour à la ligne ; après chaque traitement d’un agent détecté, nous passons à la ligne suivante afin de rendre le texte plus lisible. En dernier lieu, nous affichons le message au-dessus du prim à l’aide de la fonction llSetText() . Le script tout entier étant consigné dans l’événement state_entry() de l’état default , il s’exécute en permanence et se voit donc remis à jour toutes les secondes, comme nous l’avons indiqué à la fonction llSensorRepeat() .
Détecter la présence d’un avatar ou d’un objet et agir en conséquence
19
Un sensor pour modifier le comportement de votre propre agent Ce type de script peut remplir des rôles très différents. Dans le cadre de notre exemple, nous l’exploitons pour repérer tous les agents situés dans le giron d’une zone d’une sim. Vous avez probablement déjà expérimenté cette réaction en pénétrant dans une sim : dès qu’un utilisateur se rend à proximité d’un espace de création libre, il reçoit un message de bienvenue ou une mise en garde. Il a bel et bien été détecté automatiquement ! Mais vous pouvez également l’utiliser pour cibler un comportement vis-à-vis d’un agent bien précis … vous-même, par exemple ! Dans ce cas de figure, la fonction llSetSensorRepeat() ne va plus accepter NULL_KEY comme paramètre (qui détecte les avatars représentés par n’importe quelle clé), mais un agent bien précis, représenté par une variable key unique. Comme nous l’avons vu en préambule lorsque nous évoquions les différents types disponibles en LSL, le type key correspond à une chaîne de caractères qui définit un identifiant unique de la forme « 00000000-0000-0000-0000-000000000000 ». En 32 caractères (séparés par quatre traits d’union), on peut créer 2 128 clés distinctes : il est donc possible de personnaliser le comportement de vos sensors pour des milliards de milliards d’objets différents.
Figure 16. Nous créons dynamiquement une chaîne de caractères,
actualisée en permanence, avec le nom de tous les agents et la distance exacte qui les sépare du poteau de rendez-vous. [07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Mettons en place un second exemple qui va modifier la position de l’objet en fonction des déplacements de votre propre avatar. Nous essayons ici de reproduire les petites sphères d’entraînement de La Guerre des Étoiles, qui suivent Luke Skywalker à bord du Faucon Millenium. Commencez par créer une nouvelle sphère sur le terrain d’une Sandbox, comme vous en avez désormais l’habitude. Associez-lui ensuite le script suivant :
Créer des scripts pour Second Life
➔ Sommaire
Détecter la présence d’un avatar ou d’un objet et agir en conséquence
Créer des scripts pour Second Life
{
Exemple 5. Une sphère qui évolue en fonction de vos
llResetScript();
déplacements.
}
vector g_positionDepart; vector g_positionActuelle;
if( llDetectedOwner( 0 ) == llGetOwner() ) { vector position = llDetectedPos(0);
vector g_offset; integer g_repetitions; float g_vitesseRotation; float g_delaiSensor; default { state_entry() { llOwnerSay( "Bonjour maitre ! Touchez-moi pour lancer l'exercice." ); llSetStatus( 1, FALSE ); g_offset = < 2, 2, 1 >; g_repetitions = 0; g_vitesseRotation = .5; g_delaiSensor = .3; } touch_start(integer total_number) { g_positionDepart = llGetPos(); g_positionActuelle = g_positionDepart; llSleep( .1 ); key id = llGetOwner(); llSensorRepeat( "", id, AGENT, 96, PI, g_delaiSensor ); } sensor(integer total_number) { g_repetitions++;
float degreRotation = llRound( g_vitesseRotation * g_repetitions ) % 360; rotation Rotation = llEuler2Rot( < 0, 0, degreRotation * DEG_TO_RAD > ); vector offsetRotation = g_offset * Rotation; position += offsetRotation; llSetPos( position ); g_offset = offsetRotation; } } }
Lorsque vous êtes immobile, la sphère tourne autour de vous (c’est la dernière partie du script qui s’en charge, en créant une variable de type rotation ). Mais à l’aide d’un sensor, on va également repérer vos déplacements à intervalles réguliers. La sphère se déplace ainsi en même temps que vous, tout en effectuant des rotations autour de votre avatar. Nous commençons par définir quelques variables globales, dont la plupart ne se révéleront utiles que lors de la rotation de l’objet en lui-même (la variable g_offset décrit le « décalage » entre l’avatar et l’objet, selon les coordonnées <x, y, z> ). En jouant sur l’axe des ordonnées, nous pouvons ainsi surélever l’objet et donner l’impression d’une sphère qui flotte dans l’espace. Nous déclenchons l’événement sensor() en lui-même à l’aide des instructions suivantes : key id = llGetOwner(); llSensorRepeat( "", id, AGENT, 96, PI, g_delaiSensor );
if( g_repetitions > 300 )
[07/02/08]
20
Xavier Cazin <xavier@oreilly.fr>
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Détecter la présence d’un avatar ou d’un objet et agir en conséquence
21
Vous avez probablement déjà rencontré des avatars dans l’univers de Second Life qui sont suivis par de nombreux objets, notamment des animaux. Ce type de comportement s’inscrit précisément dans le cadre de notre exemple : il s’agit d’objets soigneusement modélisés qui détectent la présence de leur propriétaire à des intervalles très rapprochés et qui modifient leur propre position en conséquence, en maintenant un offset régulier. Les possibilités sont infinies !
Figure 17. La sphère ne gravite qu’autour de son propriétaire,
en détectant la position de ce dernier et en actualisant ses propres coordonnées. La fonction llGetOwner() récupère l’identifiant du propriétaire de l’objet. Le radar va ainsi détecter uniquement votre propre présence à intervalles réguliers et agir en conséquence. Afin d’éviter les collisions et les problèmes lorsque deux objets disposant du même script sont situés dans le même giron, nous vérifions une nouvelle fois que le propriétaire de l’objet est bien l’agent qui a été détecté. Nous procédons ensuite à la rotation de l’objet en faisant évoluer sa position à l’aide de la fonction llDetectedPos() comme dans le script précédent. En augmentant le nombre d’itérations ( g_repetitions ), nous obtenons des déplacements de plus en plus rapprochés, ce qui évite les saccades et donne l’impression d’une plus grande fluidité !
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Les têtes de gondole Aujourd’hui, j’ai l’esprit ailleurs. Même le spectacle du soleil couchant sur la baie d’Heron ne parvient pas à me sortir de mes pensées. Quel cadeau pourrais-je bien lui offrir ? J’ai déjà parcouru inlassablement tous les recoins des galeries marchandes de Sunset Island, à en user mes semelles numériques. Il y a pourtant bien quelque chose qu’elle n’a pas encore et qui pourrait lui faire plaisir ! Alors que je commençais à perdre espoir, un petit hologramme flottant se précipite vers moi. « Bonjour cher client ! Vous cherchez le cadeau idéal ? Avezvous songé à offrir un bijou personnalisé ? ». À quelques mètres de là, un large panneau fait déjà apparaître mon nom en lettres d’or. Aucun doute : ce commerçant sait attirer le regard ! Concrètement, il utilise un sensor pour détecter les avatars qui se situent à une dizaine de mètres de son échoppe, affiche leur nom au-dessus de son enseigne pour éveiller leur attention et récupère leur position en envoyant un petit robotguide pour les inviter à pénétrer dans la boutique. Vous pouvez lui rendre visite à Orchid Beach à l’adresse http://slurl.com/ secondlife/Orchid%20Beach/168/153/25.
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Créer des objets qui s’entretiennent entre eux Grâce aux timers et aux sensors, vos objets présentent désormais un premier niveau d’intelligence et d’autonomie. Outre la possibilité de « toucher » un objet grâce au menu contextuel de Second Life, le second moyen d’interagir avec une création de l’univers virtuel réside dans le système de dialogue qui apparaît en bas de l’écran. À grands renforts de boucles conditionnelles et de tests, vos objets peuvent en effet détecter vos paroles et vous renvoyer des messages. Jusqu’à présent, nous n’avons articulé nos exemples qu’autour de modèles très simples et de scripts uniques. Mais très rapidement, vous aurez besoin de lier plusieurs prims entre eux et de leur associer des scripts distincts, qui échangent des valeurs ou des instructions. C’est un aspect essentiel de la communication programmative de Second Life, qui étendra largement vos possibilités et vous permettra d’aboutir à des projets ambitieux. La notion d’éléments parents et enfants : l’exemple d’une fabrique de gâteaux Lorsque vous modélisez des objets dans Second Life, vous pouvez affiner le rendu de vos créations en regroupant plusieurs prims au sein d’un objet unique. Ainsi, une chaise est constituée d’un ensemble de prims : quatre parallélépipèdes pour les pieds et quelques formes supplémentaires pour l’assise et le dos de votre siège. Mais en programmation LSL, vous aurez également besoin de lier des prims ou des objets entre eux. Concrètement, il s’agit d’indiquer la relation qui existe entre un ensemble d’objets … parfois situés à plusieurs mètres de distance. Là encore, Linden Lab impose des limites dans le regroupement d’objets : les centres de chaque élément ne doivent pas être séparés de plus de 32 mètres de distance. Une fois liés entre eux, les ensembles de prims (vous entendrez souvent l’expression « linkset ») se comportent comme un objet unique.
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Créer des objets qui s’entretiennent entre eux
22
Passons sans plus tarder à la pratique autour d’un exemple concret. Comme vous allez le voir, la liaison d’objets est l’un des exercices les plus méticuleux pour les programmeurs LSL. Vous devez non seulement prêter une attention toute particulière au nom de vos objets, mais également les sélectionner dans un ordre spécifique : le dernier élément sur lequel vous aurez cliqué héritera du rôle « de prim parent » et contiendra le script qui s’appuiera sur les objets enfants. Dans notre exemple, nous souhaitons mettre au point une fabrique de gâteaux. Vous devez préparer deux manivelles (respectivement baptisées « pour_ gateau_1 » et « pour_gateau_2 ») et un panneau de contrôle principal (l’élément parent dans le linkset constitué des trois prims). Vous devez aussi créer les deux modèles de gâteau, leur donner un nom et les ajouter à votre inventaire avant de les greffer au « contenu » de l’ensemble. Procédez comme suit : 1. Sur un espace vierge d’une Sandbox, créez un premier modèle en cliquant sur le terrain puis en choisissant l’option « Create » du menu contextuel. 2. Dans la fenêtre d’édition de vos prims, cliquez sur l’onglet General et saisissez « pour_gateau_1 » dans le champ Name. Validez en pressant la touche Entrée de votre clavier. 3. Renouvelez l’opération pour créer la seconde manivelle, que vous baptiserez « pour_gateau_2 ». 4. Créez ensuite le panneau de commandes. Vous pourrez librement l’enrichir avec vos textures personnelles, en créant éventuellement une image aux dimensions appropriées qui contiendra les instructions nécessaires. Le nom de cet objet n’a pas d’importance. 5. Créez successivement deux modèles de gâteau et nommezles « gateau1 » et « gateau2 » en suivant la même procédure. Effectuez un clic droit sur chacun des modèles et choisissez
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
l’option Take : les deux éléments disparaissent de l’écran et se greffent à votre inventaire. 6. Effectuez un clic droit sur le panneau de commandes, choisissez l’option Edit et rendez-vous à l’onglet Content. En parallèle, ouvrez votre inventaire et ajoutez les deux objets en forme de gâteaux dans le volet « Content » par un simple glisser / déposer. 7. Cliquez ensuite sur le bouton « New Script » puis effectuez un double clic sur ce script et saisissez le listing suivant. Exemple 6. La fabrique de gâteaux. default { state_entry() { llSay( 0, "Bienvenue dans notre boulangerie ! Quelle est votre commande ?"); } touch_start(integer total_number) { string manivelle = llGetLinkName(llDetectedLinkNumber(0)); if(manivelle == "pour_gateau_1") { llRezObject("gateau1", llGetPos() + < 0, 0, 2 >, ZERO_VECTOR, ZERO_ROTATION, 42); } else if(manivelle == "pour_gateau_2") { llRezObject("gateau2", llGetPos() + < 0, 0, 2 >, ZERO_VECTOR, ZERO_ROTATION, 42); ������������������� } } }
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Créer des objets qui s’entretiennent entre eux
23
Sélectionnez à présent vos trois objets en maintenant la touche Maj. enfoncée et en commençant par les deux manivelles pour terminer par le panneau de contrôle. Pressez simultanément les touches Ctrl + L de votre clavier : vous créez un linkset avec les trois éléments. Le prim parent apparaît bordé de jaune et les éléments enfants s’encadrent d’un halo bleu : en cliquant sur l’onglet General, vous remarquerez que les trois éléments sont bien considérés comme un objet unique (« 1 Object, 3 Primitives »). Quel est l’intérêt de cette méthode ? Vous disposez de deux éléments distincts que vous pouvez toucher, les manivelles, qui peuvent ensuite déclencher des actions spécifiques. Le comportement de votre objet repose bel et bien sur une forme de communication entre un ensemble de prims. Notre script s’articule autour d’une chaîne de caractères essentielle, qui permet de déclencher la fabrication de l’un ou l’autre des deux gâteaux : string manivelle = llGetLinkName(llDetectedLinkNumber(0));
Second Life numérote les éléments d’un linkset dans l’ordre inverse de votre sélection. L’élément parent hérite toujours du numéro 1 et le premier élément enfant du numéro 2 (ici, la seconde manivelle correspond au numéro 2 et la première manivelle au numéro 1). En couplant ainsi les fonctions llGetLinkName() et llDetectedLinkNumber() , nous pouvons récupérer très simplement le nom de la manivelle activée : il est ensuite enregistré dans la variable manivelle . Nous réalisons ensuite deux tests successifs à l’aide de boucles if() et else if() . Si c’est la première manivelle qui a été touchée, le test if(manivelle == «pour_gateau_1») est vérifié. Dans notre exemple, nous faisons ainsi apparaître dynamiquement le premier gâteau à notre écran. On y parvient à l’aide de la méthode llRezObject() qui crée un élément situé dans l’inventaire de l’objet. Ici, nous créons le gâteau à deux mètres au-dessus du panneau de commandes. La dernière valeur est optionnelle : il s’agit
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
d’un paramètre que l’on passe à l’objet fraîchement créé. Vous pourrez ensuite y accéder dans un script indépendant à l’aide de la méthode llGetStartParameter() . Si le premier test n’est pas validé, c’est bel et bien que la première manivelle n’a pas été manipulée. Pourtant, nous sommes dans l’événement touch_ start() et un élément a donc été touché par l’utilisateur ! Nous devons toutefois inclure un second test portant sur la manivelle « pour_gateau_2 » : les prims ont été regroupés au sein d’un linkset et il est donc possible de « toucher » le panneau de commande en lui-même. Si la seconde manivelle a été manipulée, nous créons l’autre gâteau qui a été préparé.
Créer des objets qui s’entretiennent entre eux
24
La communication entre plusieurs objets et des scripts distincts Il existe une seconde méthode pour laisser deux objets communiquer entre eux et effectuer des actions en conséquence : la fonction llMessageLinked() et l’événement link_message() . La particularité de cette méthode réside dans la possibilité de scinder le code en deux scripts, que vous associerez à chacun des éléments. Pour illustrer cet aspect, nous allons créer un simple bouton qui va commander un chariot élévateur. Vous modéliserez les deux éléments à la suite les uns des autres et vous les regrouperez ensuite dans un linkset, comme précédemment. Là encore, il est très important de distinguer l’élément parent de l’élément enfant, notamment pour n’appliquer le repositionnement du chariot élévateur qu’au prim enfant. Attention : vous devez ajouter les deux scripts individuellement à chaque prim, avant de les regrouper. Sélectionnez le bouton-pressoir que vous avez créé dans un premier temps et associez-lui le script suivant : Exemple 7a. Le code associé au prim parent : le bouton.
Figure 18. La fabrique de gâteaux s’articule autour d’un
ensemble de prims constitués d’un élément parent et de deux éléments enfants.
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
integer g_pression = TRUE; default { touch_start(integer x) { if(g_pression == TRUE) { llMessageLinked(LINK_ALL_OTHERS, 1, "monter", NULL_KEY); g_pression = FALSE; } else if(g_pression == FALSE) {
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
llMessageLinked(LINK_ALL_OTHERS, 1, "descendre", NULL_KEY); g_pression = TRUE; } } }
Cliquez sur le bouton Save et patientez quelques secondes, pendant que l’éditeur LSL de Second Life compile votre code. Sélectionnez ensuite le second prim, qui correspond au chariot élévateur, et associez-lui ce listing : Exemple 7b. Le code associé au prim enfant : le chariot élévateur. default { link_message(integer sib, integer n, string msg, key id) { if(msg == "monter") { llSetPos(llGetLocalPos() + <0, 0, 1>); } if(msg == "descendre") { llSetPos(llGetLocalPos() + <0, 0, -1>); } } }
Nous articulons nos deux scripts autour de la variable globale booléenne pression , qui peut prendre deux valeurs : TRUE ou FALSE . Nous reproduisons ainsi peu ou prou le comportement d’un interrupteur ! Lorsque l’utilisateur touche l’élément parent, nous appelons la fonction llMessageLinked() en faisant passer un « message » en guise de paramètre. Dans le cadre de notre exemple, il s’agit de simples mots-clés (« monter » et « descendre ») mais vous pouvez exploiter de véritables chaînes de caractères, sans limite de longueur. On pourrait ainsi envisager des comportements très complexes, avec des chaînes concaténées qu’on
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Créer des objets qui s’entretiennent entre eux
25
parcourt ensuite par tronçons dans un script externe à l’aide de la fonction llGetSubString() . Nous y reviendrons. À chaque fois qu’on crée un événement de type link_message() , on en profite pour permuter l’état de la variable globale g_pression . On bascule ainsi entre les deux états et le chariot élévateur monte ou descend. Le second script ne concerne que le chariot en lui-même. À l’instar de l’exemple 6, on effectue des tests sur le message récupéré par l’événement link_message() . Si l’utilisateur a choisi de surélever le chariot, c’est-à-dire si le message est « monter », on modifie sa position à l’aide de la fonction llSetPos() . Vous devez prêter une attention toute particulière à l’ordre de vos prims. En effet, si vous inversez les deux scripts, c’est la position de l’ensemble du linkset qui va être modifiée et non seulement le chariot. Pour exercer un contrôle absolu sur le changement de position, vous devez utiliser la fonction llGetLocalPos() qui retourne la position actuelle du chariot. On « ajoute » ensuite un vecteur à cette valeur et on réassigne la position à l’aide de la fonction llSetPos() . Dans le cas de la surélévation du chariot, le vecteur est positif selon l’axe z ( <0,0,2> , soit une élévation de 2 mètres par rapport à sa position d’origine) et dans le cas contraire ce vecteur est négatif sur cet axe ( <0,0,-2> ). Testez le résultat en touchant à plusieurs reprises le bouton. Le second prim bouge immédiatement en conséquence !
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Créer des objets qui s’entretiennent entre eux
26
Pour aller plus loin Les fonctions de communication interne entre les objets nous ont permis d’entrevoir la notion plus générale d’éléments parents et enfants. C’est une notion essentielle dans la modélisation de vos objets, mais aussi dans la programmation de comportements intelligents. S’il est possible d’aboutir à des résultats impressionnants avec un script unique associé à un seul prim, vous aurez vraisemblablement besoin de restreindre les modifications à des éléments ponctuels de vos créations.
Figure 19. En appuyant sur le bouton de gauche, on fait évoluer le
plateau situé sur la droite : les deux éléments sont liés entre eux. Au bonheur des artificiers Des dizaines de câbles électriques qui courent dans l’herbe, des boîtiers de mise à feu et un ciel dévoré par des volutes de fumée et des explosions colorées : nous sommes bien à Lumindor, le paradis des artificiers ! Si le spectacle émerveille les dizaines d’avatars réunis près du pont, nous ne sommes pas dupes : ces câbles ne sont là que pour des questions de décor… Les boîtiers communiquent directement avec les fusées par l’intermédiaire de fonctions llMessageLinked() qui déclenchent la mise à feu. Vous connaissez l’arrière des coulisses et le secret de ces as de la pyrotechnique ; qu’à cela ne tienne : gardez votre âme d’enfant et rendez-leur visite à l’adresse http:// slurl.com/secondlife/West%20Lumindor/244/78/34.
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Ce type de communication est toutefois assez complexe à mettre en œuvre et vous ne devez surtout pas hésiter à préparer vos scripts sur papier dans une grande mesure. En effet, vous devez parfois scinder vos traitements en plusieurs scripts, comme nous venons de le voir avec notre exemple de chariot élévateur. Comment peut-on définir les comportements adéquats sans connaître à l’avance les intitulés des messages, des prims ou des tests conditionnels qui les actionnent ? Par ailleurs, la création d’un linkset vous oblige à manipuler vos prims avec une extrême précaution. L’ordre de sélection des éléments est primordial. Si vous réalisez un clic malheureux qui perturbe cet ordre et attribue le rôle de « parent » à un élément qui aurait dû être « enfant », n’oubliez pas de presser simultanément les touches Ctrl + Maj + L pour « délier » cet ensemble. Vous devez donc redoubler de vigilance, sous peine de passer de longues heures à déboguer vos scripts. Une fois les éléments liés, il est particulièrement difficile de retrouver tous les scripts que vous avez définis et de mettre le doigt sur l’élément fautif ! Gageons que dans un proche avenir, cet aspect sera largement amélioré au sein du client Second Life. À l’heure actuelle, on retrouve une situation un peu analogue à la version 1.0 d’ActionScript (le langage de programmation associé au format d’animation vectorielle Flash), qui poussait les développeurs à dispo-
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
ser de petits scripts ça et là, au sein des images-clés du scénario. Une vraie plaie pour le travail collaboratif et le débogage ! Avant d’aborder la communication à travers le système de dialogue, profitons-en pour exposer une dernière astuce sur le système link_message . La fonction llMessageLinked() accepte un paramètre optionnel, de type key , que nous avions laissé de côté en le remplaçant par la constante NULL_KEY . N’oubliez pas qu’une variable de type key n’est rien d’autre qu’une chaîne de caractères un peu spéciale ! Vous pouvez ainsi la détourner de son rôle initial et faire passer un second message dans un appel unique de llMessageLinked() : string chaine1 = "premier message"; string chaine2 = "second message"; llMessageLinked(LINK_ALL_OTHERS, num, chaine1, (key)chaine2); ...
Attention toutefois : une variable de type key ne peut pas directement être convertie en un entier, un nombre à virgule flottante ou un vecteur. Si votre « second » message soutient ce type de valeur, vous devez d’abord le convertir en une chaîne de caractères.
Créer un objet qui vous écoute et qui vous répond Comme vous en avez très probablement fait l’expérience par vous-même, l’un des principaux attraits de Second Life pour ses millions d’utilisateurs réside dans la possibilité de dialoguer librement à travers la barre de discussion. Mais c’est aussi l’une des possibilités les plus intéressantes pour interagir avec les objets que vous aurez créés, au même titre que la fonction « Touch » qui apparaît dans le menu contextuel ! Vous êtes en effet en mesure de créer des applications interactives « à reconnaissance vocale », que les utilisateurs manipuleront en saisissant directement des commandes dans la barre de dialogue. À
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Créer un objet qui vous écoute et qui vous répond
27
l’inverse, l’objet pourra vous répondre en jouant sur l’intensité de sa « voix » - vous serez capable de l’entendre à quelques mètres seulement lorsqu’il chuchote ou dans un rayon beaucoup plus large s’il hurle. La fonction llListen() et l’événement listen() Si les utilisateurs communiquent à travers le canal de discussion principal, ils ignorent sans doute que c’est l’un des nombreux espaces de dialogue parmi … plusieurs milliards de différents ! Linden Lab a en effet choisi de numéroter les différents canaux et de rendre seulement le canal 0 visible à tous. Plus précisément, les scripts peuvent exploiter les canaux -2.147.483.648 à 2.147.483.647 et ainsi opérer en toute discrétion, sans gêner les autres utilisateurs situés dans un rayon proche. Imaginez le brouhaha si des milliers de scripts communiquaient sans vergogne à travers le canal de discussion principal… Concrètement, il est possible de programmer des fonctions qui vont « écouter » un canal spécifique (ou le canal principal partagé par tous, bien entendu). Si un utilisateur saisit des commandes au clavier, l’événement listen() est déclenché et le script peut lancer des actions en conséquence. Pour éviter de déclencher cet événement à tort et à travers, il est possible de définir des filtres très précis qui ne vont écouter que les paroles du propriétaire d’un objet ou les messages émanant d’un autre objet. À la manière de l’événement link_message() , vous ajoutez ensuite des tests conditionnels qui vont exécuter un traitement spécifique. Pour illustrer sans plus tarder ce système de communication, nous allons adopter un petit animal de compagnie : un caméléon particulièrement docile, qui vous obéit au doigt et à l’œil ! Créez le modèle grâce à l’éditeur intégré de Second Life ou à travers un logiciel tiers, comme SketchUp par exemple. Avec un peu de patience, vous aboutirez à un résultat très précis. Et si vous
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Créer un objet qui vous écoute et qui vous répond
28
n’y arrivez toujours pas, vous pouvez toujours en acheter un chez Animania, l’une des plus belles animaleries de Second Life (http:// slurl.com/secondlife/Skynx/120/69/23). Dans un second temps, associez le script suivant à votre modèle : Exemple 8. Le cerveau du caméléon. default { state_entry() { llListen(42,"",NULL_KEY,""); llSay(0, "Votre animal vous entend sur le canal 42 !"); llSay(0, "Saisissez /42 vert ou /42 sauter par exemple"); } listen(integer channel, string name, key id, string message) { if(message=="sauter") { llSetPos(llGetLocalPos()+<0,0,2>); } if(message=="descendre") { llSetPos(llGetLocalPos()+<0,0,-2>); } if(message=="rouge") { llSetColor(<1,0,0>, ALL_SIDES); } if(message=="vert") { llSetColor(<0,1,0>, ALL_SIDES); } if(message=="bleu") { llSetColor(<0,0,1>, ALL_SIDES); } } }
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Figure 20. Le caméléon interprète les commandes que vous
saisissez dans la barre de dialogue et agit en conséquence, en se déplaçant ou en changeant de couleur. Dans cette première version, le script ne présente pas de difficultés majeures. Il ne contient qu’un seul état, default , qui commence par distiller quelques indications sur la nomenclature à respecter dans le canal de discussion. À ce titre, ces premières instructions exploitent le chat principal avec la fonction llSay(0,… ) qui indique qu’on utilise bien le canal 0 ! Le filtre mis en place avec la fonction llListen() est très ouvert : la seule restriction concerne l’écoute sur le canal 42. En revanche, n’importe quel agent, qu’il soit un simple badaud venant saluer le caméléon ou le propriétaire de l’animal, est en mesure de lui parler.
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Voici quelques filtres plus restrictifs : llListen(128, "", llGetOwner(), "");
On écoute les commandes prononcées par le propriétaire de l’objet sur le canal 128. Si vous bâtissez des objets autour de ce type de filtre avec l’intention de les commercialiser, prenez garde : après l’échange avec votre acheteur, ce dernier ne sera pas en mesure de l’utiliser. Modifiez le script en conséquence ou réinitialisez-le pour ne pas flouer vos clients ! llListen(89, "manivelle", NULL_KEY, "");
Le script écoute les messages envoyés par les objets « manivelle » sur le canal 89. llListen(57, "", NULL_KEY, "envoyer");
Le script réagit à la commande « envoyer » prononcée par n’importe quel agent ou objet sur le canal 57. Il est également possible d’enchaîner jusqu’à 64 filtres successifs. Le gestionnaire d’événement listen() est alors invoqué quel que soit le filtre déclenché. On définit ensuite une série de boucles conditionnelles dans l’événement listen() pour réagir aux commandes saisies par les agents. Notre caméléon peut ainsi sauter sur une branche (grâce à la fonction llSetPos(llGetLocalPos()+<...> que nous avons déjà utilisée précédemment), descendre ou changer de couleur à volonté. On lance les actions en faisant précéder les mots-clés de « /42 », comme « /42 rouge » par exemple. Si vous utilisez un numéro de canal très élevé, vous pouvez vous abstenir de saisir inlassablement ce numéro en indiquant « // rouge » : le dernier canal utilisé est conservé en mémoire.
Créer un objet qui vous écoute et qui vous répond
29
Il est en revanche impossible pour les agents de parler directement sur les canaux de discussion « négatifs ». On ne peut pas saisir « /-42 » par exemple : la commande n’est pas reconnue et le texte apparaît dans le canal standard, aux yeux de tous les utilisateurs (provoquant ainsi les moqueries de vos camarades !). Vos possibilités ne sont pas restreintes pour autant : les agents peuvent communiquer sur tous les canaux allant de -2.147.483.648 à -1 à travers la fonction llDialog() . Un exemple d’implémentation d’application de ce type apparaît à la fin de ce chapitre. Par ailleurs, le canal 2.147.483.647 est considéré comme le canal de débogage. Il est possible de l’écouter à travers la constante DEBUG_CHANNEL : llListen(DEBUG_ CHANNEL, «», NULL_KEY, «») ; . Mais en nouant le dialogue avec le caméléon, vous remarquerez un grave défaut : si la commande saisie dans la barre de dialogue ne correspond pas rigoureusement aux chaînes de caractères prévues par les tests conditionnels, vous ne constaterez aucune réaction. Ainsi, en saisissant « /42 Descendre », il reste parfaitement immobile – comme si notre animal était un inconditionnel de la syntaxe et qu’il ne tolérait pas la moindre incartade. Pour y remédier, exploitez la fonction llToLower() , qui réduit une chaîne de caractères en minuscule. L’instruction suivante corrige donc le problème : if (llToLower(message) == "rouge") { llSetColor(<1,0,0>, ALL_SIDES); }
Prenez l’habitude de procéder de cette manière afin d’éviter les risques. Par ailleurs, si vous mettez au point une application complexe dont les objets se manipulent exclusivement au clavier, n’hésitez pas à utiliser l’opérateur « ou » (qui se traduit par « || » comme dans la quasi-totalité des langages de programmation)
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
pour inclure les différentes orthographes ou les coquilles les plus fréquentes. C’est également un excellent moyen pour proposer des traductions des commandes les plus utiles et étendre largement le public de vos créations : if (llToLower(message) == "erreur" || llToLower(message) == «error» || llToLower(message) == "ereur") { .... }
Pour communiquer au sein de Second Life, il existe plusieurs fonctions permettant d’étendre ou de restreindre le rayon de la parole. llWhisper() va chuchoter un texte qui ne sera entendu que dans un rayon de 10 mètres, llSay() le prononce distinctement dans un rayon de 20 mètres et llShout() permet de hurler jusqu’à 100 mètres. Il existe également la fonction llRegionSay() qui diffuse un dialogue à l’ensemble d’une Sim – mais le dialogue n’apparaît pas dans la barre de discussion : il est directement interprété par des scripts qui écoutent sur un canal spécifique que vous définirez. Enfin, la fonction llOwnerSay() ne s’adresse qu’au propriétaire de l’objet, ce qui évite d’envahir le canal de discussion. Modifier le script afin de limiter l’occupation mémoire et les temps d’accès La création d’objets dont le comportement s’articule autour de commandes à saisir au clavier est très tentante mais elle présente plusieurs risques. Différents tests (que vous pouvez d’ailleurs mener en ouvrant la console de débogage et d’utilisation mémoire, en déroulant le menu Client et en cliquant sur Consoles / Memory) ont démontré que la communication « interne » entre les objets, via l’événement link_message() , est 40% plus rapide que le lancement d’action à travers l’événement listen() . Dans la mesure du possible, évitez de faire passer des
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Créer un objet qui vous écoute et qui vous répond
30
messages entre plusieurs objets à travers un canal de discussion et essayez de les réunir au sein d’un linkset. Vous ne perdez d’ailleurs pas au change : les messages transitant par un canal de discussion sont limités à 1023 octets tandis que les chaînes de caractères traitées par link_message() sont illimitées (jusqu’à épuisement de la mémoire !). N’oubliez pas que vous n’êtes pas seul sur une Sim ; c’est d’ailleurs l’un des principaux attraits de Second Life. En déposant des objets qui écoutent en permanence les messages transitant sur le canal 0, quel que soit l’agent, vous participez à ralentir l’ensemble de l’écosystème : le filtre est évalué au moindre message apparaissant sur la fenêtre de chat. Si vous devez impérativement écouter les messages sur le canal 0, envisagez quelques restrictions. À l’aide d’un timer, vous pouvez limiter l’écoute à une certaine durée seulement. En déclenchant le chronomètre dans un événement touch_start() et en utilisant la fonction llListenRemove() qui désactive un gestionnaire d’écoute, vous optimisez votre code et vous limitez l’occupation mémoire. Exemple 9. Une méthode pour optimiser vos gestionnaires
d'écoute. integer g_listen; string g_message; default { state_entry() { llSay(0,"Touchez l’objet pour debuter l’ecoute"); } touch_start(integer s) { llListenRemove(g_listen); g_listen = llListen(42,"","",g_message); llSetText("Ecoute amorcee",<1,0,0>,1); llSetTimerEvent(20);
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
} listen(integer canal, string nom, key id, string msg) { g_message = msg; llWhisper(0,g_message); } timer() { llListenRemove(g_listen); llSetText("Ecoute arretee",<1,0,0>,1); llSleep(1); llSay(0,"Touchez l’objet pour debuter l’ecoute"); llSetTimerEvent(0); } }
Le traitement en lui-même présente peu d’intérêt : nous écoutons les messages transitant sur le canal 42 et l’objet les « chuchote » en retour sur le canal principal. C’est plutôt la structure du code qui mérite votre attention : la fonction llListen() apparaît dans l’événement touch_start() . En parallèle, on déclenche un chronomètre de 20 secondes. Au-delà de ce délai, on utilise la fonction llListenRemove() pour désactiver l’écoute. Il faut à nouveau toucher l’objet (et donc relancer le chronomètre) pour l’activer une seconde fois. Réfléchissez à l’intérêt de cette méthode dans le cadre de votre projet. Les utilisateurs consentent assez facilement à s’inscrire dans un délai que vous imposez : c’est d’ailleurs une pratique courante des interfaces homme / machine depuis leurs balbutiements. Lancer des traitements plus complexes avec des chaînes de caractères Dans le cadre de nos exemples, nous avons envoyé des commandes qui tenaient en un mot-clé unique. Il est toutefois possible de traiter des instructions plus complexes saisies par les utilisateurs dans la fenêtre de chat. La fonction llParseString2List()
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Créer un objet qui vous écoute et qui vous répond
31
permet de séparer une chaîne de caractères en une liste d’éléments, en définissant une série de séparateurs à identifier. Dans l’exemple suivant, nous manipulons une voiture télécommandée à l’aide de commandes saisies dans la barre de dialogue : on indique la direction dans laquelle le bolide se déplace et on la fait suivre par la distance exprimée en mètres. Exemple 10. Le déplacement d’une voiture télécommandée par
le système de chat. vector g_positionDepart; default { state_entry() { llListen(42, "", llGetOwner(), ""); g_positionDepart = llGetPos(); llSay( 0, "On deplace cet objet avec des commandes sur le canal 42 :" ); llSay( 0, "'gauche', 'droite', 'avant' et 'arriere' suivi de la distance en metres.” ); �} listen( integer canal, string nom, key id, string msg ) { list liste_commande = llParseString2List( msg, [ " " ], [] ); // Première section : dans quel sens // l’objet se déplace-t-il ? string direction = llList2String( liste_commande, 0 ); // Seconde section : la distance du // déplacement, en mètres string distance_chaine = llList2String( liste_commande, 1 ); float distance = ( float )distance_chaine;
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Créer un objet qui vous écoute et qui vous répond
32
if( direction == "gauche" ) { llSetPos( llGetLocalPos() + < -distance, 0, 0 > ); } else if( direction == "droite" ) { llSetPos( llGetLocalPos() + < distance, 0, 0 > ); } else if( direction == "avant" ) { llSetPos( llGetLocalPos() + < 0, distance, 0 > ); } else if( direction == "arriere" ) { llSetPos( llGetLocalPos() + < 0, -distance, 0 > ); } } }
Figure 21. Nous déplaçons notre bolide à l’aide d’une série
Le propriétaire de l’objet s’approche de la voiture et saisit « /42 avant 3 » dans la barre de dialogue. Cette chaîne de caractères passe dans la fonction llParseString2List() : le délimiteur est un simple espace et la variable liste_commande correspond à [«avant», «3»] . Nous isolons ces deux éléments grâce à la fonction llList2String() : l’entier qui apparaît en guise de paramètre correspond au numéro de l’élément à extraire. La distance étant ici considérée comme une variable à virgule flottante, l’utilisateur peut saisir des valeurs en centimètres (« /42 gauche 0.3 » par exemple). On peut imaginer toutes sortes d’applications à ce principe et même envisager des commandes beaucoup plus longues, contenant une dizaine de paramètres !
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
de commandes que l’on émet sur un canal de discussion spécifique. Une application concrète de ce principe : le « Ditéou » de Forest
Afin de résumer l’ensemble des principes que nous avons mis en valeur au cours de ce chapitre, n’hésitez pas à vous reporter à une fabuleuse application mise en œuvre par un utilisateur français de Second Life : le « Ditéou » de Forest. Il s’agit d’un radar que l’on équipe en HUD (c’est-à-dire en surimpression à l’écran, sur l’interface principale) et qui indique la position de l’agent de votre choix dans une Sim au moyen d’une flèche. On lance la recherche d’un agent particulier à travers une ligne de commande à saisir dans la barre de dialogue. Le code s’appuie donc à la fois sur un sensor (pour détecter les environs) et sur un événement listen() qui va recueillir la saisie de l’utilisateur. Vous
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
trouverez le code complet de l’application à l’adresse http:// tinyurl.com/2mpjp4. L’utilisateur saisit « /10teou PolluxAce » dans la fenêtre de chat : il souhaite connaître la position de l’agent PolluxAce. Un événement listen() récupère cette requête puis la sépare en une série de commandes, comme nous l’avons fait précédemment avec la voiture téléguidée. On lance ensuite un événement sensor() en recherchant spécifiquement ce nom d’agent dans les 96 mètres environnant. S’il est trouvé, on récupère sa position : il ne reste plus qu’à calculer l’angle de rotation d’une flèche qui va pointer dans sa direction.
Créer un objet qui vous écoute et qui vous répond
Exemple 11. Mise en place d'une boîte de dialogue. list Titre1=["Introduction","Comportements","Detection"]; list SousTitre1=["Le LSL","La modelisation", "Les Sandbox"]; integer g_canal; integer g_menu; default { state_entry() { g_canal = (integer)(llFrand(99999.0) * -1); g_menu = llListen(g_canal,"","",""); }
Communiquer sur un canal négatif et proposer une boîte de dialogue Nous avons déjà vu par la pratique qu’il est impossible pour un agent de saisir des requêtes du type « /- 42 bonjour » et de s’entretenir ainsi sur un canal « négatif ». Il existe pourtant une solution : l’affichage d’une boîte de dialogue dans le coin supérieur droit de l’interface. Dotée de boutons que l’utilisateur peut presser à volonté, cette boîte de dialogue transmet ses commandes sur un canal négatif. Ce n’est pas une obligation et les messages pourraient même transiter sur le canal de discussion normal, mais autant en profiter : peu utilisés, ces canaux négatifs ne risquent pas d’être accaparés par des scripts concurrents, situés dans les 100 mètres avoisinants ! La création d’une boîte de dialogue passe par la déclaration de listes contenant les éléments à afficher et surtout par la fonction llDialog() . En guise d’exemple, voici un script affichant le plan de cet ouvrage sous la forme de boutons. Lorsque l’utilisateur clique sur un titre de niveau 1, une seconde liste lui est proposée, avec les titres de la partie correspondante.
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
33
touch_start(integer s) { llDialog(llDetectedKey(0),"Choisissez votre chapitre", Titre1,g_canal); } listen(integer canal, string nom, key id, string msg) { if(msg == "Introduction") llDialog(id,"Choisissez votre partie",SousTitre1,g_canal); if(msg == "Le LSL") { llDialog(id,"Cette partie vous fait decouvrir le LSL\n Types de variables\n Evenements et fonctions",SousTitre1,g_canal); �} } on_rez(integer start_param) { llResetScript(); } }
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Envoyer dynamiquement un e-mail à travers un objet
34
Nous commençons par créer deux listes qui vont contenir les intitulés des boutons. Faites attention au nombre de caractères : au-delà d’une douzaine, le bouton risque d’être tronqué et peu lisible (mais la limite réelle est de 24 caractères). Nous déterminons le numéro de canal à utiliser de manière aléatoire, grâce à l’instruction g_canal = (integer)(llFrand(99999.0) * -1); . Il s’agira ici de l’un des 100.000 premiers canaux négatifs. Peu importe la valeur : c’est le script qui va communiquer à travers le canal de discussion et l’utilisateur n’aura pas à la connaître. La fonction llDialog() met en place la boîte de dialogue à proprement parler, avec les éléments de la première liste en guise d’options. Un bouton « ignore » est automatiquement ajouté, pour clore la boîte. On lance ensuite un événement listen() , comme si la communication transitait directement par le canal de discussion : en cliquant sur le bouton « introduction », l’agent saisit en réalité « /g_canal introduction ». À l’aide d’une série de boucles if() , notre script explore tous les choix offerts à l’agent : on détecte ainsi les boutons qui ont été pressés et on affiche un sous-menu en appelant à nouveau la fonction llDialog() . Le contenu de la première boîte est automatiquement remplacé : les deux boîtes ne vont pas se superposer. En imbriquant de nombreuses listes contenant chacune jusqu’à 12 boutons, on crée ainsi une interface homme/machine très complète, capable d’effectuer des traitements très divers ! Pour certains projets, c’est un excellent moyen de communication, beaucoup plus intuitif que la saisie de commandes au clavier … que l’on ne connaît pas toujours.
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Figure 22. La boîte de dialogue s’affiche à droite de l’écran. En
cliquant sur les boutons, vous entamez en réalité un dialogue sur un canal spécifique (ici, négatif ) qui va charger de nouvelles listes afin de remplacer les boutons dynamiquement.
Envoyer dynamiquement un e-mail à travers un objet Dispositif par excellence de la communication électronique, l’envoi et la réception d’e-mails trouvent naturellement une place de choix dans Second Life. Il s’agit toutefois d’une méthode beaucoup plus restreinte en LSL que l’acheminement de messages à travers la barre de dialogue : transitant en sens unique (de votre objet vers le client de courrier électronique des agents, en règle générale), l’envoi d’e-mails ne s’articule qu’autour d’une poignée de fonctions. Mais dans la mesure où nous explorons les possibilités communiquantes du LSL, nous nous devions de lui dédier un chapitre au sein de cet ouvrage !
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Le traitement du courrier électronique en LSL L’envoi de courriers électroniques en LSL s’articule essentiellement autour de la fonction llEmail(adresse_destinataire,objet, corps_du_message) . Effectuez un premier essai en créant un simple prim et en lui associant le listing ci-dessous : default { touch_start(integer s) { llEmail("adresse@fournisseur.fr","Voici mon objet", "Voici le corps du message"); } }
Envoyer dynamiquement un e-mail à travers un objet
expéditeur. Le message entier est limité à 4096 caractères (cet en-tête compris) et les textes plus longs renverront une erreur. Les serveurs de Second Life reposent sur PostFix (http://www. postfix.org/) pour expédier les courriers électroniques. On peut d’ores et déjà envisager de créer des objets tout à fait fonctionnels autour de cette modeste fonction. À titre d’exemple, voici le code d’un système de vidéosurveillance que vous placerez sur le seuil de votre domicile virtuel. Il détecte la présence d’agents dans les cinq mètres environnants et vous alerte par courrier électronique. Idéal pour vous reconnecter immédiatement à Second Life et vérifier si des brigands ne sont pas en train de saccager votre maison lorsque vous êtes au travail ! Exemple 12.
Sauvegardez le script, patientez le temps de la compilation puis fermez l’éditeur de script LSL. Il vous suffit ensuite de toucher l’objet pour envoyer le courrier électronique. Vérifiez le résultat dans votre client. Le message devrait adopter la forme suivante : De : Object <76728f45-21d2-03de-efa6-e68d00632fe8@lsl. secondlife.com> Sujet : Voici mon objet Object-Name: Object Region: Sunset (224887, 238007) Local-Position: (44, 181, 121)
Le nom de l’expéditeur correspond au nom de votre objet. L’adresse e-mail obéit automatiquement à la structure id@lsl. secondlife.com où id équivaut à la variable de type key associée à l’objet contenant le script. Par défaut, le message débute toujours par un en-tête qui indique la Sim et la position de l’objet-
[07/02/08]
Le système de vidéosurveillance.
// Variables globales string g_corps = "Un intrus a ete detecte !\n"; string g_objet = "Alerte de securite"; string g_destinataire = "adresse@fournisseur.fr"; float g_delaiSensor = 1; default { state_entry() { llSensorRepeat("", NULL_KEY, AGENT, 5, PI, g_delaiSensor); } sensor(integer nbr_detectes) {
Voici le corps du message
Xavier Cazin <xavier@oreilly.fr>
35
integer i; for(i = 0 ; i < nbr_detectes ; i++) { g_corps += llDetectedName(i) + " s'approche de votre domicile\n";
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
} llEmail(g_destinataire,g_objet,g_corps); llSay(0,"Presence detectee ! Veuillez vous eloigner"); } }
Envoyer dynamiquement un e-mail à travers un objet
36
2. Associez le script précédent à l’objet : dès qu’un agent apparaît à cinq mètres de la « caméra » de surveillance, un message s’affiche dans le canal de discussion principal pour le dissuader d’aller plus loin. Un e-mail vous est envoyé en parallèle. Attention : ce script ne vous est proposé que pour illustrer la fonction llEmail() . Si des avatars s’amusent avec votre dispositif de sécurité en effectuant des allers-et-venues incessantes, vous recevrez de nombreux courriers électroniques … ce qui pourrait s’apparenter à du spam. Pour y remédier, vous pouvez installer un filtre supplémentaire qui cesse de vous envoyer des messages si un certain agent (que l’on détecte ici avec la fonction llDetectedName() ) a déjà été repéré.
Figure 23 . Notre caméra de vidéosurveillance notifie l’intrus
s’il s’approche trop près de notre bien. En parallèle, vous recevez un courrier électronique. Pour mettre en place le système de vidéosurveillance, procédez comme suit : 1. Modélisez votre objet comme vous en avez maintenant l’habitude. Prêtez une attention particulière à son nom : il apparaîtra dans le courrier électronique, en guise d’expéditeur. C’est d’ailleurs un excellent moyen pour définir une règle de courrier électronique dans votre client et isoler automatiquement les messages dans un répertoire particulier.
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Comme vous pouvez vous en rendre compte, la fonction llEmail() est une véritable aubaine pour les spammeurs. Fort heureusement, Linden Lab a intégré un système qui prévient ce type de comportement en « mettant en pause » le script lorsque deux courriers sont trop rapprochés. Cette restriction n’est pas réellement documentée sur le site officiel et il semblerait qu’elle évolue au cours du temps – l’équipe de Linden Lab veille particulièrement à détecter les comportements négligents et « accentue » ce type de protection de version en version. En règle générale, un compteur limite l’envoi rapproché de courriers électroniques (de l’ordre de 50 e-mails par minute, ce qui offre déjà d’immenses possibilités !) et totalise le nombre de messages que vous avez envoyés par jour. Toutes les vingt-quatre heures, à minuit heure pacifique plus précisément, ce compteur est remis à zéro. L’échange d’e-mails entre les objets et le traitement du courrier électronique Comme nous l’avons vu, Second Life crée automatiquement une « adresse e-mail » pour chaque objet qui en envoie. Vous pouvez ainsi répondre à un objet ou laisser deux objets s’entretenir entre eux afin d’échanger des données ou des commandes. Pour les
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Envoyer dynamiquement un e-mail à travers un objet
37
raisons évoquées précédemment, nous vous conseillons d’exploiter cette méthode en dernier recours, si les autres moyens de communication ( link_message ou listen ) ne correspondent pas à votre projet. En effet, l’envoi et la réception de courriers électroniques peuvent rapidement engendrer une grande surcharge des serveurs et contribuer à la lenteur générale d’une Sim. C’est toutefois une possibilité très intéressante, notamment pour déclencher des actions à partir de courriers électroniques que vous envoyez vers votre objet !
message = llDeleteSubString(message, 0, llSubStringIndex(message, "\n\n") + 1);
Pour mettre en place un tel système, vous devez vous appuyer sur la fonction llGetNextEmail(string expediteur, string objet) . Les deux paramètres sont optionnels et correspondent à la définition d’un filtre : à l’instar de llListen() , vous pouvez restreindre la réception des courriers électroniques à un expéditeur seulement, ou à un sujet de message particulier. Les adresses électroniques générées pour chaque objet peuvent héberger une file d’attente contenant jusqu’à 100 courriers. Si un message correspondant au filtre défini est détecté, on déclenche l’événement email() qui traite les courriers de la manière suivante :
1. Préparez un objet qui va traiter le courrier. Il est très important de repérer son id pour en déduire l’adresse de courrier électronique qui lui est associée ! Plusieurs possibilités existent, notamment avec la fonction llGetKey() , mais vous pouvez également lancer une première fois le script de l’exemple 12. L’adresse est de la forme id@lsl.secondlife.com.
email(string heure, string expediteur, string objet, string message, integer nbr_restant)
3. Associez à votre objet un script qui vérifie la réception du courrier électronique grâce à la fonction llGetNextEmail() . Si vous êtes le seul expéditeur susceptible de communiquer avec votre objet, vous pouvez restreindre le filtre en mentionnant votre adresse de courrier électronique. Tous les autres courriers ne déclencheront pas le moindre événement. Contrairement aux filtres llListen() , llGetNextEmail() n’est pas activé en permanence : vous devez l’exécuter à chaque fois pour vérifier la présence d’un nouveau courrier dans votre file d’attente. Un timer permet d’automatiser l’opération à intervalles réguliers.
Le message intègre le même en-tête que nous avons vu précédemment : Object-Name: nom_objet\n Region: nom_sim (coordonnees_sim)\n Local-Position: (position)\n \n corps_du_message Pour supprimer cet en-tête et ne récupérer que le corps du message, ajoutez la ligne suivante au script, dans l’événement email() :
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Grâce à cette simple instruction, on supprime tout ce qui précède le dernier retour-chariot, identifié par « \n ». La variable message ne contient donc que le texte brut envoyé par l’expéditeur. Pour lancer un traitement à partir d’un courrier électronique, suivez cette procédure générale :
2. À l’aide de votre client de courrier électronique, expédiez manuellement un e-mail à cette adresse. Le corps du message peut contenir une instruction ou une valeur, qui sera isolée puis traitée par l’objet dans Second Life.
4. Lorsqu’un message épouse le filtre que vous avez défini, l’événement email() est déclenché. Vous pouvez alors « nettoyer » le corps du message afin d’isoler la commande ou l’instruc-
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
tion que vous aviez envoyée manuellement. Votre script poursuit en réalisant un traitement à partir de cette instruction. Une fois encore, nous insistons sur cette règle d’or : n’utilisez pas cette méthode coûte que coûte si d’autres moyens de communication sont à votre disposition. En particulier, si vous exploitez ce procédé pour laisser deux objets s’entretenir ensemble (le premier objet expédiera le courrier avec la fonction llEmail() ), vous devriez plutôt opter pour une communication à travers l’événement link_message() . Avec des limites imposées par Linden Lab qui changent régulièrement, il est dangereux de faire reposer des scripts complets (notamment ceux que vous commercialisez !) sur des timers et des traitements d’e-mails plusieurs dizaines de fois par minute. Par ailleurs, n’oubliez pas que l’adresse e-mail associée à votre objet est temporaire. Si vous portez cet objet sur vous, un nouvel id lui sera réattribué à chaque fois que vous vous téléportez et que vous changez de Sim… ce qui rendra l’adresse e-mail originale obsolète ! Toutefois, cette méthode est particulièrement efficace si deux objets séparés par une grande distance doivent communiquer entre eux. Considérez-la essentiellement comme un « moyen détourné » de franchir les limites imposées en LSL. Le traitement des messages instantanés sous la forme de courriers électroniques Même si nous sortons légèrement du cadre de notre sujet, sachez qu’il est possible d’expédier des messages instantanés (censés apparaître dans la barre de dialogue) par courrier électronique. Il s’agit en fait d’une option que vous activez dans votre profil, après vous être authentifié à l’adresse www.secondlife.com. Cochez la case « Send IM to Email » à l’onglet General de la page des Préférences : en votre absence, tous les messages instantanés qui vous sont adressés sont réacheminés par défaut vers l’adresse e-mail qui est associée à votre compte.
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Envoyer dynamiquement un e-mail à travers un objet
38
Vous pouvez exploiter cette possibilité pour envoyer automatiquement des e-mails sans vous montrer trop « envahissant » visà-vis des autres agents. Si l’agent est en ligne au moment de l’envoi du message, il le recevra dans la barre de dialogue. Dans le cas contraire, le message échouera dans sa boîte aux lettres. Le principal intérêt est de restreindre la longueur du message : originellement prévu pour s’afficher dans la barre de dialogue, il ne contient que 1023 caractères maximum et ne présente pas d’en-tête (des informations qui s’avèrent bien souvent superflues !). La plupart des Sandbox exploitent cette possibilité pour vous signaler que vos créations ont été automatiquement supprimées. Lorsque vous créez un objet sur ce type de « bac à sable », un timer est déclenché. Au bout de deux heures en moyenne, l’événement timer() est déclenché et votre objet est automatiquement supprimé. Un message instantané vous est alors expédié. Il n’existe qu’une seule fonction pour traiter les messages instantanés, sans événement particulier : llInstantMessage(key agent, string message) . On peut ainsi récrire notre système de vidéosurveillance en le rendant moins abusif : llInstantMessage(llGetOwner(), llDetectedName(0) + " approche dangereusement !");
Cette modeste ligne s’inscrit dans l’événement sensor() que nous avons défini précédemment. Si un agent s’approche à cinq mètres, on vous envoie automatiquement un message instantané pour vous le signaler. Grâce à la fonction llGetOwner() vous êtes le seul à être notifié. Si vous êtes en ligne au moment de l’infraction, le message apparaît directement dans la barre de dialogue, comme si le script exploitait la fonction llOwnerSay() . Vous n’embêtez donc pas les autres agents avec des messages d’avertissement qui alourdissent l’espace de discussion ! En revanche, si vous êtes déconnecté de Second Life, vous recevez un courrier électronique. Il n’est pas possible de spécifier une
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
adresse e-mail particulière : il s’agit impérativement de l’adresse que vous avez associée à votre compte. Pesez le pour et le contre de chaque méthode et choisissez votre protocole avec discernement. Dans la plupart des cas, il vaut mieux éviter d’exploiter le courrier électronique pour réduire la charge des serveurs. L’envoi de messages instantanés correspond ainsi à une solution « de compromis » : on n’expédie réellement un courrier électronique qu’en dernier lieu, si vous n’êtes pas en ligne au moment des faits.
Faire appel à l’API du service web de Flickr Le Web 2.0 est particulièrement en vogue depuis quelques années déjà et autour de cette notion gravitent de très nombreux services web mis à la disposition des programmeurs par des sociétés emblématiques, comme Google, Yahoo!, Amazon ou YouTube. Concrètement, ces services web s’articulent autour d’une API (Application Programming Interface) qui est une bibliothèque regroupant un ensemble de fonctions permettant d’accéder aux services et de lancer des requêtes. Vous pouvez ainsi développer des scripts qui vont rechercher des vidéos sur YouTube à partir d’un certain mot-clé, afficher une carte en provenance de Google Maps ou proposer une liste de produits depuis Amazon ! Les possibilités sont infinies et les API s’adressent à une immense communauté de développeurs PHP, Ruby, Java, .NET, Perl, Python, etc. La récente démocratisation des API a permis l’émergence d’un nouveau type d’applications : les mashup (littéralement, des « combinaisons ») qui regroupent plusieurs services web autour d’une interface unique. Il est ainsi possible de lancer une vidéo YouTube à partir d’un repère affiché sur une carte Google Maps, sans ouvrir de fenêtre de navigation supplémentaire. Mieux encore : les requêtes étant asynchrones (c’est le principe d’Ajax – Asynchronous JavaScript And XML), elles s’émettent en toile de
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Faire appel à l’API du service web de Flickr
39
fond, sans nécessiter l’actualisation du navigateur. Cette famille d’applications et ce principe dépassent largement le cadre de notre sujet, mais nous allons voir qu’ils constituent une formidable ouverture pour vos scripts en LSL. Vous serez ainsi en mesure de communiquer avec l’extérieur, bien au-delà du cadre de Second Life, et de glaner tous types d’informations et de médias à travers des scripts externes que vous programmerez ! En guise d’exemple, nous allons étudier l’API de Flickr (www. flickr.com), le service de partage de photos de Yahoo!, en interagissant avec sa base de données en PHP. Toutefois, vous pourrez facilement adapter ces scripts à d’autres services web et à des langages de programmation auxquels vous êtes davantage familier. Première étape : à la découverte des requêtes asynchrones en LSL Le langage LSL ne présente aujourd’hui qu’une seule fonction permettant d’émettre des requêtes HTTP : llHTTPRequest() . Encore relativement peu utilisée, cette fonction est la pierre angulaire de la communication vers l’extérieur dans Second Life. Gageons que dans un avenir très proche, LSL va se doter d’une série de fonctions allant dans ce sens qui permettront d’interagir très rapidement avec une quantité de services web, dans des formats très divers ! Signe de l’impatience des développeurs, certains pionniers ont baptisé ce principe « ALAS » (Asynchronous LSL and … Some-sort-of-data, « LSL asynchrone et … quelques données »). Rassurez-vous : ce type de communication est tout à fait fonctionnel et en rivalisant d’ingéniosité, il est possible de contourner les limites actuelles du langage en la matière. La fonction llHTTPRequest() obéit à la nomenclature suivante : llHTTPRequest(string url, list parametres, string requete)
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
L’argument url correspond à l’adresse du script côté serveur vers lequel on envoie la requête. En effet, vous devez programmer un script qui va communiquer avec l’API de Flickr et réaliser tous les traitements nécessaires. Développé dans le langage de programmation de votre choix, ce script récupère généralement un motclé que l’on passe dans l’URL afin de formater une requête. L’API du service web lui retourne une réponse, qu’il va traiter et afficher en retour. Vous récupérez cette information en LSL et vous la traitez dans un dernier temps avec votre objet intelligent. La liste parametres accepte un grand nombre d’arguments qui vont définir le type de requête à envoyer. En particulier, la constante HTTP_METHOD indique la méthode à employer : « GET » (par défaut) et « POST » sont les deux types principaux. Nous y reviendrons. On définit ensuite le comportement du script LSL dans l’événement http_response() . Ce dernier récupère les données brutes envoyées par le script côté serveur, que l’on peut alors traiter en LSL comme nous en avons désormais l’habitude ! Afin d’illustrer ce principe général, mettons en place un exemple très simple. Créez un nouveau document texte et saisissez ces quelques lignes : <? $test="Bienvenue chez OReilly"; echo $test; ?>
Enregistrez le fichier sous le nom essai.php et déposez-le sur un serveur web doté de PHP. Vous pouvez le parcourir dans votre navigateur web : il se contente d’afficher « Bienvenue chez OReilly » à l’écran. Dans votre Sandbox de prédilection, créez un objet au sol et associez-lui le script suivant :
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Faire appel à l’API du service web de Flickr
40
Exemple 13. La récupération de données avec llHTTPRequest(). default { touch_start(integer s) { string url = "http://www.serveur.fr/essai.php"; llHTTPRequest(url,[HTTP_METHOD,"GET"],""); } http_response(key request_id, integer status, list metadata, string body) { // La requête a abouti if(status == 200) { llSay(0,body); } } }
Touchez votre objet : la phrase « Bienvenue chez OReilly » apparaît dans le canal de discussion. Nous avons défini l’adresse du script côté serveur dans la chaîne de caractères url . Nous invoquons ensuite la fonction llHTTPRequest() en passant cette adresse en guise d’argument et en indiquant que la méthode HTTP est de type « GET » (nous souhaitons récupérer des données). Nous définissons enfin l’événement http_response() : si le statut de la réponse est 200 , la requête a abouti. D’autres statuts sont susceptibles d’apparaître, notamment 499 si la transaction a échoué et 503 si le nom de domaine cible n’est pas accessible. En dernier lieu, nous affichons directement les données brutes sur le canal 0. Même si cet exemple ne présente pas d’intérêt particulier, il illustre le principe général : on est en mesure de récupérer des données externes en LSL, à travers une requête HTTP.
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Faire appel à l’API du service web de Flickr
41
Deuxième étape : accéder à l’API de Flickr Maintenant que nous sommes capables de communiquer avec un script côté serveur, nous devons préparer une série d’instructions pour interagir avec l’API de Flickr. Là encore, de très nombreuses solutions sont à votre disposition. Dans un premier temps, rendez-vous à l’adresse http://flickr.com/services/api/keys/ et inscrivez-vous (gratuitement) au service. Vous obtenez en retour une clé de développeur : il s’agit d’un identifiant unique qui vous permettra de vous entretenir avec l’API du service. Vous êtes en effet limité sur le nombre de requêtes quotidiennes que vous pouvez effectuer. Rendez-vous ensuite à l’adresse http:// phpflickr.com/ pour découvrir la bibliothèque phpFlickr de Dan Coulter qui offre une interface simple et efficace pour communiquer avec l’API de Flickr en PHP. Téléchargez la bibliothèque et décompressez l’archive sur votre disque dur. phpFlickr reprend toutes les méthodes de l’API de Flickr, dont vous découvrirez la liste complète à l’adresse http://www.flickr. com/services/api/, sur le volet droit de l’écran. Elles sont triées par catégories : flickr.photos.search permet de rechercher une photo à partir d’un mot-clé et flickr.groups.search renvoie le nom d’un groupe d’utilisateurs, par exemple. Nous ne pouvons pas détailler l’ensemble de ces méthodes dans les pages qui suivent ; toutefois, la documentation de l’API de Flickr est un modèle du genre : à l’aide de cases à cocher et de champs de texte, vous pouvez tester le résultat de toutes vos requêtes et observer la réponse XML qui vous est envoyée. C’est précisément là où phpFlickr s’avère essentiel : à l’aide de la classe phpFlickr() , on crée automatiquement un parseur de réponses qui affiche les résultats sous forme brute. Vous gagnez ainsi un temps précieux ! Vous pouvez appeler n’importe quelle méthode de l’API en remplaçant les points par le caractère « underscore ». La méthode flickr.photos.search devient ainsi phpFlickr->photos_search .
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Figure 24. Consultez les fonctions de l’API de Flickr afin
d’imaginer des services intéressants à intégrer dans Second Life ! N’hésitez pas à vous reporter sur de nombreux services web, pour ajouter des comportements originaux à vos scripts. Dans le cadre de notre exemple, nous utilisons une méthode qui retourne systématiquement des résultats différents : flickr.photos.getRecent. Toutes les images récemment publiées sur le service de partage en ligne apparaissent en guise de résultat. Vous pourrez aisément adapter le script à vos propres besoins, et même profiter des fonctions de communication en LSL pour récupérer un mot-clé saisi par l’utilisateur et rechercher les photos correspondantes.
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Dans un nouveau document texte, saisissez le listing suivant : <? require_once("phpFlickr.php"); $f = new phpFlickr("<votre_clé_API>"); $recent = $f->photos_getRecent(1,1); foreach ($recent['photo'] as $photo) { $owner = $f->people_getInfo($photo[‘owner’]); echo "<img border='0' alt='$photo[title]' "."src=" . $f>buildPhotoURL($photo, "Square") . ">"; } ?>
Enregistrez-le dans le répertoire où vous avez décompressé phpFlickr et déposez l’ensemble du dossier sur un serveur web. À l’aide de votre navigateur web, vérifiez le résultat : la toute dernière image déposée sur le service apparaît directement dans la fenêtre. Nous avons en effet créé une nouvelle instance de la classe phpFlickr() en précisant notre clé de développeur, puis nous avons fait appel à la méthode photos_getRecent() . Les deux arguments indiquent que l’on récupère une page de résultat ne contenant qu’une seule réponse. On « construit » alors une balise <img> en HTML, avec les différents détails correspondants à cette image (auteur, titre, URL). Notre script côté serveur fonctionne : il ne nous reste plus qu’à programmer son traitement en LSL. Troisième étape : construire le traitement de la réponse en LSL Nous avons vu à l’exemple 13 qu’il est possible de récupérer des données brutes en provenance d’un script déposé sur un serveur web. C’est précisément notre intention : nous souhaitons obtenir automatiquement l’URL de la dernière image déposée sur Flickr afin de l’afficher dans Second Life. Ce traitement est un peu particulier : comme vous l’avez probablement déjà expérimenté, les textures personnelles correspondent à l’envoi d’une image à travers le menu File / Upload image. L’opération vous coûte 10 Lin-
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Faire appel à l’API du service web de Flickr
42
den dollars à chaque fichier et attribue alors une variable de type key à votre image. Il est impensable d’automatiser ce type d’action en LSL ! Vous feriez banqueroute très rapidement si votre script se bloque dans une boucle infinie… Heureusement, il existe une alternative si vous possédez votre propre terrain. Notre objectif est de créer un cadre de photo dynamique, qui charge une nouvelle image à chaque fois qu’on le touche. Grâce à la fonction llParcelMediaCommandList() , vous êtes en mesure de charger un média depuis une source externe. Vous l’utiliserez notamment pour organiser un concert et diffuser de la musique, ou pour afficher une vidéo dans votre parcelle. Commencez par créer un cadre photo que vous déposez sur un mur de votre habitation. Associez-lui le script de l’exemple 14. Exemple 14. Le chargement dynamique de votre cadre photo key VIDEO_DEFAULT = "6e0f05ad-1809-4edc-df29-fae3d2a6c9b8"; cadre_photo(string url) { key video_texture = llList2Key(llParcelMediaQuery( [PARCEL_ MEDIA_COMMAND_TEXTURE]), 0); if(video_texture == NULL_KEY) { video_texture = VIDEO_DEFAULT; llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_TEXTURE, VIDEO_DEFAULT]); } llSetTexture(video_texture,ALL_SIDES); llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_URL,url]); llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_PLAY]); llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_AUTO_ALIGN,TRUE]); } default { touch_start(integer s) {
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
string url = "http://www.serveur.fr/phpFlickr/recuperation. php"; llHTTPRequest(url,[HTTP_METHOD,"GET"],""); } http_response(key request_id, integer status, list metadata, string body) { if(status == 200) { cadre_photo(body); } } }
Modifiez légèrement le script PHP côté serveur : nous n’avons besoin que de l’URL de l’image et surtout pas de la balise <img> en HTML, qui n’est pas interprétable en LSL ! Saisissez le listing de l’exemple 15 et enregistrez-le sous le nom recuperation.php. Exemple 15. Le script côté serveur. <? require_once("phpFlickr.php"); $f = new phpFlickr("<votre_cle_API>"); $recent = $f->photos_getRecent(1,1); foreach ($recent['photo'] as $photo) { $adresse = $f->buildPhotoURL($photo,"Square"); echo $adresse; } ?>
Là encore, vous pouvez tester le résultat à travers votre navigateur web dans un premier temps. En actualisant la page, vous constaterez que l’URL change à chaque fois : il s’agit bien de la dernière image envoyée sur Flickr. Le script LSL correspond au canevas que nous avions mis en place précédemment. Nous récupérons cette URL depuis le script côté serveur et nous la traitons à l’aide de la fonction cadre_photo() que nous avons définie. La fonction llParcelMediaCommandList() présente une [07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Faire appel à l’API du service web de Flickr
43
particularité : elle doit remplacer une texture déjà établie. Nous choisissons ainsi une texture prédéfinie, repérée par sa variable key , et nous l’appliquons à l’aide de la fonction llSetTexture() . Nous la remplaçons ensuite par l’image chargée dynamiquement depuis les serveurs de Flickr. Ce modeste exemple illustre le traitement de requêtes asynchrones en LSL, depuis des services web externes. Vous pouvez imaginer tout type d’applications à ce principe ! Au-delà des services web « officiels » qui disposent d’une API complète, n’hésitez pas à articuler votre objet autour de vos propres scripts dans le langage de votre choix. Si vous administrez un site internet, vous pouvez ainsi tisser des ponts entre le monde du Web et celui de Second Life en affichant régulièrement vos billets et vos images dans le métavers. Le robot bavard Il est déjà bien tard et une tenture étoilée s’étend au-dessus de Portugal Porto. Pas une âme numérique qui vive à l’horizon. Pourtant, je suis en pleine discussion avec Olhos, le robot qui garde les environs ! Mes questions ne l’ennuient jamais et il tente toujours d’y répondre avec précision. Ce robot de dialogue a été mis en place autour d’une série de requêtes HTTP, stockées dans une base de données MySQL. Tous les utilisateurs qui entament un dialogue avec lui participent à son savoir encyclopédique : dès qu’il ne comprend pas un mot, il demande des détails supplémentaires. En formulant vos questions à nouveau, il s’avère plus perspicace et anticipe vos réactions ! Rendez-lui visite à votre tour en vous téléportant sur http://slurl.com/secondlife/Portugal%20Porto/188/25/24.
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Figure 25. Ce robot puise ses réponses depuis une base de
données MySQL afin d’apprendre de nouvelles réactions au fur et à mesure de ses dialogues avec les agents.
Créer un téléporteur à l’aide de coordonnées récupérées en XML-RPC Dernier moyen de communication intégré au LSL, l’échange de données à travers le protocole XML-RPC offre des possibilités colossales. Il s’agit d’une technologie développée en 1998 par la société Userland Software qui repose sur l’échange de données en XML et sur le protocole RPC (Remote Procedure Call). Comme son nom l’indique, nous allons procéder à des « appels » successifs entre un client externe (dans notre exemple, un navigateur web) et un objet intégré à Second Life. Les données seront échangées au format XML et permettront de déclencher des actions dans le multivers … ou dans le navigateur web.
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Créer un téléporteur à l’aide de coordonnées récupérées en XML-RPC
44
Pour d’évidentes raisons de sécurité et de congestion des réseaux, Linden Lab a souhaité limiter l’utilisation de ce protocole au sein de Second Life. Tous les appels XML-RPC doivent être envoyés vers un script CGI unique, mis en place par Linden Lab à l’adresse http://xmlrpc.secondlife.com/cgi-bin/xmlrpc.cgi. Il est donc délicat de programmer des applications ambitieuses autour de cette architecture, notamment lorsqu’une sim est particulière active et qu’elle traite une large quantité de données. Vous n’avez la possibilité d’envoyer qu’une seule requête à la fois vers ce script. La fonction llRemoteDataReply() qui est utilisée pour laisser un objet répondre à une requête extérieure met votre script en pause durant trois secondes. Dans ces conditions, il est difficile de gérer la « pile » des requêtes et d’assurer un dialogue constant entre la source externe et votre objet dans Second Life. Mais là encore, ces fonctions et la capacité des serveurs sont amenées à évoluer au cours du temps. Dans le cadre de notre exemple, nous allons voir comment acheminer un message en XML depuis un formulaire web vers un objet dans Second Life. Le document XML contiendra des coordonnées, que nous utiliserons pour créer un téléporteur dynamique. En réponse, l’objet de Second Life va retourner un document XML au navigateur web pour indiquer que le message a bien été traité. Vous serez ainsi en mesure d’interagir avec le métavers sans nécessairement y être actif ! Généralités sur la création d’un téléporteur Les téléporteurs comptent parmi les objets les plus populaires de Second Life. Ils sont essentiels pour couvrir en un instant une énorme distance et pour accéder instantanément à des localités originales et méconnues. En particulier, vous les utiliserez pour populariser vos propres créations – parfois situées à l’intérieur de bâtiments ou dans des zones qui ne bénéficient pas d’un grand nombre de visites.
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Avant d’aborder plus précisément les techniques de communication en XML-RPC, attardons-nous sur la création d’un téléporteur. Au-delà de la récupération de données à travers Internet, vous pourrez exploiter ce type de scripts dans vos propres projets. Si vous avez mis en place une boutique de plusieurs étages, par exemple, vous transformerez aisément le script suivant en un « ascenseur » virtuel qui guide vos visiteurs entre les pièces du bâtiment. La création d’un téléporteur repose essentiellement sur une astuce détournée : la possibilité de « s’asseoir » sur un prim, que l’on décale vers une position précise. La fonction llSitTarget() déclenche l’événement changed() et nous en profitons pour « relever » l’agent, qui aura ainsi l’impression d’être téléporté vers la destination. Les coordonnées indiquées à la fonction llSitTarget() sont relatives au prim auquel on associe le script (considérez-les comme un décalage par rapport à cet objet). En créant un nouvel objet dans une zone, une fenêtre affiche ses coordonnées au milieu de l’écran. Il s’agit ici de coordonnées globales, exprimées par rapport à la région entière. Si vous les appliquez directement à la fonction llSitTarget() , elles correspondront à un décalage : vous ne serez absolument pas téléporté à la destination attendue. Vous devez donc retrancher les coordonnées de l’objet à celles de la destination afin de calculer le vecteur du déplacement. Il est en effet beaucoup plus simple de repérer les coordonnées de votre destination à l’aide de la fenêtre du mode de création ! Passons à la pratique. Pour mettre en place un téléporteur, effectuez les opérations suivantes : 1. Commencez par vous rendre manuellement à la destination. Créez un objet au sol afin de lire les coordonnées dans la fenêtre d’édition, au centre de l’écran. Notez-les soigneusement : nous allons les exploiter immédiatement. Vous pouvez supprimer la forme que vous venez de créer.
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Créer un téléporteur à l’aide de coordonnées récupérées en XML-RPC
45
2. Rendez-vous à l’emplacement du téléporteur. Modélisez votre forme : il ne s’agit pas forcément d’un siège, même si les agents vont s’asseoir dessus ! 3. Saisissez ensuite le listing de l’exemple 16 et associez-le à votre forme. Modifiez en particulier les coordonnées du vecteur ciblePosition , en les remplaçant par les valeurs que vous aviez relevées à l’étape 1. 4. Enregistrez le script puis effectuez un clic droit sur votre objet et choisissez « Sit Here ». Vous vous relevez instantanément à la bonne destination ! Exemple 16. Un simple téléporteur. vector ciblePosition = <32.826,197.976,131.250>; reset() { vector cible; cible = (ciblePosition - llGetPos()) * (ZERO_ROTATION / llGetRot()); llSitTarget(cible,ZERO_ROTATION); ��������������������������������� } default { state_entry() { reset(); } on_rez(integer x) { reset(); } changed(integer change) { llUnSit(llAvatarOnSitTarget()); reset(); ��������
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
}
Créer un téléporteur à l’aide de coordonnées récupérées en XML-RPC
46
En LSL, la communication XML-RPC transite sur un canal de discussion que l’on ouvre à l’aide de la fonction llOpenRemoteDataChannel() . En parallèle, le gestionnaire d’événements remote_ data() va réceptionner l’appel XML-RPC et éventuellement y répondre à l’aide de la fonction llRemoteDataReply() . L’une des principales difficultés réside dans la transmission du numéro de canal : l’appel en lui-même, depuis votre navigateur web, doit le mentionner. En règle générale, on le saisit manuellement. Vous pourrez toutefois automatiser l’opération à l’aide de la fonction llEmail() , qui enverra ce numéro vers une adresse e-mail. Un script supplémentaire permettra de l’extraire du message, mais cette technique est relativement lourde à mettre en place !
}
Figure 26. Les téléporteurs peuvent revêtir des aspects très
divers. Dans la mesure du possible, essayez de modéliser un objet qui indique clairement aux agents qu’il remplit une telle fonction. La communication en XML-RPC Pour envisager la communication entre un objet dans Second Life et votre navigateur internet, vous devez commencer par créer un formulaire web soutenu par du code JavaScript. Ce dernier crée un objet de requête Msxml2.XMLHTTP , qui correspond à un contrôle ActiveX : dans notre exemple, la communication ne pourra donc transiter qu’à travers Internet Explorer. C’est cet objet qui va encapsuler le document XML et soutenir la requête vers le script CGI de Second Life.
Notre exemple s’appuie en partie sur le travail de Ruben Kleiman, qui a notamment mis en place un système de vidéosurveillance et d’alarme pour vos objets dans Second Life. Vous retrouverez l’ensemble de ses créations sur son blog personnel, à l’adresse http://rubenkleiman.com/. Trois scripts sont nécessaires pour mettre en place le dispositif. Créez un petit objet à proximité de votre téléporteur : il va récupérer les coordonnées de la destination qui vont être expédiées depuis Internet Explorer, avant de les passer au téléporteur en lui-même. Associez à cet objet le script de l’exemple 17a. Exemple 17a. Le script qui récupère les données en XML-RPC
dans Second Life. string REPONSE_SCRIPT_LSL = "OK!"; key monCanal; default { state_entry() { llOwnerSay("Ouvrez un canal pour la communication XML-RPC en me touchant");
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Créer des scripts pour Second Life
➔ Sommaire
Créer un téléporteur à l’aide de coordonnées récupérées en XML-RPC
Créer des scripts pour Second Life
}
state_exit() { llCloseRemoteDataChannel(monCanal); llOwnerSay("Canal ferme. Touchez-moi pour l’ouvrir a nouveau."); }
touch_start(integer n) { llOpenRemoteDataChannel(); llOwnerSay("Ouverture du canal en cours"); }
}
remote_data(integer type, key channel, key uid, string from, integer integerValue, string stringValue) { if (type == REMOTE_DATA_CHANNEL) { monCanal = channel; llOwnerSay("Le canal est ouvert : identifiant="+(string) channel); state waiting; } } } state waiting { state_entry() { llOwnerSay("Attente de requete XML-RPC"); } remote_data(integer type, key channel, key uid, string from, integer integerValue, string stringValue) { llSay(0,stringValue); if (type == REMOTE_DATA_REQUEST) { llRemoteDataReply(channel, uid, REPONSE_SCRIPT_LSL, 1); }
Occupons-nous à présent du script en HTML / JavaScript, que vous ouvrez dans votre navigateur web. Il est inutile de le déposer sur un serveur web : vous pouvez l’exécuter en local, directement depuis votre disque dur. Exemple 17b. Le formulaire qui envoie des données en XML-RPC
depuis Internet Explorer. <html> <head> <title>Communication en XML-RPC avec Second Life</title> <script> // Objet de requête var request = null; // Transaction avec le script LSL function appelRPCScript() { try { var key = document.getElementById('key'); var chaineMessage = document.getElementById('chaineMessage'); var intMessage = document.getElementById('intMessage'); request = getXMLHttpRequest(); if (request == null) { alert("Vous devez utiliser Internet Explorer."); return; }
string vectorCible; string destinationCible = "<"+stringValue+">"; vectorCible = destinationCible; llSay(0,destinationCible); }
// Vous pouvez librement reformater la chaine XML va r xml = '<?xml version=\"1.0\"?><methodCall><methodName> llRemoteData</methodName><params><param><value><struct> <member><name>Channel</name><value><string>'+key.value+'
touch_start(integer n) { state default; }
[07/02/08]
47
Xavier Cazin <xavier@oreilly.fr>
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
</string></value></member><member><name>IntValue</name> <value><int>'+intMessage.value+'</int></value></member> <member><name>StringValue</name><value><string>' +chaineMessage.value+'</string></value></member></struct> </value></param></params></methodCall>'; alert("On envoie: "+xml); request.open('POST', 'http://xmlrpc.secondlife.com/cgi-bin /xmlrpc.cgi', true); request.onreadystatechange = getHttpResponse; request.setRequestHeader('Content-Type', 'application /x-www-form-urlencoded'); request.setRequestHeader('Cache-Control', 'no-cache'); request.send(xml); } catch (err) { alert("Erreur XML-RPC : "+err.message); return; } } // Récupération de la réponse depuis le script de SL function getHttpResponse() { if (request.readyState == 4) { alert("Statut de la réponse : "+request.status+" "+request. statusText); alert("Contenu de la réponse :"+request.responseText); } } // Objet function if if
de requête XMLHTTPRequest getXMLHttpRequest() { (request != null) return request; (typeof XMLHttpRequest != 'undefined') { return new XMLHttpRequest(); } try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (err1) { try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (err2) { } }
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Créer un téléporteur à l’aide de coordonnées récupérées en XML-RPC
48
return false; } </script> </head> <body> Ke y du canal : <input type='text' id='key' size='40' maxlength='50' value='73e4212b-e8d1-8219-e536-ef1b79699941' /> <br/> Co ordonnées de la téléportation: <input type='text' name='chaineMessage' id='chaineMessage' size='40' maxlength='255' value='32.826,197.976,131.250' /><br/> En tier à envoyer: <input type='text' name='intMessage' id='intMessage' size='40' maxlength='10' value='42' /><br/> <input onclick='appelRPCScript()' type='button' value="Communication XML-RPC" /> </body> </html>
Pour activer la transaction, cliquez une première fois sur l’objet dans Second Life. On lance alors la fonction llOpenRemoteDataChannel() et on indique à l’utilisateur le numéro du canal ouvert automatiquement. Ce numéro correspond à une variable de type key renvoyée par l’événement remote_data() . Le script dans Second Life surveille alors les requêtes émises sur ce canal. En parallèle, le code HTML met en place un formulaire avec une série de champs de texte. Les deux éléments principaux sont le numéro du canal (que vous récupérez à partir de la barre de dialogue, dans Second Life) et les coordonnées de la téléportation. Un autre champ contenant un entier permet d’ajouter des détails supplémentaires, notamment le canal de discussion qui va transférer ces coordonnées vers le téléporteur lui-même. En pressant le bouton de validation, vous appelez la méthode JavaScript appelRPCScript() . Celle-ci récupère les données du formulaire, puis les encapsule dans un document XML. On crée alors l’objet de requête, en appelant le script CGI situé à l’adresse http:// xmlrpc.secondlife.com/cgi-bin/xmlrpc.cgi. Afin de déboguer l’ap-
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Créer un téléporteur à l’aide de coordonnées récupérées en XML-RPC
49
plication, nous affichons le contenu du document XML dans le navigateur web en appelant la méthode alert() . Le script LSL obtient enfin une réponse sur le canal de réception ! L’événement remote_data() récupère le document XML et isole la chaîne de caractères, qui contient les coordonnées en elles-mêmes. Toujours pour tester l’application, nous appelons la fonction llRemoteDataReply() et nous envoyons un petit message dans le document XML de retour. La méthode getHttpResponse() en JavaScript la récupère et nous affichons à nouveau deux boîtes de dialogue pour indiquer le statut de la réponse et le contenu du document XML. Vous déclinerez ce principe à des applications très diverses, qui entretiennent un véritable dialogue avec votre script LSL. En effet, il est possible d’envoyer une seconde requête depuis votre navigateur web vers le script LSL et ainsi de suite.
Figure 28. Le formulaire de notre page web permet de définir
un ensemble de coordonnées qui seront reprises par le téléporteur.
Figure 27. On clique une première fois sur notre objet :
le canal de discussion s’ouvre et son identifiant apparaît dans la fenêtre de dialogue.
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Créer un téléporteur à l’aide de coordonnées récupérées en XML-RPC
50
En guise d’exercice, il ne vous reste plus qu’à lier les deux prims entre eux, et à faire transiter la chaîne de caractères (ici déjà transformée en vecteur) vers le script du téléporteur. Il s’agit de notre exemple 16. Lier les prims et échanger des données sur un canal interne présente un double intérêt : vous attribuez ainsi un rôle précis à chaque élément de votre objet et la programmation de vos scripts est plus simple – vous pouvez librement définir l’état default de chaque élément constitutif de votre modèle, sans craindre des heurts ou des conflits.
Figure 29. Au bout de quelques secondes, la réponse est
interprétée par le script LSL : le vecteur correspondant aux nouvelles coordonnées de téléportation apparaît dans le canal de discussion. En multipliant les essais, vous remarquerez toutefois que la mise en place du protocole XML-RPC au sein de Second Life connaît quelques heurts. En particulier, un certain temps de latence apparaît ; si vous rapprochez deux envois, la requête n’aboutit pas toujours. La faute en revient à la congestion du réseau et aux appels multiples vers ce script CGI qui est partagé entre toutes les applications de ce type ! Dans la mesure du possible, évitez de faire reposer des projets ambitieux sur ce type d’architecture. Et n’hésitez pas à surveiller la parution de nouvelles fonctions dédiées à la communication en XML-RPC, sur le site officiel de Second Life, afin de vous mettre à la page.
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Votre coach LSL personnel Le langage est en mutation permanente et de nouvelles fonctions viennent ponctuellement élargir vos possibilités. Pour vous tenir informé de l’évolution du langage, ne cherchez plus un site web qui s’en fait une spécialité : adoptez sans plus tarder votre coach personnel O’Reilly ! Plutôt que de vous renvoyer vers le site web officiel de cet ouvrage, nous avons choisi de vous proposer une application à intégrer directement à Second Life en LSL. Vous y trouverez une aide constante pour développer en LSL, ainsi qu’un flux d’actualités permanent sur toutes les nouveautés du langage. Concrètement, il s’agit d’un objet doté d’un script en LSL qui interagit avec une base de données MySQL. Vous recherchez vous-même les informations qui vous intéressent à travers la barre de dialogue, sur le canal 42. Ainsi, en saisissant la commande « /42 news » vous affichez les dernières actualités du langage, et en indiquant « /42 nom_de_la_fonction », vous découvrez le prototype de toutes les fonctions du langage. La commande « /42 llsetcolor » renvoie les paramètres à indiquer à la fonction llSetColor() du LSL, par exemple.
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Créer un téléporteur à l’aide de coordonnées récupérées en XML-RPC
51
Le code source Ajoutez le code suivant à un objet que vous déposez au sol, dans une Sandbox. Développez vos propres scripts à proximité : cet objet vous « écoute » et vous pouvez lui demander de plus amples précisions sur les fonctions sur lesquelles vous butez : default { state_entry() { llListen(42, "", llGetOwner(), ""); llOwnerSay("Saisissez une commande sur le canal 42 :" ); llOwnerSay("/42 news pour les dernieres actualites"); llOwnerSay("/42 une_fonction pour des details sur une fonction !"); } listen( integer canal, string nom, key id, string msg ) { string ma_requete = "http://www.showbuzz.org/lsl/index. php?nom=" + msg; llHTTPRequest(ma_requete,[HTTP_METHOD,"GET"],""); } http_response(key request_id, integer status, list metadata, string body) { if(status == 200) { llOwnerSay(body); } } }
Figure 30. Saisissez « /42 news » pour afficher les dernières
actualités avec votre coach personnel.
Figure 31. En saisissant « /42 llsetcolor », vous obtenez le
prototype de la fonction correspondante. Poursuivez votre développement en LSL sous l’égide de cet instructeur ! [07/02/08]
Xavier Cazin <xavier@oreilly.fr>
Créer des scripts pour Second Life
➔ Sommaire
Créer des scripts pour Second Life
Conclusion Notre tour d’horizon du LSL nous a fait découvrir une large panoplie de fonctions liées à la communication et à l’échange de données, qu’elles se restreignent à l’univers de Second Life ou qu’elles s’ouvrent sur l’extérieur. Dans tous vos projets, n’oubliez pas de tester en permanence la réactivité de vos applications – le métavers est en extension perpétuelle et les utilisateurs sont toujours plus nombreux. Ne participez pas à votre tour au ralentissement général des sims, avec des protocoles de communication mal calibrés, qui congestionnent le réseau ! Mais ne bridez pas votre imagination pour autant. LSL est un langage encore jeune, qui offre déjà un impressionnant arsenal de fonctions dédiées à de nombreux thèmes. Programmation ludique, graphique, comportementale et événementielle : vos créations peuvent aller dans tous les sens et surtout apporter une réelle originalité au multivers. C’est d’ailleurs le principal atout de la programmation en LSL : avec des scripts précis et innovants, vous apportez un réel intérêt à Second Life et vous renouvelez sans cesse ses possibilités. Vous rendez vos objets interactifs et vous leur conférez une indéniable valeur ajoutée, qui sera saluée par vos homologues virtuels ! Accorder un peu plus de chaleur, de vie, de consistance et de communication à un univers virtuel, c’est peut-être bien là le véritable apport du LSL… !
[07/02/08]
Xavier Cazin <xavier@oreilly.fr>