Aller au contenu principal
Le modèle de votre jeu

Cette page n’est pas encore traduite : la version anglaise est affichée.

Héritage et composition

Les modules s’appuient les uns sur les autres, sans aucune sous-classe. Il n’existe ni module de base dont hériter, ni hiérarchie à étendre : les modules forment un graphe. Cette page explique ce que « héritage » veut dire ici, et présente les six mécanismes qui en tiennent lieu.

Ce que « héritage » veut dire ici

one lista decorator, narrowing what is borrowedthe room owns who is inthe chat owns who hears under entry rulesunder delivery rules
Une même liste empruntée deux fois via un décorateur : la salle décide qui est présent, le chat décide qui entend

Le mot recouvre quatre mécanismes différents :

  • Les RPC d’une entité font partie de l’entité. Elles n’existent nulle part ailleurs : ni sur un parent, ni dans un registre partagé. Voir Entity.
  • Un preset est un ensemble nommé, pas une classe de base. Statistiques, capacités, projectiles, générateurs de butin et objets du monde sont des presets de entity — des ensembles d’aspects qu’une vue d’entité applique. C’est pourquoi ils tiennent sur une seule page, Entity Presets, au lieu de former cinq modules. Appliquer un preset ajoute des aspects ; cela ne fait pas de votre type la sous-classe de quoi que ce soit.
  • Surcharger une étape de la plateforme, c’est poser un attribut sur votre version de remplacement. Vous ne dérivez pas de la nôtre : vous déclarez la vôtre, et la version retenue dépend d’une condition, avec le comportement par défaut de la plateforme en repli. Voir Extensibility.
  • Un module en emprunte un autre via un décorateur, qui restreint ou enrichit l’interface empruntée ; derrière, l’implémentation reste interchangeable. L’exemple détaillé — un chat dans une salle (room) — se trouve sur Groups.

Il n’y a pas de hiérarchie de classes entre modules : un arbre n’autorise que des branches, alors que les vraies fonctionnalités les traversent. Le matchmaking réserve des places (seat) dans les salles ; le butin dépose des objets par l’intermédiaire de la carte ; un classement (leaderboard) est alimenté par un hook déclenché à la fermeture d’une salle.

Les six mécanismes

Chacun se déclare par un attribut placé à côté de ce qu’il compose — la même règle déclarative qui régit tout le reste du SDK.

Des points de montage, comme dans un système de fichiers. Un module se monte à la racine — plusieurs interfaces se composent alors en une seule — ou dans un espace de noms. Un second module qui réclame un point de montage déjà occupé est rejeté au montage, jamais au premier appel. Le mécanisme est décrit dans Sous le capot.

Visibilité lexicale. La visibilité des noms suit l’imbrication : une déclaration globale est visible dans un module, une déclaration locale ne remonte jamais vers le haut. Ce qu’un module émet est une autre question, déclarée dans son propre contrat — un module ne connaît que les événements qu’il a déclarés ou qu’on a enregistrés auprès de lui.

L’encapsulation comme contrat. Un module ne sait jamais qui l’appelle ni pourquoi. Ce qu’il expose et ce qu’il émet forment tout son contrat public, et rien chez l’appelant ne modifie son comportement, hormis les droits accordés à cet appelant.

Réutilisation par décorateur et inversion de contrôle. Un module en désigne un autre via un décorateur au lieu d’aller fouiller dans ses entrailles, et l’implémentation derrière l’interface est interchangeable. C’est ce mécanisme qui vous permet de remplacer l’un de nos modules par le vôtre sans que les modules qui en dépendent s’en aperçoivent.

Les déclarations enrichissent l’API. Déclarez un événement sur un groupe, et group.Send.ChatMessage(…) apparaît avec son contrat ; déclarez des données members, et un getter typé apparaît. La déclaration sert d’entrée à la génération de code — c’est aussi pourquoi vous versionnez la déclaration, et non le code généré.

Trois axes d’adressage pour un seul module. Toutes les instances, une instance, et l’administrateur d’une instance sont trois API distinctes, pas une seule API avec un flag. Le détail se trouve sur Groups.

Arguments implicites

Dans une entité, vous ne passez jamais l’entité en argument. Le destinataire, l’appelant et le contexte ambiant se lient automatiquement, car tous trois découlent déjà de l’endroit d’où part l’appel et de qui l’a fait. Le mécanisme est décrit sur RPC.