L'équipe de Minecraft Forge France ne fait désormais plus de support pour la 1.7.10. La catégorie Cauldron a été archivée, ce type de serveur étant obsolète et plus développé. Plus d'information ici

[1.8.9] [1.9.x] Créer une table de craft compatible avec JEI et NEI
Note de ce sujet :
  • Moyenne : 4.43 (7 vote(s))
  • 1
  • 2
  • 3
  • 4
  • 5
#1
Sommaire

Introduction

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
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 :

Exclamation 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).
Exclamation 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[i];
           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  Sourire

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  Clin d'oeil
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");
Exclamation 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à  Surpris (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 Tirer la langue ), 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 (2*2, 3*3, 4*4, 5*8...), 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[i] 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[i] 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 + 1];
           Object component = null;
           character = (Character)recipeComponents[i];
           if (in instanceof Item)
           {
               component = new ItemStack((Item)recipeComponents[i + 1]);
           }
           else if (in instanceof Block)
           {
               component = new ItemStack((Block)recipeComponents[i + 1], 1, 32767);
           }
           else if (in instanceof ItemStack)
           {
               component = (ItemStack)recipeComponents[i + 1];
           }
           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  Clin d'oeil

- 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 Sourire

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[i] != null)
           {
               NBTTagCompound nbttagcompound = new NBTTagCompound();
               nbttagcompound.setInteger("Slot", i);
               this.inventory[i].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 Sourire

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;

Exclamation 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 Pleurs).
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 :

[Image: mini_72700020160629162916.png]

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 Sourire, 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  Clin d'oeil

Bonus

Crédits

Rédaction :
  • AymericRed

Correction/Améliorations :
  • MajorSquirrel pour une idée d'amélioration de la fonction transferStackInSlot du Container

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

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.
N'hésitez pas à m'envoyer des idées de tuto, je compte en faire 1 un de ces jours.

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.
Répondre
#2
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 Clin d'oeil

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.




[Image: 1467472020-midona-kawai.jpg]     [Image: 1472978280-koneko-chan2.gif]
Répondre
#3
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.
N'hésitez pas à m'envoyer des idées de tuto, je compte en faire 1 un de ces jours.

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.
Répondre
#4
Ajout NEI ? en bonus bis
Répondre
#5
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.
N'hésitez pas à m'envoyer des idées de tuto, je compte en faire 1 un de ces jours.

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.
Répondre
#6
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 Sourire
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 Sourire

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 
Répondre
#7
De rien Sourire
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.
N'hésitez pas à m'envoyer des idées de tuto, je compte en faire 1 un de ces jours.

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.
Répondre
#8
(29-06-2016, 22:22)AymericRed a écrit : De rien Sourire
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 Sourire
(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 Sourire
et pour les craft inversé je vais m'y mettre après la nouvelle table de craft en 1.7.10 Sourire 

Merci beaucoup Sourire

Ps ce tuto = 5 étoiles Sourire

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 
Répondre
#9
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.
N'hésitez pas à m'envoyer des idées de tuto, je compte en faire 1 un de ces jours.

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.
Répondre
#10
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[i];
          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 
Répondre


Atteindre :


Utilisateur(s) parcourant ce sujet : 1 visiteur(s)