24 févr. 2017, 22:04

Sommaire

Introduction

Dans ce tutoriel vous allez apprendre à créer des items basiques en 1.11.

Pré-requis

Code

La classe des items :

Nous allons donc commencer par créer une classe qui regroupera l’intégralité des items que nous allons créer dans le mod. Commencez par créer un package pour tous les items. Dans mon cas ce sera “fr.minecraftforgefrance.tutorial.items” car le package de mon mod est “fr.minecraftforgefrance.tutorial”. Adaptez le nom du vôtre en conséquence.
Nous allons créer une classe nommée “[ModId]Items” en remplaçant [ModId] par votre modid. Par exemple “TutorialItems”.

Dans cette classe, nous allons ajouter trois fonctions : setItemName pour donner un nom à notre objet, registerItemModels présente uniquement du côté client pour l’enregistrement des modèles et registerModel présente uniquement du côté client pour simplifier l’enregistrement des modèles.
Attention ! Selon votre version, certaines parties changent.

package fr.minecraftforgefrance.tutorial.items;

import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

/** EventBusSubscriber ne doit être utilisé qu'à partir de la 1.12\. L'annotation n'est pas nécessaire en 1.11.
N'oubliez pas d'importer net.minecraftforge.fml.common.Mod.EventBusSubscriber.
value contient le côté que nous souhaitons utiliser. Ici, nous voulons uniquement le côté Client, puisque nous utiliserons seulement l'event pour enregistrer les modèles.
modid est votre modid. */
@EventBusSubscriber(value = Side.CLIENT, modid = ModTutorial.MODID)
public class TutorialItems
{
    // ici on va déclarer les items

    public static void setItemName(Item item, String name)
    {
        // ici on va attribuer un nom à nos objets
    }

    // Cette version de la fonction ne doit être utilisée qu'en 1.11.x
    @SideOnly(Side.CLIENT)
    public static void registerItemModels()
    {
        // ici on va appeler la fonction registerModel pour chaque item.
    }

    /* Cette version de la fonction ne doit être utilisée qu'à partir de la 1.12.
Pensez à inclure net.minecraftforge.client.event.ModelRegistryEvent. */
    @SideOnly(Side.CLIENT)
@SubscribeEvent
    public static void registerItemModels(ModelRegistryEvent event)
    {
        // ici on va appeler la fonction registerModel pour chaque item.
    }

    @SideOnly(Side.CLIENT)
    public static void registerModel(Item item, int metadata)
    {
        // et ici on va enregistrer les modèles (fichiers json)
    }
}

Ce code servira pour tous les items que nous allons créer, et ne doit être présent qu’une seule fois par mod.

Par contre, la suite est à répéter pour chaque item que vous souhaitez créer.

    public static final Item NOM = new ItemTutorial();

Ceci est la déclaration de l’item. Nous déclarons une constante, et la convention est d’écrire le nom entièrement en majuscule et de séparer les différents mots par un underscore (_). Remplacez NOM par le nom de votre variable. J’ai appelé mon item TUTORIAL et c’est une instance de l’objet ItemTutorial, que nous allons prochainement créer.

Nous allons définir la fonction setItemName comme ceci :

public static void setItemName(Item item, String name)
{
    item.setRegistryName(ClassePrincipale.MODID, name).setUnlocalizedName(ClassePrincipale.MODID + "." + name);
}

Cette ligne attribue à l’Item le nom que nous passons en paramètre de la fonction comme nom de registre et nous attribuons le même nom précédé du modid et d’un point au nom non-localisé. Il sera utilisé pour les fichiers .lang.
Par exemple, pour mon item, mon modid étant “tutorial”, je devrais ajouter cette ligne dans les fichiers .lang :

item.tutorial.item_tutorial.name=Tutorial Item

Le jeu affichera comme nom d’objet “Tutorial Item”.
Pour le nom de registre, il est conseillé de n’utiliser que des minuscules et des underscore au lieu des espaces (attention, si les majuscules sont déconseillées, les espaces sont interdits !). Ces conseils permettent de rester en accord avec l’écriture de Mojang. Vous pouvez voir ce nom pour n’importe quel item avec la combinaison de touches F3 + H, il sera affiché tout en bas de la description, en gris. Pour les objets vanilla, vous verrez un nom du type minecraft:stone, avec stone remplacé par un autre nom selon l’objet. (Tip : Lorsque vous faites la combinaison F3 + H, vous devriez avoir un message qui s’affiche pour vous dire si l’option a été activée ou désactivée).
Nous utiliserons cette fonction plus tard.

Pour finir, nous allons enregistrer le modèle de l’item. Placez-vous dans la fonction registerItemModels et écrivez ceci :

        registerModel(NOM, 0);

Remplacez ici NOM par le nom de votre variable (le même que celui dans la déclaration). 0 est la valeur de metadata de votre item. Ici, nous ne souhaitons pas créer un objet ayant plusieurs valeurs de metadata, alors nous le mettons à 0, qui est la valeur par défaut.
Nous allons donc définir registerModel :

@SideOnly(Side.CLIENT)
public static void registerModel(Item item, int metadata)
{
    if (metadata < 0) metadata = 0;
    String resourceName = item.getRegistryName();
    if (metadata > 0) resourceName += "_m" + String.valueOf(metadata);

    ModelLoader.setCustomModelResourceLocation(item, metadata, new ModelResourceLocation(resourceName, "inventory"));
}

Tout d’abord, nous vérifions si la metadata est positive ou nulle parce qu’il ne peut pas y avoir de valeur négative.

String resourceName = item.getUnlocalizedName().subString(5).replace('.', ':');

Cette ligne récupère le nom de la ressource. getUnlocalizedName va renvoyer le nom non-localisé que nous avons défini sous cette forme : “item.modid.nom_item”. Avec substring(5), nous retirons la partie “item.”, qui ne nous est pas utile. Il nous reste donc “modid.nom_objet”. Le nom du modèle doit être passé sous le format “modid:nom_modele”. Ici, nous allons utiliser pour “nom_modele” la même valeur que “nom_item”, alors nous avons uniquement besoin de changer le ‘.’ en ‘:’.

Si la metadata est supérieure à 0, nous ajoutons un suffixe au nom de notre modèle, qui sera donc de la forme “modid:nom_modele_mX” avec X le nombre choisi pour la metadata.

Ensuite, nous enregistrons le modèle, avec comme premier paramètre l’item auquel nous voulons attribuer ce modèle, en second la fameuse metadata et en dernier un ModelResourceLocation prenant comme paramètres le nom de la ressource et “inventory”.

Voici le résultat que vous devriez obtenir (avec des noms différents) :

package fr.minecraftforgefrance.tutorial.items;

import fr.minecraftforgefrance.tutorial.ModTutorial;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.item.Item;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

@EventBusSubscriber(value = Side.CLIENT, modid = ModTutorial.MODID) // En 1.12+
public class TutorialItems
{
    public static final Item TUTORIAL = new ItemTutorial();

    public static void setItemName(Item item, String name)
    {
        item.setRegistryName(ModTutorial.MODID, name).setUnlocalizedName(ModTutorial.MODID + "." + name);
    }

    // En 1.11.x
    @SideOnly(Side.CLIENT)
    public static void registerItemModels()
    {
        registerModel(TUTORIAL, 0);
    }

    // En 1.12+
    @SideOnly(Side.CLIENT)
    @SubscribeEvent
    public static void registerItemsModels(ModelRegistryEvent event)
    {
    registerModel(TUTORIAL, 0);
        registerModel(BLOCK_TUTORIAL_ITEM, 0);
    }

    @SideOnly(Side.CLIENT)
    public static void registerModel(Item item, int metadata)
    {
        if (metadata < 0) metadata = 0;
        String resourceName = item.getUnlocalizedName().subString(5).replace('.', ':');
        if (metadata > 0) resourceName += "_m" + String.valueOf(metadata);

        ModelLoader.setCustomModelResourceLocation(item, metadata, new ModelResourceLocation(resourceName, "inventory"));
    }

}

La classe de l’item :

Créez la classe de votre Item, elle doit hériter de la classe net.minecraft.item.Item.

public class ItemTutorial extends Item
{
    public static final String NAME = "item_tutorial";
}

Définissez NAME avec le nom d’objet que vous souhaitez attribuer. Nous allons utiliser ce nom pour le nom non-localisé, le nom dans le registre et le nom du modèle.

Le but étant de créer un item simple, nous n’avons rien à ajouter, si ce n’est que quelques petites informations pour finir la création de l’item. Ajoutez un constructeur, comme celui-ci :

    public ItemTutorial()
    {
        super();

        TutorialItems.setItemName(this, NAME);
        setCreativeTab(CreativeTabs.MISC);
    }

Nous appelons la fonction setItemName dans TutorialItems, en passant comme paramètre l’item (puisque nous sommes dans la définition-même de l’item, nous pouvons utiliser this) et son nom, définit quelques lignes plus haut.
setCreativeTab permet de placer l’objet dans un onglet créatif. Cet appel n’est pas nécessaire, un objet peut très bien ne pas apparaître dans le menu créatif.

On peut maintenant s’amuser à ajouter d’autres caractéristiques dans notre constructeur.

        setMaxStackSize(1);

Cette ligne fait que l’objet ne peut être empilé que par 1 au maximum. Si vous mettez une valeur supérieure à 64, le maximum sera mis à 64, mais l’onglet créatif aura quelques bugs. Alors ne jouez pas avec le jeu, vous ne gagnerez pas.
Un autre exemple :

    @Override
    public ActionResult <ItemStack>onItemRightClick(World world, EntityPlayer player, EnumHand hand)
    {
        if(!world.isRemote)
        {
            player.addChatMessage(new ChatComponentText("bonjour " + player.getName()));
        }
        return new ActionResult(EnumActionResult.PASS, playerIn.getHeldItem(handIn));
    }

Celui-ci affiche "bonjour " avec le nom du joueur à la suite dans le chat, lorsque celui-ci fait un clic droit avec l’objet en main.
Je vous laisse regarder la classe Item, vous y trouverez de nombreuses choses intéressantes !

La classe client et la classe principale :

Encore une fois, le code change selon votre version. Suivez attentivement les instructions.

[1.11.x]
Dans la classe client (ou client proxy), appelez la fonction registerItemModels :

package fr.minecraftforgefrance.tutorial.client;

import java.io.File;

import fr.minecraftforgefrance.tutorial.TutorialCommon;
import fr.minecraftforgefrance.tutorial.items.TutorialItems;

public class TutorialClient extends TutorialCommon
{
    @Override
    public void preInit(File configFile)
    {
        super.preInit(configFile);
        TutorialItems.registerItemModels();
    }

    @Override
    public void init()
    {
        super.init();
    }
}

Toutes les versions :
Ensuite, dans votre classe principale (pour moi, ce sera ModTutorial), ajoutez un constructeur, comme ceci :

public ModTutorial() {
    MinecraftForge.EVENT_BUS.register(new RegisteringHandler());
}

Nous allons aller légèrement plus loin qu’un simple objet, puisqu’ici, nous ajoutons un event. Oui, vous avez bien entendu, un event.
En réalité, nous l’avons déjà fait depuis le début, mais j’ai passé ces détails pour l’instant.
Qu’est-ce qu’un event ? C’est un événement appelé lors d’une action spécifique. Ici, nous disons à Forge que nous avons une classe RegisteringHandler qui contient des événements à traiter et qu’il faut donc les appeler.
Nous allons donc créer cette classe RegisteringHandler !

Vous pouvez trouver plus d’information sur les events ici.

La classe RegisteringHandler :

Nous voici donc avec la dernière classe.
Celle-ci va uniquement nous servir à enregistrer les items. Parce que oui, nous avons tout préparé pour les enregistrer, mais nous n’avons dit nulle part à forge “enregistre nos items”.

Voici donc la classe, que nous allons gentiment décortiquer :

public class RegisteringHandler
{
    @SubscribeEvent
    public void registerItems(RegistryEvent.Register<Item> event) {
        event.getRegistry().registerAll(TutorialItems.TUTORIAL); 
    }
}

@SubscribeEvent signifie que la fonction qui suit utilise un événement, ici, l’événement est RegistryEvent. Cet événement est appelé une fois par Registre. Ici, nous voulons enregistrer un Item, alors nous allons utiliser le registre des items, soit Register. Cette fonction sera appelée une fois AVANT le pre-init. J’insiste sur le mot avant. Vos items sont enregistrés AVANT que le pre-init soit appelé. Vous devez le savoir.

event.getRegistry().registerAll(TutorialItems.TUTORIAL);

Cette ligne enregistre tous les items passés en argument. Nous ne voulons en enregistrer qu’un : TUTORIAL. Mais si nous en avions plusieurs, nous devrions écrire :

event.getRegistry().registerAll(block1, block2, block3);

Il n’y a aucune limite de nombre. Vous pouvez en enregistrer autant que vous voulez. TutorialItems est le nom de la classe que nous avons créée en début de tutoriel, il devrait être différent pour vous.

Vous en avez fini avec votre Item, il est fonctionnel ! Lancez le jeu, vous verrez par vous-même !
Je ne suis absolument pas responsable de tout problème technique comme un nom un peu étrange ou des textures manquantes.

Le modèle et la texture :

Dans un premier temps, voici le fichier JSON de cet item, c’est le fichier JSON de base pour tous les items basiques de Minecraft. Il faut le placer dans assets/modid/models/item/nom_non_enregistre.json, en remplaçant modid par votre modid et nom_non_enregistre par votre nom non enregistré, simple comme bon jeu !

{
    "parent": "item/generated",
    "textures": {
        "layer0": "tutorial:items/tutorial_item"
    }
}

Je vais vous expliquer ce petit bout de code :

La ligne “parent” permet de définir un “json mère”, en quelque sorte. Ici, nous voulons créer un item se basant sur la base d’un item minecraft “item/generated”.
La ligne “textures” indique à Forge que nous allons définir toutes nos textures entre les accolades.
La ligne “layer0” sert à définir la texture de notre Item
(équivalent, à l’époque de la 1.7.x, au this.setTextureName() )

Changez “tutorial” et “tutorial_item” par le modid de votre mod et le nom de votre texture.
La texture doit toujours se trouver dans vos assets ! (assets/modid/textures/items/nomdelatexture.png)

Si vous souhaitez modifier le fichier JSON tout en évitant les erreurs je vous conseille ce site qui corrigera vos erreurs s’il y en a : http://jsoneditoronline.com
Il existe également des plug-ins Eclipse créés pour l’édition des JSON.

Il y a aussi les détails complets pour modifier votre fichier JSON sur le wiki officiel de Minecraft
Comme par exemple les particules, les layers…

Vous avez maintenant tous les outils en main pour personnaliser le fichier JSON de votre item !

Une dernière chose, modifiez le fichier de langue de votre mod. Ajoutez la ligne suivante dedans :

item.nom non localisé.name=Nom localisé

Un exemple concret :

  • pour le fichier en_US.lang :
item.tutorial.name=Tutorial Item
  • pour le fichier fr_FR.lang :
item.tutorial.name=Item Tutoriel

Et voilà, le nom devrait apparaître en jeu !

Résultat

Crédits

Rédaction :

Correction :

Inspiration / Aide :

Creative Commons
Ce tutoriel de Minecraft Forge France est mis à disposition selon les termes de la licence Creative Commons Attribution - Pas d’Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International

retourSommaire des tutoriels