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

    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

    Creative Commons
    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

    retourRetour vers le sommaire des tutoriels



  • 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


  • Moddeurs confirmés Rédacteurs Administrateurs

    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; 😉


Log in to reply