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.
Après la partie très théorique du dernier article, je vous propose de mettre en pratique tout cela ! Nous avons déjà vu comment créer une entité personnalisée à l’aide des NBT, donc nous ne reviendrons donc pas dessus mais sachez que cela fonctionne exactement pareil pour les blocs (comme les coffres), voici un petit exemple :
/setblock ~ ~ ~ minecraft:chest{Items:[{Slot:13b,id:"minecraft:slime_block",Count:1b}]} replace
La seule différence est que le NBT se colle au nom du bloc à poser.
Non, ici ce qui va nous intéresser, c’est comment les manipuler et comment se détourner du sens premier de ces derniers (qui est donc de décrire l’état d’un bloc ou d’une entité) afin de s’en servir comme véritable moyen de stockage.
Cette partie sera un peu plus complexe et abstraite sur sa fin, n’hésitez donc pas à la relire. Néanmoins, elle permet d’illustrer le véritable potentiel des NBT et vous débloquera sans doute plein de voies dans vos créations.
La commande /data get
Pour modifier ou manipuler les NBT, il y a une commande importante à connaître : la commande /data. Cette commande est assez complexe de prime abord, mais nous allons prendre le temps de l’expliquer.
Commençons par la récupération d’une donnée à l’aide de la sous-commande /data get, voici sa structure:
Cette sous-commande est assez simple à comprendre. On choisit si l’on veut récupérer la donnée d’un bloc ou d’une entité et on précise sa position (ou le sélecteur).
À noter que le sélecteur ne doit pointer que vers une seule entité (il faut donc toujours, sauf dans le cadre d’un @s, ajouter l’argument de sélecteur “limit=1”).
Le chemin en pointillé n’est disponible qu’à partir de la version 1.15
Si vous voulez pointer plusieurs entités, vous pouvez le faire par le execute:
/execute as @e[type=slime] run data get entity @s [...]
Néanmoins, cette commande va nous permettre d’étudier la notion la plus importante de la commande data : les Paths.
Les Paths
L’argument “Path” est récurrent dans la commande data, il est donc important de bien comprendre comment l’utiliser.
En effet, il est bien beau de dire d’où l’on veut obtenir la donnée, mais il l’est d’autant plus de préciser quelle donnée l’on souhaite.
Avec une approche un peu naïve, on pourrait penser qu’il suffit de préciser la donnée au format NBT, par exemple :
{Leash:{X}} pour obtenir la valeur de l’axe X du poteau sur lequel est attaché l’entité (par une laisse).
Mais comme nous l’avons vu dans la partie précédente, le format NBT exprime les données sous la forme de couples clé-valeur, ce que ne respecte pas l’exemple ci-dessus. De plus, nous cherchons justement à récupérer la valeur associée à la clé, alors il ne serait pas possible à l’aide de ce format d’exprimer cela.
Les paths classiques
Pour cela, Mojang nous propose un format permettant de pointer une clé particulière que l’on appelle “path” (ou chemin d’accès en français). Comme son nom l’indique, il est très proche des chemins d’accès que nous avons l’habitude d’utiliser pour naviguer sur notre ordinateur comme “C:\Desktop\foo.json” pour pointer le fichier “foo.json” dans le dossier “C:\Desktop”. Sauf que dans le cadre de Minecraft, les noeuds de notre arborescence ne sont pas séparé par le caractère backslash (‘\’) mais par le caractère point (‘.’).
Pour reprendre l’exemple que nous avons cité ci-dessus, si l’on souhaite obtenir la valeur de l’axe X du poteau sur lequel est attaché l’entité, on le fera de la sorte :
Leash.X
qui retournera l’entier associé au noeud.
Pour un peu de pratique, je vous propose de taper cette commande :
/data get entity @s Health
Bravo ! Vous avez réussi à obtenir le nombre de points de vie que vous avez !
Nous venons de voir comment parcourir les nœuds de type “compound” pour arriver à un nœud dit terminal (qui a une valeur qui n’est ni un tableau, ni un compound), mais qu’en est-il du parcours d’un tableau ?
Avant toute chose, je vous propose de voir rapidement comment fonctionne un tableau.
Un tableau est un type de structure dit “ordonné”, c’est à dire que chaque élément est posé dans une case du tableau et que chaque case du tableau à un numéro associé (que l’on appelle index ou indice). Le tableau est organisé de sorte à ce que les index soient classés du plus petit au plus grand, en commençant par 0. Ainsi, prenons le tableau NBT Pos:[5.1, 64.0, 78.7], le tableau est en fait implicitement sous cette forme:
0 | 1 | 2 |
5.1 | 64.0 | 78.7 |
Où 0, 1 et 2 sont les index des cases des valeurs.
Ainsi, si l’on veut accéder à une valeur en particulier du tableau de NBT, on peut utiliser son index pour cela ! Pour le faire, on précise l’index entre crochets (‘[‘, ‘]’) suivant le noeud du tableau.
Par exemple, tapez cette commande:
/data get entity @s Pos[1]
Et vous obtenez votre position sur l’axe Y !
Il faut savoir que sur Minecraft, l’index peut être négatif. Lorsque c’est le cas, vous ne parcourez pas le tableau de gauche à droite, mais de droite à gauche ! Ainsi:
/data get entity @s Pos[-1]
Retournera votre position en Z.
On peut donc représenter le tableau des valeurs de la sorte :
0 | 1 | 2 |
-3 | -2 | -1 |
5.1 | 64.0 | 78.7 |
Où les deux premières lignes sont les indices des cases de la troisième ligne.
Si vous mettez pour indice une valeur qui sort du tableau, vous aurez une belle erreur:
Retenez bien cela, on s’en servira plus tard.
Vous pouvez aussi afficher tout le contenu du tableau en ne mettant pas de crochets.
Les paths avec filtre
Alors c’est bien sympa de récupérer une valeur précise d’un tableau, mais comment faisons-nous si nous ne connaissons pas sa position dans le tableau ?
Par exemple, dans le cadre de l’inventaire du joueur, l’index dans le tableau ne correspond pas au slot dans l’inventaire.
Comment dois-je faire dans ce cas pour savoir combien d’items j’ai dans le slot 8 sans savoir l’index de celui-ci ?
Et bien c’est très simple, Mojang nous propose d’ajouter des conditions pour le retour des valeurs !
Ainsi, à la place de l’index, nous pouvons mettre des NBT entre les crochets, par exemple:
Inventory[{Slot:8b}]
Nous retournera tous les noeuds dans Inventory qui possède pour fils un noeud Slot ayant pour valeur 8 !
Dans ce cas, la commande nous retournera le compound
{Slot: 8b, id: “minecraft:slime_ball”, Count: 64b}
Et comme nous avons un compound, nous pouvons continuer sur un parcours classique pour obtenir le nombre d’item:
Inventory[{Slot:8b}].Count
Qui retournera un tableau d’entiers correspondant aux valeurs de tous les noeuds Count se trouvant dans un compound ou le noeud Slot à pour valeur 8. Comme dans notre cas, il ne peut y avoir qu’un seul type d’item par Slot, la commande nous retournera la valeur unique et non pas un tableau:
Je vous donne un autre exemple avec le path
Inventory[{Count:5b}].Slot
Cette commande devrait permettre d’obtenir un tableau dans lequel se trouve tout les slots ayant exactement 5 items !
Si vous exécutez cette commande:
Vous aurez une belle erreur…
Voici une limitation de la commande data get, elle ne peut retourner qu’une valeur.
Je vous disais que cette commande renverrait un tableau, ce qui n’est pas exactement vrai. En réalité, la commande renvoie tous les noeuds répondant à la condition qui, en fonction du cas d’utilisation, mettra tout ces noeuds dans un tableau. Dans le cadre du get, cette commande ne pourra pas marcher (car la commande ne voit pas cela comme un tableau), mais nous verrons plus loin qu’avec une autre sous-commande, on pourra exploiter ce type de chemin d’accès !
Il faut savoir que, comme le montre la syntaxe, l’argument “path” est facultatif pour la sous-commande data get. Si vous ne le spécifiez pas, il montrera par défaut toute la structure NBT de l’entité/bloc.
Maintenant que vous êtes bien calé sur tout ce qui concerne les paths, je vous propose d’expliquer le dernier argument de la commande data get, le scale.
Le scale
L’argument scale se caractérise par un nombre à virgule. Il ne marche que sur les données de type nombre, donc int, double, float, long, short ou byte.
Il s’agit d’un multiplicateur qui sera appliqué à la valeur retournée.
Par exemple, si vous mettez 2 et que la valeur du tag vaut 10, alors la valeur retournée sera 20.
Cela peut sans doute vous paraître un peu inutile mais détrompez-vous ! Voici un cas d’application plus qu’utile:
Comme vous pouvez le voir, ma position actuelle sur l’axe Y est 102.76189… mais si j’applique un multiplicateur de 100, la valeur retournée sera 10276, j’ai donc obtenu ma position non pas en bloc mais en centième de bloc ! De plus, cette valeur est un nombre entier, cela veut donc dire qu’il peut ensuite être placé dans un scoreboard puis manipulé comme tout autre score.
Il est bien sûr possible de faire l’inverse, et mettre un scale de 0.1 pour obtenir la valeur non pas en bloc mais en déca bloc (donc ici, obtenir 10).
Voilà, maintenant vous comprenez tout le fonctionnement de la commande data get. Comme vous avez pu le voir, commencer par cette sous-commande était plutôt une raison pour aborder ces deux arguments plus que la commande en elle-même (qui a un rôle très simple).
Édition des tags NBT
Rentrons maintenant dans le vif du sujet: nous avons vu comment obtenir, voyons maintenant comment modifier ces NBT à l’aide de la commande data modify.
La commande /data modify
Voici donc ce qui est sans aucun doute ma commande favorite, le data modify !
Cette commande va nous permettre de modifier un tag à partir d’une valeur préalablement définie, voire directement à partir d’une valeur d’un autre tag !
La commande peut vous sembler assez complexe, mais ne vous inquiétez pas, nous allons décortiquer tout cela ensemble.
Déjà, vous pouvez constater que le départ est exactement le même que la commande data get, et cela jusqu’au paramètre “path”. Ce qui est nouveau est donc sur la deuxième partie de la commande et donc les différents attributs “append”, “prepend”, “insert”, “merge” et “set”.
J’ai séparé ces 5 arguments en 3 groupes, chacun représentés en une couleur.
Le “set” (groupe rouge), est un argument pouvant s’appliquer à n’importe quel type de noeud NBT. Il permet comme son nom l’indique de définir la valeur d’un noeud NBT.
Dans cet exemple, je définis donc la hauteur de mon entité à la valeur 64 (on reviendra sur le l’argument “value” un peu plus tard).
Le “merge” (groupe vert), ne s’applique que sur des noeuds de types compound. Il permet comme son nom l’indique de fusionner deux compounds NBT en un seul.
Par exemple, si j’ai par défaut ceci:
{id:”test”,foo:”bar”}
et que j’y fusionne cela:
{id:”test2”,type:”slime”}
J’obtiendrai cela:
{id:”test2”,type:”slime”,foo:”bar”}
Donc la fusion des deux éléments, avec remplacement de la valeur par la nouvelle si le noeud existe déjà.
Le dernier groupe, le groupe bleu, ne concerne que les tableaux.
- “append” permettra d’ajouter une valeur à la fin du tableau (donc à l’index -1).
- “prepend” permettra d’ajouter une valeur au début du tableau (donc à l’index 0).
- “insert” permettra d’insérer une valeur à l’index spécifié à la suite de l’argument.
Par exemple:
/data modify entity @s foo insert 5 value "bar"
insérera la valeur à l’index 5 du tableau. Si il y a déjà une valeur à cette case, alors celle-ci se verra décaler à l’index 6.
Maintenant que l’on a spécifié la valeur à modifier, il faut dire par quelle valeur le faire.
Minecraft propose pour cela deux possibilités:
- L’ajout d’une valeur directement dans la commande, comme montré dans les exemples, par l’argument “value”.
- L’ajout d’une valeur à partir d’une valeur se trouvant dans une structure NBT par l’argument “from”.
Petit exemple rapide sur ce dernier avec cette commande
/data modify entity @e[type=husk,limit=1] ArmorItems set from entity @e[tag=foo,limit=1] ArmorItems
Avant l’exécution de la commande:
Après l’exécution de la commande:
Comme vous pouvez le voir, en une commande, j’ai copié la totalité de l’armure que portait mon Armor Stand sur le Husk !
Autre exemple un peu plus créatif:
Si j’applique cette commande au contenu du coffre:
/data modify block 159 4 -209 Items[{id:"minecraft:redstone"}].Count set from entity @s Health
Comme vous pouvez le voir, le nombre de poudre de poudre de redstone passe à 20 par slot, soit le nombre de points de vie que j’ai !
Notez qu’ici, il n’y a aucun soucis à l’utilisation d’un path avec filtre renvoyant plusieurs items ;)
Je ne vous ai donné que deux exemples, mais sachez que le nombre de possibilités est très grand ! Copier le contenu de l’inventaire du joueur dans un coffre, faire qu’une entité à autant de points de vie que vous avez de points de saturation ou encore copier les enchantements d’un item à un autre par exemple.
Je vous propose que l’on fasse une pause ici, cette partie était un gros morceau, alors n’hésitez pas à la relire au besoin. Nous finirons les NBT sur la prochaine partie, au programme : execute store, et stockage sur NBT ;)
Merci pour ce guide !