Créer un item container (type backpack / sac à dos)
-
Sommaire
Introduction
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.
Pré-requis
- Savoir créer un item
- Savoir faire une TileEntity (facultatif mais aide à la compréhension)
- Savoir créer un GUI et un container (vidéo youtube)
Code
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; /** * @author SCAREX * */ 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; // N'oubliez pas ceci, çà empêche l'item d'être stackable this.register(); } /** * Used to add the item to the game registry */ public final void register() { GameRegistry.registerItem(this, NAME); } /** * Used to open the gui */ @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; /** * @author SCAREX * */ 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: // The last parameter must be a multiple of 9 (e.g: 9, 18, 27, 54) // Condition to check if the player has the right item in hand 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: // The last parameter must be a multiple of 9 (e.g: 9, 18, 27, 54) // Condition to check if the player has the right item in hand 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; /** * @author SCAREX * */ 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()); } /** * This methods reads the content of the NBTTagCompound inside the container * * @param comp * the container NBTTagCompound */ 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); } } /** * This methods saves the content inside the container * * @param comp * the NBTTagCompound to write in */ 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() {} /** * Prevents backpack-ception */ @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; /** * @author SCAREX * */ 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; // Adding slots to the backpack 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)); } } // Adding player's slots 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(); // Prevents backpack-ception (backpack inside backpack) with // shift-click 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; } /** * @param buttonPressed * left click, right click, wheel click, etc. * @param flag * category (e.g.: hotbar keys) */ @Override public ItemStack slotClick(int slotIndex, int buttonPressed, int flag, EntityPlayer player) { // Prevents from removing current backpack 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); } /** * Used to save content */ @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; /** * @author SCAREX * */ public class SlotBackPack extends Slot { public SlotBackPack(IInventory inv, int index, int x, int y) { super(inv, index, x, y); } /** * Method used to prevent backpack-ception (backpacks inside backpacks) */ @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; /** * @author SCAREX * */ 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; // Calculate the number of rows this.rows = inv.getSizeInventory() / 9; // Height of the GUI using the number of rows 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); // Centering GUI int k = (this.width - this.xSize) / 2; int l = (this.height - this.ySize) / 2; // Drawing the first part of the GUI (slots of the backpack) this.drawTexturedModalRect(k, l, 0, 0, this.xSize, this.rows * 18 + 17); // And after the slots from the player's inventory this.drawTexturedModalRect(k, l + this.rows * 18 + 17, 0, 126, this.xSize, 96); } }
Bonus
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; /** * @author SCAREX * * @ChestContainer InventoryTweaks API implementation * * isLargeChest indicates whether the buttons should be placed at the top of the gui or on the right. */ @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; // Adding slots to the backpack 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)); } } // Adding player's slots 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(); // Prevents backpack-ception (backpack inside backpack) with // shift-click 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; } /** * @param buttonPressed * left click, right click, wheel click, etc. * @param flag * category (e.g.: hotbar keys) */ @Override public ItemStack slotClick(int slotIndex, int buttonPressed, int flag, EntityPlayer player) { // Prevents from removing current backpack 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); } /** * Used to save content */ @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.
Résultat
Avec InventoryTweaks :
Voir sur github :
Crédits
Rédaction :
- SCAREX
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 -
Merci pour se nouveau tutoriel. je m’empresse de le faire
-
Tuto parfait! Exactement ce que je cherchai.
-
Je pense rajouter en bonus comment faire pour intégrer Inventory Tweaks au container. Malheureusement, j’ai quelques problèmes avec Inventory tweaks.Bonus rajouté : implémentation d’InventoryTweaks
-
Au top merci beaucoup Scarex, j’ai même réussie à faire ce sac en 1.8 avec quelque fonction en plus (rien de très méchant).
Petit astuce pas vraiment mentionnée ici, de une, oui c’est bien les deux valeurs 54 qu’il faut modifier dans le GuiHandler pour changer les slots (parait logique mais bon):
return new GuiBackPack(player.inventory, new InventoryBackPack(player.getHeldItem(), 54));
Et finalement, pour enregistrer votre GuiHandler il faut utiliser ça (à l’intérieur de FMLInitializationEvent):
NetworkRegistry.INSTANCE.registerGuiHandler(instance, new EmotionGuiHandler());
Voilà c’est tout, encore merci à toi ,)
-
@‘EmotionFox’:
Au top merci beaucoup Scarex, j’ai même réussie à faire ce sac en 1.8 avec quelque fonction en plus (rien de très méchant).
Petit astuce pas vraiment mentionnée ici, de une, oui c’est bien les deux valeurs 54 qu’il faut modifier dans le GuiHandler pour changer les slots (parait logique mais bon):
return new GuiBackPack(player.inventory, new InventoryBackPack(player.getHeldItem(), 54));
Et finalement, pour enregistrer votre GuiHandler il faut utiliser ça (à l’intérieur de FMLInitializationEvent):
NetworkRegistry.INSTANCE.registerGuiHandler(instance, new EmotionGuiHandler());
Voilà c’est tout, encore merci à toi ,)
NOTE : il faut changer LES 2 VALEURS, sinon vous aurez de grande chances de crasher.
Je vois pas comment être plus clair ;).
Effectivement j’ai oublié de fournir la classe principale où le GuiHandler est enregistré.
-
Ne serais-ce pas une traduction du tuto de MinecraftForge ? En tout cas c’est nickel
-
MinecraftForge n’a pas fait de tuto là dessus à ce je sache, ou alors je l’ai pas trouvé.
-
CoolAlias en a fait un mais vos code ne correspondent pas ^^
-
Y’a moyen d’adapter ça pour un item “bouteille” avec un GUI? Genre, pas d’inventaire, mais qui stocke un entier (la quantité d’eau).
-
Techniquement tu peux afficher n’importe quel GUI que tu veux, il faut seulement changer le chargement et la sauvegarde des données dans les NBTs de l’ItemStack ainsi que l’affichage du GUI.
-
@‘SCAREX’:
Techniquement tu peux afficher n’importe quel GUI que tu veux, il faut seulement changer le chargement et la sauvegarde des données dans les NBTs de l’ItemStack ainsi que l’affichage du GUI.
Ouais mais du coup y’a ça :
return new ContainerBackPack(player.inventory, new InventoryBackPack(player.getHeldItem(), 54));
Donc je suis obligé de passer par un Inventory qui gère un int au lieu d’un tableau d’ItemStack?
-
Bonjour, j’ai fais un sac pour mon mod et je l’ai mis en multi. Cependant je remarque des crash du serveur dût à cet item. J’ai supposé que ceci survenait lorsque deux joueurs ouvraient leurs sacs simultanément. Aurais tu une idée?
-
Envoi le crash report
-
Je te l’envoie dès que le serveur recrash
[Server thread/ERROR] : This crash report has been saved to: /var/directory_serv/servmc_116233/./crash-reports/crash-2015-10-26_12.40.37-server.txt
[Erreur Java] java.lang.Thread.run(Thread.java:722) [?:1.7.0]
[Erreur Java] net.minecraft.server.MinecraftServer.run(MinecraftServer.java:646) [MinecraftServer.class:?]
[Erreur Java] net.minecraft.server.MinecraftServer.func_71217_p(MinecraftServer.java:783) ~[MinecraftServer.class:?]
[Erreur Java] net.minecraft.server.dedicated.DedicatedServer.func_71190_q(DedicatedServer.java:432) ~[lj.class:?]
[Erreur Java] net.minecraft.server.MinecraftServer.func_71190_q(MinecraftServer.java:953) ~[MinecraftServer.class:?]
[Erreur Java] net.minecraft.network.NetworkSystem.func_151269_c(NetworkSystem.java:166) ~s.class:?]
[Erreur Java] net.minecraft.network.NetHandlerPlayServer.func_147231_a(NetHandlerPlayServer.java:969) ~x.class:?]
[Erreur Java] net.minecraft.server.management.ServerConfigurationManager.disconnect(ServerConfigurationManager.java:419) ~[ld.class:?]
[Erreur Java] net.minecraft.world.World.func_72900_e(World.java:1844) ~[afn.class:?]
[Erreur Java] net.minecraft.entity.player.EntityPlayer.func_70106_y(EntityPlayer.java:1481) ~[xl.class:?]
[Erreur Java] laserflip33.ordreduphenix.common.ContainerBourseMoke.func_75134_a(ContainerBourseMoke.java:96) ~[ContainerBourseMoke.class:?]
[Erreur Java] laserflip33.ordreduphenix.common.ContainerBourseMoke.writeToNBT(ContainerBourseMoke.java:47) ~[ContainerBourseMoke.class:?]
[12:40:37] [Server thread/ERROR] : Encountered an unexpected exception -
Et le code de la classe ContainerBourseMoke :
package laserflip33.ordreduphenix.common; 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; public class ContainerBourseMoke extends Container { public InventoryBourseMoke invBackpack; public int rows; public ContainerBourseMoke(InventoryPlayer playerInv, InventoryBourseMoke inv) { this.invBackpack = inv; this.rows = inv.getSizeInventory() / 9; int i = (this.rows - 4) * 18; int j; int k; // Adding slots to the backpack for (j = 0; j < this.rows; ++j) { for (k = 0; k < 9; ++k) { this.addSlotToContainer(new SlotBourseMoke(inv, k + j * 9, 8 + k * 18, 18 + j * 18)); } } // Adding player's slots 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(); // Prevents backpack-ception (backpack inside backpack) with // shift-click if (itemstack.getItem() instanceof BourseMoke) 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; } /** * @param buttonPressed * left click, right click, wheel click, etc. * @param flag * category (e.g.: hotbar keys) */ @Override public ItemStack slotClick(int slotIndex, int buttonPressed, int flag, EntityPlayer player) { // Prevents from removing current backpack 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); } /** * Used to save content */ @Override public void onContainerClosed(EntityPlayer player) { this.writeToNBT(player.getHeldItem()); super.onContainerClosed(player); } }
Et le crash report complet :
–-- Minecraft Crash Report ---- // I'm sorry, Dave. Time: 26/10/15 13:06 Description: Exception in server tick loop java.lang.NullPointerException: Exception in server tick loop at laserflip33.ordreduphenix.common.ContainerBourseMoke.writeToNBT(ContainerBourseMoke.java:47) at laserflip33.ordreduphenix.common.ContainerBourseMoke.func_75134_a(ContainerBourseMoke.java:96) at net.minecraft.entity.player.EntityPlayer.func_70106_y(EntityPlayer.java:1481) at net.minecraft.world.World.func_72900_e(World.java:1844) at net.minecraft.server.management.ServerConfigurationManager.disconnect(ServerConfigurationManager.java:419) at net.minecraft.network.NetHandlerPlayServer.func_147231_a(NetHandlerPlayServer.java:969) at net.minecraft.network.NetworkSystem.func_151269_c(NetworkSystem.java:166) at net.minecraft.server.MinecraftServer.func_71190_q(MinecraftServer.java:953) at net.minecraft.server.dedicated.DedicatedServer.func_71190_q(DedicatedServer.java:432) at net.minecraft.server.MinecraftServer.func_71217_p(MinecraftServer.java:783) at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:646) at java.lang.Thread.run(Thread.java:722) A detailed walkthrough of the error, its code path and all known details is as follows: --------------------------------------------------------------------------------------- -- System Details -- Details: Minecraft Version: 1.7.2 Operating System: Linux (amd64) version 3.14-0.bpo.1-amd64 Java Version: 1.7.0, Oracle Corporation Java VM Version: Java HotSpot(TM) 64-Bit Server VM (mixed mode), Oracle Corporation Memory: 366335336 bytes (349 MB) / 1116057600 bytes (1064 MB) up to 18407424000 bytes (17554 MB) JVM Flags: 21 total; -Xms512M -XX:PermSize=384m -XX:MaxPermSize=768m -XX:-UseConcMarkSweepGC -XX:+UseParNewGC -XX:+UseNUMA -XX:+CMSParallelRemarkEnabled -XX:+UseAdaptiveGCBoundary -XX:-UseGCOverheadLimit -XX:+UseBiasedLocking -XX:SurvivorRatio=8 -XX:TargetSurvivorRatio=90 -XX:MaxTenuringThreshold=15 -XX:UseSSE=3 -XX:+UseLargePages -XX:+UseFastAccessorMethods -XX:+UseStringCache -XX:+UseCompressedOops -XX:+OptimizeStringConcat -XX:+AggressiveOpts -XX:ParallelGCThreads=1 AABB Pool Size: 7109 (398104 bytes; 0 MB) allocated, 6560 (367360 bytes; 0 MB) used IntCache: cache: 0, tcache: 0, allocated: 12, tallocated: 94 FML: MCP v9.03 FML v7.2.217.1147 Minecraft Forge 10.12.2.1147 13 mods loaded, 13 mods active mcp{9.03} [Minecraft Coder Pack] (minecraft.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available->Available->Available FML{7.2.217.1147} [Forge Mod Loader] (cauldron.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available->Available->Available Forge{10.12.2.1147} [Minecraft Forge] (cauldron.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available->Available->Available CustomSpawner{3.2.0.dev.R3} [DrZhark's CustomSpawner] (CustomMobSpawner 3.2.0-DEV-R3.zip) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available->Available->Available customnpcs{1.7.2-2} [CustomNpcs] (CustomNPCs_1.7.2.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available->Available->Available MoCreatures{6.2.0.dev.R3} [DrZhark's Mo'Creatures Mod] (DrZharks MoCreatures Mod v6.2.0-DEV-R3.zip) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available->Available->Available ftfloocraft{1.7.10-0.3.1} [Floocraft] (Floocraft-1.7.10-0.3.1.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available->Available->Available MineChess{1.3.7} [MineChess] (MineChess-Mod-1.7.2.zip) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available->Available->Available halloween{1.0.0} [Halloween] (ModHalloween.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available->Available->Available ordreduphenix{1.0.0} [Ordre du Phenix] (ordreduphenix-1.0.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available->Available->Available pottermod{0.2} [PotterMod] (Pottermod-0.2.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available->Available->Available quidcraft{0.1} [Quidcraft] (Quidcraft-0.1(1.7.2).jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available->Available->Available witchery{0.20.4} [Witchery] (witchery-1.7.2-0.20.4.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available->Available->Available Profiler Position: N/A (disabled) Vec3 Pool Size: 56493 (3163608 bytes; 3 MB) allocated, 6233 (349048 bytes; 0 MB) used Player Count: 5 / 50; [EntityPlayerMP['Xemox'/1437, l='MapOrdrePhenix', x=-2577,64, y=48,00, z=2512,38](Xemox at -2577.63824231431,48.0,2512.379903864352), EntityPlayerMP['unai64700'/2173, l='MapOrdrePhenix', x=-2583,59, y=54,50, z=2489,30](unai64700 at -2583.5871402555135,54.5,2489.300000011921), EntityPlayerMP['yas35400'/51794, l='MapOrdrePhenix', x=-2578,97, y=54,48, z=2478,82](yas35400 at -2578.969493942492,54.4807108763317,2478.8155894892357), EntityPlayerMP['Actiz'/8176, l='MapOrdrePhenix', x=-2811,37, y=40,00, z=1950,95](Actiz at -2811.3673737126605,40.0,1950.946107101118), EntityPlayerMP['EmmaCarena'/344622, l='MapOrdrePhenix', x=-2581,05, y=54,00, z=2440,25](EmmaCarena at -2581.0475033284024,54.0,2440.2492956906467)] Is Modded: Definitely; Server brand changed to 'cauldron,craftbukkit,mcpc,fml,forge' Type: Dedicated Server (map_server.txt)
-
Je pense que ce qu’il se passe c’est que l’item en main du joueur disparaît ou alors le joueur change son slot utilisé, or ce n’est pas censé arriver, as-tu une idée de comment le joueur pourrait changer son slot utilisé ou déplacer l’ItemStack ?
-
@‘SCAREX’:
Je pense que ce qu’il se passe c’est que l’item en main du joueur disparaît ou alors le joueur change son slot utilisé, or ce n’est pas censé arriver, as-tu une idée de comment le joueur pourrait changer son slot utilisé ou déplacer l’ItemStack ?
J’ai vraiment aucune idée sur ce coup là… Par contre mon hypothèse est fausse : le crash ne survient pas lorsque deux sacs s’ouvrent. Je connais désormais la raison, certaines personnes s’amusent à ouvrir et fermer très rapidement leurs sacs. Après ça le serveur crash quasiment à coup sûr…
-
Tu peux verifier à chaque tick si le joueur a toujours le sac en main et ne change pas de slot en cours, s’il change tu fermes le sac
-
Il faut ajouter un null check pour corriger ce NPE.
Et dans le container dans la fonction canInteractWith il devrait avoir return player.getHeldItem() != null && player.getHeldItem().getItem() == ClassePrincipale.leSac; et non return true;