• S'inscrire
    • Se connecter
    • Recherche
    • Récent
    • Mots-clés
    • Populaire
    • Utilisateurs
    • Groupes

    Créer une table de craft compatible avec JEI et NEI

    Les interfaces (GUI) et les container
    1.8.9 1.9.x
    11
    90
    16931
    Charger plus de messages
    • Du plus ancien au plus récent
    • Du plus récent au plus ancien
    • Les plus votés
    Répondre
    • Répondre à l'aide d'un nouveau sujet
    Se connecter pour répondre
    Ce sujet a été supprimé. Seuls les utilisateurs avec les droits d'administration peuvent le voir.
    • AymericRed
      AymericRed dernière édition par robin4002

      Sommaire

      • Introduction
      • Pré-requis
      • Code
        • La classe principale
        • Le bloc
        • Le GuiHandler
        • Le container et le slot du résultat
        • Le gui
        • Le CraftingManager et les classes de recette
      • Faire une table de craft qui ne pert pas ses items
        • Modifications du bloc
        • Le TileEntity
        • Modifications du container
        • Modifications du gui
        • Modifications du GuiHandler
      • Résultat
      • Bonus
        • Intégrer JEI à sa table de craft
        • Intégrer NEI à sa table de craft
      • Crédits

      Introduction

      ❗ EDIT : La mise en forme du tutoriel a été changée pour être compatible avec la V4 de MFF, et le code vérifié mais si vous trouvez une erreur bizarre, demandez :)

      Dans ce tutoriel je vais vous montrer comment créer une table de craft entièrement customisable, vous pourrez la faire garder les items (empêcher les items d’être droppés à la fermeture du gui), via une TileEntity, et lui donner la possibilité d’être utilisée à plusieurs en même temps. Et vous pourrez aussi changer la taille des recettes, nous allons utiliser une taille de 4*4 dans ce tutoriel mais vous pourrez la modifier très simplement. Cette table de crafting permettra aussi d’utiliser simplement l’ore dictionary de Forge qui permet de donner un nom à un item/block pour une compatibilité entre mods. Ce tutoriel permet également d’apprendre à faire des guis.

      Pré-requis

      • Créer la base de son mod
      • Créer un bloc basique
      • Avoir lu ça (facultatif car je vais tout expliquer) et donc savoir ce qu’est un gui dans Minecraft

      Code

      La classe principale :

      Tout d’abord, vous devez ajouter votre bloc comme si vous en ajoutiez un basique (je vous laisse le faire puisque vous avez tous lu le tuto), donnez-lui un nom et enregistrez-le.
      Ensuite, il va falloir enregistrer le GuiHandler, ajoutez ceci dans votre fonction init :

          NetworkRegistry.INSTANCE.registerGuiHander(instance, new GuiHandler());
      

      ceci va enregistrer la classe qui va permettre d’enregistrer tous vos guis, vous aurez une erreur, c’est normal nous créerons la classe plus tard.
      Vous en avez maintenant fini avec la classe principale et nous allons donc nous occuper du bloc.

      La classe du bloc :

      Pour que la fenêtre de craft s’affiche lors du clic droit, vous allez devoir ajouter cette fonction dans la classe de votre bloc :

      • 1.9.x :
          @Override
          public boolean onBlockActivated(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, EnumHand hand, ItemStack heldItem, EnumFacing side, float hitX, float hitY, float hitZ)
          {
           if (!worldIn.isRemote)
           {
           playerIn.openGui(ModTutoriel.instance, GuiHandler.guiCraftingTableID, worldIn, pos.getX(), pos.getY(), pos.getZ());
           }
                  return true;
          }
      
      • 1.8.x :
         @Override
         public boolean onBlockActivated (World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumFacing side, float hitX, float hitY, float hitZ)
         {
          if (!worldIn.isRemote)
          {
          playerIn.openGui(ModTutoriel.instance, GuiHandler.guiCraftingTableID, worldIn, pos.getX(), pos.getY(), pos.getZ());
          }
          return true;
         }
      

      Cette fonction va ouvrir le gui si on est sur le serveur, puis le serveur enverra automatiquement un packet au client pour afficher ce gui, je fais la remarque que cette fonction n’est pas appelée si le joueur sneak. Vous aurez une erreur sur “GuiHandler.guiCraftingTableID”, nous allons tout de suite corriger ça.

      Le GuiHandler :

      C’est lui qui va afficher un gui en fonction de l’id donné, il y a deux fonctions à l’intérieur, getServerGuiElement qui doit renvoyer un Container, c’est lui qui assurera la synchronisation, (il n’est pas obligatoire si le gui n’a pas d’inventaire, mais ça c’est autre chose). La deuxième fonction est getClientGuiElement, qui elle doit retourner le gui à afficher.
      Voici la classe toute “nue” (créez-en une si ce n’est pas déjà fait) :

          public class GuiHandler implements IGuiHandler 
          {
          @Override
          public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) 
          {
          BlockPos pos = new BlockPos(x, y, z);
          return null;
          }
      
          @Override
          public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) 
          {
          BlockPos pos = new BlockPos(x, y, z);
          return null;
          }
          }
      

      Puis ajoutez cette variable au début de votre classe, ce sera l’id du gui de crafting, vous pouvez mettre n’importe quel chiffre, mais il doit être différent pour chaque gui.

          public static final int guiCraftingTableID = 0;
      

      Ensuite rajoutez ceci dans votre fonction getServerGuiElement, vous comprendrez le code :

          if(ID == guiCraftingTableID)
          {
          return new ContainerCraftingTable(player.inventory, world, pos); //On retourne le container du gui, vous aurez une erreur, c'est normal
          }
      

      Puis mettez ceci dans la fonction getClientGuiElement :

          if(ID == guiCraftingTableID)
          {
          return new GuiCraftingTable(player.inventory, world, pos); //On retourne le gui, vous aurez une erreur, c'est normal
          }
      

      Le container :

      C’est lui qui va gérer les slots et leur synchronisation, créez une nouvelle classe (je vous conseille de laisser Container dans son nom) extends Container puis collez-y le code que je vais vous donner. Certains vont dire que c’est du bête copier-coller mais j’ai trouvé plus logique de tout donner, j’ai bien sur commenté chaque partie utile, donc voici le code que nous allons avoir :

      ❗ EDIT DU 11/01/16, le contenu de la fonction transferStackInSlot a été amélioré via notepad++ et n’a pas été testé, si vous avez un problème rapportez le moi.

         /** Largeur du craft */
         public static final int craftWidth = 4;
         /** Hauteur du craft */
         public static final int craftHeigth = 4;
      
         /** Inventaire contenant le craft */
         private final InventoryCrafting craftMatrix = new InventoryCrafting(this, craftWidth, craftHeigth);
         /** Inventaire contenant le résultat du craft */
         private final IInventory craftResult = new InventoryCraftResult();
      
         private final World worldObj;
         private final BlockPos pos;
      
         public RemplacerParLeNomDeVotreClasse(InventoryPlayer invPlayer, World world, BlockPos pos) 
         {
         this.worldObj = world; 
         this.pos = pos;
      
         //Ajout du slot pour le résultat
         this.addSlotToContainer(new TutorielSlotCrafting(invPlayer.player, craftMatrix, craftResult, 0, 141, 43));
      
         int startX = 8; //Position x ou les slots de craft commencent à être dessinés
         int startY = 7; //Position y ou les slots de craft commencent à être dessinés
         //Ajout des slots de craft
         for (int y = 0; y < craftHeigth; ++y)
         {
         for(int x = 0; x < craftWidth; ++x) 
         {
         this.addSlotToContainer(new Slot(craftMatrix, x + y * craftWidth, startX + x * 18, startY + y * 18));
         }
         }
      
         startX = 8; //Position x ou les slots de l'inventaire commencent à être dessinés
         startY = 106; //Position y ou les slots de l'inventaire commencent à être dessinés
         //Ajout des slots de l'inventaire du joueur
         for (int y = 0; y < 3; ++y) 
         {
         for(int x = 0; x < 9; ++x)
         {
         this.addSlotToContainer(new Slot(invPlayer, x + y * 9 + 9, startX + x * 18, startY + y * 18));
         }
         }
         startY = 164; //Position y ou les slots de la hotbar commencent à être dessinés
         //Ajout des slots de la hotbar
         for (int x = 0; x < 9; ++x) 
         {
         this.addSlotToContainer(new Slot(invPlayer, x, startX + x * 18, startY));
         }
         }
      
         /**
         * Appelé quand la matrice (les slots de craft) change
         */
         @Override
         public void onCraftMatrixChanged(IInventory iiventory)
         {
         //On met le résultat du craft dans le slot de résultat
         craftResult.setInventorySlotContents(0, TutorielCraftingManager.getInstance().findMatchingRecipe(craftMatrix, worldObj));
         }
      
         /**
         * Retourne true si le joueur peut interagir avec ce gui, en général on teste la distance par rapport au joueur dans cette fonction
         */
         @Override
         public boolean canInteractWith(EntityPlayer player) 
         {
         return this.worldObj.getBlockState(this.pos).getBlock() != ModTutoriel.cratingTable ? false : player.getDistanceSq((double)this.pos.getX() + 0.5D, (double)this.pos.getY() + 0.5D, (double)this.pos.getZ() + 0.5D) <= 64.0D;
         }
      
         /**
         * Appelé quand le container est fermé
         */
         @Override
         public void onContainerClosed(EntityPlayer player) 
         {
                super.onContainerClosed(player);
                if (!this.worldObj.isRemote) //Si on est sur le serveur, on loot les items à la fermeture du gui
                {
                    for (int i = 0; i < 9; ++i)
                    {
                        ItemStack itemstack = this.craftMatrix.removeStackFromSlot(i);
                        if (itemstack != null)
                        {
                         player.dropItem(itemstack, false); //TODO A utiliser en 1.9
                            //player.dropPlayerItemWithRandomChoice(itemstack, false); //TODO A utiliser en 1.8
                        }
                    }
                }
            }
      
         /**
         * Cette fonction est appelée lors du shift+clic (je vous conseille de la laisser comme tel, elle s'adaptera en fonction de la taille de votre craft)
         * EDIT 11/01/16 Le contenu de cette fonction a été modifié via notepad++ et n'a pas été testé, si vous avez un problème rapportez le moi
         */
         @Override
         public ItemStack transferStackInSlot(EntityPlayer player, int slotId)
         {
                ItemStack itemstack = null;
                Slot slot = this.inventorySlots.get(slotId);
      
                if (slot != null && slot.getHasStack())
                {
                    ItemStack itemstack1 = slot.getStack();
                    itemstack = itemstack1.copy();
      
                    int invStart = craftWidth * craftHeigth + 1;
           int hotbarStart = invStart + 27;
                   if (slotId == 0)
                   {
                       if (!this.mergeItemStack(itemstack1, invStart, hotbarStart + 9, true))
                       {
                           return null;
                       }
                       slot.onSlotChange(itemstack1, itemstack);
                   }
                   else if (slotId >= invStart && slotId < invStart + 27)
                   {
                       if (!this.mergeItemStack(itemstack1, hotbarStart, hotbarStart + 9, false))
                       {
                           return null;
                       }
                   }
                   else if (slotId >= hotbarStart && slotId < hotbarStart + 9)
                   {
                       if (!this.mergeItemStack(itemstack1, invStart, invStart + 27, false))
                       {
                           return null;
                       }
                   }
                   else if (!this.mergeItemStack(itemstack1, invStart, hotbarStart + 9, false))
                   {
                       return null;
                   }
                    if (itemstack1.stackSize == 0)
                    {
                        slot.putStack((ItemStack)null);
                    }
                    else
                    {
                        slot.onSlotChanged();
                    }
                    if (itemstack1.stackSize == itemstack.stackSize)
                    {
                        return null;
                    }
      
                    slot.onPickupFromSlot(player, itemstack1);
                }
                return itemstack;
            }
      
         /**
         * Appelé quand on double clic sur un slot :
             * Called to determine if the current slot is valid for the stack merging (double-click) code. The stack passed in
             * is null for the initial slot that was double-clicked.
         */
            public boolean canMergeSlot(ItemStack stack, Slot slotIn)
            {
                return slotIn.inventory != this.craftResult && super.canMergeSlot(stack, slotIn);
            }
      

      Vous pouvez voir tout en haut les variables qui vont gérer la taille de votre craft, vous n’aurez que celles-ci à changer et tout sera géré par le Container, j’ai également rajouté des variables dans le constructeur afin de modifier facilement la position où les slots sont dessinés (les variables startX et startY).

      ❗ Pour ceux en 1.8 : dans la fonction onGuiClosed, vous devrez avoir une erreur, j’ai mis la ligne qui est correcte en commentaire juste en dessous de la ligne erronée.

      Le container est maitenant fait, il devrait vous rester une erreur sur “TutorielSlotCrafting”, c’est le slot qui va contenir le résultat, il doit avoir son propre code car il va retirer les items des slots de craft quand on cliquera dessus, créez-le en veillant à mettre extends Slot, voici sa classe :

         /** The craft matrix inventory linked to this result slot. */
            private final InventoryCrafting craftMatrix;
            /** The player that is using the GUI where this slot resides. */
            private final EntityPlayer thePlayer;
            /** The number of items that have been crafted so far. Gets passed to ItemStack.onCrafting before being reset. */
            private int amountCrafted;
      
            public ARemplacerParLeNomDeVotreClasse(EntityPlayer player, InventoryCrafting craftingInventory, IInventory inventoryIn, int slotIndex, int xPosition, int yPosition)
            {
                super(inventoryIn, slotIndex, xPosition, yPosition);
                this.thePlayer = player;
                this.craftMatrix = craftingInventory;
            }
      
            /**
             * Check if the stack is a valid item for this slot. Always true beside for the armor slots.
             */
            @Override
            public boolean isItemValid(@Nullable ItemStack stack)
            {
                return false;
            }
      
            /**
             * Decrease the size of the stack in slot (first int arg) by the amount of the second int arg. Returns the new
             * stack.
             */
            @Override
            public ItemStack decrStackSize(int amount)
            {
                if (this.getHasStack())
                {
                    this.amountCrafted += Math.min(amount, this.getStack().stackSize);
                }
                return super.decrStackSize(amount);
            }
      
            /**
             * the itemStack passed in is the output - ie, iron ingots, and pickaxes, not ore and wood. Typically increases an
             * internal count then calls onCrafting(item).
             */
            @Override
            protected void onCrafting(ItemStack stack, int amount)
            {
                this.amountCrafted += amount;
                this.onCrafting(stack);
            }
      
            /**
             * Appelé quand on craft, permet de gérer les achievements
             */
            @Override
            protected void onCrafting(ItemStack stack)
            {
                if (this.amountCrafted > 0)
                {
                    stack.onCrafting(this.thePlayer.worldObj, this.thePlayer, this.amountCrafted);
                }
                this.amountCrafted = 0;
                if (stack.getItem() == Item.getItemFromBlock(Blocks.CRAFTING_TABLE))
                {
                    this.thePlayer.addStat(AchievementList.BUILD_WORK_BENCH);
                }
                if (stack.getItem() instanceof ItemPickaxe)
                {
                    this.thePlayer.addStat(AchievementList.BUILD_PICKAXE);
                }
                if (stack.getItem() == Item.getItemFromBlock(Blocks.FURNACE))
                {
                    this.thePlayer.addStat(AchievementList.BUILD_FURNACE);
                }
                if (stack.getItem() instanceof ItemHoe)
                {
                    this.thePlayer.addStat(AchievementList.BUILD_HOE);
                }
                if (stack.getItem() == Items.BREAD)
                {
                    this.thePlayer.addStat(AchievementList.MAKE_BREAD);
                }
                if (stack.getItem() == Items.CAKE)
                {
                    this.thePlayer.addStat(AchievementList.BAKE_CAKE);
                }
                if (stack.getItem() instanceof ItemPickaxe && ((ItemPickaxe)stack.getItem()).getToolMaterial() != Item.ToolMaterial.WOOD)
                {
                    this.thePlayer.addStat(AchievementList.BUILD_BETTER_PICKAXE);
                }
                if (stack.getItem() instanceof ItemSword)
                {
                    this.thePlayer.addStat(AchievementList.BUILD_SWORD);
                }
                if (stack.getItem() == Item.getItemFromBlock(Blocks.ENCHANTING_TABLE))
                {
                    this.thePlayer.addStat(AchievementList.ENCHANTMENTS);
                }
                if (stack.getItem() == Item.getItemFromBlock(Blocks.BOOKSHELF))
                {
                    this.thePlayer.addStat(AchievementList.BOOKCASE);
                }
            }
      
            /**
             * Appelée quand le joueur retire l'item du slot, permet de retirer le composants utilisés pour le craft
             */
            @Override
            public void onPickupFromSlot(EntityPlayer playerIn, ItemStack stack)
            {
                net.minecraftforge.fml.common.FMLCommonHandler.instance().firePlayerCraftingEvent(playerIn, stack, craftMatrix); //Distribue l'event de craft
                this.onCrafting(stack); //Gestion des achievements
                net.minecraftforge.common.ForgeHooks.setCraftingPlayer(playerIn); //Utilisé afin de retirer les items utiliser (pas sur de cela)
                ItemStack[] aitemstack = TutorielCraftingManager.getInstance().getRemainingItems(this.craftMatrix, playerIn.worldObj); //On récupère les items restants
                net.minecraftforge.common.ForgeHooks.setCraftingPlayer(null);
      
                for (int i = 0; i < aitemstack.length; ++i) //On actualise les slots de craft
                {
                    ItemStack itemstack = this.craftMatrix.getStackInSlot(i);
                    ItemStack itemstack1 = aitemstack*;
                    if (itemstack != null)
                    {
                        this.craftMatrix.decrStackSize(i, 1);
                        itemstack = this.craftMatrix.getStackInSlot(i);
                    }
                    if (itemstack1 != null)
                    {
                        if (itemstack == null)
                        {
                            this.craftMatrix.setInventorySlotContents(i, itemstack1);
                        }
                        else if (ItemStack.areItemsEqual(itemstack, itemstack1) && ItemStack.areItemStackTagsEqual(itemstack, itemstack1))
                        {
                            itemstack1.stackSize += itemstack.stackSize;
                            this.craftMatrix.setInventorySlotContents(i, itemstack1);
                        }
                        else if (!this.thePlayer.inventory.addItemStackToInventory(itemstack1))
                        {
                            this.thePlayer.dropItem(itemstack1, false);
                        }
                    }
                }
            }
      

      J’ai commenté les fonctions utiles, le code ne devrait pas être compliqué à comprendre  🙂

      Maintenant que le container est terminé, occupons-nous du gui.

      Le gui :

      C’est lui qui va afficher tous les éléments à l’écran, je vais encore vous donner la classe entière commentée, mais attention, vous aurez des erreurs en copiant ceci car j’ai retiré quelques éléments que je vous donnerai après  😉
      Créez une nouvelle classe extends GuiContainer et collez-y le code suivant :

           public ARemplacerParLeNomDeVotreClasse(InventoryPlayer invPlayer, World world, BlockPos pos) 
          {
          super(new ContainerCraftingTable(invPlayer, world,pos));
          this.xSize = 176; //La largeur du gui en pixels (supprimez-le pour laisser celle par défaut)
          this.ySize = 188; //La hauteur du gui en pixels (supprimez-le pour laisser celle par défaut)
          }
      
          /**
          * Fonction pour dessiner le premier plan
          */
          @Override
          protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) 
          { 
          fontRendererObj.drawString(I18n.format("container.crafting_table"), 100, 5, 0xFFFFFF); //On dessine le "titre" du gui, le I18n.format va traduire le texte donné, n'oubliez pas de l'ajouter dans votre fichier de langues !
          }
      
          /**
          * Fonction pour dessiner l'arrière plan
          */
          @Override
          protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY)
          {
          mc.getTextureManager().bindTexture(texture); //On bind la texture
          drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize); //Et on la dessine
          }
      

      Le titre va être traduit puis dessiné donc pensez bien à l’ajouter dans votre fichier de langues.
      Maintenant, ajoutons la déclaration de la texture (au début de la classe) :

          private ResourceLocation texture = new ResourceLocation(ModTutoriel.MODID, "textures/gui/CraftingTable.png");
      

      ❗ Pensez à remplacer “CraftingTable” par le nom de votre texture.

      Si vous voulez, vous pouvez essayer de lancer le jeu, et si vous n’avez pas changé la position des slots que j’ai donné, vous vous direz “Il y a un problème, c’est quoi ce tuto de ***” avec une tête comme celle là  😮 (pour ceux qui ont la flemme de lancer, le gui est coupé). La raison est que la taille par défaut des guis de Minecraft est trop petite, mais heuresement il suffit de rajouter ceci :

           this.xSize = 176; //La largeur du gui en pixels (supprimez-le pour laisser celle par défaut)
          this.ySize = 188; //La hauteur du gui en pixels (supprimez-le pour laisser celle par défaut)
      

      dans votre constructeur.

      Le gui est maintenant terminé, nous allons maintenant nous occuper du plus compliqué (pour moi, vu que vous, vous n’aurez rien à changer 😛 ), le système des recettes.

      Le système de recettes : CraftingManager et classes de recettes :

      Le CraftingManager va contenir toutes les recettes de votre table de craft, nous allons aussi ajouter deux classes de recettes, une pour chaque type, qui s’adapteront à n’importe quelle taille de craft (22, 33, 44, 58…), je précise que Forge a commencé à implémenter ceci dans les classes ShapedOreRecipe et ShapelessOreRecipe, mais étant donné qu’ils ne l’ont jamais terminé, il faut faire des classes custom.
      Voici le TutorielCraftingManager (créez sa classe) :

          import java.util.List;
          import java.util.Map;
      
          import javax.annotation.Nullable;
      
          import net.minecraft.block.Block;
          import net.minecraft.inventory.InventoryCrafting;
          import net.minecraft.item.Item;
          import net.minecraft.item.ItemStack;
          import net.minecraft.item.crafting.IRecipe;
          import net.minecraft.world.World;
      
          import com.google.common.collect.Lists;
          import com.google.common.collect.Maps;
      
          public class TutorielCraftingManager 
          {
             private static final TutorielCraftingManager INSTANCE = new TutorielCraftingManager();
             public static TutorielCraftingManager getInstance()
             {
                 return INSTANCE;
             }
      
             /** La liste des recettes */
             private final List <irecipe>recipes = Lists.<irecipe>newArrayList();
      
             private TutorielCraftingManager()
             {
              //Vous pouvez ajouter des recettes ici
             }
      
             /**
              * Adds a shaped recipe to the games recipe list.
              */
             public TutorielShapedRecipes addRecipe(ItemStack result, Object... recipeComponents)
             {
                 String s = "";
                 int i = 0;
                 int j = 0;
                 int k = 0;
                 if (recipeComponents* instanceof String[])
                 {
                     String[] astring = (String[])((String[])recipeComponents[i++]);
                     for (int l = 0; l < astring.length; ++l)
                     {
                         String s2 = astring[l];
                         ++k;
                         j = s2.length();
                         s = s + s2;
                     }
                 }
                 else
                 {
                     while (recipeComponents* instanceof String)
                     {
                         String s1 = (String)recipeComponents[i++];
                         ++k;
                         j = s1.length();
                         s = s + s1;
                     }
                 }
                 Character character;
                 Map <character, object="">components = Maps.<character, object="">newHashMap();
                 Object in;
                 for ( ; i < recipeComponents.length; i += 2)
                 {
                  in = recipeComponents[i];
                     Object component = null;
                     character = (Character)recipeComponents*;
                     if (in instanceof Item)
                     {
                         component = new ItemStack((Item)recipeComponents[i]);
                     }
                     else if (in instanceof Block)
                     {
                         component = new ItemStack((Block)recipeComponents[i], 1, 32767);
                     }
                     else if (in instanceof ItemStack)
                     {
                         component = (ItemStack)recipeComponents[i];
                     }
                     else if (in instanceof String)
                     {
                      component = (String)in;
                     }
                     else
                     {
                      throw new IllegalArgumentException("Invalid shaped recipe: unknown type " + in.getClass().getName() + "!");
                     }
                     components.put(character, component);
                 }
                 Object[] aitemstack = new Object[j * k];
                 char key;
                 Object component;
                 for (int i1 = 0; i1 < j * k; ++i1)
                 {
                     key = s.charAt(i1);
                     if (components.containsKey(Character.valueOf(key)))
                     {
                      component = components.get(Character.valueOf(key));
                         if(component instanceof ItemStack) 
                          aitemstack[i1] = ((ItemStack)component).copy();
                         else
                          aitemstack[i1] = component;
                     }
                     else
                         aitemstack[i1] = null;
                 }
                 TutorielShapedRecipes shapedrecipes = new TutorielShapedRecipes(j, k, aitemstack, result);
                 this.recipes.add(shapedrecipes);
                 return shapedrecipes;
             }
      
             /**
              * Adds a shapeless crafting recipe to the the game.
              */
             public void addShapelessRecipe(ItemStack result, Object... recipeComponents)
             {
                 List list = Lists.newArrayList();
                 for (Object component : recipeComponents) //Pour chaque composant de la recette
                 {
                     if (component instanceof ItemStack)
                     {
                         list.add(((ItemStack)component).copy());
                     }
                     else if (component instanceof Item)
                     {
                         list.add(new ItemStack((Item)component));
                     }
                     else if(component instanceof Block)
                     {
                         list.add(new ItemStack((Block)component));
                     }
                     else if(component instanceof String) //Pour l'ore dictionnary
                     {
                      list.add(component);
                     }
                     else throw new IllegalArgumentException("Invalid shapeless recipe: unknown type " + component.getClass().getName() + "!");
                 }
                 this.recipes.add(new TutorielShapelessRecipe(result, list));
             }
      
             /**
              * Adds an IRecipe to the list of crafting recipes.
              */
             public void addRecipe(IRecipe recipe)
             {
                 this.recipes.add(recipe);
             }
      
             /**
              * Retourne le résultat de la recette ou null si il n'y en a aucun
              */
             @Nullable
             public ItemStack findMatchingRecipe(InventoryCrafting craftMatrix, World worldIn)
             {
                 for (IRecipe irecipe : this.recipes) //Pour chaque recette
                 {
                     if (irecipe.matches(craftMatrix, worldIn)) //Si elle correspond à la matrice actuelle
                     {
                         return irecipe.getCraftingResult(craftMatrix); //On donne son résultat
                     }
                 }
                 return null;
             }
      
             /**
              * Retourne les items retants après un craft
              */
             public ItemStack[] getRemainingItems(InventoryCrafting craftMatrix, World worldIn)
             {
                 for (IRecipe irecipe : this.recipes) //Pour chaque recette
                 {
                     if (irecipe.matches(craftMatrix, worldIn)) //Si elle correspond à la matrice actuelle
                     {
                         return irecipe.getRemainingItems(craftMatrix); //On retourne les items restants
                     }
                 }
                 ItemStack[] aitemstack = new ItemStack[craftMatrix.getSizeInventory()];
                 for (int i = 0; i < aitemstack.length; ++i)
                 {
                     aitemstack[i] = craftMatrix.getStackInSlot(i);
                 }
                 return aitemstack; //Si ça ne correspond à aucune recette, on retourne tous les items qui sont présents dans la matrice
             }
      
             public List <irecipe>getRecipeList()
             {
                 return this.recipes;
             }
          }
      

      Voilà pour le CraftingManager, j’ai commenté chaque endroit utile, sauf la fonction addShapedRecipe qui elle est plus compliquée à comprendre et que vous n’êtes donc pas obligés de comprendre.

      Vous devriez avoir deux erreurs sur TutorielShapedRecipes et TutorielShapelessRecipe, créez les classes en veillant bien à ce qu’elle simplements IRecipe puis je vais vous donner le code :

      • TutorielShapedRecipes :
           /** How many horizontal slots this recipe is wide. */
             public final int recipeWidth;
             /** How many vertical slots this recipe uses. */
             public final int recipeHeight;
             /** Is a array of ItemStack that composes the recipe. */
             public final Object[] recipeItems;
             /** Is the ItemStack that you get when craft the recipe. */
             private final ItemStack recipeOutput;
             private boolean copyIngredientNBT;
      
             public TutorielShapedRecipes(int width, int height, Object[] items, ItemStack output)
             {
                 this.recipeWidth = width;
                 this.recipeHeight = height;
                 this.recipeItems = items;
                 this.recipeOutput = output;
             }
      
             public ItemStack getRecipeOutput()
             {
                 return this.recipeOutput;
             }
      
             public ItemStack[] getRemainingItems(InventoryCrafting inv)
             {
                 ItemStack[] aitemstack = new ItemStack[inv.getSizeInventory()];
                 for (int i = 0; i < aitemstack.length; ++i)
                 {
                     ItemStack itemstack = inv.getStackInSlot(i);
                     aitemstack[i] = net.minecraftforge.common.ForgeHooks.getContainerItem(itemstack);
                 }
                 return aitemstack;
             }
      
             /**
              * Used to check if a recipe matches current crafting inventory
              * Retourne true si la recette correspond à la matrice donnée (le craft que le joueur a fait)
              */
             public boolean matches(InventoryCrafting inv, World worldIn)
             {
                 for (int i = 0; i <= inv.getWidth() - this.recipeWidth; ++i)
                 {
                     for (int j = 0; j <= inv.getHeight() - this.recipeHeight; ++j)
                     {
                         if (this.checkMatch(inv, i, j, true))
                         {
                             return true;
                         }
                         if (this.checkMatch(inv, i, j, false))
                         {
                             return true;
                         }
                     }
                 }
                 return false;
             }
      
             /**
              * Checks if the region of a crafting inventory is match for the recipe.
              * Compare deux parties du craft
              */
             private boolean checkMatch(InventoryCrafting inv, int regionX, int regionY, boolean mirror)
             {
                 for (int x = 0 ; x < inv.getWidth() ; ++x)
                 {
                     for (int y = 0 ; y < inv.getHeight() ; ++y)
                     {
                         int x1 = x - regionX;
                         int y1 = y - regionY;
                         Object patternStack = null;
                         if (x1 >= 0 && y1 >= 0 && x1 < this.recipeWidth && y1 < this.recipeHeight)
                         {
                          if (mirror) 
                          patternStack = this.recipeItems[this.recipeWidth - x1 - 1 + y1 * this.recipeWidth];
                          else
                          patternStack = this.recipeItems[x1 + y1 * this.recipeWidth];
                          if(patternStack instanceof String)
                          {
                          List <itemstack>stacks = OreDictionary.getOres((String) patternStack);
                          boolean matches = false;
                          for(ItemStack stack : stacks)
                          {
                          if(areItemStacksEquals(stack, inv.getStackInRowAndColumn(x, y))) //If the pattern's stack doesn't match with the stack in the inv crafting
                          {
                          matches = true;
                          }
                          }
                          if(!matches)
                          return false;
                          }
                          else if(!areItemStacksEquals((ItemStack) patternStack, inv.getStackInRowAndColumn(x, y)))
                          {
                          return false;
                          }
                         }
                     }
                 }
                 return true;
             }
      
             /**
              * Compare les deux stacks
              */
             public static boolean areItemStacksEquals(ItemStack stack1, ItemStack stack2)
             {
              if(stack1 == null || stack2 == null) return stack1 == stack2;
              return stack1.getItem() == stack2.getItem() && (stack1.getMetadata() == OreDictionary.WILDCARD_VALUE || stack1.getMetadata() == stack2.getMetadata());
             }
      
             /**
              * Returns an Item that is the result of this recipe
              */
             public ItemStack getCraftingResult(InventoryCrafting inv)
             {
                 ItemStack itemstack = this.getRecipeOutput().copy();
                 if (this.copyIngredientNBT)
                 {
                     for (int i = 0; i < inv.getSizeInventory(); ++i)
                     {
                         ItemStack itemstack1 = inv.getStackInSlot(i);
                         if (itemstack1 != null && itemstack1.hasTagCompound())
                         {
                             itemstack.setTagCompound((NBTTagCompound)itemstack1.getTagCompound().copy());
                         }
                     }
                 }
                 return itemstack;
             }
      
             /**
              * Returns the size of the recipe area
              */
             public int getRecipeSize()
             {
                 return this.recipeWidth * this.recipeHeight;
             }
      
             /**
              * Set this crafting recipe to copy the NBT tag compound of the last ItemStack that has one in the crafting table.
              */
             public TutorielShapedRecipes setCopyIngredientNBT()
             {
                 this.copyIngredientNBT = true;
                 return this;
             }
      

      Vous devriez comprendre toutes les fonctions, à part une qui est plus compliquée, qui sert à comparer une partie de la recette avec la matrice que le joueur à rempli, vous n’aurez pas à modifier cette fonction, donc ce n’est pas très gênant si  vous ne la comprenez pas  😉

      • TutorielShapelessRecipe :
           /** Is the ItemStack that you get when craft the recipe. */
             private final ItemStack recipeOutput;
             /** Is a List of ItemStack that composes the recipe. */
             public final List recipeItems;
      
             public TutorielShapelessRecipe(ItemStack output, List inputList)
             {
                 this.recipeOutput = output;
                 this.recipeItems = inputList;
             }
      
             public ItemStack getRecipeOutput()
             {
                 return this.recipeOutput;
             }
      
             public ItemStack[] getRemainingItems(InventoryCrafting inv)
             {
                 ItemStack[] aitemstack = new ItemStack[inv.getSizeInventory()];
                 for (int i = 0; i < aitemstack.length; ++i)
                 {
                     ItemStack itemstack = inv.getStackInSlot(i);
                     aitemstack[i] = net.minecraftforge.common.ForgeHooks.getContainerItem(itemstack);
                 }
                 return aitemstack;
             }
      
             /**
              * Used to check if a recipe matches current crafting inventory
              * Retourne true si la recette correspond à la matrice donnée (le craft que le joueur a fait)
              * 
              * La fonction prend une liste des items requis pour le craft, puis pour chaque item rencontré dans la matrice, le retire de la liste des items,
              * si la liste ne contient pas l'item, c'est qu'il y a un item en trop dans le craft et la fonction retourne false, à la fin, si la liste est vide, la
              * fonction retourne true.
              */
             public boolean matches(InventoryCrafting inv, World worldIn)
             {
                 ArrayList arraylist = Lists.newArrayList(this.recipeItems); //Copie les items du craft dans une nouvelle liste
                 for (int i = 0; i < inv.getHeight(); ++i)
                 {
                     for (int j = 0; j < inv.getWidth(); ++j)
                     {
                         ItemStack itemstack = inv.getStackInRowAndColumn(j, i);
                         if (itemstack != null)
                         {
                             boolean flag = false;
                             for(Object component : arraylist)
                             {
                              if(component instanceof String) //Search in ore dictionary
                              {
                              List <itemstack>stacks = OreDictionary.getOres((String) component);
                              for(ItemStack itemstack1 : stacks)
                              {
                              if (TutorielShapedRecipes.areItemStacksEquals(itemstack1, itemstack))
                                     {
                                         flag = true;
                                         arraylist.remove(itemstack1);
                                         break;
                                     }
                              }
                              }
                              else
                              {
                                 ItemStack itemstack1 = (ItemStack)component;
                                 if (TutorielShapedRecipes.areItemStacksEquals(itemstack1, itemstack))
                                 {
                                     flag = true;
                                     arraylist.remove(itemstack1);
                                     break;
                                 }
                              }
                             }
                             if (!flag)
                              return false;
                         }
                     }
                 }
                 return arraylist.isEmpty();
             }
      
             /**
              * Returns an Item that is the result of this recipe
              */
             public ItemStack getCraftingResult(InventoryCrafting inv)
             {
                 return this.recipeOutput.copy();
             }
      
             /**
              * Returns the size of the recipe area
              */
             public int getRecipeSize()
             {
                 return this.recipeItems.size();
             }
      

      Il y a une fonction qui peut-être compliquée à comprendre, j’ai donc résumé son fonctionnement en commentaire, mais vous n’aurez de toute façon pas à la modifier.

      • Note : en 1.8.9, dans la classe TutorielShapedRecipe, vous devez changer les getMetadata() par des getItemDamage().
        J’ai adapté chacune de ces classes à partir de celles vanilla afin qu’elles acceptent n’importe quel taille de craft et qu’elles acceptent les items de l’ore dictionnary (au lieu de mettre des ItemStack quand vous ajoutez votre recette, vous pourrez utiliser des String correspondant à un minerai/bloc/item/lingot… de l’ore dictionnary (ici et ici pour plus d’infos (en Anglais)).

      Voilà c’est terminé, vous pouvez maintenant utiliser votre table de craft, si vous voulez un exemple pour ajouter les recettes, regardez le résultat.

      Faire une table de craft qui ne pert pas ses items :

      Dans Minecraft, lorsque l’on ferme la fenêtre de craft, les items qui sont à l’intérieur tombent au sol, dans cette partie, je vais vous expliquer comment éviter cela, il suffira d’utiliser un tile entity (entitée de bloc) qui sauvegardera vos items.

      Modifications du bloc :

      Nous allons tout d’abord modifier le code du bloc afin qu’il puisse “créer” le tile entity : changer le extends de votre block en BlockContainer puis ajoutez cette fonction :

          @Override
          public TileEntity createNewTileEntity(World worldIn, int meta) 
          {
          return new TileEntityCraftingTable();
          }
      
      • 1.9.x : pour une raison qui m’est inconnue, la classe BlockContainer redéfini la fonction getRenderType qui retourne le type de rendu et en retourne un invisible, il faut donc nous-mêmes redéfinir la fonction comme ceci :
          @Override
          public EnumBlockRenderType getRenderType(IBlockState state)
          {
              return EnumBlockRenderType.MODEL;
          }
      

      dans la classe de votre block afin d’avoir un rendu de block standard.Si vous souhaitez que votre de table craft puisse avoir un nom custom, ajoutez  également cette fonction, appelée quand le block est posé par une entité :

           @Override
          public void onBlockPlacedBy(World world, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack)
          {
          super.onBlockPlacedBy(world, pos, state, placer, stack);
          if(stack.hasDisplayName()) //Si l'item de l'entité a un nom custom
          {
          TileEntity te = world.getTileEntity(pos);
          if(te instanceof TileEntityCraftingTable) //On vérifie que c'est la bonne TileEntity
          {
          ((TileEntityCraftingTable) te).setCustomName(stack.getDisplayName()); //On lui donne le nom
          }
          }
          }
      

      Vous aurez une erreur sur new TileEntityCraftingTable(), créez la classe en veillant bien à mettre extends TileEntity et implements IInventory.

      L’entité de bloc (TileEntity) :

      La classe est assez longue, donc je vais donner le code en entier, commenté par mes soins 🙂

          private String customName; //Le nom custom
          private ItemStack[] inventory = new ItemStack[ContainerCraftingTable.craftWidth * ContainerCraftingTable.craftHeigth]; //L'inventaire contenant les ingrédients
      
          @Override
          public String getName() 
          {
          return hasCustomName() ? customName : I18n.format("container.crafting_table");
          }
          @Override
          public boolean hasCustomName() 
          {
          return customName != null;
          }
          @Override
          public ITextComponent getDisplayName()
          {
          return new TextComponentString(getName());
          }
             public void setCustomName(String name)
             {
                 this.customName = name;
             }
      
          @Override
          public int getSizeInventory()
          {
          return inventory.length;
          }
      
          /**
              * Returns the stack in the given slot.
              */
          @Override
             @Nullable
             public ItemStack getStackInSlot(int index)
             {
                 return this.inventory[index];
             }
      
             /**
              * Removes up to a specified number of items from an inventory slot and returns them in a new stack.
              * Retire une quantité donnée d'items d'un slot
              */
          @Override
             @Nullable
             public ItemStack decrStackSize(int index, int count)
             {
                 ItemStack itemstack;
                 if (index >= 0 && index < inventory.length && inventory[index] != null && count > 0)
                 {
                     itemstack = inventory[index].splitStack(count);
                     if (inventory[index].stackSize == 0)
                      inventory[index] = null;
                 }
                 else 
                  itemstack =  null;
                 if (itemstack != null) 
                  this.markDirty();
                 return itemstack;
             }
      
             /**
              * Removes a stack from the given slot and returns it.
              */
          @Override
             @Nullable
             public ItemStack removeStackFromSlot(int index)
             {
                 if (index >= 0 && index < inventory.length)
                 {
                     ItemStack itemstack = inventory[index];
                     inventory[index] = null;
                     return itemstack;
                 }
                 else
                 {
                     return null;
                 }
             }
      
             /**
              * Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections).
              */
          @Override
             public void setInventorySlotContents(int index, @Nullable ItemStack stack)
             {
                 this.inventory[index] = stack;
                 if (stack != null && stack.stackSize > this.getInventoryStackLimit())
                 {
                     stack.stackSize = this.getInventoryStackLimit();
                 }
                 this.markDirty();
             }
      
          @Override
             public void readFromNBT(NBTTagCompound compound)
             {
                 super.readFromNBT(compound);
                 if (compound.hasKey("CustomName", 8)) //Si le tag un à String (8) contenant le nom
                 {
                     this.customName = compound.getString("CustomName"); //Lecture du nom custom
                 }
                 NBTTagList nbttaglist = compound.getTagList("Items", 10);
                 for (int i = 0; i < nbttaglist.tagCount(); ++i) //Pour chaque tag de la liste des items
                 {
                     NBTTagCompound nbttagcompound = nbttaglist.getCompoundTagAt(i);
                     int j = nbttagcompound.getInteger("Slot");
                     if (j >= 0 && j < this.inventory.length)
                     {
                         this.inventory[j] = ItemStack.loadItemStackFromNBT(nbttagcompound); //On place l'item lu dans l'inventaire
                     }
                 }
             }
      
          @Override
             public NBTTagCompound writeToNBT(NBTTagCompound compound)
             {
                 super.writeToNBT(compound);
                 NBTTagList nbttaglist = new NBTTagList();
                 //On place tous les items dans une liste sous forme de tags
                 for (int i = 0; i < this.inventory.length; ++i)
                 {
                     if (this.inventory* != null)
                     {
                         NBTTagCompound nbttagcompound = new NBTTagCompound();
                         nbttagcompound.setInteger("Slot", i);
                         this.inventory*.writeToNBT(nbttagcompound);
                         nbttaglist.appendTag(nbttagcompound);
                     }
                 }
                 compound.setTag("Items", nbttaglist);
                 if (this.hasCustomName()) //Si il y a un nom custom
                 {
                     compound.setString("CustomName", this.customName); //On le sauvegarde
                 }
                 return compound;
             }
      
             /**
              * Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended.
              */
          @Override
             public int getInventoryStackLimit()
             {
                 return 64;
             }
      
             /**
              * Do not make give this method the name canInteractWith because it clashes with Container
              */
          @Override
             public boolean isUseableByPlayer(EntityPlayer player)
             {
                 return this.worldObj.getTileEntity(this.pos) != this ? false : player.getDistanceSq((double)this.pos.getX() + 0.5D, (double)this.pos.getY() + 0.5D, (double)this.pos.getZ() + 0.5D) <= 64.0D;
             }
      
          @Override
          public void openInventory(EntityPlayer player) {}
      
          @Override
          public void closeInventory(EntityPlayer player) {}
      
          @Override
          public boolean isItemValidForSlot(int index, ItemStack stack)
          {
          return index >= 0 && index < inventory.length;
          }
      
          @Override
          public int getField(int id) 
          {
          return 0;
          }
      
          @Override
          public void setField(int id, int value) {}
      
          @Override
          public int getFieldCount()
          {
          return 0;
          }
      
          @Override
          public void clear()
          {
          int size = inventory.length;
          inventory = new ItemStack;
          }
      

      C’est tout pour cette classe, maintenant, il faut enregistrer le tile entity pour que Minecraft le reconnaisse : dans la fonction init de votre classe principale, ajoutez ceci :

          GameRegistry.registerTileEntity(TileEntityCraftingTable.class, "CraftingTable");
      

      Maintenant, modifions le Container et le Gui pour qu’ils fonctionnent en symbiose avec le tile entity 🙂

      Modifications du container :

      Nous allons ajouter tout ce qu’il faut pour que votre container lise le contenu des slots du tileentity à son ouverture et update ce contenu lorsqu’il est modifié. Ajoutez

          private final TileEntityCraftingTable tileentity;
      

      à vos variables puis dans le constructeur, ajoutez “TileEntityCraftingTable tileentity” aux arguments et ajoutez ceci :

           //Pour chaque slot du tileentity, on update les slots de la matrice
          for(int slot = 0 ; slot < craftMatrix.getSizeInventory() ; slot++)
          {
          craftMatrix.setInventorySlotContents(slot, tileentity.getStackInSlot(slot));
          }
          this.tileentity = tileentity;
      

      ❗ Veillez à laisser “this.tileentity = tileentity;” après le for car la modification de la matrice va appeler la fonction onCraftMatrixChanged qui elle va changer le contenu du tile entity, ce que nous ne voulons pas étant donné que la matrice n’est pas encore complète (en gros c’est compliqué et ça m’a fait perdre 10 minutes de ma vie :'().

      Ensuite, modifions cette fameuse fonction onCraftMatrixChanged et ajoutons ceci :

           if(tileentity != null)
          {
          //Pour chaque slot de la matrice, on update les slots du tileentity
          for(int slot = 0 ; slot < tileentity.getSizeInventory() ; slot++)
          {
          tileentity.setInventorySlotContents(slot, craftMatrix.getStackInSlot(slot));
          }
          }
      

      ceci, si on a complété la matrice à l’ouverture du gui (“if(tileentity != null)”), va update les contenus du tile entity à chaque modification de la matrice.
      Ensuite, pour finir, retirez la fonction onContainerClosed qui elle droppait le contenu du container, ce que nous ne voulons plus.

      Modifications du gui:

      Il nous reste encore à modifier le gui afin qu’il puisse afficher le nom custom.
      Comme pour le Container, ajoutez

          private final TileEntityCraftingTable tileentity;
      

      à vos variables et dans le constructeur, ajoutez “TileEntityCraftingTable tileentity” aux arguments puis remplacez la première ligne du constructeur par ceci :

           super(new ContainerCraftingTable(invPlayer, world,pos, tileentity));
          this.tileentity = tileentity;
      

      (on ajoute “tileentity” au contructeur du Container et on défini la variable “tileentity”).
      Et pour finir, modifiez la ligne où vous dessinez le titre par ceci :

          fontRendererObj.drawString(tileentity.getName(), 100, 5, 0xFFFFFF); //On dessine le "titre" du gui
      

      Si vous enregistrez maintenant, vous aurez des erreurs dans votre GuiHandler, corrigeons-les :

      Modifications du GuiHandler :

      Ajoutez ceci

          TileEntity tileentity = world.getTileEntity(pos);
      

      après la déclaration de votre variable “BlockPos pos” dans les deux fonctions du GuiHandler, puis pour le Container et pour le Gui, ajoutez ceci

          (TileEntityCraftingTable) tileentity
      

      à l’appel de leur constructeur pour correspondre à ce que nous avons mis dans les classes.

      Résultat

      Voici le résultat obtenu :

      Et le code permettant d’ajouter les recettes correspondant :

          this.addShapelessRecipe(new ItemStack(Blocks.ANVIL), Items.CARROT, Items.GOLDEN_APPLE);
          this.addRecipe(new ItemStack(cratingTable), " C ", "X X", " C ", 'C', "slabWood", 'X', Blocks.PLANKS); //"slabWood" est le nom des dalles de bois dans l'ore dictionnary, ceci est ajouté par Forge
          this.addRecipe(new ItemStack(Items.GOLDEN_APPLE), "A  A", "X  X", "X  X", "A  A", 'A', Items.CARROT, 'X', Blocks.PLANKS);
      
      

      à placer dans le constructeur du TutorielCraftingManager.

      (Commme vous pouvez le voir, j’ai insisté sur le côté rp des recettes ^^).

      Vous avez maintenant fini de lire cet assez long tuto, bravo à vous ! Je vais ajouter la possibilité de garder les items dans la table de craft très bientôt :), si vous voulez un bonus particulier ou si vous avez un problème quelque part (j’ai fait une erreur ou vous ne comprenez pas quelque chose), n’hésitez pas à demander  😉

      Bonus

      • Intégrer JEI (Just Enought Items, dérivé de NEI) à la table de craft : ici
      • Intégrer NEI (Not Enought Items) à la table de craft : ici
      • Proposez-moi ce que vous souhaitez avoir en bonus 🙂

      Crédits

      Rédaction :

      • AymericRed

      Correction/Améliorations :

      • MajorSquirrel pour une idée d’amélioration de la fonction transferStackInSlot du Container


      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

      Si je vous ai aidé, n'oubliez pas d’être heureux, j'aiderai encore +

      AymericRed, moddeur expérimenté qui aide sur ce forum et qui peut accepter de faire un mod Forge rémunéré de temps en temps.

      Mes tutos : Table de craft, plugin NEI, plugin JEI, modifier l'overlay
      Je suis un membre apprécié et joueur, j'ai déjà obtenu 6 points de réputation.

      C 1 réponse Dernière réponse Répondre Citer 0
      • Tristepin
        Tristepin dernière édition par

        Très bonne idée ce tutoriel ça peut permettre de créer un table de craft custom rien que pour les crafts d’un mod 😉

        Edit: pour le bonus je ne sais pas si cela rentre dans la catégorie mais peut-être comment changer la table de craft qui se trouve
        dans l’inventaire ce serait très pratique je trouve de pouvoir tout craft à porter de main ^^

        Modélisateur sur son temps libre.

        1 réponse Dernière réponse Répondre Citer 0
        • AymericRed
          AymericRed dernière édition par

          Pour l’idée de bonus, ça peut être un truc cool, mais étant donné qu’il faudrait remplacer le gui de l’inventaire, je pense qu’il faudrait un tuto à part entière.

          Si je vous ai aidé, n'oubliez pas d’être heureux, j'aiderai encore +

          AymericRed, moddeur expérimenté qui aide sur ce forum et qui peut accepter de faire un mod Forge rémunéré de temps en temps.

          Mes tutos : Table de craft, plugin NEI, plugin JEI, modifier l'overlay
          Je suis un membre apprécié et joueur, j'ai déjà obtenu 6 points de réputation.

          1 réponse Dernière réponse Répondre Citer 0
          • moscaphone421
            moscaphone421 dernière édition par

            Ajout NEI ? en bonus bis

            1 réponse Dernière réponse Répondre Citer 0
            • AymericRed
              AymericRed dernière édition par

              Ah oui ça, ça serait bien à mettre ici, je verrais…

              Si je vous ai aidé, n'oubliez pas d’être heureux, j'aiderai encore +

              AymericRed, moddeur expérimenté qui aide sur ce forum et qui peut accepter de faire un mod Forge rémunéré de temps en temps.

              Mes tutos : Table de craft, plugin NEI, plugin JEI, modifier l'overlay
              Je suis un membre apprécié et joueur, j'ai déjà obtenu 6 points de réputation.

              1 réponse Dernière réponse Répondre Citer 0
              • leo01418
                leo01418 dernière édition par

                Déjà gg AymericRed et merci beaucoup à toi pour ce tuto grâce à toi je vais réalisé ce que j’ai voulu faire il à longtemps 🙂
                après en bonus tu pourra rajouté 
                NEI,de décraft les objet qu’on on a craft du genre je craft une épée spécial avec 1 stick et 8 diamand et par rapport à sa durabilité par exemple si il est à 200 on récupéré 2 diamant

                Merci infiniment pour ce tuto 🙂

                Edit 
                comme je pourrais mettre ceci

                @Override
                public boolean canInteractWith(EntityPlayer player) 
                {
                return this.worldObj.getBlockState(this.pos).getBlock() != enderdeath.AnvilDragon ? false : player.getDistanceSq((double)this.pos.getX() + 0.5D, (double)this.pos.getY() + 0.5D, (double)this.pos.getZ() + 0.5D) <= 64.0D;
                }
                
                

                en 1.7.10?

                Voila ma signature

                1 réponse Dernière réponse Répondre Citer 0
                • AymericRed
                  AymericRed dernière édition par

                  De rien 🙂
                  Donc du coup NEI c’est prévu, et pour ta proposition, il suffit d’ajouter les crafts mais en inversé.

                  Si je vous ai aidé, n'oubliez pas d’être heureux, j'aiderai encore +

                  AymericRed, moddeur expérimenté qui aide sur ce forum et qui peut accepter de faire un mod Forge rémunéré de temps en temps.

                  Mes tutos : Table de craft, plugin NEI, plugin JEI, modifier l'overlay
                  Je suis un membre apprécié et joueur, j'ai déjà obtenu 6 points de réputation.

                  1 réponse Dernière réponse Répondre Citer 0
                  • leo01418
                    leo01418 dernière édition par

                    @‘AymericRed’:

                    De rien 🙂
                    Donc du coup NEI c’est prévu, et pour ta proposition, il suffit d’ajouter les crafts mais en inversé.

                    Merci grace à toi j’ai fait ma nouvelle table de craft dans mon mod en 1.9 et je m’attaque pour une nouvelle table de craft pour mon mod en 1.7.10 🙂
                    (sa va je pensé que c’était plus dur de passé du codage 1.9 en 1.7.10 mais c’est bon ^^)
                    et pour NEI Yes 🙂
                    et pour les craft inversé je vais m’y mettre après la nouvelle table de craft en 1.7.10 🙂

                    Merci beaucoup 🙂

                    Ps ce tuto = 5 étoiles 🙂

                    Edit comme je peux passé ceci

                    @Override
                    public boolean canInteractWith(EntityPlayer player) 
                    {
                    return this.worldObj.getBlockState(this.pos).getBlock() != enderdeath.AnvilDragon ? false : player.getDistanceSq((double)this.pos.getX() + 0.5D, (double)this.pos.getY() + 0.5D, (double)this.pos.getZ() + 0.5D) <= 64.0D;
                    }
                    
                    

                    en 1.7.10

                    Voila ma signature

                    1 réponse Dernière réponse Répondre Citer 0
                    • AymericRed
                      AymericRed dernière édition par

                      getBlockState(…).getBlock() devient getBlock et ensuite il faut que tu fasses trois variables pour X, y, et z.

                      Envoyé de mon RAINBOW LITE 4G en utilisant Tapatalk

                      Si je vous ai aidé, n'oubliez pas d’être heureux, j'aiderai encore +

                      AymericRed, moddeur expérimenté qui aide sur ce forum et qui peut accepter de faire un mod Forge rémunéré de temps en temps.

                      Mes tutos : Table de craft, plugin NEI, plugin JEI, modifier l'overlay
                      Je suis un membre apprécié et joueur, j'ai déjà obtenu 6 points de réputation.

                      1 réponse Dernière réponse Répondre Citer 0
                      • leo01418
                        leo01418 dernière édition par

                        J’ai un autre problème dans cette classe

                        package ed.enderdeath.mod.AnvilDragon;
                        
                        import com.sun.istack.internal.Nullable;
                        
                        import cpw.mods.fml.common.FMLCommonHandler;
                        import net.minecraft.entity.player.EntityPlayer;
                        import net.minecraft.init.Blocks;
                        import net.minecraft.init.Items;
                        import net.minecraft.inventory.IInventory;
                        import net.minecraft.inventory.InventoryCrafting;
                        import net.minecraft.inventory.Slot;
                        import net.minecraft.item.Item;
                        import net.minecraft.item.ItemHoe;
                        import net.minecraft.item.ItemPickaxe;
                        import net.minecraft.item.ItemStack;
                        import net.minecraft.item.ItemSword;
                        import net.minecraft.stats.AchievementList;
                        import net.minecraftforge.common.ForgeHooks;
                        
                        public class DragonSlotCrafting extends Slot {
                        /** The craft matrix inventory linked to this result slot. */
                          private final InventoryCrafting craftMatrix;
                          /** The player that is using the GUI where this slot resides. */
                          private final EntityPlayer thePlayer;
                          /** The number of items that have been crafted so far. Gets passed to ItemStack.onCrafting before being reset. */
                          private int amountCrafted;
                        
                          public DragonSlotCrafting(EntityPlayer player, InventoryCrafting craftingInventory, IInventory inventoryIn, int slotIndex, int xPosition, int yPosition)
                          {
                              super(inventoryIn, slotIndex, xPosition, yPosition);
                              this.thePlayer = player;
                              this.craftMatrix = craftingInventory;
                          }
                        
                          /**
                           * Check if the stack is a valid item for this slot. Always true beside for the armor slots.
                           */
                          @Override
                          public boolean isItemValid(@Nullable ItemStack stack)
                          {
                              return false;
                          }
                        
                          /**
                           * Decrease the size of the stack in slot (first int arg) by the amount of the second int arg. Returns the new
                           * stack.
                           */
                          @Override
                          public ItemStack decrStackSize(int amount)
                          {
                              if (this.getHasStack())
                              {
                                  this.amountCrafted += Math.min(amount, this.getStack().stackSize);
                              }
                              return super.decrStackSize(amount);
                          }
                        
                          /**
                           * the itemStack passed in is the output - ie, iron ingots, and pickaxes, not ore and wood. Typically increases an
                           * internal count then calls onCrafting(item).
                           */
                          @Override
                          protected void onCrafting(ItemStack stack, int amount)
                          {
                              this.amountCrafted += amount;
                              this.onCrafting(stack);
                          }
                        
                          /**
                           * Appelé quand on craft, permet de gérer les achievements
                           */
                          @Override
                          protected void onCrafting(ItemStack stack)
                          {
                              if (this.amountCrafted > 0)
                              {
                                  stack.onCrafting(this.thePlayer.worldObj, this.thePlayer, this.amountCrafted);
                              }
                              this.amountCrafted = 0;
                        
                              if (stack.getItem() == Item.getItemFromBlock(Blocks.bookshelf))
                              {
                                  this.thePlayer.addStat(AchievementList.bookcase, 1);
                              }
                          }
                        
                          /**
                           * Appelée quand le joueur retire l'item du slot, permet de retirer le composants utilisés pour le craft
                           */
                          @Override
                          public void onPickupFromSlot(EntityPlayer playerIn, ItemStack stack)
                          {
                             FMLCommonHandler.instance().firePlayerCraftingEvent(playerIn, stack, craftMatrix); //Distribue l'event de craft
                              this.onCrafting(stack); //Gestion des achievements
                             ForgeHooks.setCraftingPlayer(playerIn); //Utilisé afin de retirer les items utiliser (pas sur de cela)
                              ItemStack[] aitemstack = TutorielCraftingManager.getInstance().getRemainingItems(this.craftMatrix, playerIn.worldObj); //On récupère les items restants
                              ForgeHooks.setCraftingPlayer(null);
                        
                              for (int i = 0; i < aitemstack.length; ++i) //On actualise les slots de craft
                              {
                                  ItemStack itemstack = this.craftMatrix.getStackInSlot(i);
                                  ItemStack itemstack1 = aitemstack*;
                                  if (itemstack != null)
                                  {
                                      this.craftMatrix.decrStackSize(i, 1);
                                      itemstack = this.craftMatrix.getStackInSlot(i);
                                  }
                                  if (itemstack1 != null)
                                  {
                                      if (itemstack == null)
                                      {
                                          this.craftMatrix.setInventorySlotContents(i, itemstack1);
                                      }
                                      else if (ItemStack.areItemStacksEqual(itemstack, itemstack1) && ItemStack.areItemStackTagsEqual(itemstack, itemstack1))
                                      {
                                          itemstack1.stackSize += itemstack.stackSize;
                                          this.craftMatrix.setInventorySlotContents(i, itemstack1);
                                      }
                                      else if (!this.thePlayer.inventory.addItemStackToInventory(itemstack1))
                                      {
                                          this.thePlayer.dropOneItem(false);
                                      }
                                  }
                              }
                          }
                        }
                        
                        

                        Le problème c’est que setCraftingPlayer n’existe pas donc j’ai éssayé de trouve une alternative mais j’ai pas trouvé

                        Voila ma signature

                        1 réponse Dernière réponse Répondre Citer 0
                        • AymericRed
                          AymericRed dernière édition par

                          Pour le slot, je regarde tout à l’heure, pour le gui, ça devrait marcher mais retire xSize1 et ySize1, c’est totalement inutile.

                          EDIT : PS : Tu peux regarder dans la classe SlotCrafting de mc qui est comparable à celle du tuto.

                          Envoyé de mon RAINBOW LITE 4G en utilisant Tapatalk

                          Si je vous ai aidé, n'oubliez pas d’être heureux, j'aiderai encore +

                          AymericRed, moddeur expérimenté qui aide sur ce forum et qui peut accepter de faire un mod Forge rémunéré de temps en temps.

                          Mes tutos : Table de craft, plugin NEI, plugin JEI, modifier l'overlay
                          Je suis un membre apprécié et joueur, j'ai déjà obtenu 6 points de réputation.

                          1 réponse Dernière réponse Répondre Citer 1
                          • leo01418
                            leo01418 dernière édition par

                            Merci beaucoup 🙂

                            Mais j’ai un autre problème

                               return irecipe.getRemainingItems(craftMatrix); //On retourne les items restants
                            
                            getRemainingItems(craftMatrix);
                            ``` n'existe pas j'ai essaye de trouvé un internative mais cela ne marche pas ):
                            
                            Merci de ta réponse :)

                            Voila ma signature

                            1 réponse Dernière réponse Répondre Citer 0
                            • AymericRed
                              AymericRed dernière édition par

                              Essaye un icrecipe.func_quelquechose qui retourne la même chose (array de stack) et qui a un InventoryCrafting en paramètre.

                              Si je vous ai aidé, n'oubliez pas d’être heureux, j'aiderai encore +

                              AymericRed, moddeur expérimenté qui aide sur ce forum et qui peut accepter de faire un mod Forge rémunéré de temps en temps.

                              Mes tutos : Table de craft, plugin NEI, plugin JEI, modifier l'overlay
                              Je suis un membre apprécié et joueur, j'ai déjà obtenu 6 points de réputation.

                              1 réponse Dernière réponse Répondre Citer 0
                              • leo01418
                                leo01418 dernière édition par

                                c’est à dire il na pas de func dans la classe IRecipe et pour moi les seul truc que j’ai son :

                                getCraftingResult

                                matches

                                getRecipeSize

                                plus précisément

                                boolean matches(InventoryCrafting p_77569_1_, World p_77569_2_);

                                ItemStack getCraftingResult(InventoryCrafting p_77572_1_);

                                int getRecipeSize();

                                après c’est peut être ma version de forge   😛

                                Merci de ta réponse rapide 🙂

                                Voila ma signature

                                1 réponse Dernière réponse Répondre Citer 0
                                • AymericRed
                                  AymericRed dernière édition par

                                  Ah bon, je pensait qu’il y aurait ça en 1.7.10, ça doit fonctionner autrement, il faut regarder le SlotCrafting de Minecraft pour voir comment est-ce qu’il fait.

                                  Si je vous ai aidé, n'oubliez pas d’être heureux, j'aiderai encore +

                                  AymericRed, moddeur expérimenté qui aide sur ce forum et qui peut accepter de faire un mod Forge rémunéré de temps en temps.

                                  Mes tutos : Table de craft, plugin NEI, plugin JEI, modifier l'overlay
                                  Je suis un membre apprécié et joueur, j'ai déjà obtenu 6 points de réputation.

                                  1 réponse Dernière réponse Répondre Citer 0
                                  • AymericRed
                                    AymericRed dernière édition par

                                    Quelques updates du tuto ont été réalisées :

                                    • Modification du code du Container, changement des variables craftWidth et craftHeigth de private à public et ajout de “final” aux différents variables.
                                    • Rédaction de la partie “Faire une table de craft qui ne pert pas ses items” terminée.

                                    Le bonus sur NEI arrivera quand NEI en 1.9.4 existera 🙂

                                    Si je vous ai aidé, n'oubliez pas d’être heureux, j'aiderai encore +

                                    AymericRed, moddeur expérimenté qui aide sur ce forum et qui peut accepter de faire un mod Forge rémunéré de temps en temps.

                                    Mes tutos : Table de craft, plugin NEI, plugin JEI, modifier l'overlay
                                    Je suis un membre apprécié et joueur, j'ai déjà obtenu 6 points de réputation.

                                    1 réponse Dernière réponse Répondre Citer 0
                                    • leo01418
                                      leo01418 dernière édition par

                                      @‘AymericRed’:

                                      Quelques updates du tuto ont été réalisées :

                                      • Modification du code du Container, changement des variables craftWidth et craftHeigth de private à public et ajout de “final” aux différents variables.
                                      • Rédaction de la partie “Faire une table de craft qui ne pert pas ses items” terminée.

                                      Le bonus sur NEI arrivera quand NEI en 1.9.4 existera 🙂

                                      Bravo sa complète ce tutoriel très bon 🙂

                                      Bonne chance pour NEI 🙂

                                      Pour revenir à mon problème après plusieurs recherche je n’ai pas trouvé peut être que je devrais cherché dans la classe qui gère les crafts

                                      Merci de complété ce tutoriel  qui est déjà très bon  et de ton aide 😄

                                      Voila ma signature

                                      1 réponse Dernière réponse Répondre Citer 0
                                      • AymericRed
                                        AymericRed dernière édition par

                                        Merci du compliment ^^ Je regarderais cet aprem dans les sources 1.7 que je devrais toujours avoir, pour ton problème 🙂

                                        Envoyé de mon RAINBOW LITE 4G en utilisant Tapatalk

                                        Si je vous ai aidé, n'oubliez pas d’être heureux, j'aiderai encore +

                                        AymericRed, moddeur expérimenté qui aide sur ce forum et qui peut accepter de faire un mod Forge rémunéré de temps en temps.

                                        Mes tutos : Table de craft, plugin NEI, plugin JEI, modifier l'overlay
                                        Je suis un membre apprécié et joueur, j'ai déjà obtenu 6 points de réputation.

                                        1 réponse Dernière réponse Répondre Citer 0
                                        • SCAREX
                                          SCAREX dernière édition par

                                          Si c’est ce que je pense, avant la 1.8 c’était une autre méthode qui était utilisée : on configurait l’item qui restait depuis l’item et non depuis le craft, ça a du être modifié dans les dernières versions. Peut être qu’en retirant cette partie là ça fonctionnera (à vérifier)

                                          Site web contenant mes scripts : http://SCAREXgaming.github.io

                                          Pas de demandes de support par MP ni par skype SVP.
                                          Je n'accepte sur skype que l…

                                          1 réponse Dernière réponse Répondre Citer 0
                                          • AymericRed
                                            AymericRed dernière édition par

                                            Alors j’ai regardé rapidement le SlotCrafting de mc 1.7.10, il faut que tu retires toutes les fonctions getRemainingItems du crafting manager et des classes de recette, puis recopies la fonction onPickupFromSlot de la classe SlotCrafting dans la classe de ton Slot.

                                            Si je vous ai aidé, n'oubliez pas d’être heureux, j'aiderai encore +

                                            AymericRed, moddeur expérimenté qui aide sur ce forum et qui peut accepter de faire un mod Forge rémunéré de temps en temps.

                                            Mes tutos : Table de craft, plugin NEI, plugin JEI, modifier l'overlay
                                            Je suis un membre apprécié et joueur, j'ai déjà obtenu 6 points de réputation.

                                            1 réponse Dernière réponse Répondre Citer 0
                                            • 1
                                            • 2
                                            • 3
                                            • 4
                                            • 5
                                            • 1 / 5
                                            • Premier message
                                              Dernier message
                                            Design by Woryk
                                            Contact / Mentions Légales

                                            MINECRAFT FORGE FRANCE © 2018

                                            Powered by NodeBB