Vous avez déjà créé un coffre ou une TileEntity et vous voudriez faire la même chose sous forme d’Item ? Alors suivez ce tutoriel pour savoir comment faire pour créer un backpack.
Classe de l’Item :
Tout d’abord il nous faut un item sur lequel appliquer notre container :
| package fr.scarex.tutorialmod.item; |
| |
| import net.minecraft.creativetab.CreativeTabs; |
| import net.minecraft.entity.Entity; |
| import net.minecraft.entity.player.EntityPlayer; |
| import net.minecraft.item.Item; |
| import net.minecraft.item.ItemStack; |
| import net.minecraft.world.World; |
| import cpw.mods.fml.common.registry.GameRegistry; |
| import fr.scarex.tutorialmod.TutorialMod; |
| |
| |
| |
| |
| |
| public class ItemBackPack extends Item |
| { |
| public static final String NAME = "backpack"; |
| |
| public ItemBackPack() { |
| this.setUnlocalizedName(TutorialMod.MODID + "_" + NAME); |
| this.setTextureName(TutorialMod.MODID + ":" + NAME); |
| this.setCreativeTab(CreativeTabs.tabTools); |
| this.maxStackSize = 1; |
| |
| this.register(); |
| } |
| |
| |
| |
| |
| public final void register() { |
| GameRegistry.registerItem(this, NAME); |
| } |
| |
| |
| |
| |
| @Override |
| public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) { |
| player.openGui(TutorialMod.INSTANCE, 0, world, (int) player.posX, (int) player.posY, (int) player.posZ); |
| return stack; |
| } |
| } |
Classe du Gui Handler :
Il nous faut bien sûr un Gui Handler pour gérer tout çà.
| package fr.scarex.tutorialmod; |
| |
| import net.minecraft.entity.player.EntityPlayer; |
| import net.minecraft.world.World; |
| import cpw.mods.fml.common.network.IGuiHandler; |
| import fr.scarex.tutorialmod.client.gui.inventory.GuiBackPack; |
| import fr.scarex.tutorialmod.inventory.InventoryBackPack; |
| import fr.scarex.tutorialmod.inventory.container.ContainerBackPack; |
| import fr.scarex.tutorialmod.item.ItemBackPack; |
| |
| |
| |
| |
| |
| public class CommonProxy implements IGuiHandler |
| { |
| @Override |
| public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) { |
| switch (ID) { |
| case 0: |
| |
| |
| if (player.getHeldItem() == null || !(player.getHeldItem().getItem() instanceof ItemBackPack)) return null; |
| return new ContainerBackPack(player.inventory, new InventoryBackPack(player.getHeldItem(), 54)); |
| } |
| return null; |
| } |
| |
| @Override |
| public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) { |
| switch (ID) { |
| case 0: |
| |
| |
| if (player.getHeldItem() == null || !(player.getHeldItem().getItem() instanceof ItemBackPack)) return null; |
| return new GuiBackPack(player.inventory, new InventoryBackPack(player.getHeldItem(), 54)); |
| } |
| return null; |
| } |
| } |
NOTE : ici j’utilise le common proxy comme Gui Handler, vous pouvez le mettre dans une classe à part.
Classe de l’inventaire du backpack :
Tout comme les TileEntity, il nous faut une classe implements IInventory qui stockera le contenu du sac à dos.
| package fr.scarex.tutorialmod.inventory; |
| |
| import net.minecraft.entity.player.EntityPlayer; |
| import net.minecraft.inventory.IInventory; |
| import net.minecraft.item.ItemStack; |
| import net.minecraft.nbt.NBTTagCompound; |
| import net.minecraft.nbt.NBTTagList; |
| import net.minecraftforge.common.util.Constants; |
| import fr.scarex.tutorialmod.TutorialMod; |
| import fr.scarex.tutorialmod.item.ItemBackPack; |
| |
| |
| |
| |
| |
| public class InventoryBackPack implements IInventory |
| { |
| public ItemStack[] content; |
| public int size; |
| |
| public InventoryBackPack(ItemStack container, int size) { |
| this.size = size; |
| this.content = new ItemStack; |
| if (!container.hasTagCompound()) container.setTagCompound(new NBTTagCompound()); |
| this.readFromNBT(container.getTagCompound()); |
| } |
| |
| |
| |
| |
| |
| |
| |
| public void readFromNBT(NBTTagCompound comp) { |
| NBTTagList nbtlist = comp.getTagList("Inventory", Constants.NBT.TAG_COMPOUND); |
| for (int i = 0; i < nbtlist.tagCount(); i++) { |
| NBTTagCompound comp1 = nbtlist.getCompoundTagAt(i); |
| int slot = comp1.getInteger("Slot"); |
| this.content[slot] = ItemStack.loadItemStackFromNBT(comp1); |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| public void writeToNBT(NBTTagCompound comp) { |
| NBTTagList nbtlist = new NBTTagList(); |
| |
| for (int i = 0; i < this.size; i++) { |
| if (this.content[i] != null) { |
| NBTTagCompound comp1 = new NBTTagCompound(); |
| comp1.setInteger("Slot", i); |
| this.content[i].writeToNBT(comp1); |
| nbtlist.appendTag(comp1); |
| } |
| } |
| comp.setTag("Inventory", nbtlist); |
| } |
| |
| @Override |
| public int getSizeInventory() { |
| return this.size; |
| } |
| |
| @Override |
| public ItemStack getStackInSlot(int index) { |
| return this.content[index]; |
| } |
| |
| @Override |
| public ItemStack decrStackSize(int index, int amount) { |
| ItemStack stack = getStackInSlot(index); |
| if (stack != null) { |
| if (stack.stackSize > amount) { |
| stack = stack.splitStack(amount); |
| if (stack.stackSize == 0) this.content[index] = null; |
| } else { |
| this.content[index] = null; |
| } |
| } |
| return stack; |
| } |
| |
| @Override |
| public ItemStack getStackInSlotOnClosing(int index) { |
| ItemStack stack = getStackInSlot(index); |
| if (stack != null) this.content[index] = null; |
| return stack; |
| } |
| |
| @Override |
| public void setInventorySlotContents(int index, ItemStack stack) { |
| this.content[index] = stack; |
| } |
| |
| @Override |
| public String getInventoryName() { |
| return TutorialMod.MODID + ".container.backpack"; |
| } |
| |
| @Override |
| public boolean hasCustomInventoryName() { |
| return false; |
| } |
| |
| @Override |
| public int getInventoryStackLimit() { |
| return 64; |
| } |
| |
| @Override |
| public void markDirty() {} |
| |
| @Override |
| public boolean isUseableByPlayer(EntityPlayer player) { |
| return true; |
| } |
| |
| @Override |
| public void openInventory() {} |
| |
| @Override |
| public void closeInventory() {} |
| |
| |
| |
| |
| @Override |
| public boolean isItemValidForSlot(int index, ItemStack stack) { |
| return !(stack.getItem() instanceof ItemBackPack); |
| } |
| } |
NOTE : ici j’ai décidé qu’il serait impossible de mettre des backpacks dans des backpacks. Vous pouvez toujours le modifier : il y a des commentaires à chaque endroit où les backpacks sont bloqués.
Classe du container du backpack :
Maintenant il nous faut un container pour gérer notre inventaire côté serveur.
| package fr.scarex.tutorialmod.inventory.container; |
| |
| import net.minecraft.entity.player.EntityPlayer; |
| import net.minecraft.entity.player.InventoryPlayer; |
| import net.minecraft.inventory.Container; |
| import net.minecraft.inventory.Slot; |
| import net.minecraft.item.ItemStack; |
| import net.minecraft.nbt.NBTTagCompound; |
| import fr.scarex.tutorialmod.inventory.InventoryBackPack; |
| import fr.scarex.tutorialmod.inventory.slot.SlotBackPack; |
| import fr.scarex.tutorialmod.item.ItemBackPack; |
| |
| |
| |
| |
| |
| public class ContainerBackPack extends Container |
| { |
| public InventoryBackPack invBackpack; |
| public int rows; |
| |
| public ContainerBackPack(InventoryPlayer playerInv, InventoryBackPack inv) { |
| this.invBackpack = inv; |
| this.rows = inv.getSizeInventory() / 9; |
| int i = (this.rows - 4) * 18; |
| int j; |
| int k; |
| |
| |
| for (j = 0; j < this.rows; ++j) { |
| for (k = 0; k < 9; ++k) { |
| this.addSlotToContainer(new SlotBackPack(inv, k + j * 9, 8 + k * 18, 18 + j * 18)); |
| } |
| } |
| |
| |
| for (j = 0; j < 3; ++j) { |
| for (k = 0; k < 9; ++k) { |
| this.addSlotToContainer(new Slot(playerInv, k + j * 9 + 9, 8 + k * 18, 103 + j * 18 + i)); |
| } |
| } |
| |
| for (j = 0; j < 9; ++j) { |
| this.addSlotToContainer(new Slot(playerInv, j, 8 + j * 18, 161 + i)); |
| } |
| } |
| |
| @Override |
| public boolean canInteractWith(EntityPlayer player) { |
| return true; |
| } |
| |
| public void writeToNBT(ItemStack stack) { |
| if (!stack.hasTagCompound()) stack.setTagCompound(new NBTTagCompound()); |
| invBackpack.writeToNBT(stack.getTagCompound()); |
| } |
| |
| @Override |
| public ItemStack transferStackInSlot(EntityPlayer player, int index) { |
| ItemStack itemstack = null; |
| Slot slot = (Slot) this.inventorySlots.get(index); |
| |
| if (slot != null && slot.getHasStack()) { |
| ItemStack itemstack1 = slot.getStack(); |
| itemstack = itemstack1.copy(); |
| |
| |
| |
| if (itemstack.getItem() instanceof ItemBackPack) return null; |
| |
| if (index < this.invBackpack.getSizeInventory()) { |
| if (!this.mergeItemStack(itemstack1, this.invBackpack.getSizeInventory(), this.inventorySlots.size(), true)) return null; |
| } else if (!this.mergeItemStack(itemstack1, 0, this.invBackpack.getSizeInventory(), false)) { return null; } |
| |
| if (itemstack1.stackSize == 0) |
| slot.putStack((ItemStack) null); |
| else |
| slot.onSlotChanged(); |
| } |
| |
| return itemstack; |
| } |
| |
| |
| |
| |
| |
| |
| |
| @Override |
| public ItemStack slotClick(int slotIndex, int buttonPressed, int flag, EntityPlayer player) { |
| |
| if (flag == 2 && buttonPressed == player.inventory.currentItem) return null; |
| if (slotIndex - this.invBackpack.getSizeInventory() - 27 == player.inventory.currentItem) return null; |
| return super.slotClick(slotIndex, buttonPressed, flag, player); |
| } |
| |
| |
| |
| |
| @Override |
| public void onContainerClosed(EntityPlayer player) { |
| this.writeToNBT(player.getHeldItem()); |
| super.onContainerClosed(player); |
| } |
| } |
Classe du slot du backpack :
Ici j’utilise un slot custom pour éviter que les joueurs mettent des backpacks dans des backpack. Comme dit avant, vous pouvez utiliser un slot normal si vous voulez que le joueur puisse mettre des backpacks dans des backpacks.
| package fr.scarex.tutorialmod.inventory.slot; |
| |
| import net.minecraft.inventory.IInventory; |
| import net.minecraft.inventory.Slot; |
| import net.minecraft.item.ItemStack; |
| import fr.scarex.tutorialmod.item.ItemBackPack; |
| |
| |
| |
| |
| |
| public class SlotBackPack extends Slot |
| { |
| public SlotBackPack(IInventory inv, int index, int x, int y) { |
| super(inv, index, x, y); |
| } |
| |
| |
| |
| |
| @Override |
| public boolean isItemValid(ItemStack stack) { |
| return !(stack.getItem() instanceof ItemBackPack); |
| } |
| } |
Classe du GUI :
Et nous voici à la dernière classe de ce tutoriel : le GUI. Dans cette classe j’ai décidé d’utiliser la texture utilisée par Minecraft et j’ai aussi décidé de mettre une taille custom pour l’inventaire, comme çà si vous voulez utiliser plus ou moins de slot (par exemple selon les metadatas d’un Item pour avoir des sac à dos plus ou moins grands), il vous suffira juste de changer les 2 valeurs dans le GuiHandler.
NOTE : il faut changer LES 2 VALEURS, sinon vous aurez de grande chances de crasher.
| package fr.scarex.tutorialmod.client.gui.inventory; |
| |
| import net.minecraft.client.gui.inventory.GuiContainer; |
| import net.minecraft.client.resources.I18n; |
| import net.minecraft.entity.player.InventoryPlayer; |
| import net.minecraft.util.ResourceLocation; |
| |
| import org.lwjgl.opengl.GL11; |
| |
| import fr.scarex.tutorialmod.inventory.InventoryBackPack; |
| import fr.scarex.tutorialmod.inventory.container.ContainerBackPack; |
| |
| |
| |
| |
| |
| public class GuiBackPack extends GuiContainer |
| { |
| public static final ResourceLocation texture = new ResourceLocation("textures/gui/container/generic_54.png"); |
| protected InventoryBackPack inv; |
| protected InventoryPlayer playerInv; |
| public int rows; |
| |
| public GuiBackPack(InventoryPlayer playerInv, InventoryBackPack inv) { |
| super(new ContainerBackPack(playerInv, inv)); |
| this.playerInv = playerInv; |
| this.inv = inv; |
| this.allowUserInput = false; |
| |
| this.rows = inv.getSizeInventory() / 9; |
| |
| this.ySize = 114 + this.rows * 18; |
| } |
| |
| @Override |
| protected void drawGuiContainerForegroundLayer(int x, int y) { |
| this.fontRendererObj.drawString(I18n.format(this.inv.getInventoryName(), new Object[0]), 8, 6, 4210752); |
| this.fontRendererObj.drawString(this.playerInv.hasCustomInventoryName() ? this.playerInv.getInventoryName() : I18n.format(this.playerInv.getInventoryName(), new Object[0]), 8, this.ySize - 96 + 2, 4210752); |
| } |
| |
| @Override |
| protected void drawGuiContainerBackgroundLayer(float prt, 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.rows * 18 + 17); |
| |
| this.drawTexturedModalRect(k, l + this.rows * 18 + 17, 0, 126, this.xSize, 96); |
| } |
| } |
Vous aimeriez que vos utilisateurs puissent utiliser Inventory Tweaks avec votre sac à dos ? C’est tout simple :
- Ajoutez Inventory Tweaks à votre build path
- Rajoutez l’annotation @ChestContainer au-dessus de votre container comme ceci :
| package fr.scarex.tutorialmod.inventory.container; |
| |
| import invtweaks.api.container.ChestContainer; |
| import net.minecraft.entity.player.EntityPlayer; |
| import net.minecraft.entity.player.InventoryPlayer; |
| import net.minecraft.inventory.Container; |
| import net.minecraft.inventory.Slot; |
| import net.minecraft.item.ItemStack; |
| import net.minecraft.nbt.NBTTagCompound; |
| import fr.scarex.tutorialmod.inventory.InventoryBackPack; |
| import fr.scarex.tutorialmod.inventory.slot.SlotBackPack; |
| import fr.scarex.tutorialmod.item.ItemBackPack; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| @ChestContainer(isLargeChest = false) |
| public class ContainerBackPack extends Container |
| { |
| public InventoryBackPack invBackpack; |
| public int rows; |
| |
| public ContainerBackPack(InventoryPlayer playerInv, InventoryBackPack inv) { |
| this.invBackpack = inv; |
| this.rows = inv.getSizeInventory() / 9; |
| int i = (this.rows - 4) * 18; |
| int j; |
| int k; |
| |
| |
| for (j = 0; j < this.rows; ++j) { |
| for (k = 0; k < 9; ++k) { |
| this.addSlotToContainer(new SlotBackPack(inv, k + j * 9, 8 + k * 18, 18 + j * 18)); |
| } |
| } |
| |
| |
| for (j = 0; j < 3; ++j) { |
| for (k = 0; k < 9; ++k) { |
| this.addSlotToContainer(new Slot(playerInv, k + j * 9 + 9, 8 + k * 18, 103 + j * 18 + i)); |
| } |
| } |
| |
| for (j = 0; j < 9; ++j) { |
| this.addSlotToContainer(new Slot(playerInv, j, 8 + j * 18, 161 + i)); |
| } |
| } |
| |
| @Override |
| public boolean canInteractWith(EntityPlayer player) { |
| return true; |
| } |
| |
| public void writeToNBT(ItemStack stack) { |
| if (!stack.hasTagCompound()) stack.setTagCompound(new NBTTagCompound()); |
| invBackpack.writeToNBT(stack.getTagCompound()); |
| } |
| |
| @Override |
| public ItemStack transferStackInSlot(EntityPlayer player, int index) { |
| ItemStack itemstack = null; |
| Slot slot = (Slot) this.inventorySlots.get(index); |
| |
| if (slot != null && slot.getHasStack()) { |
| ItemStack itemstack1 = slot.getStack(); |
| itemstack = itemstack1.copy(); |
| |
| |
| |
| if (itemstack.getItem() instanceof ItemBackPack) return null; |
| |
| if (index < this.invBackpack.getSizeInventory()) { |
| if (!this.mergeItemStack(itemstack1, this.invBackpack.getSizeInventory(), this.inventorySlots.size(), true)) return null; |
| } else if (!this.mergeItemStack(itemstack1, 0, this.invBackpack.getSizeInventory(), false)) { return null; } |
| |
| if (itemstack1.stackSize == 0) |
| slot.putStack((ItemStack) null); |
| else |
| slot.onSlotChanged(); |
| } |
| |
| return itemstack; |
| } |
| |
| |
| |
| |
| |
| |
| |
| @Override |
| public ItemStack slotClick(int slotIndex, int buttonPressed, int flag, EntityPlayer player) { |
| |
| if (flag == 2 && buttonPressed == player.inventory.currentItem) return null; |
| if (slotIndex - this.invBackpack.getSizeInventory() - 27 == player.inventory.currentItem) return null; |
| return super.slotClick(slotIndex, buttonPressed, flag, player); |
| } |
| |
| |
| |
| |
| @Override |
| public void onContainerClosed(EntityPlayer player) { |
| this.writeToNBT(player.getHeldItem()); |
| super.onContainerClosed(player); |
| } |
| } |
- Modifiez la valeur isLarge à true si vous voulez que les boutons soient placés sur le côté droit.

Avec InventoryTweaks :

Voir sur github :
Rédaction :
Correction :
Textures :
- Faithful pack (FTB) pour la texture du sac à dos modifiée

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
Retour vers le sommaire des tutoriels