Partager via


Bonnes pratiques de création de scripts visuels mesh pour la mise en réseau

Vue d’ensemble

Dans Mesh, la plupart des propriétés de scène sont automatiquement partagées par défaut sur tous les clients connectés à la même salle. Par exemple, la position et la rotation de transformation d’un objet de scène, l’état activé d’un composant ou le texte d’un textMeshPro.

En règle générale, les propriétés de composant et les variables Object qui ont les types de valeurs suivants sont automatiquement partagées par défaut :

Les types de collection (listes et jeux) et les références d’objets de scène ne sont pas partagés.

Les nœuds de script visuel qui accèdent ou modifient des propriétés dans Mesh sont étiquetés avec une étiquette qui indique s’ils sont « Partagés par tous les clients » ou « Local à ce client » :

______________

Les variables d’objet sont partagées par défaut si vous les avez déclarées avec l’un des types valeur répertoriés ci-dessus :

______________

Mesh ne prend pas en charge les variables de scène, mais vous pouvez utiliser des composants variables autonomes dans l’environnement pour mettre en cache des variables qui peuvent être partagées indépendamment de n’importe quel composant de machine de script spécifique.

Si vous ne souhaitez pas partager automatiquement des propriétés ou des variables d’objet, vous pouvez ajouter un composant d’étendue de script local à votre scène. Cela rend toutes les propriétés de scène et variables de script sur cet objet de jeu et l’un de ses descendants locaux.

______________

Conseil : Vous pouvez voir plusieurs exemples de l’utilisation du composant Étendue de script local dans le chapitre 3 de notre didacticiel Mesh 101 qui se concentre sur les scripts visuels.

Pour les variables de script locales que vous utilisez uniquement dans une seule machine de script, il est préférable d’utiliser des variables Graph, qui ne sont jamais partagées entre les clients par Mesh.

Le partage via mesh Visual Scripting offre les garanties suivantes :

  • Cohérence éventuelle garantie : tous les clients arrivent finalement à l’état partagé.

  • Atomicité garantie par composant : toutes les mises à jour apportées aux propriétés du même composant de scène (ou du même composant Variables ) dans la même mise à jour sont appliquées atomiquement sur chaque client.

Toutefois :

  • Aucune garantie de commande : les mises à jour appliquées par un client à plusieurs composants de scène différents peuvent arriver dans des commandes différentes sur différents clients.

  • Aucune garantie de chronologie : Mesh essaiera de répliquer les modifications d’état dans les clients le plus rapidement possible, mais les conditions réseau peuvent retarder l’arrivée d’une mise à jour d’état donnée sur certains ou tous les clients.

  • Aucune garantie de granularité : tout client peut ne pas voir toutes les mises à jour incrémentielles individuelles à l’état partagé. Cela peut se produire lorsque les conditions réseau forcent le serveur Mesh à limiter les mises à jour. Cela se produit également lorsqu’un client rejoint une salle tardivement.

L’état n’est pas des événements partagés

Vous ne pouvez pas envoyer ou recevoir de messages réseau explicites avec mesh Visual Scripting. Cela peut être surprenant au début, mais il permet d’établir un paradigme de mise en réseau qui facilite la gestion uniforme des modifications d’exécution ainsi que la jointure tardive. Au lieu des messages, il existe un état partagé dans les propriétés de scène et les variables de script.

Vos scripts peuvent répondre aux mises à jour d’état partagées de manière uniforme, que ces mises à jour aient été effectuées par un script local ou un utilisateur, par un autre client qui partage l’expérience dans la même salle, ou par d’autres clients qui étaient déjà dans la salle avant même de les joindre vous-même.

L’impossibilité d’envoyer explicitement des messages réseau signifie que vous devrez commencer à réfléchir à l’état partagé qui obtient des mises à jour au lieu d’événements partagés qui provoquent des mises à jour d’état. Les événements partagés sont une conséquence de la mise à jour de l’état partagé, et non de l’inverse.

Heureusement, mesh Visual Scripting facilite la réaction de vos scripts visuels aux mises à jour d’état. Utilisez le nœud d’événement On State Changed et connectez ses entrées de gauche avec n’importe quelle variable de script ou propriété de composant que vous souhaitez observer pour les modifications, et le nœud d’événement déclenchera votre script (connecté à son côté droit) chaque fois que l’une des variables ou propriétés connectées à celle-ci modifie sa valeur.

______________

Cela fonctionne avec l’état partagé ainsi qu’avec l’état local. L’événement On State Changed se déclenche, que les variables ou les propriétés qu’il observe aient été modifiées par le client local, par un client distant ou même par un client distant avant que le client local n’ait même rejoint la salle.

L’utilisation de On State Changed pour répondre aux modifications d’état est efficace : il n’y a pas de coût de bande passante inactive ou de performances. Vous pouvez avoir un nombre quelconque de scripts visuels à l’écoute passive des mises à jour d’état de cette façon sans affecter négativement la fréquence d’images ou l’utilisation de la bande passante de votre environnement.

Jointure tardive

Une jointure tardive se produit lorsqu’un client rejoint une salle qui a déjà d’autres clients connectés à celui-ci.

Lors de la jonction tardive, Mesh reçoit l’état actuel de la salle à partir du serveur, par exemple, qui est déjà dans la salle et où leurs avatars sont actuellement situés et prépare rapidement la version locale du client de jointure de l’environnement partagé afin qu’elle corresponde à l’état partagé par tous les membres de la salle.

Pour une grande partie, mesh Visual Scripting fait de même. Toutes les propriétés de composant partagé et les variables de script visuel qui ont été modifiées dans la salle avant que le client ne soit juste joint localement pour correspondre à l’état partagé, puis les nœuds d’événements On State Changed qui observent ces propriétés ou variables sont déclenchés.

Les jointures tardives ne relectent pas les événements partagés : ils obtiennent l’état partagé.

Du point de vue du client local, l’environnement évolue toujours à partir de son état initial qu’il avait juste après le chargement de la scène que vous avez chargée sur Mesh. Dans le cas d’une jointure tardive, le premier changement d’état peut être supérieur à ce qui se passe lorsque l’utilisateur local interagit avec la salle dans une session en cours, mais c’est exactement la même chose en principe.

Tout cela se produit à mesure que l’environnement se charge avant même qu’il s’est fondu en noir. Dès que l’utilisateur peut réellement voir et interagir avec l’environnement, la jointure tardive est déjà effectuée.

Rendre l’état local suivi de l’état partagé

Très souvent, l'« état partagé » qu’un utilisateur peut observer dans un environnement est en fait une combinaison d’état partagé directement par Mesh et l’état local qui a été établi par des scripts visuels en réponse à un événement qui s’est produit dans la salle. Par exemple, lorsqu’un utilisateur retourne un commutateur dans l’environnement (état partagé), un script visuel peut modifier la couleur du skybox (état local). Vous pouvez être tenté d’appliquer la modification locale (mettre à jour la couleur skybox) directement en réponse à l’interaction de l’utilisateur avec le commutateur. Toutefois, même si l’événement d’interaction se produit sur tous les clients actuellement dans la salle, tous les clients qui rejoignent la salle ultérieurement ne recevront pas cet événement simplement parce qu’ils n’étaient pas là quand il s’est produit. Au lieu de cela, vous devez faire en sorte que l’état local suive l’état partagé comme suit :

  1. Lorsque l’utilisateur interagit (par exemple, retourne le commutateur), déclenchez un événement local qui met à jour une variable partagée (par exemple, l’état activé/désactivé du commutateur).
  2. Utilisez On State Changed pour observer la variable partagée.
  3. Lorsque les déclencheurs d’événement On State Changed (car la variable partagée a changé sa valeur), appliquez toute modification locale souhaitée (par exemple, mettez à jour la couleur skybox).

De cette façon, l’état local (couleur skybox) suit l’état partagé (état du commutateur). Ce qui est agréable, c’est qu’il fonctionne sans modification pour le client local qui a retourné le commutateur, pour tous les autres clients distants présents dans la salle en même temps, et pour tous les futurs clients qui rejoignent la salle plus tard.

Faire en sorte que l’état local suive l’état partagé : Meilleures pratiques

Événements locaux : par exemple, un nœud d’événement On State Changed qui observe la propriété Is Selected Local d’un composant Mesh Interactable Body :

  • 🆗 Peut changer l’état local privé d’un client. Ces modifications d’état restent strictement sur le client local et elles disparaîtront lorsque le client quitte la session.
  • 🆗 Peut modifier l’état partagé.
  • Impossible de modifier l’état local pour qu’il soit cohérent entre les clients. Un événement local s’exécute uniquement sur un client, de sorte que les mises à jour nécessaires pour assurer la cohérence de l’état local entre les clients ne se produisent que sur un autre client.

Événements partagés : par exemple, un nœud d’événement On Trigger Enter attaché à un collisionneur de déclencheurs de physique partagé :

  • 🆗 Peut modifier l’état local pour les effets momentanaires : par exemple, un effet de particule ou un effet audio court. Seuls les clients présents dans la salle lorsque l’événement partagé se produit peuvent voir l’effet local ; les clients qui rejoignent la salle ultérieurement ne le feront pas.
  • Impossible de modifier l’état local pour qu’il soit cohérent entre les clients. Un événement partagé s’exécute uniquement sur les clients présents au moment où il se produit, mais il ne sera pas relecté pour les clients qui rejoignent la session ultérieurement.
  • Ne doit pas modifier l’état partagé. Étant donné qu’un événement partagé s’exécute sur tous les clients, tout ce qu’il fait est effectué par tous les clients très près dans le temps. En fonction de la nature de la modification, elle peut se répéter plusieurs fois (par exemple, un compteur de score peut être incrémenté par plusieurs en réponse à un événement unique).

Sur les événements Changement d’état qui observent l’état partagé dans les variables partagées ou les propriétés des composants partagés :

  • 🆗 Peut modifier l’état local pour qu’il soit cohérent avec l’état partagé entre les clients. Pour que cela fonctionne correctement de manière reproductible et cohérente pour tous les clients, vous devez traduire toutes les nouvelles valeurs possibles de l’état partagé observé en état local, pas seulement quelques transitions d’état choisies en cerise (telles que Is Selected deviennent vraies).

Faire en sorte que l’état local suive l’état partagé : exemple

Dans cet exemple, il existe deux boutons interactifs dans cet environnement : un nommé « Étoile », l’autre étiqueté avec « Éponge ». La sélection de l’un des boutons est censée effectuer deux opérations :

  • Stockez l’étiquette correspondante dans une variable de chaîne partagée nommée ObjectKind.
  • Stockez la référence à un objet de scène correspondant dans une variable de référence GameObject locale nommée ObjectRef.

Voici les deux flux de script, un pour chaque bouton. Chaque écoute la propriété Partagée Is Selected du composant Corps interagissant mesh d’un bouton et met à jour ObjectKind et ObjectRef en fonction du bouton sélectionné :

______________

Tout semble fonctionner correctement, mais uniquement pour les utilisateurs qui sont déjà dans la salle quand l’un des boutons est sélectionné. Tout utilisateur qui rejoint la session trouve ultérieurement un état incohérent dans sa version locale de l’environnement partagé : seul ObjectKind est correctement défini en fonction du bouton sélectionné le plus récemment, mais ObjectRef reste null.

Qu’est-ce qui ne va pas avec ces deux flux de script ?

Tout d’abord, notez que ces flux de script sont déclenchés par un événement partagé, car ils écoutent tous les deux la propriété partagée de chaque bouton est sélectionnée . Cela semble logique, car il s’agit de la seule façon d’obtenir la variable ObjectRef locale à mettre à jour sur tous les clients.

Toutefois :

  • Les événements partagés ne doivent pas changer d’état partagé, mais ces flux de script mettent à jour la variable ObjectKind partagée.
  • Les événements partagés ne peuvent pas modifier l’état local pour qu’ils soient cohérents entre les clients, mais ces flux de script mettent à jour la variable ObjectRef locale, que nous prévoyons d’être cohérentes sur tous les clients, tout comme ObjectKind.

Ainsi, la façon dont cela est actuellement configuré, nous ne devrions en fait pas faire l’une des choses que nous avons besoin des boutons à faire.

La seule façon évidente de sortir de ce problème consiste à rendre les événements qui déclenchent ces flux locaux. Nous pouvons le faire en rendant le nœud d’événement On State Changed observer la propriété Is Selected Local au lieu d’Is Selected.

L’événement étant maintenant local, cela signifie...

  • Les événements locaux peuvent changer d’état partagé afin que nous puissions maintenant mettre à jour en toute sécurité la variable ObjectKind partagée et sa valeur sera automatiquement partagée entre les clients par la mise en réseau intégrée de Mesh Visual Scripting.
  • Les événements locaux ne peuvent pas modifier l’état local de façon à être cohérents entre les clients, afin que nous ne puissions toujours pas mettre à jour la variable ObjectRef locale dans ces flux de script. On devra trouver une autre façon.

Voici comment les deux flux de script s’occupent de ces modifications :

______________

Que pouvons-nous faire pour définir la variable ObjectRef locale afin qu’elle reste cohérente avec cela ? Heureusement, ces deux flux de script établissent déjà un état partagé que nous pourrions suivre : la variable ObjectKind partagée. Tout ce que nous devons faire consiste à utiliser un événement On State Changed qui observe cette variable et met à jour la variable ObjectRef locale en fonction de sa valeur :

______________

Il s’agit d’une bonne façon de le faire, car les événements On State Changed qui observent l’état partagé peuvent modifier l’état local pour qu’il soit cohérent avec celui-ci. Cela fonctionnera pour le client qui a appuyé sur le bouton, pour tous les autres clients présents dans la même salle en même temps, et pour tous les clients qui participeront à la session ultérieurement.

Pièges réseau

Mises à jour partagées à haute fréquence

Presque l’état de la scène entière est partagé par mesh Visual Scripting par défaut. C’est idéal pour le partage, mais il peut également se faufiler par accident et provoquer une charge réseau inutile. Par exemple, le flux de script suivant inonde le réseau avec des mises à jour redondantes de la rotation de la transformation. Toutefois, étant donné que tous les clients l’exécutent en même temps, aucune des mises à jour à distance n’aura jamais d’impact réel sur n’importe quel client localement :

______________

Dans ce cas, vous devez probablement utiliser une étendue de script local pour rendre le composant Transform local pour chaque client. En outre, vous devez probablement utiliser un composant Animator plutôt qu’un flux de script On Update pour commencer.

Le panneau Diagnostics de script visuel Mesh et le contenu Analyseur de performances (CPA), à partir de Mesh Toolkit 5.2411, affichent un avertissement « Mise à jour partagée à haute fréquence » pour ce type de construction.

Le démarrage s’exécute sur chaque client

Vous pouvez être tenté de considérer l’événement On Start comme quelque chose qui s’exécute au démarrage de la session, mais il est réellement déclenché sur chaque client, localement, lorsqu’il rejoint la session. Il est parfaitement adapté à l’initialisation de l’état local :

______________

Toutefois, lorsque vous essayez d’utiliser On Start pour initialiser l’état partagé, vous constaterez que l’état partagé sera involontairement réinitialisé pour tout le monde chaque fois que tout le monde rejoint la session :

______________

Le panneau Diagnostics de script visuel Mesh (à partir de Mesh Toolkit 5.2410) et du Analyseur de performances de contenu (à partir de Mesh Toolkit 5.2411) affiche un avertissement « Mise à jour partagée sur la jonction de session » lorsqu’ils détectent ce problème.

Le partage est typé, mais l’attribution de variable n’est pas

Pour des raisons de sécurité et de sécurité, les variables de script visuel partagé sont fortement typées. Cela signifie que le type que vous sélectionnez dans le composant Variables pour les variables de script que vous avez déclarées définit le type de valeur exact qui sera synchronisé entre les clients.

Malheureusement, Unity Visual Scripting ignore complètement le type déclaré d’une variable lorsque vous mettez à jour sa valeur. Par exemple, il est facile de stocker accidentellement une valeur de type Float dans une variable déclarée pour le type Integer. Dans le client local, vos scripts visuels ne remarquent pas cette erreur, car Visual Scripting convertit automatiquement le float erroné en entier attendu, le cas échéant. Toutefois, lorsqu’il s’agit de synchroniser cette valeur entre les clients, mesh Visual Scripting ne peut pas prendre les mêmes libertés : la garantie « cohérence éventuelle » empêche toute conversion de valeur en vol, et les considérations relatives à la sécurité et à la sécurité ne permettent pas d’accepter un type de valeur différent d’un client distant que ce qui a été déclaré pour la variable.

Par exemple, considérez cette déclaration d’une variable partagée nommée MyIntegerVar :

______________

Voici un flux de script qui met à jour cette variable :

______________

Risques potentiels liés à la gestion des certificats Malheureusement, le nœud de script plage aléatoire | utilisé dans cet exemple est fourni dans deux versions : une qui produit une valeur entière aléatoire et une valeur float aléatoire. La différence entre ces deux nœuds de script dans le panneau sélecteur de nœuds est subtile :

______________

Par conséquent, si vous sélectionnez accidentellement le nœud de script de plage aléatoire | incorrect, votre script risque de stocker involontairement une valeur Float dans votre variable de type Entier, mais cette valeur Float erronée ne sera pas répliquée sur d’autres clients.

Gardez cela à l’esprit comme une raison potentielle pour laquelle une variable partagée que vous avez créée peut sembler avoir cessé d’être partagée. Les futures versions de Mesh Visual Scripting peuvent avertir ce type d’erreur de script lorsqu’elles peuvent la détecter.

Étapes suivantes