Attention : Ce tutoriel comporte des erreurs, il reste cependant fonctionnel, la machine que vous créerai fonctionnera. Pour un tutoriel de meilleur qualité veuillez changer de version et vous référer aux tutoriels des versions supérieurs.
Dans ce tutoriel nous allons apprendre à faire un bloc ressemblant au four (inputs -> outputs). Le bloc possèdera sa classe, un TileEntity, un Container et nous complèterons cela par une classe contenant les différentes recettes que réalisera le bloc.
Je n’est pas besoin de rappeler qu’il faut importer (Ctrl + Maj + O) et si vous avez le choix entre plusieurs imports, choisissez toujours ceux commençants par net.minecraft puis ceux commençants par java.util.
La classe principale
Tout d’abord, déclarez votre bloc dans votre classe principale avec tous vos autres blocs :
public static Block machineTuto;
Puis instanciez-le dans la méthode pre-init :
| @EventHandler |
| public void preInit(FMLPreInitializationEvent event) |
| machineTuto = new MachineTuto().setBlockName("machineTuto"); |
| |
| GameRegistry.registerBlock(machineTuto, "machineTuto"); |
Vous avez une erreur sur la classe MachineTuto(), créez-la.
La classe du bloc
La classe de votre bloc devrait être extends BlockContainer, si ce n’est pas le cas, faites-le. Créez aussi le constructeur de la classe :
| public MachineTuto() |
| { |
| super(Material.rock); |
| this.setResistance(8.0F); |
| this.setHarvestLevel("pickaxe", 2); |
| this.setBlockTextureName(ModTutoriel.MODID + ":nom_de_la_texture"); |
| |
| } |
Maintenant nous allons nous attaquer au TileEntity du bloc, il faut d’abord dire que le bloc possède un TileEntity :
| @Override |
| public TileEntity createNewTileEntity(World world, int metadata) |
| { |
| return new TileEntityMachineTuto(); |
| } |
| |
| @Override |
| public boolean hasTileEntity(int metadata) |
| { |
| return true; |
| } |
Il y a une erreur sur la classe TileEntityMachineTuto(), créez-la on y revient dans pas longtemps.
Et ajoutons aussi la méthode qui permet de loot les objets contenus dans le bloc sur le sol (j’ai repris la méthode de minecraft):
| public void breakBlock(World world, int x, int y, int z, Block block, int metadata) |
| { |
| TileEntity tileentity = world.getTileEntity(x, y, z); |
| |
| if (tileentity instanceof IInventory) |
| { |
| IInventory inv = (IInventory)tileentity; |
| for (int i1 = 0; i1 < inv.getSizeInventory(); ++i1) |
| { |
| ItemStack itemstack = inv.getStackInSlot(i1); |
| |
| if (itemstack != null) |
| { |
| float f = world.rand.nextFloat() * 0.8F + 0.1F; |
| float f1 = world.rand.nextFloat() * 0.8F + 0.1F; |
| EntityItem entityitem; |
| |
| for (float f2 = world.rand.nextFloat() * 0.8F + 0.1F; itemstack.stackSize > 0; world.spawnEntityInWorld(entityitem)) |
| { |
| int j1 = world.rand.nextInt(21) + 10; |
| |
| if (j1 > itemstack.stackSize) |
| { |
| j1 = itemstack.stackSize; |
| } |
| |
| itemstack.stackSize -= j1; |
| entityitem = new EntityItem(world, (double)((float)x + f), (double)((float)y + f1), (double)((float)z + f2), new ItemStack(itemstack.getItem(), j1, itemstack.getItemDamage())); |
| float f3 = 0.05F; |
| entityitem.motionX = (double)((float)world.rand.nextGaussian() * f3); |
| entityitem.motionY = (double)((float)world.rand.nextGaussian() * f3 + 0.2F); |
| entityitem.motionZ = (double)((float)world.rand.nextGaussian() * f3); |
| |
| if (itemstack.hasTagCompound()) |
| { |
| entityitem.getEntityItem().setTagCompound((NBTTagCompound)itemstack.getTagCompound().copy()); |
| } |
| } |
| } |
| } |
| |
| world.func_147453_f(x, y, z, block); |
| } |
| |
| super.breakBlock(world, x, y, z, block, metadata); |
| } |
La classe du TileEntity
Nous allons coder la classe la plus longue de ce tutoriel, alors prenez-vous un bon café et c’est partie !
Je ne vais pas détailler toute les fonctions car la plupart sont expliquées dans le tutoriel de robin sur les TileEntity.
Nous allons faire un bloc qui aura trois slots d’input et un slot d’output, cela fait en tout quatre slots pour notre bloc.
Implémentez d’abord IIventory à TileEntityMachineTuto, n’implémentez cependant pas les méthodes, nous allons le faire manuellement au fur et à mesure.
Instancions d’abord nos ItemStack correspondants à nos slots :
private ItemStack[] contents = new ItemStack[4];
Nous allons aussi tout de suite déclarer deux int qui correspondent au temps de “cuisson” déjà atteint et au temps de “cuisson” nécessaire pour finir la recette :
| private int workingTime = 0; |
| private int workingTimeNeeded = 200; |
Ces deux valeurs doivent être écrites dans le NBT ainsi que notre tableau d’ItemStack :
| @Override |
| public void writeToNBT(NBTTagCompound compound) |
| { |
| super.writeToNBT(compound); |
| NBTTagList nbttaglist = new NBTTagList(); |
| |
| for (int i = 0; i < this.contents.length; ++i) |
| { |
| if (this.contents[i] != null) |
| { |
| NBTTagCompound nbttagcompound1 = new NBTTagCompound(); |
| nbttagcompound1.setByte("Slot", (byte)i); |
| this.contents[i].writeToNBT(nbttagcompound1); |
| nbttaglist.appendTag(nbttagcompound1); |
| } |
| } |
| |
| compound.setTag("Items", nbttaglist); |
| compound.setShort("workingTime",(short)this.workingTime); |
| compound.setShort("workingTimeNeeded", (short)this.workingTimeNeeded); |
| } |
Et la méthode pour les lire :
| @Override |
| public void readFromNBT(NBTTagCompound compound) |
| { |
| super.readFromNBT(compound); |
| |
| NBTTagList nbttaglist = compound.getTagList("Items", 10); |
| this.contents = new ItemStack[this.getSizeInventory()]; |
| |
| for (int i = 0; i < nbttaglist.tagCount(); ++i) |
| { |
| NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i); |
| int j = nbttagcompound1.getByte("Slot") & 255; |
| |
| if (j >= 0 && j < this.contents.length) |
| { |
| this.contents[j] = ItemStack.loadItemStackFromNBT(nbttagcompound1); |
| } |
| } |
| |
| this.workingTime = compound.getShort("workingTime"); |
| this.workingTimeNeeded = compound.getShort("workingTimeNeeded"); |
| } |
Voilà deux grosses méthodes de faites, on s’arrête pas, on passe aux autres :
| @Override |
| public int getSizeInventory() { |
| return this.contents.length; |
| } |
| @Override |
| public ItemStack getStackInSlot(int slotIndex) { |
| return this.contents[slotIndex]; |
| } |
| @Override |
| public ItemStack decrStackSize(int slotIndex, int amount) { |
| if (this.contents[slotIndex] != null) |
| { |
| ItemStack itemstack; |
| |
| if (this.contents[slotIndex].stackSize <= amount) |
| { |
| itemstack = this.contents[slotIndex]; |
| this.contents[slotIndex] = null; |
| this.markDirty(); |
| return itemstack; |
| } |
| else |
| { |
| itemstack = this.contents[slotIndex].splitStack(amount); |
| |
| if (this.contents[slotIndex].stackSize == 0) |
| { |
| this.contents[slotIndex] = null; |
| } |
| |
| this.markDirty(); |
| return itemstack; |
| } |
| } |
| else |
| { |
| return null; |
| } |
| } |
| |
| @Override |
| public ItemStack getStackInSlotOnClosing(int slotIndex) { |
| if (this.contents[slotIndex] != null) |
| { |
| ItemStack itemstack = this.contents[slotIndex]; |
| this.contents[slotIndex] = null; |
| return itemstack; |
| } |
| else |
| { |
| return null; |
| } |
| } |
| |
| @Override |
| public void setInventorySlotContents(int slotIndex, ItemStack stack) { |
| this.contents[slotIndex] = stack; |
| |
| if (stack != null && stack.stackSize > this.getInventoryStackLimit()) |
| { |
| stack.stackSize = this.getInventoryStackLimit(); |
| } |
| |
| this.markDirty(); |
| } |
| |
| @Override |
| public String getInventoryName() { |
| return "tile.machineTuto"; |
| } |
| |
| @Override |
| public boolean hasCustomInventoryName() { |
| return false; |
| } |
| |
| @Override |
| public int getInventoryStackLimit() { |
| return 64; |
| } |
| |
| @Override |
| public boolean isUseableByPlayer(EntityPlayer player) { |
| return this.worldObj.getTileEntity(this.xCoord, this.yCoord, this.zCoord) != this ? false : player.getDistanceSq((double)this.xCoord + 0.5D, (double)this.yCoord + 0.5D, (double)this.zCoord + 0.5D) <= 64.0D; |
| } |
| |
| @Override |
| public void openInventory() { |
| |
| } |
| |
| @Override |
| public void closeInventory() { |
| |
| } |
| |
| @Override |
| public boolean isItemValidForSlot(int slot, ItemStack stack) { |
| return slot == 3 ? false : true; |
| } |
Voilà, référez-vous encore une fois au tutoriel de robin pour la partie ci-dessus.
Maintenant nous allons voir les méthodes propres à l’aspect machine du bloc.
Cette méthode renvoie true si la recette est en train de procéder et false si ce n’est pas le cas.
| public boolean isBurning() |
| { |
| return this.workingTime > 0; |
| } |
Cette méthode vérifie si les trois slots d’inputs ne sont pas vides, si les trois items forment une recette et si le slot d’output n’est pas plein et que l’item étant à l’intérieur n’est pas différent de celui que l’on veut créer. Retourne true si on peut lancer le processus de recette et false si on ne peut pas.
| private boolean canSmelt() |
| { |
| if (this.contents[0] == null || this.contents[1] == null || this.contents[2] == null) |
| { |
| return false; |
| } |
| else |
| { |
| ItemStack itemstack = MachineTutoRecipes.smelting().getSmeltingResult(new ItemStack[]{this.contents[0], this.contents[1], this.contents[2]}); |
| if (itemstack == null) return false; |
| if (this.contents[3] == null) return true; |
| if (!this.contents[3].isItemEqual(itemstack)) return false; |
| int result = contents[3].stackSize + itemstack.stackSize; |
| return result <= getInventoryStackLimit() && result <= this.contents[3].getMaxStackSize(); |
| } |
| } |
La méthode suivante est simple à comprendre, vous allez voir :
| public void updateEntity() |
| { |
| if(this.isBurning() && this.canSmelt()) |
| { |
| ++this.workingTime; |
| } |
| if(this.canSmelt() && !this.isBurning()) |
| { |
| this.workingTime = 1; |
| } |
| if(this.canSmelt() && this.workingTime == this.workingTimeNeeded) |
| { |
| this.smeltItem(); |
| this.workingTime = 0; |
| } |
| if(!this.canSmelt()) |
| { |
| this.workingTime= 0; |
| } |
| } |
La méthode suivante est celle qui “cuit” les items, vous aurez des erreurs car on utilise la classe qu’on crée juste après :
| public void smeltItem() |
| { |
| if (this.canSmelt()) |
| { |
| ItemStack itemstack = MachineTutoRecipes.smelting().getSmeltingResult(new ItemStack[]{this.contents[0], this.contents[1], this.contents[2]}); |
| if (this.contents[3] == null) |
| { |
| this.contents[3] = itemstack.copy(); |
| } |
| else if (this.contents[3].getItem() == itemstack.getItem()) |
| { |
| this.contents[3].stackSize += itemstack.stackSize; |
| } |
| |
| --this.contents[0].stackSize; |
| --this.contents[1].stackSize; |
| --this.contents[2].stackSize; |
| |
| if (this.contents[0].stackSize <= 0) |
| { |
| this.contents[0] = null; |
| } |
| if (this.contents[1].stackSize <= 0) |
| { |
| this.contents[1] = null; |
| } |
| if (this.contents[2].stackSize <= 0) |
| { |
| this.contents[2] = null; |
| } |
| } |
| } |
Voilà pour le TileEntity ! Pas trop long ? On passe aux recettes.
La classe des recettes
Créez cette classe une laissant votre souris sur MachineTutoRecipes() et en cliquant sur create class.
Votre classe n’aura pas d’extends ni d’implémentation.
En tout premier lieu, instanciez deux objets :
| private static final MachineTutoRecipes smeltingBase = new MachineTutoRecipes(); |
| private Map smeltingList = new HashMap(); |
Mettons en place notre constructeur dans lequel nous mettrons nos recettes :
| public MachineTutoRecipes() |
| { |
| this.addRecipe(Items.apple, Items.apple, Items.arrow, new ItemStack(Blocks.diamond_block)); |
| } |
Il y a une erreur sur la fonction addRecipe, ne vous inquiétez pas, il suffit de la créer. Cependant ici il faut faire un choix : quel genre d’items pourront apparaîtrent dans vos recettes ? Que des blocs ? Que des items ? Les deux ? Les deux évidemment il faut alors faire plusieurs versions de la fonction addRecipe(), je prends en compte que dans mon exemple il y a trois slots d’inputs, il y a donc 4 cas possibles :
- Trois items
- Un bloc et deux items
- Deux blocs et un item
- Trois blocsLors de mes recettes, si elles comprennent des blocs, je mettrai ces derniers dans les slots 0 puis 1 puis 2.
Ce qui m’amène à ces fonctions :
| public void addRecipe(ItemStack stack1, ItemStack stack2, ItemStack stack3, ItemStack stack4) |
| { |
| ItemStack[] stackList = new ItemStack[]{stack1, stack2, stack3}; |
| this.smeltingList.put(stackList, stack4); |
| } |
| |
| public void addRecipe(Item item1, Item item2, Item item3, ItemStack stack) |
| { |
| this.addRecipe(new ItemStack(item1), new ItemStack(item2), new ItemStack(item3), stack); |
| } |
| |
| public void addRecipe(Block block1, Item item2, Item item3, ItemStack stack) |
| { |
| this.addRecipe(Item.getItemFromBlock(block1), item2, item3, stack); |
| } |
| |
| public void addRecipe(Block block1, Block block2, Item item3, ItemStack stack) |
| { |
| this.addRecipe(Item.getItemFromBlock(block1), Item.getItemFromBlock(block2), item3, stack); |
| } |
| |
| public void addRecipe(Block block1, Block block2, Block block3, ItemStack stack) |
| { |
| this.addRecipe(Item.getItemFromBlock(block1), Item.getItemFromBlock(block2), Item.getItemFromBlock(block3), stack); |
| } |
Chaque fonction est très simple à comprendre, cela ne devrai pas vous poser de problèmes.
Maintenant une fonction qui permet d’avoir le résultat d’une recette :
| public ItemStack getSmeltingResult(ItemStack[] stack) |
| { |
| Iterator iterator = this.smeltingList.entrySet().iterator(); |
| Entry entry; |
| |
| do |
| { |
| if (!iterator.hasNext()) |
| { |
| return null; |
| } |
| entry = (Entry)iterator.next(); |
| } |
| while (!this.isSameKey(stack, (ItemStack[])entry.getKey())); |
| |
| return (ItemStack)entry.getValue(); |
| } |
Cette fonction compare les items des slots avec ceux de la recette :
| private boolean isSameKey(ItemStack[] stackList, ItemStack[] stackList2) |
| { |
| boolean isSame = false; |
| for(int i=0; i<=2; i++) |
| { |
| if(stackList[i].getItem() == stackList2[i].getItem()) |
| { |
| isSame = true; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| return isSame; |
| } |
Deux fonctions qui permettent : d’avoir la liste des recettes et d’avoir l’instance de la classe MachineTutoRecipes
| public Map getSmeltingList() |
| { |
| return this.smeltingList; |
| } |
| |
| public static MachineTutoRecipes smelting() |
| { |
| return smeltingBase; |
| } |
S’en est fini de la classe pour les recettes, il vous suffit maintenant de rajouter autant de recettes que vous le voulez dans le constructeur.
La classe du container
Créez un nouvelle classe ContainerMachineTuto extends Container
| public class ContainerMachineTuto extends Container { |
| |
| } |
Déclarez un objet de type TileEntityMachineTuto mais ne l’instanciez pas :
private TileEntityMachineTuto tileMachineTuto;
Et ajoutez les slots via le constructeur :
| public ContainerMachineTuto(TileEntityMachineTuto tile, InventoryPlayer inventory) |
| { |
| this.tileMachineTuto = tile; |
| this.addSlotToContainer(new Slot(tile, 0, 49, 75)); |
| this.addSlotToContainer(new Slot(tile, 1, 89, 75)); |
| this.addSlotToContainer(new Slot(tile, 2, 129, 75)); |
| this.addSlotToContainer(new SlotResult(tile, 3, 89, 135)); |
| this.bindPlayerInventory(inventory); |
| } |
Les fonctions vues dans le tutoriel de robin (modifiées pour l’alignement) :
| @Override |
| public boolean canInteractWith(EntityPlayer player) { |
| return this.tileMachineTuto.isUseableByPlayer(player); |
| } |
| |
| private void bindPlayerInventory(InventoryPlayer inventory) |
| { |
| int i; |
| for (i = 0; i < 3; ++i) |
| { |
| for (int j = 0; j < 9; ++j) |
| { |
| this.addSlotToContainer(new Slot(inventory, j + i * 9 + 9, 17 + j * 18, 171 + i * 18)); |
| } |
| } |
| |
| for (i = 0; i < 9; ++i) |
| { |
| this.addSlotToContainer(new Slot(inventory, i, 17 + i * 18, 229)); |
| } |
| } |
| |
| public ItemStack transferStackInSlot(EntityPlayer player, int quantity) |
| { |
| ItemStack itemstack = null; |
| Slot slot = (Slot)this.inventorySlots.get(quantity); |
| |
| if (slot != null && slot.getHasStack()) |
| { |
| ItemStack itemstack1 = slot.getStack(); |
| itemstack = itemstack1.copy(); |
| |
| if (quantity < this.tileMachineTuto.getSizeInventory()) |
| { |
| if (!this.mergeItemStack(itemstack1, this.tileMachineTuto.getSizeInventory(), this.inventorySlots.size(), true)) |
| { |
| return null; |
| } |
| } |
| else if (!this.mergeItemStack(itemstack1, 0, this.tileMachineTuto.getSizeInventory(), false)) |
| { |
| return null; |
| } |
| |
| if (itemstack1.stackSize == 0) |
| { |
| slot.putStack((ItemStack)null); |
| } |
| else |
| { |
| slot.onSlotChanged(); |
| } |
| } |
| |
| return itemstack; |
| } |
| |
| public void onContainerClosed(EntityPlayer player) |
| { |
| super.onContainerClosed(player); |
| this.tileMachineTuto.closeInventory(); |
| } |
La classe du SlotResult
Créez une classe SlotResult extends Slot.
Voici la classe du slot d’output, le but étant que on ne puisse pas y mettre d’items manuellement :
| public class SlotResult extends Slot { |
| |
| public SlotResult(IInventory inventory, int id, int x, int y) |
| { |
| super(inventory, id, x, y); |
| } |
| |
| @Override |
| public boolean isItemValid(ItemStack stack) |
| { |
| return false; |
| } |
| |
| public ItemStack decrStackSize(int amount) |
| { |
| return super.decrStackSize(amount); |
| } |
| |
| public void onPickupFromSlot(EntityPlayer player, ItemStack stack) |
| { |
| super.onCrafting(stack); |
| super.onPickupFromSlot(player, stack); |
| } |
| } |
Passons à la dernière classe.
La classe du GUI
Créez une classe GuiMachineTuto extends GuiContainer.
Voici la classe du GUI :
| public class GuiMachineTuto extends GuiContainer { |
| |
| private static final ResourceLocation texture = new ResourceLocation(ModTutoriel.MODID,"textures/gui/container/guiMachineTuto.png"); |
| @SuppressWarnings("unused") |
| private TileEntityMachineTuto tileMachineTuto; |
| private IInventory playerInv; |
| |
| public GuiMachineTuto(TileEntityMachineTuto tile, InventoryPlayer inventory) |
| { |
| super(new ContainerMachineTuto(tile, inventory)); |
| this.tileMachineTuto = tile; |
| this.playerInv = inventory; |
| this.allowUserInput = false; |
| this.ySize = 256; |
| this.xSize = 256; |
| } |
| |
| @Override |
| protected void drawGuiContainerBackgroundLayer(float partialRenderTick, int x, int y) |
| { |
| |
| GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); |
| this.mc.getTextureManager().bindTexture(texture); |
| int k = (this.width - this.xSize) / 2; |
| int l = (this.height - this.ySize) / 2; |
| this.drawTexturedModalRect(k, l, 0, 0, this.xSize, this.ySize); |
| this.drawTexturedModalRect(0, 0, 176, 14, 100 + 1, 16); |
| |
| } |
| |
| protected void drawGuiContainerForegroundLayer(int x, int y) |
| { |
| this.fontRendererObj.drawString(this.playerInv.hasCustomInventoryName() ? this.playerInv.getInventoryName() : I18n.format(this.playerInv.getInventoryName()), 10, this.ySize - 98, 4210752); |
| } |
| |
| } |
Voici la texture du GUI :

Ajoutez dans la classe du bloc :
| public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float hitx, float hity, float hitz) |
| { |
| if (world.isRemote) |
| { |
| return true; |
| } |
| else |
| { |
| player.openGui(ModTutoriel.instance, 0, world, x, y, z); |
| return true; |
| } |
| } |
N’oubliez pas de gérer le guiHandler et d’enregistrer votre TileEntityMachineTuto dans la classe principale :
GameRegistry.registerTileEntity(TileEntityMachineTuto.class, "ModTutoriel:MachineTutoTileEntity");
Je suis passé vite sur le container et le gui car ce n’est pas tout à fait le sujet du tutoriel.
Il y aura plusieurs choses dans ce bonus, je les posterais au fur et à mesure. Commençons tout de suite par la première :
1.Afficher une barre de progression de la recette (merci à Martin67370 pour sa participation)
Ceci est très simple, dans la texture de votre gui dessinez la barre de progression en entière mais de façon à ce qu’elle ne soit pas affiché lorsque l’on ouvre le GUI. Dans notre exemple cela pourrais donner ceci :

Ensuite retournez dans la classe GuiMachineTuto et dans la fonction drawGuiContainerBackgroundLayout(…) ajoutez :
| if(this.tileMachineTuto.isBurning()) |
| { |
| int i = this.tileMachineTuto.getCookProgress(); |
| this.drawTexturedModalRect(x, y, u, v, width, height) |
| } |
Elle devrait ressembler à ça :
| @Override |
| protected void drawGuiContainerBackgroundLayer(float partialRenderTick, int x, int y) |
| { |
| |
| GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); |
| this.mc.getTextureManager().bindTexture(texture); |
| int k = (this.width - this.xSize) / 2; |
| int l = (this.height - this.ySize) / 2; |
| this.drawTexturedModalRect(k, l, 0, 46, this.xSize, this.ySize); |
| |
| if(this.tileCompressor.isBurning()) |
| { |
| int i = this.tileCompressor.getCookProgress(); |
| this.drawTexturedModalRect(k + 47, l + 46, 0, 2, 100, i); |
| } |
| } |
Examinons cette fonction :
x correspond à la coordonnée x du gui (in-game) où s’affichera la texture de la barre de progression.
y correspond à la coordonnée y du gui (in-game) où s’affichera la texture de la barre de progression.
u correspond à la position x de votre barre de progression sur votre texture (dans les ressources, l’image .png).
v correspond à la position y de votre barre de progression sur votre texture (dans les ressources, l’image .png).
width correspond à la largeur du morceau de texture que vous voulez afficher.
height correspond à la hauteur du morceau de texture que vous voulez afficher.
La fonction pour notre texture sera donc :
this.drawTexturedModalRect(k + 47, l + 46, 0, 2, 100, i)
Dans le constructeur changez les valeur ySize et xSize :
| this.ySize = 207; |
| this.xSize = 195; |
Donc votre classe TileEntityMachineTuto rajoutez la fonction :
| @SideOnly(Side.CLIENT) |
| public int getCookProgress() |
| { |
| return this.workingTime * 41 / this.workingTimeNeeded |
| } |
Expliquation de cette fonction, elle retourne un nombre entre 0 et 41 suivant le temps de cuisson actuel. Il faut le voir comme un tableau de proportionnalité :
Quantité de texture affichée : x | 41 (toute le texture)
Temps de cuisson : this.workingTime | this.workingTimeNeeded
Pour trouver x il faut faire l’opération suivante : 41 * this.workingTime / this.workingTimeNeeded
Ceci étant fait vous devriez obtenir cela après ré-ajustement de l’emplacement des slots de la classe du container :


Voir le commit sur GitHub