NodeWorld

Objets et valeurs synchronisés

Le jeu de chaque joueur fait tourner sa propre copie de tes scripts. Déplacer un objet ou changer une valeur ne le change que pour ce joueur. Pour le partager, l'objet reçoit un Network Id et un joueur, son propriétaire, envoie ce que les autres suivent.

L'ID réseau

Donne à l'objet un Network Id sur son composant FL# Script : un nom au choix, unique dans le monde, 256 caractères au plus. Les transforms synchronisés, l'état synchronisé, la propriété et les événements réseau en ont besoin. Un script qui essaie sans lui l'apprend dans le journal : 'Porte' has no network id (set it on its FL# Script component).

Le propriétaire et le maître

Networking.masterId, Networking.isMasterLe maître de la salle : le joueur qui y est depuis le plus longtemps. Quand il part, le suivant prend sa place et chaque script reçoit OnMasterChanged(masterId).
Networking.GetOwner(go), Networking.IsOwner(go)Le propriétaire d'un objet : le joueur qui l'a pris en dernier, ou le maître si personne ne l'a pris. Les objets d'un joueur qui part vont au maître.
Networking.RequestOwnership(go)Le joueur local prend l'objet.

Prendre un objet :

  1. Les scripts de l'objet dans le jeu de ce joueur reçoivent OnOwnershipRequest(requesterId), puis ceux du jeu du propriétaire ; il suffit qu'un seul renvoie false pour refuser. Le jeu du propriétaire a 3 secondes pour répondre ; ensuite, l'objet est donné quand même.
  2. IsOwner vaut true tout de suite, sauf refus dans ce jeu. Refusé par le propriétaire, il revient.
  3. Chaque script de l'objet, dans chaque jeu, reçoit OnOwnershipChanged(newOwnerId).

Un joueur qui attrape un objet qui a un ID réseau le prend de la même façon. En cas de refus, l'objet reste en place et le journal dit Grab of 'Tasse' refused by one of its scripts (OnOwnershipRequest): the object stays with player 3.

Synchroniser un transform

csharp
protected override void Start() => Networking.SyncTransform(gameObject, 20f);

Le propriétaire envoie la position, la rotation et la vitesse de l'objet ce nombre de fois par seconde (60 au plus ; 0 arrête), et les autres joueurs le suivent. Appelle-le dans le jeu de chaque joueur, dans Start : chaque jeu doit savoir que l'objet est synchronisé. Chez les joueurs qui ne le possèdent pas, son rigidbody est kinematic : il suit le propriétaire au lieu de tomber tout seul.

Networking.FlagDiscontinuity(go) : le prochain transform envoyé est un saut (une réapparition, une téléportation) ; les autres placent l'objet tout de suite au lieu de le faire glisser.

Synchroniser des valeurs : l'état synchronisé

Le script du propriétaire écrit ses valeurs dans OnSerialize, les autres les lisent dans OnDeserialize, dans le même ordre.

csharp
using NodeWorld.Flux;

namespace MonMonde
{
    public class Compteur : FluxScript
    {
        public Text texte;
        private int _total;

        protected override void Start()
        {
            Interaction.SetInteractable(gameObject, true);
            Afficher();
        }

        protected override void OnInteract()
        {
            if (!Networking.IsOwner(gameObject)) Networking.RequestOwnership(gameObject);
            _total++;
            RequestSerialization();
            Afficher();
        }

        protected override void OnSerialize(NetWriter writer) => writer.Write(_total);

        protected override void OnDeserialize(NetReader reader)
        {
            _total = reader.ReadInt();
            Afficher();
        }

        private void Afficher() => texte.text = _total.ToString();
    }
}
  • RequestSerialization() envoie l'état à la fin de l'image, une fois par image au plus, si ce joueur possède l'objet. Demandé pendant que la propriété arrive, il part une fois l'objet accordé, et il est abandonné en cas de refus.
  • RequestSerialization(false) l'envoie sans garantie de livraison : aussi souvent que tu veux, le dernier gagne. Pour une valeur qui change tout le temps (un curseur qu'on fait glisser).
  • OnPostSerialization(sent) dit si l'état est parti (false : ce joueur n'est pas le propriétaire).
  • Le serveur garde le dernier état de chaque script : un joueur qui arrive plus tard le reçoit dans OnDeserialize.
  • Un état fait 16 Ko au plus.

NetWriter.Write prend byte, bool, int, uint, long, float, double, string, Vector2, Vector3, Vector4, Quaternion, Color, et des tableaux de int, float, bool, string, byte et Vector3. NetReader a une méthode Read… pour chacun. Lire plus loin que ce qui a été écrit lance Network data ended before what the script reads (written with another layout?).

L'horloge du serveur

Networking.serverTimeMilliseconds (un int, qui repart à zéro en débordant) et Networking.serverTime (en secondes, un double) sont l'horloge du serveur, la même pour chaque joueur à sa latence près. Partage un instant avec elle : « la vidéo a démarré à l'heure serveur T » permet à chaque joueur de calculer où elle en est (lecteurs vidéo). En Play mode, c'est l'horloge de l'éditeur.

Sur le serveur

Le serveur n'est pas un joueur : il ne possède rien (RequestOwnership y est refusé) et ses scripts n'envoient pas d'état synchronisé. Ils reçoivent OnOwnershipChanged, et les événements réseau que les joueurs leur envoient (événements réseau).

En Play mode, tu es seul et maître : une demande est accordée à l'image suivante, et rien n'est envoyé.