Cet article fait partie d’une série servant à enseigner l’art du développement sur Minecraft. Vous pourrez retrouver l’introduction et le sommaire en cliquant ici.
Aujourd’hui et lors des deux chapitres suivants nous allons nous attaquer à du lourd, à ce qui est sans doute la partie la plus compliquée de ce guide : les structures de données ! Derrière ce nom barbare se cache un concept assez simple qui permet de résoudre un problème qui l’est moins : comment sauvegarder les données telles que l’inventaire du joueur, ses coordonnées, sa rotation ou encore les crafts du jeu ou les progrès ? La réponse, vous vous en doutez je pense : les structures de données !
Principe
Déjà nous pouvons séparer le exemples en deux groupes : ceux qui sont dynamiques (au sens où ils sont modifiés pendant le cours d’une partie) comme les coordonnées ou la rotation et ceux qui sont statiques (donc ceux qui ne changeront pas tout le long d’une partie) comme les crafts ou les advancements. Chacun de ces groupes sera donc lié à un type de structure de données que nous verrons sur ces trois chapitres. Nous commencerons avec le format NBT pour les données dynamiques !
Mais avant cela, un peu de théorie !
Le format NBT (Named Binary Tag), tout comme le JSON, est un format que l’on peut représenter sous forme d’arbre. Il est d’ailleurs très proche de ce dernier dans sa syntaxe, bien que moins stricte, et fonctionne lui aussi sur un système de clé-valeur (on y revient un peu plus bas).
Et non, je vous vois venir, quand je dis arbre je ne pense pas à ça :
Bien qu’il y ait pas mal de ressemblance !
Vocabulaire
En effet, un arbre, en structure de données possède aussi une racine, des branches et des feuilles mais est représenté… À l’envers ! Voici l’exemple du même arbre mais sous une forme respectant plus celle des structures :
On peut donc remarquer que l’élément le plus en haut est appelé la racine (root en anglais). Une racine est toujours unique, un arbre ne peut donc pas commencer avec deux racines. Les éléments qui terminent notre arbre sont des feuilles. Jusqu’ici j’ai utilisé le terme élément, mais il existe un terme plus spécifique qui englobe donc les feuilles, les racines et tous les autres éléments intermédiaires de notre arbre que j’utiliserai durant tout le reste de ce chapitre : les noeuds.
Chaque noeud A est donc relié par une branche aux noeuds B qui le suivent par ce que l’on appelle une branche (ici représenté par un trait). On dit que les noeuds B sont les fils de A et que le noeud A est le parent des noeuds B. Un noeud peut avoir autant de fils qu’on le souhaite, mais chaque noeud ne possède qu’un seul parent. La racine est donc le seul noeud n’ayant aucun parent, et les feuilles sont tous les noeuds n’ayant aucun fils. Ici, l’arbre possède 4 niveaux (celui de la racine, du noeud avec avec une feuille et un autre noeud pour fils, du noeud ayant deux feuilles qui le suivent, puis des deux feuilles seules), on dit donc que sa hauteur est de 4.
Voilà pour le vocabulaire, pas trop perdu ? Non ? Bon alors sans plus attendre, on passe à la suite !
Cas concret
C’est bien beau d’avoir un arbre de données avec des feuilles, une racine et des noeuds, mais pour l’instant, rien à voir avec les NBT, alors rendons ça plus concret avec une commande de summon :
/summon armor_stand ~ ~ ~ {Marker:1b,Invisible:0,Pose:{Body:[5f,0f,0f],LeftArm:[7f,0f,4f]}}
Analysons un peu la partie NBT :
La première chose que l’on remarque en partant de la gauche, c’est les accolades (les symboles {}), permettant de délimiter ici les arbres. En deuxième, nous constatons plusieurs couples clés-valeurs comme “Marker:1b”, cela signifie qu’à chaque clé (argument/propriété), comme Marker, on associe… une valeur décrivant l’état de la propriété. Ici donc, armor_stand aura l’attribut “Marker” à 1 (donc il n’aura pas de hitbox, ou tout du moins une minimale).
Pourquoi avoir mis un ‘b’ ou un ‘f’ après certaines valeurs ?
C’est seulement pour spécifier à Minecraft quel type de valeur c’est en Java. Mettre un ‘b’ à la suite de mon nombre indiquera donc que c’est du type Byte et un ‘f’ du type Float (donc un petit nombre, et un nombre à virgule); je ne rentre pas plus en détail dans le typage en Java, ce qu’il faut juste savoir, c’est que ces lettres ne sont pas obligatoires, mais c’est tout de même mieux de les mettre !
Donc comme vous l’avez compris, on se base ici sur des couples clés-valeurs, mais dans ce cas, quelle est la valeur de “Pose” ? Et de “Body” ?
Rien de bien compliqué, ne vous inquiétez pas ! Dans le cas, du premier, il a pour valeur… Un autre arbre NBT dont il est donc la racine. En fait, ça sert juste à dire qu’il est noeud parent des noeuds compris entre les accolades qui suivent, donc qu’il est parent de Body et LeftArm ! Pour ce qui est de “Body”, il possède pour valeur un tableau de nombres à virgule (les crochets délimitants donc le tableau), servant ici à définir la rotation du corps sur les 3 axes.
Voici donc le résultat sous forme d’arbre :
Je vous vois venir, vous allez me dire que je triche et que j’écris “Noeud racine” pour combler le manque de racine dans ma structure NBT, et vous avez raison ! Que je vous explique : le noeud racine est implicite, il n’est pas visible dans la structure NBT en jeu, mais il est bien existant côté code ! Je vous rassure, nous n’allons pas rentrer en détail dedans, il ne s’agit pas du sujet de l’article.
Outre ce noeud racine quelque peu étrange, vous pouvez voir que l’on retrouve bien notre structure en forme d’arbre, structurée, dans notre chaîne NBT, par les accolades. Il est important de comprendre que les accolades délimitent bien des arbres. En effet, bien que “Pose” se trouve dans notre arbre, il est lui-même noeud racine de l’arbre composé de lui-même, Body, et LeftArm. On dit dans ce cas que ce deuxième arbre est un sous-arbre du premier.
En savoir plus
Pour aller un peu plus loin, chaque noeud peut être vu comme un arbre, les feuilles étant juste des arbres à un seul élément, composé seulement de la racine (donc d’eux-mêmes). Et cela est le principe même d’une structure de données : un motif simple (donc ici, un noeud pouvant avoir un parent et des enfants) se répétant plusieurs fois de façon à construire… Une structure !
Vous êtes encore là ? Courage, on a passé le plus dur ! N’hésitez pas à relire plusieurs fois si vous ne comprenez pas, je me doute que ce n’est pas facile à appréhender lorsque l’on débute sur ce point.
Bon, je ne vais pas vous faire une liste complète de tous les NBTs, ce serait long (pour moi comme pour vous) et très rébarbatif, surtout que d’autres le font bien mieux que moi ! Je vous invite donc à parcourir cette page du wiki que je trouve formidable; c’est un peu comme la bible du command-blocker, qui répertorie donc, comme vous l’avez sans doute devinez, tous les NBT tags de chaque entité, et sur comment les structurer dans une commande, voici la page… Chunk format ! (Oui bon je vous avoue que le nom fait bien moins classe, mais que voulez-vous…). Pour les anglophobes, voici la page en français ici, mais cette dernière est moins vite mise à jour. Ici, les arbres sont représentés un peu différemment, mais le principe reste le même : la racine se trouve donc le plus à gauche, et il suffit de décaler vers le droite pour parcourir les niveaux.
Merci encore une fois pour la suite du guide.