Cas pratique 2 : NodeCG pour gérer un festival de podcast
Comme je joue souvent à du jeu de rôle, j’ai l’occasion de créer des overlays où NodeCG tient une place centrale.
L’overlay ne se limite alors pas à afficher quelques informations à l’écran : il peut aller chercher des données dans différents services, réagir à ce qui se passe pendant la partie, piloter des animations et même interagir directement avec OBS.
L’idée générale est toujours la même : récupérer une information quelque part, la faire transiter par NodeCG, puis faire réagir l’overlay en conséquence.
Récupérer et gérer les données
Section titled “Récupérer et gérer les données”FoundryVTT
Section titled “FoundryVTT”En général, nous jouons avec FoundryVTT, une plateforme permettant de jouer à des jeux de rôle à distance.
Chaque joueur et joueuse possède son propre personnage, avec sa feuille de statistiques, son équipement, ses compétences, etc. FoundryVTT permet également de gérer les jets de dés directement depuis l’interface.
Cela donne beaucoup d’informations intéressantes à afficher sur un overlay : les statistiques des personnages, leur état actuel, les jets de dés qui viennent d’être effectués, leur résultat, et ainsi de suite.
Le problème : récupérer les données
Section titled “Le problème : récupérer les données”Le problème est que Foundry VTT ne propose pas d’API externe simple permettant de récupérer directement toutes ces informations depuis NodeCG.
J’ai longtemps expérimenté pour trouver une solution satisfaisante. Au tout début, je récupérais les informations des logs (la galère), maintenant le processus est un peu différent.
L’idée générale est assez simple : faire transiter les données de Foundry VTT jusqu’à NodeCG, puis les rendre accessibles au reste de l’application.
- Foundry VTT prépare les données
J’ai crée un module perso que j’ai intégré dans FoundryVTT. Son rôle est de rassembler les données dont j’ai besoin et de les envoyer dans le système de socket de Foundry.
Sur Foundry, le socket permet à différentes parties de l’application (serveur, navigateur…) de s’échanger des messages en temps réel.
Par exemple, lorsqu’un personnage est modifié, mon module envoie ses nouvelles données avec un type permettant de savoir de quel événement il s’agit :
game.socket.emit("module.foundryvtt-to-nodecg", { type: "characterUpdate", data: characterData});- NodeCG reçoit les événements
De l’autre côté, l’extension NodeCG écoute ce socket. Lorsqu’un message arrive, elle regarde son type et transmet les données au reste de l’application via un événement interne.
socket.on("module.foundryvtt-to-nodecg", (data) => { if (data.type === "characterUpdate") { foundryEmitter.emit("character-update", data.data); }});Cette étape sert essentiellement de pont entre Foundry VTT et mon extension : Foundry envoie les données, NodeCG les récupère et les transmet sous une forme plus pratique à manipuler.
- Les données sont stockées dans le Replicant
Il ne reste ensuite qu’à stocker les données dans le Replicant.
Lorsqu’un personnage est mis à jour, je vérifie s’il existe déjà dans la liste : s’il n’existe pas, je l’ajoute, sinon je remplace ses données par la nouvelle version.
foundryEmitter.on("character-update", (character) => { const characters = foundryRep.value.characters; const index = characters.findIndex(c => c.id === character.id);
if (index === -1) { characters.push(character); } else { characters[index] = character; }
foundryRep.value.characters = characters; // Je stocke les données dans le Replicant});Une alternative : récupérer les données depuis Google Sheets
Section titled “Une alternative : récupérer les données depuis Google Sheets”FoundryVTT n’est pas la seule source de données que j’ai utilisée.
Pour l’un de nos jeux de rôle, nous utilisions une feuille Google Sheets pour gérer les personnages, les jets de dés et certaines informations de la partie.
J’avais donc développé un script permettant à NodeCG de récupérer automatiquement les données de la feuille via une API, à partir de l’URL.
Au final, la source peut changer, mais l’interface fournie aux graphics reste la même.
Une limite cependant : le nombre d’appels à l’API est limité par Google Spreadsheets, donc je me limite à un appel toutes les deux secondes.
Des Replicants et des Messages
Section titled “Des Replicants et des Messages”À ce stade, je rencontre principalement deux types d’informations : les données qui décrivent l’état de la partie, comme les statistiques des personnages, et les événements ponctuels, comme les jets de dés.
Ces deux types de données ne sont pas gérés de la même manière.
Comme expliqué dans le guide, il faut simplement retenir une distinction :
- une donnée qui représente un état → Replicant ;
- un événement qui vient de se produire → événement/message.
Concrètement ici :
-
J’ai besoin de conserver les statistiques et les informations des personnages d’une session à l’autre. Un Replicant est donc adapté à ce besoin puisqu’il permet de conserver ces données (la persistance des données)
-
Pour un jet de dé, c’est différent : je veux simplement transmettre l’événement au moment où il se produit. Une fois le résultat affiché, je n’ai aucune raison de conserver l’information.
Si le dashboard est ouvert après le début de la partie ou rechargé, il doit pouvoir récupérer immédiatement les informations actuelles des personnages.
En revanche, il n’y pas besoin de recevoir les jets de dés qui ont eu lieu cinq minutes auparavant, juste celui du moment.
Controler l’overlay
Section titled “Controler l’overlay”Gérer des cartes de jeu de rôle
Section titled “Gérer des cartes de jeu de rôle”Pour certains projets, j’ai également eu besoin d’afficher et de manipuler des cartes.
Pour cela, j’ai utilisé Leaflet, une bibliothèque JavaScript open source permettant de créer des cartes interactives dans une page web.
Dans le dashboard NodeCG, j’avais une interface permettant à la personne qui contrôle le stream de :
- charger une carte
- se déplacer dessus
- zoomer et dézoomer
- placer des marqueurs
- identifier des points d’intérêt
- gérer les différents éléments visibles sur la carte.
Le dashboard d’interface d’administration de la carte.
Du côté des “graphics”, le principe est différent : l’écran du stream affiche simplement le résultat final.
Conceptuellement, cela fonctionne bien, mais il me faudrait beaucoup de temps pour terminer de développer le module et en faire quelque chose de propre.
Faire réagir l’ovelay
Section titled “Faire réagir l’ovelay”Animer les personnages quand quelqu’un parle
Section titled “Animer les personnages quand quelqu’un parle”Un problème se pose lorsqu’on réalise un overlay de JDR sans webcam.
Sans webcams, comment indiquer à l’écran quelle personne (et son personnage) parle ?
L’idée était simple : faire légèrement bouger le personnage lorsqu’il parle, un peu comme un indicateur vocal.
Récupérer le statut vocal avec Mumble
Section titled “Récupérer le statut vocal avec Mumble”Nous utilisons Mumble pour discuter en ligne pendant nos parties.
J’ai donc développé, là encore dans une extension NodeCG, un petit bot capable de se connecter au serveur Mumble grâce à la bibliothèque mumble-client
Le bot ne récupère pas la voix des participant·e·s. Il récupère uniquement leur statut : parle/ne parle pas
Il faut ensuite faire le lien entre ce statut vocal et les personnages affichés à l’écran. Pour cela, je maintiens une correspondance entre la personne sur Mumble et son personnage.
Sur Mumble : Pepe parle, sur l’overlay son personnage “Lafitte” s’anime
Lorsqu’une personne commence à parler, l’extension envoie donc un message aux éléments graphiques avec l’identifiant du personnage concerné.
Celui-ci active son animation. Lorsque la personne arrête de parler, l’animation est désactivée.
Un décor piloté par la météo
Section titled “Un décor piloté par la météo”L’overlay est construit autour d’une sorte de petit théâtre de marionnettes.
Les personnages sont placés devant un décor et différents éléments graphiques peuvent être ajoutés ou retirés : nuages, torches, effets météorologiques, etc.
J’ai donc ajouté la possibilité de modifier le décor à la volée depuis le dashboard de NodeCG.
Une petite télécommande dans le dashboard
Section titled “Une petite télécommande dans le dashboard”Le dashboard contient une interface permettant de contrôler les différents éléments du décor pendant la partie. Cela permet, par exemple, de modifier rapidement l’ambiance d’une scène sans devoir modifier manuellement les fichiers graphiques.
Mais je me suis demandé s’il était possible d’aller un peu plus loin et de laisser le décor réagir automatiquement. Pour pousser l’idée, j’ai connecté NodeCG à une API météo gratuite.
Imaginons par exemple un scénario dans lequel la météo d’une ville ou d’un village est complètement détraquée et change sans arrêt. Plutôt que de choisir moi-même la météo à afficher, j’ai testé un script qui récupère toutes les quelques minutes la météo d’un lieu choisi au hasard dans le monde.
Le décor réagit automatiquement au résultat :
- ☀️ soleil → ambiance ensoleillée
- ☁️ nuages → ciel couvert
- 🌧️ pluie → pluie dans le décor
- ❄️ neige → neige
- 💨 vent → éléments animés par le vent
La météo devient ainsi une source de données supplémentaire pour l’overlay. Ce qui était au départ un simple bouton dans le dashboard peut désormais être déclenché automatiquement par une information extérieure.
J’aime l’idée mais je n’ai pas encore eu le temps de bien la creuser : la météo réelle d’un lieu choisi au hasard peut directement influencer ce qui se passe dans le décor de l’overlay.
Ajouter des confettis (oui)
Section titled “Ajouter des confettis (oui)”J’aime bien les confettis et pour cet overlay, je les utilise pour simuler entre autres certains effets magiques ou du sang.
Dans NodeCG, j’utilise la bibliothèque canvas-confetti pour pouvoir déclencher des effets de confettis directement dans les Graphics de l’overlay.
Ici, j’ai utilisé les confettis dans différentes situations :
- lorsqu’un personnage gagne des points de vie (sang, donc confettis rouges)
- lorsqu’un personnage perd des points de vie (effet de “soin” donc confettis verts)
- lors d’une réussite critique à un jet de dés (explosion de confettis)
Ici, quand le Replicant qui gère les données des personnages detecte une modification de la valeur “Points de vie” , il envoie un message avec la nouvelle valeur pour déclencher l’animation.
On peut même aller plus loin, ici le nombre de confettis depend du nombre de points de vie perdus (petit dégats = peu de confettis).
NodeCG comme colonne vertébrale de l’overlay
Section titled “NodeCG comme colonne vertébrale de l’overlay”Tous ces exemples peuvent sembler assez différents : récupérer un jet de dés, détecter quelqu’un qui parle, changer une météo, afficher une carte, déclencher des confettis ou contrôler OBS.
Pourtant, le principe derrière ces fonctionnalités est toujours le même, NodeCG sert de colonne vertébrale entre les différentes sources d’information et les différents éléments du stream.