1.10.x 1.8.x 1.9.x [JEI] Créer un addon JustEnoughItems pour sa table de craft/son four



  • Sommaire

    Introduction

    Dans ce tutoriel, vous allez apprendre à créer un plugin pour JEI (JustEnoughItems) qui est un mod dérivé de NotEnoughItems (si vous ne le connaisez pas, je vous invite à aller acheter une corde, l'accrocher en hauteur, faire un noeud coulant, passer votre tête à l'intérieur et enfin vous pendre xD). Je tiens à préciser qu'une version du tutoriel expliquant la même chose que celui-ci mais avec NEI sortira d'ici peu de temps.

    Ce tutoriel expliquera comment l'utiliser pour une table de craft custom (cf ce tutoriel écrit par moi-même, il y aura des références vers celui-ci dans le code, faciles à modifier), et pour un four custom (cf ce tutoriel (1.7.10) écrit par BrokenSwing, il y aura quelques modifications par rapport à la table de craft, notament les animations).

    L'entièretée du code a été inspiré du code de JEI pour Minecraft vanilla, donc si vous vous posez une question, n'hésitez pas à regarder le code de JEI.

    Il existe aussi une version de ce tutoriel pour NEI : ici.

    Pré-requis

    Avoir une table de craft, un four ou tout autre machine avec des recettes:

    Installation de JEI dans votre workspace

    Tout d'abord, pour créer un addon JEI, vous allez avoir besoin des sources de JEI, le meilleur moyen est d'utiliser gradlew qui va télécharger le mod déobfusqué et l'ajouter dans eclipse.

    Ouvrez votre fichier .gradle et ajoutez-y ceci :

    repositories {
      maven {
    // location of the maven that hosts JEI files
        url "http://dvs1.progwml6.com/files/maven"
      }
    }
    

    ceci indiquera à gradlew d'utiliser le repo maven de JEI pour accéder aux téléchargements du mod, ensuite, dans le bloc "dependencies" (en bas), ajoutez

     // compile against the JEI API
      deobfCompile "mezz.jei:jei_${mcversion}:${jei_version}:api"
      // at runtime, use the full JEI jar
      runtime "mezz.jei:jei_${mcversion}:${jei_version}"
    

    ça indiquera à gradlew d'ajouter le mod déobfusqué au classpath d'eclipse pour accéder aux sources et avoir le mod in-game.

    Remplacez les ${mcversion} et ${jei_version}" par les versions que vous souhaitez, vous pouvez aussi regarder ce tutoriel de SCAREX pour mettre ces valeurs dans un autre fichier (méthode conseillée). La version utilisée dans le tutoriel est JEI 3.6.7.216 pour Minecraft 1.9.4.

    Note : si vous avez une erreur lors d la compilation avec gradlew, retirez le ':api' de la ligne 'deobfCompile "mezz.jei:jei_${mcversion}:${jei_version}:api"'.

    Maintenant lancez la commande

    gradlew eclipse
    

    dans l'invite de commande (

    .gradlew eclipse
    

    pour linux et OSX) pour configurer JEI et c'est bon, lancez eclipse et vous pourrez utiliser JEI 🙂

    Code

    Classe du plugin JEI :

    Nous allons commencer par créer la classe qui va gérer le plugin, cette classe ne devra en aucun cas être appelée par une autre classe de votre mod, sinon il plantera si le mod JEI n'est pas chargé ; JEI se chargera lui-même de détecter votre classe.
    Créer une classe (par exemple JEITutorielPlugin) avec comme extends BlankModPlugin puis ajoutez-y l'annotation

    @JEIPlugin
    

    qui permettra à JEI de détecter votre plugin. Ensuite, dans la classe, faîtes ctrl+espace et commencez à écrire "register" puis sélectionnez la fonction que eclipse propose, cette fonction contiendra tout ce qu'il faut pour enregistrer les classes nécessaires au plugin.

    Notez qu'il existe une autre fonction, "onRuntimeAvailable", appelée quand tout les mods ont étés chargés, ou vous pouvez, par exemple, modifer le plugin d'un autre mod.

    Votre classe devrait ressembler à ceci :

    package net.mff.tuto.jei;
    
    import mezz.jei.api.BlankModPlugin;
    import mezz.jei.api.IModRegistry;
    
    @mezz.jei.api.JEIPlugin
    public class JEITutorielPlugin extends BlankModPlugin
    {
       @Override
       public void register(IModRegistry registry) 
       {
    
       }
    }
    

    Catégorie de recette :

    Pour ajouter des crafts, vous allez avoir besoin d'une "RecipeCategory" qui contiendra toutes les données concernant la machine (texture, slots, nom...), identifé avec un String unique, les catégories vanilla sont "minecraft.crafting, minecraft.smelting, minecraft.fuel, minecraft.brewing".

    Créez une classe TutorielCraftingRecipeCategory implémentant IRecipeCategory et ajoutez-y les fonctions manquantes que eclipse vous demandera.
    Ajoutez le champ

    public static final String CATEGORYUID = ModTutoriel.MODID + ".tutorielCraftingRecipeCategory";
    

    qui identifiera votre catégorie (il doit être unique, donc laissez-y bien votre modid).

    Tables de craft :

    Maintenant, ajoutez ces deux variables et le constructeur :

    private final IDrawable background;
    private final ICraftingGridHelper gridHelper; //Seulement pour les tables de craft
    
    public TutorielCraftingRecipeCategory(IGuiHelper helper)
    {
       background = helper.createDrawable(VotreGui.texture, u, v, width, height);
       gridHelper = new TutorielCraftingGridHelper(1, 0);
    }
    

    Remplacez "VotreGui.texture" par la texture de votre gui. Les x et y correspondent à la position de la portion de texture que JEI va utiliser pour représenter votre recette (prenez le point le plus en haut à gauche de votre slot le plus en hauteur à gauche), le width et le height correspondent à la longueur et à la largeur de la portion de texture que JEI va utiliser.
    Le 1 de "new TutorielCraftingGridHelper(1, 0)" correspond à l'index du premier slot servant au craft (en général 1), et le 0 correspond à l'index du slot servant au résultat (en général 0).

    Fours et autres machines :

    private final IDrawable background;
    private final IDrawableAnimated flame;
    private final IDrawableAnimated arrow;
    
    public FurnaceRecipeCategory(IGuiHelper guiHelper) 
    {
        background = helper.createDrawable(VotreGui.texture, u, v, width, height);
    
        IDrawableStatic flameDrawable = guiHelper.createDrawable(backgroundLocation, u, v, width, height); //Le u correspond à la position x de la portion de texture sur l'image utilisée pour l'animation, le v la position y, width la largeur et height la hauteur (respectivement 176, 0, 14 et 14 pour le four vanilla)
        flame = guiHelper.createAnimatedDrawable(flameDrawable, 300/*durée_de_l'animation*/, IDrawableAnimated.StartDirection.TOP, true/*Inverse l'animation (commence pleine puis de vide)*/);
    
        IDrawableStatic arrowDrawable = guiHelper.createDrawable(backgroundLocation, u, v, width, height); //Le u correspond à la position x de la portion de texture sur l'image utilisée pour l'animation, width la largeur et height la hauteur (respectivement 176, 14, 24 et 17 pour le four vanilla)
        this.arrow = guiHelper.createAnimatedDrawable(arrowDrawable, 200/*durée_de_l'animation*/, IDrawableAnimated.StartDirection.LEFT, false);
    }
    

    Remplacez "VotreGui.texture" par la texture de votre gui. Les x et y correspondent à la position de la portion de texture que JEI va utiliser pour représenter votre recette (prenez le point le plus en haut à gauche de votre slot le plus en hauteur à gauche), le width et le height correspondent à la longueur et à la largeur de la portion de texture que JEI va utiliser.
    Je précise que vous pouvez retirer certaines des animations proposées ou en ajouter.

    Commun à toutes les machines :

    Ensuite, dans la fonction "getUid", retournez l'uid de votre catégorie de recette (CATEGORYUID), dans "getTitle", retournez le titre traduit qui sera affiché au dessus de votre recette. Dans "getBackground", retournez votre arrière plan, soit la variable "background". La fonction "drawExtras" sert à dessiner des extras autour de votre recette, vous pouvez la laisser de côté.
    La fonction "drawAnimations" va gérer les animations, elle sera surtout utile au fours, mais si vous voulez utilisez des animations sur une table de craft, référez-vous à la sous-partie précédente.

    Code de la fonction (uniquement si vous utilisez des animations) :

    flame.draw(minecraft, x, y);
    arrow.draw(minecraft, x, y);
    //x et y correspondent à la position où dessiner l'animation sur la portion de texture définie dans le constructeur
    

    Puis, passons à la fonction "setRecipe" qui placera les éléments dans les bons slots :

    Pour les tables de craft :

    Voici le contenu commenté de la fonction :

    IGuiItemStackGroup guiItemStacks = recipeLayout.getItemStacks(); //On récupère la classe qui va afficher les slots
    
    guiItemStacks.init(0, false, 133, 37); //On ajoute l'output slot, 133 et 37 sont la position x et y du slot par rapport à la portion de texture dessinée
    
    for (int y = 0; y < ContainerCraftingTable.craftHeigth; y++) 
    {
        for (int x = 0; x < ContainerCraftingTable.craftWidth; x++) 
        {
            int index = x + y * ContainerCraftingTable.craftWidth + 1;
            guiItemStacks.init(index, true, x * 18, y * 18 + 1); //On ajoute les slots d'input, 18 est la taille d'un slot
        }
    }
    
    if (recipeWrapper instanceof IShapedCraftingRecipeWrapper) //Si on peut obtenir la hauteur et la largeur
    {
        IShapedCraftingRecipeWrapper wrapper = (IShapedCraftingRecipeWrapper) recipeWrapper;
        gridHelper.setInput(guiItemStacks, wrapper.getInputs(), wrapper.getWidth(), 
        wrapper.getHeight()); //On place les items dans les slots
        gridHelper.setOutput(guiItemStacks, wrapper.getOutputs()); //on place le résultat
    }
    else 
    {
        gridHelper.setInput(guiItemStacks, recipeWrapper.getInputs()); //On place les items dans les slots
        gridHelper.setOutput(guiItemStacks, recipeWrapper.getOutputs()); //on place le résultat
    }
    

    Il devrait maintenant vous rester une erreur sur le "new TutorielCraftingGridHelper(1, 0)", si votre table a la même taille qu'une table vanilla (33), remplacez-le par "new CraftingGridHelper(1, 0)" et faites l'import, sinon, créez la classe en implémentant ICraftingGridHelper, puis ajoutez-y ce contenu que j'ai modfié pour prendre en compte la taille 44 de la table de craft du tutoriel de création de table de craft, vous devrez modifier la fonction getCraftingIndex si elle a une autre taille. Cette classe permet de placer correctement sur la grille de craft les items d'un recette.

    Classe TutorielCraftingGridHelper :

    public static final int DEFAULT_CRAFT_WIDTH = ContainerCraftingTable.craftWidth; //Remplacez par la largeur de votre craft si vous n'avez pas suivi le tuto de table de craft
    public static final int DEFAULT_CRAFT_HEIGHT = ContainerCraftingTable.craftHeigth;//Remplacez par la hauteurde votre craft si vous n'avez pas suivi le tuto de table de craft
    
    private final int craftInputSlot1;
    private final int craftOutputSlot;
    
    public TutorielCraftingGridHelper(int craftInputSlot1, int craftOutputSlot) 
    {
        this.craftInputSlot1 = craftInputSlot1;
        this.craftOutputSlot = craftOutputSlot;
    }
    
    @Override
    public void setInput(@Nonnull IGuiItemStackGroup guiItemStacks, @Nonnull List input) 
    {
        //Obtention de la largeur et hauteur en fonction du nombre d'items dans la recette
        int width, height;
        if(input.size() >= 10) // >3*3
            width = height = 4;
        else if (input.size() >= 5) // >2*2
            width = height = 3;
        else if (input.size() >= 2) // >1*1
            width = height = 2;
        else 
            width = height = 1;
        setInput(guiItemStacks, input, width, height);
    }
    @Override
    public void setInput(@Nonnull IGuiItemStackGroup guiItemStacks, @Nonnull List input, int width, int height)
    {
        for (int i = 0; i < input.size(); i++) 
        {
            Object recipeItem = input.get(i); //Pour chaque stack de la recette
            int index = getCraftingIndex(i, width, height); //Position sur la grille
            List <itemstack>itemStacks = Internal.getStackHelper().toItemStackList(recipeItem);
            setInput(guiItemStacks, index, itemStacks); //Placement des items sur la grille
        }
    }
    
    private int getCraftingIndex(int indexInRecipeItemsList, int width, int height) 
    {
        int index; //Pour savoir a quoi correspond tel ou tel index, dessinez sur une feuille un carré avec des cases et numérotez les de gauche droite en commençant à 0
                   //Cette algorithme qui a l'air compliqué mais ne l'est pas autant que ça détermine l'index sur la grille de craft en fonction de la largeur et la hauteur nécessaires pour une recette afin de centrer celle-ci sur la grille
        if (width == 1)
        {
            //Alignement des items en colonne
            if (height >= 3)
                index = (indexInRecipeItemsList * DEFAULT_CRAFT_WIDTH) + 1;
            else if (height == 2)
                index = (indexInRecipeItemsList * DEFAULT_CRAFT_WIDTH) + DEFAULT_CRAFT_WIDTH;
            else //height == 1
                index = 5;
        }
        else if (height == 1) //Alignement en ligne
            index = indexInRecipeItemsList + DEFAULT_CRAFT_WIDTH;
        else if (width == 2) 
        {
            //Alignement en deux colonnes
            index = indexInRecipeItemsList + 1;
            while(indexInRecipeItemsList >= 2)
            {
                indexInRecipeItemsList -= 2;
                index++;
            }
            if(height < 3) 
                index += DEFAULT_CRAFT_WIDTH;
        }
        else if (height == 2) //Alignement en 2 lignes
            index = indexInRecipeItemsList + DEFAULT_CRAFT_WIDTH;
        else if (width == 3)
        {
            //Alignement en trois colonnes
            index = indexInRecipeItemsList;
            while(indexInRecipeItemsList >= 3)
            {
                    indexInRecipeItemsList -= 3;
                    index++;
            }
            if(height < 3) 
                index += DEFAULT_CRAFT_WIDTH;
        }
        else //On peut les placer sur le grille de craft sans changer leur index
                index = indexInRecipeItemsList;
        return index;
    }
    
    @Override
    public void setOutput(@Nonnull IGuiItemStackGroup guiItemStacks, @Nonnull List <itemstack>output) 
    {
        guiItemStacks.set(craftOutputSlot, output); //Placement du résultat dans son slot
    }
    
    private void setInput(@Nonnull IGuiItemStackGroup guiItemStacks, int inputIndex, @Nonnull Collection <itemstack>input)
    {
        guiItemStacks.set(craftInputSlot1 + inputIndex, input); //Placement d'un item sur la grille de craft
    }
    

    Pour les fours et autres machines sans grille de craft :

    Pous les machines sans grille de craft, vous devez simplement initialiser les slots et placer le contenu de la recette à l'intérieur :

    IGuiItemStackGroup guiItemStacks = recipeLayout.getItemStacks(); //On récupère la classe qui va afficher les slots
    
    guiItemStacks.init(inputSlot, true, x, y); //Remplacez inputSlot par l'index du slot de résultat
    guiItemStacks.init(outputSlot, false, x, y); //Remplacez outputSlotpar l'index du slot de résultat
    //Les x et y représentent la position où les slots seront placés sur la portion de texture que nous avons créé dans le constructeur
    
    guiItemStacks.setFromRecipe(inputSlot, recipe.getInputs()); //Remplacez inputSlot par l'index du slot de résultat
    guiItemStacks.setFromRecipe(outputSlot, recipe.getOutputs()); //Remplacez outputSlotpar l'index du slot de résultat
    

    Enregistrement de la RecipeCategory :

    Pour en finir avec la RecipeCategory, ajoutez ces deux lignes dans la fonction register de la classe de votre plugin :

     IGuiHelper guiHelper = registry.getJeiHelpers().getGuiHelper();
    registry.addRecipeCategories(new TutorielCraftingRecipeCategory(guiHelper));
    

    afin d'enregistrer la catégorie.

    Les RecipeHandler :

    Maintenant, nous allons ajouter les classes qui vont gérer les recettes, les RecipesHandlers.

    Créer une classe (par exemple TutorielShapedRecipeHandler, TutorielSmeltingRecipeHandler...) puis ajoutez-y le implements

    implements IRecipeHandler <laclassedevotrerecette>
    

    ensuite ajoutez les fonctions que eclipse vous demande.

    ❗ Si vous n'avez pas de classe de recette spécifique (comme pour les fours), le wrapper sera utilisé comme classe de recette, donc remplacez "LaClasseDeVotreRecette" par "TutorielSmeltingRecipeWrapper" (ou un autre nom) et créez juste la classe.

    Pour la fonction "getRecipeClass", elle doit retourner l'objet "Class" de la classe de votre recette (donc "LaClasseDeVotreRecette.class"), les deux fonctions "getRecipeCategoryUid" doivent retourner la même chose, le nom de la catégorie de recette créée précédement.

    La fonction "getRecipeWrapper" doit retourner un wrapper pour la recette, nous verrons cela dans la partie suivante et enfin la fonction "isRecipeValid" doit retourner "true" si la recette proposée est valide, le plugin vanilla de JEI vérifie si l'input et l'ouput ne sont pas vides, mais étant donné que (normalement) on ne peut pas ajouter de recette vide, je ne fais pas ce test, donc vous pouvez laisser "return true;".

    ❗ Pour les ShapelessRecipes :
    Nous aurons besoin d'un objet IGuiHelper pour dessiner l'icône de la ShapelessRecipe, donc ajoutez la variable

    private final IGuiHelper guiHelper;
    

    à votre classe,  et ajoutez un constructeur avec un argument de type IGuiHelper puis affectez sa valeur à la variable "guiHelper".

    Enregistrement :

    Pour en finir avec les Handlers, enregistrons-les (car il y en a deux pour une table de craft, un pour les ShapedRecipes et un pour les ShapelessRecipes, tout comme pour le four, SmeltingRecipes et FuelRecipes).
    Ajoutez ce code dans la fonction register de votre plugin

    registry.addRecipeHandlers(new TutorielShapedRecipeHandler(), new TutorielShapelessRecipeHandler(guiHelper));//Vous pouvez ajoutez autant d'handlers que vous voulez dans la même fonction
    

    Les RecipesWrapper :

    ❗ Il faut en général 1 wrapper par RecipeHandler.

    Pour les recettes qui n'ont pas de classe spécifique (par exemple si vous avez suivi le tuto sur le fours), donc pas celles de craft
    Dans la fonction "getRecipeWrapper" de votre(vos) handler(s), retournez l'object recipe.
    Ajoutez le "implements IRecipeWrapper" à la classe de recette et de wrapper normalement créée précédement, ajoutez les fonction manquantes, puis ajoutez ceci au début de la classe :

    private final List<list<itemstack>> input;
    private final List <itemstack>outputs;
    private final String experienceString;
    
    public SmeltingRecipe(List <itemstack>input, ItemStack output, float experience) 
    {
        this.input = Collections.singletonList(input);
        this.outputs = Collections.singletonList(output);
    
        if (experience > 0.0)
            experienceString = Translator.translateToLocalFormatted("gui.jei.category.smelting.experience", experience);
        else
            experienceString = null;
        }
    

    qui va permettre de stocker les inputs et le résultat de la recette.
    Vous pouvez retirer ce qui est en rapport avec l'experience si votre machine n'en donne pas.

    Maintenant ajoutez cette fonction dans la classe (je vous conseille, à la fin), elle va permettre de créer une instance de la classe pour chaque recette de la machine qui existe :

    public static List <smeltingrecipe>getRecipes(IJeiHelpers helpers) 
    {
        IStackHelper stackHelper = helpers.getStackHelper();
        MachineTutoRecipes recipes = MachineTutoRecipes.instance();
        List <smeltingrecipe>recipes = new ArrayList<>();
        for (Map.Entry <itemstack, itemstack="">itemStackItemStackEntry : recipes.getSmeltingList().entrySet())  //Pour chaque recette enregistrée
        {
            ItemStack input = itemStackItemStackEntry.getKey();
            ItemStack output = itemStackItemStackEntry.getValue();
            float experience = recipes.getSmeltingExperience(output); //Si vous avez suivi le tuto sur le four, le système utilisé n'utilise pas d'xp, donc soit vous l'adpatez, soit vous pouvez retirer tout ce qui est en rapport avec l'experience
            List <itemstack>inputs = stackHelper.getSubtypes(input); //Obtention des blocks de même type (planches par exemple)
            recipes.add(new SmeltingRecipe(inputs, output, experience));
        }
        return recipes;
    }
    

    Pour les ShapedRecipe :

    Dans la fonction "getRecipeWrapper" de votre(vos) handler(s), retournez un

    return new TutorielShapedRecipeWrapper(recipe);
    

    (passez également l'argument "guiHelper" si c'est une ShapelessRecipe).
    Créez la classe en implémentant IShapedCraftingRecipeWrapper si c'est une ShapedRecipe, ou IRecipeWrapper dans les autres cas, déclarez une variable pour la recette que le wrapper va contenir et affectez sa valeur dans le constructeur comme ceci :

    private final TutorielShapedRecipes recipe;
    
    public TutorielShapedRecipeWrapper(TutorielShapedRecipes recipe)
    {
    this.recipe = recipe;
    }
    

    Puis ajoutez les fonctions que eclipse vous demandera.

    Pour les ShapelessRecipe :

    Dans la fonction "getRecipeWrapper" de votre(vos) handler(s), retournez un

    return new TutorielShapedRecipeWrapper(recipe);
    

    (passez également l'argument "guiHelper" si c'est une ShapelessRecipe).
    Créez la classe avec extends AbstractShapelessRecipeWrapper (sans implémenter IShapedCraftingRecipeWrapper), comme pour les autres types de recettes, ajouter la variable de la recette avec le constructeur :

    public TutorielShapelessRecipeWrapper(IGuiHelper guiHelper, TutorielShapelessRecipe recipe) 
    {
    super(guiHelper);
    this.recipe = recipe;
    }
    

    Puis ajoutez les fonction que eclipse vous demandera.

    Commun à tous les types de recettes :

    La première fonction du wrapper, "getInputs" doit retourner une liste des ingrédients de la recette, dans le cas d'une recette du tutoriel sur les tables de craft, ça sera

    return Lists.newArrayList(recipe.recipeItems);
    

    et dans le cas d'une recette sans classe spéciale (par ex un four),

    return input;
    

    La seconde, "getOutputs" doit retourner une liste des outputs,

    return Lists.newArrayList(recipe.getRecipeOutput());
    

    dans le cas d'une recette du tutoriel sur les tables de craft, et

    return outputs;
    

    dans le cas d'une recette sans classe spéciale.

    Les fonctions "getFluidInputs" et "getFluidOutputs" vont servir si vous utilisez des fluides, si ce n'est pas le cas, mettez leur

    return Collections.emptyList();
    

    pour retourner une liste vide.

    ❗ Ces quatres fonctions ne doivent en aucun cas retourner null, vous devez retourner une liste vide si il n'y a rien.

    Pour toutes les recettes, sauf pour les ShapelessRecipe où vous devez ajoutez manuellement les fonctions :

    La fonction "drawInfo" permet de dessiner d'autres informations sur la recette, la fonction "drawAnimations" permet de dessinez des animations en fonction de la recette (indépendantes du type de la recette où c'est dessiné via la RecipeCategory), "getTooltipStrings" doit retourner une liste de Strings à dessiner dans un hover en fonction de la position de la souris, "handleClick" est appelée lors d'un clic, cela peut vous permettre d'ajoutez des boutons desssinés avec "drawInfo".

    Pour les ShapedRecipe :

    Les fonctions "getWidth" et "getHeight" doivent respectivement  retourner la largeur et la hauteur de la grille de craft ("recipe.recipeWidth" et "recipe.recipeHeight" dans le cas d'une recette du tutoriel sur les tables de craft).

    Pour les machines qui donnent de l'xp :

    Vous pouvez afficher l'xp donné par la recette en ajoutant ceci dans la fonction "drawInfo" :

    if (experienceString != null) 
    {
        FontRenderer fontRendererObj = minecraft.fontRendererObj;
        int stringWidth = fontRendererObj.getStringWidth(experienceString);
        fontRendererObj.drawString(experienceString, recipeWidth - stringWidth, 0,     Color.gray.getRGB());
    }
    

    Ajout de choses diverses nécessaires :

    Ajout d'un TransferHandler pour transférer les item directement dans l'inventaire de la machine :

    Ajoutez cette ligne dans la fonction register de votre plugin :

    registry.getRecipeTransferRegistry().addRecipeTransferHandler(VotreContainer.class, TutorielCraftingRecipeCategory.CATEGORYUID, 1, 16, 10, 36);
    

    Le 1 représente l'index du premier slot contenant les "ingrédients" et 16 le nombre de ces slots.
    Le 10 est l'index du premier slot de l'inventaire du joueur et 36 le nombre de ces slots (dans la plupart des Container, ce sera toujours ces valeurs-ci.

    Ajout d'une zone cliquable pour voir toutes les recettes d'une machine :

    Ajoutez cette ligne dans la fonction register de votre plugin :

    registry.addRecipeClickArea(ClasseDuGui.class, x, y, width, height, TutorielCraftingRecipeCategory.CATEGORYUID/*, UneCatégorie.unAutreUid, UneCatégorie1.unAutreUid, etc*/);
    

    Si vous cliquez sur cette zone dans votre Gui, vous verrez toutes les recettes qui lui sont associées.

    Associer une catégorie de craft à un item :

    Ajoutez cette ligne dans la fonction register de votre plugin :

    registry.addRecipeCategoryCraftingItem(new ItemStack(ModTutoriel.cratingTable), TutorielCraftingRecipeCategory.CATEGORYUID/*, UneCatégorie.unAutreUid, UneCatégorie1.unAutreUid, etc*/));
    

    Ajouter des recettes :

    Pour ajoutez les recettes, ajoutez un simplement cette ligne dans la fonction register du plugin :

    registry.addRecipes(TutorielCraftingManager.getInstance().getRecipeList());
    

    en changeant par la classe qui contient vos recettes.
    Mais pour les fours et autres machines qui n'ont pas de classes dédiées aux recettes, ça va être différent, il va falloir utiliser la fonction du RecipeWrapper que nous avons créé tout à l'heure :

    registry.addRecipes(ClasseDuWrapperDesRecettes.getRecipes(registry.getJeiHelpers()));
    

    Conclusion :

    Et voilà ce tutoriel très attendu est terminé, j'espère qu'il vous a plus et que vous avez bien tout compris, si vous avez un problème ou une suggestion quelque part, n'hésitez pas 😉

    Bonus

    Ajouter une description à un item

    Vous pouvez ajouter une description à un bloc qui apparaîtra dans une fenêtre spéciale avec une simple ligne dans la fonction register du plugin :

    registry.addDescription(new ItemStack(ModTutoriel.votreItem), "Description de l'item");
    

    Proposez d'autres bonus 😉

    Résultat

    Coming soon 🙂

    Crédits

    Rédaction :

    • →AymericRed←Sur l'idée originale de moscaphone421 pour le bonus du tutoriel sur la création de table de craft.

    Correction :

    • Nobody

    Ce tutoriel de AymericRed publié sur 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

    Retour vers le sommaire des tutoriels



  • Tuto très complet et très utile a première vue pas d'erreur mais petit problème je ne code pas en 1.8 + par contre je comptait y passé 🙂



  • Merci 🙂
    Le truc c'est que JEI n'existe pas en 1.7.10, mais normalement avec NEI ça passera (à moins qu'il y ait eu de gros changements dans NEI après la 1.7.



  • @'AymericRed':

    Merci 🙂
    Le truc c'est que JEI n'existe pas en 1.7.10, mais normalement avec NEI ça passera (à moins qu'il y ait eu de gros changements dans NEI après la 1.7.

    C'est fort possible vu que le développeur n'est plus le même, de toute façon JEI est inutilisable en 1.7 car toutes les versions du CCL avant la 1.9 ont été supprimées



  • Ajout des sous-parties manquantes pour le four et les autres machines du même type.



  • @'AymericRed':

    Ajout des sous-parties manquantes pour le four et les autres machines du même type.

    IL sort quand le tuto NEI?



  • Je savais que tu allais demander ça 😉
    Alors déjà dsl j'ai pris un peu de retard (pb avec l'installation de NEI), le code est bientôt terminé donc je pense le sortir demain soir/lundi.



  • @'AymericRed':

    Je savais que tu allais demander ça 😉
    Alors déjà dsl j'ai pris un peu de retard (pb avec l'installation de NEI), le code est bientôt terminé donc je pense le sortir demain soir/lundi.

    OK merci 🙂 PS: c'est mon annif ajrd



  • Ah moi c'est jeudi ^^ (le jour de la rentrée :'()
    Bon anniv alors n!



  • @'AymericRed':

    Ah moi c'est jeudi ^^ (le jour de la rentrée :'()
    Bon anniv alors n!

    Merci 🙂 Ps: nous on rentre le 2 car les 1e(cinquième) rentre le 1 pour ne pas les perturber car ils rentres en secondaires