Créer un gui et un container sur un bloc (type coffre)


  • Administrateurs

    Dans ce tutoriel, nous allons apprendre à créer un container et un gui. D'autres tutoriels sont (seront pour l'instant) disponible afin de plus détailler chaque partie.

    (Il y aura un tutoriel sur les container et les slots en détail, et un autre sur les gui qui sera plus généralisé, donc aussi sur les gui de type menu)

    Comme expliqué dans l'introduction, il va y avoir plus de 5 classes, soyez bien attentif afin de ne pas vous perdre.

    Le bloc

    Pour commencer, il faut un bloc. Pour ça, rendez-vous sur le tutoriel d'un bloc basique, et des TileEntity.
    Dans mon cas, je vais ajoutez le gui au metadata 3 du bloc tutoriel avec metadata. Je considère que vous un bloc avec un tileEntity prêt. Nous allons ajouter quelques méthode :

    public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int par6, float par7, float par8, float par9)
    {
        if(world.getBlockMetadata(x, y, z) == 3)
        {
            FMLNetworkHandler.openGui(player, ModTutoriel.instance, 0, world, x, y, z);
            return true;
        }
        return false;
    }
    

    Je vous l'ai dit au dessus, je mets mon gui et mon container sur mon bloc avec metadata, sur le metadata 3, d’où la condition au dessus. Si vous n'avez pas de metadata, mettez le code openGui directement dans la méthode.
    Ce code sert à ouvrir le gui. La méthode openGui prend déjà en compte si le joueur est accroupi ou pas, inutile d'ajouter une condition. Modtutoriel.instance est l'instance de mon mod, et 0 est l'id du gui, dans notre cas les id de gui ne nous servirons pas, vous pouvez toujours mettre 0, car nous allons utiliser le TileEntity dans le guiHandler, en revanche si vous souhaitez mettre plusieurs gui sur un même TiteEntity (genre des boutons qui ouvre un autre gui, ces id seront nécessaire, mais cela sera traité dans un autre tutoriel)

    public void onBlockPlacedBy(World world, int x, int y, int z, EntityLivingBase living, ItemStack stack)
    {
        TileEntity te = world.getBlockTileEntity(x, y, z);
        if(te != null && stack.getItemDamage() == 3 && te instanceof TileEntityBigChest && stack.hasDisplayName())
        {
            ((TileEntityBigChest)te).setCustomGuiName(stack.getDisplayName());
        }
    }
    

    TileEntity big chest est le nom de mon TileEntity, une fois de plus la condition stack.getItemDamage() == 3 sert à faire en sorte que le code ne soit que fait pour le metadata 3. Ce code sert à mettre un nom Custom dans le gui si le bloc à été renommé avec l'enclume. Pour l'instant vous allez avoir une erreur sur setCustomGuiName, c'est normal.

    public void breakBlock(World world, int x, int y, int z, int side, int metadata)
    {
        if(metadata == 3)
        {
            dropContainerItem(world, x, y, z);
        }
        super.breakBlock(world, x, y, z, side, metadata);
    }
    

    Comme avant, la condition vérifie que le metadata est bien 3, passez à la retirer si votre bloc n'a pas de metadata ou à changer la valeur si besoin. dropContainerItem est une fonction que nous allons créer pour droper le contenu du coffre :

    protected void dropContainerItem(World world, int x, int y, int z)
    {
        TileEntityBigChest bigchest = (TileEntityBigChest)world.getBlockTileEntity(x, y, z);
    
        if (bigchest != null)
        {
            for (int slotId = 0; slotId < bigchest.getSizeInventory(); slotId++)
            {
                ItemStack stack = bigchest.getStackInSlot(slotId);
    
                if (stack != 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; stack.stackSize > 0; world.spawnEntityInWorld(entityitem))
                    {
                        int k1 = world.rand.nextInt(21) + 10;
    
                        if (k1 > stack.stackSize)
                        {
                            k1 = stack.stackSize;
                        }
    
                        stack.stackSize -= k1;
                        entityitem = new EntityItem(world, (double)((float)x + f), (double)((float)y + f1), (double)((float)z + f2), new ItemStack(stack.itemID, k1, stack.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 (stack.hasTagCompound())
                        {
                            entityitem.getEntityItem().setTagCompound((NBTTagCompound)stack.getTagCompound().copy());
                        }
                    }
                }
            }
        }
    }
    

    C'est la même fonction que le coffre de minecraft, vous aurez aussi une erreur dessus.
    C'est fini pour le bloc, on passe au tile entity.

    Le Tile Entity

    Commencez par ajoutez ceci à la suite de la déclaration de la classe, juste après le extends :

    implements IInventory
    

    Vous allez avoir une erreur sur la classe, add missing method. Cliquez dessus, et la de nombreuse méthode vont être créées, nous allons les compléter.
    Déclarer les ItemStack est un String (juste après l'accolade de la classe) :

        private ItemStack[] inventory = new ItemStack[72];
        private String customName;
    

    72 est le nombre de slot que va avoir mon container, faite attention à cette variable, si vous créez plus de slot que de la taille de ce tableau, le jeu va crasher avec un ArrayIndexOutOfBoundException.

    Ensuite, nous allons ajoutez les deux méthodes pour les tag NBT :

    public void readFromNBT(NBTTagCompound nbttag)
    {
        super.readFromNBT(nbttag);
        NBTTagList nbttaglist = nbttag.getTagList("Items");
        this.inventory = new ItemStack[this.getSizeInventory()];
    
        if (nbttag.hasKey("CustomName"))
        {
            this.customName = nbttag.getString("CustomName");
        }
    
        for (int i = 0; i < nbttaglist.tagCount(); i++)
        {
            NBTTagCompound nbttagcompound1 = (NBTTagCompound)nbttaglist.tagAt(i);
            int j = nbttagcompound1.getByte("Slot");
    
            if (j >= 0 && j < this.inventory.length)
            {
                this.inventory[j] = ItemStack.loadItemStackFromNBT(nbttagcompound1);
            }
        }
    }
    
    public void writeToNBT(NBTTagCompound nbttag)
    {
        super.writeToNBT(nbttag);
        NBTTagList nbttaglist = new NBTTagList();
    
        for (int i = 0; i < this.inventory.length; i++)
        {
            if (this.inventory* != null)
            {
                NBTTagCompound nbttagcompound1 = new NBTTagCompound();
                nbttagcompound1.setByte("Slot", (byte)i);
                this.inventory*.writeToNBT(nbttagcompound1);
                nbttaglist.appendTag(nbttagcompound1);
            }
        }
    
        nbttag.setTag("Items", nbttaglist);
    
        if (this.isInvNameLocalized())
        {
            nbttag.setString("CustomName", this.customName);
        }
    }
    

    Ces deux fonctions enregistre et charge les ItemStack ainsi que le nom custom si il y en a un.
    Maintenant nous allons modifier les méthodes de l'interface IInventory :

        @Override
        public int getSizeInventory()
        {
            return inventory.length;
        }
    

    Cette méthode donne la taille de l'inventaire, le return doit donc donner la taille du tableau d'ItemStack.

        @Override
        public ItemStack getStackInSlot(int slotId)
        {
            return inventory[slotId];
        }
    

    Une fonction pour récupérer un ItemStack sur un slot précis.

        @Override
        public ItemStack decrStackSize(int slotId, int quantity)
        {
            if (this.inventory[slotId] != null)
            {
                ItemStack itemstack;
    
                if (this.inventory[slotId].stackSize <= quantity)
                {
                    itemstack = this.inventory[slotId];
                    this.inventory[slotId] = null;
                    this.onInventoryChanged();
                    return itemstack;
                }
                else
                {
                    itemstack = this.inventory[slotId].splitStack(quantity);
    
                    if (this.inventory[slotId].stackSize == 0)
                    {
                        this.inventory[slotId] = null;
                    }
    
                    this.onInventoryChanged();
                    return itemstack;
                }
            }
            else
            {
                return null;
            }
        }
    
        @Override
        public ItemStack getStackInSlotOnClosing(int slotId)
        {
            if (this.inventory[slotId] != null)
            {
                ItemStack itemstack = this.inventory[slotId];
                this.inventory[slotId] = null;
                return itemstack;
            }
            else
            {
                return null;
            }
        }
    
        @Override
        public void setInventorySlotContents(int slotId, ItemStack stack)
        {
            this.inventory[slotId] = stack;
    
            if (stack != null && stack.stackSize > this.getInventoryStackLimit())
            {
                stack.stackSize = this.getInventoryStackLimit();
            }
    
            this.onInventoryChanged();
        }
    

    Ces trois fonction servent à retirer des ItemStack dans l'inventaire, en ajouter, et à récupérer un ItemStack lorsque vous sortez la souris du container (pour mettre à jour ce qui a été prit ou ajouté).

        @Override
        public String getInvName()
        {
            return this.isInvNameLocalized() ? this.customName : "container.bigchest";
        }
    
        @Override
        public boolean isInvNameLocalized()
        {
            return this.customName != null && this.customName.length() > 0;
        }
    
        public void setCustomGuiName(String name)
        {
            this.customName = name;
        }
    

    Les trois fonction pour le nom custom. La première ramène sur le nom du container, si il a un nom custom, il utilise le String customName, sinon il utilise le nom container.bigchest (qui sera localisé grâce à une fonction dans le gui). C'est donc le nom non localisé, sans mon fichier en_US.lang je vais devoir mettre container.bigchest=Big Chest
    isInvNameLocalized sert à vérifier si le bloc à un nom custom ou pas, donc si le String customName n'est pas null et que sa taille est supérieur à 0.
    La troisième méthode sert à définir le nom custom.

        @Override
        public int getInventoryStackLimit()
        {
            return 64;
        }
    

    La taille maximum des ItemStack dans le container (pas plus que 64).

        @Override
        public boolean isUseableByPlayer(EntityPlayer player)
        {
            return worldObj.getBlockTileEntity(xCoord, yCoord, zCoord) == this && player.getDistanceSq(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5) < 64;
        }
    

    Pour savoir si le joueur peut ouvrir le gui (qu'il est pas trop loin)

        @Override
        public void openChest()
        {
    
        }
    
        @Override
        public void closeChest()
        {
    
        }
    

    Peut être utile pour une animation, mais ce ne sera pas traité dans ce sujet.

        @Override
        public boolean isItemValidForSlot(int slotId, ItemStack stack)
        {
            return true;
        }
    

    Pour savoir si un ItemStack spécifique peut aller dans un slot donné. (ici tous les ItemStack peuvent aller dans n'importe quel slot, le tutoriel sur le four est un bon exemple d'utilisation de cette méthode)

    Le GuiHandler

    Nous allons commencer par enregistrer le guiHandler, dans la classe principale à la suite des enregistrements de TileEntity, ajoutez :

    NetworkRegistry.instance().registerGuiHandler(this.instance, new GuiHandlerTutorial());
    

    Créez le GuiHandler. Dans la méthode getServerGuiElement, ajoutez :

    TileEntity te = world.getBlockTileEntity(x, y, z);
    if(te instanceof TileEntityBigChest)
    {
        return new ContainerBigChest(player.inventory, (TileEntityBigChest)te);
    }
    return null;
    

    Comme dit plus haut, nous passons par un condition avec le TileEntity. Si le TileEntity est d'instance TileEntityBigChest, il retourne sur le ContainerBigChest, sinon il retourne null.
    Même chose pour le client, mais avec le gui (getClientGuiElement)

    TileEntity te = world.getBlockTileEntity(x, y, z);
    if(te instanceof TileEntityBigChest)
    {
        return new GuiBigChest(player.inventory, (TileEntityBigChest)te);
    }
    return null;
    

    Le container

    package tutoriel.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;
    
    public class ContainerBigChest extends Container
    {
        private TileEntityBigChest tileEntity;
    
        public ContainerBigChest(InventoryPlayer playerInventory, TileEntityBigChest teChest)
        {
            this.tileEntity = teChest;
    
            for(int i = 0; i < 6; i++)
            {
                for(int j = 0; j < 9; j++)
                {
                    this.addSlotToContainer(new Slot(teChest, j + i * 9, 8 + j * 18, 18 + i * 18));
                }
            }
            this.bindPlayerInventory(playerInventory);
        }
    
        private void bindPlayerInventory(InventoryPlayer playerInventory)
        {
            int i;
            for(i = 0; i < 3; i++)
            {
                for(int j = 0; j < 9; j++)
                {
                    this.addSlotToContainer(new Slot(playerInventory, j + i * 9 + 9, 8 + j * 18, 103 + i * 18 + 37));
                }
            }
    
            for(i = 0; i < 9; i++)
            {
                this.addSlotToContainer(new Slot(playerInventory, i, 8 + i * 18, 161 + 37));
            }
        }
    
        @Override
        public boolean canInteractWith(EntityPlayer player)
        {
            return tileEntity.isUseableByPlayer(player);
        }
    
        public ItemStack transferStackInSlot(EntityPlayer player, int slotId)
        {
            ItemStack itemstack = null;
            Slot slot = (Slot)this.inventorySlots.get(slotId);
    
            if(slot != null && slot.getHasStack())
            {
                ItemStack itemstack1 = slot.getStack();
                itemstack = itemstack1.copy();
    
                if(slotId < 9)
                {
                    if(!this.mergeItemStack(itemstack1, 9, this.inventorySlots.size(), true))
                    {
                        return null;
                    }
                }
                else if(!this.mergeItemStack(itemstack1, 0, 9, false))
                {
                    return null;
                }
    
                if(itemstack1.stackSize == 0)
                {
                    slot.putStack((ItemStack)null);
                }
                else
                {
                    slot.onSlotChanged();
                }
            }
            return itemstack;
        }
    }
    

    Dans le constructeur, on initialise le TileEntity, puis les slots du TileEntity ainsi que l'inventaire du joueur (this.bindPlayerInventory(playerInventory); et la fonction qui va avec)

    La fonction addSlotToContainer ajoute les slots, le constructeur de la classe slot est :
    new Slot(l'inventaire (donc notre TileEntity comme il est implémenté IInventory), l'id du slot (pensez à ne pas dépasser la taille du tableau d'ItemStack du TileEntity), position X, position Y)
    La boucle for et les quelques calcules sert à simplifier le code. Les valeurs 18 correspondent à l'espace entre chaque slot (un slot fait 16x16, donc 18 pour laisser deux pixels entre eux)
    Pour ajouter vos slot, je vous conseil fortement de lancer Minecraft en mode "Debug", c'est le scarabée à côté de run :

    Ainsi vous aurez juste besoin de fermer et de ré-ouvrir le gui en jeu pour voir les changements, plutôt que de relancer le jeu à chaque fois.
    canInteractWith est la fonction pour savoir si le joueur est assez proche pour ouvrir le container (utilise avec la fonction dans le TileEntity)
    Et transferStackInSlot est une méthode pour faire passer les items dans les slots. Le container du four est à nouveau un bon exemple pour faire quelque chose de plus complexe.

    Le gui

    package tutoriel.client;
    
    import net.minecraft.client.gui.inventory.GuiContainer;
    import net.minecraft.client.resources.I18n;
    import net.minecraft.entity.player.InventoryPlayer;
    import net.minecraft.inventory.IInventory;
    import net.minecraft.util.ResourceLocation;
    
    import org.lwjgl.opengl.GL11;
    
    import tutoriel.common.ContainerBigChest;
    import tutoriel.common.TileEntityBigChest;
    
    public class GuiBigChest extends GuiContainer
    {
        public static ResourceLocation texture = new ResourceLocation("modtutoriel", "textures/gui/container/bigChest.png");
        private TileEntityBigChest bigChest;
        private IInventory playerInventory;
    
        public GuiBigChest(InventoryPlayer inventory, TileEntityBigChest tileEntity)
        {
            super(new ContainerBigChest(inventory, tileEntity));
            this.bigChest = tileEntity;
            this.playerInventory = inventory;
            this.ySize = 230;
        }
    
        protected void drawGuiContainerForegroundLayer(int par1, int par2)
        {
            this.fontRenderer.drawString(this.playerInventory.isInvNameLocalized() ? this.playerInventory.getInvName() : I18n.getString(this.playerInventory.getInvName()), 8, 129, 0);
            this.fontRenderer.drawString(this.bigChest.isInvNameLocalized() ? this.bigChest.getInvName() : I18n.getString(this.bigChest.getInvName()), 8, 7, 0);
        }
    
        @Override
        protected void drawGuiContainerBackgroundLayer(float f, int i, int j)
        {
            GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
            this.mc.getTextureManager().bindTexture(texture);
            int x = (this.width - this.xSize) / 2;
            int y = (this.height - this.ySize) / 2;
            this.drawTexturedModalRect(x, y, 0, 0, this.xSize, this.ySize);
        }
    }
    

    Dans l'ordre, je commence par déclarer une localisation de ressource : new ResourceLocation("votre mod id", "le chemin de la texture après assets/modid/") C'est la même chose que pour les mobs.
    Ensuite je déclare le TileEntity est l'inventaire du joueur, ils sont initialisés dans le constructeur. D'ailleurs vous pouvez voir que je déclare aussi le Container, en effet même si il est géré par le serveur, le client l'utilise aussi pour connaître le nombre de slot et leurs emplacements. J'ai également modifier la taille y du gui, vous pouvez aussi modifier la taille x selon vos besoin.

    La méthode drawGuiContainerForegroundLayer est utilisé pour les textes et autres truc à mettre en premier plan, comme je vous l'avais expliqué lorsque nous avons fait le TileEntity, les méthodes isInvNameLocalized, et getName sont utilisés ici, et comme vous pouvez le voir, si un nom custom à été entré, il n'est pas localisé (c'est I18n.getString ajoute le nom au fichier de lang). Les paramètres de la fonction sont :
    this.fontRenderer.drawString(texte, position x, position y, couleur)
    Une fois de plus le debug est très pratique pour placer le texte au bon endroit, utilisez-le. Pour la couleur, c'est un int, petit rappel, en java pour les couleurs c'est : rouge * 65536 + bleu * 256 + vert. Ou alors utilisez new Color(rouge, bleu, vert).getRGB();

    La méthode drawGuiContainerBackgroundLayer va servir à faire apparaitre notre texture. (Background = fond, donc c'est logique, on va pas mettre la texture par dessus les textes ^^)

    Le reste (affichage des items, etc …) et déjà géré dans la classe GuiContainer, et comme notre classe est extends GuiContainer, tout est déjà fait 🙂

    Rendu final et finition

    Pensez à ajouter dans les fichiers de lang le nom du gui. Votre gui et votre container est désormais opérationnel !

    Rendu final sur Github



  • robin4002 est un dieu vivent !!! 😉
    Demain je vais suivre se tuto a la lettre ;).
    Merci beaucoup 😄



  • quand je clic droit sur mon bloc j'ai un message qui dit

    [Avertissement] [ForgeModLoader] A mod tried to open a gui on the server without being a NetworkMod


  • Administrateurs

    Dans ta classe principale, vérifie que tu as bien le @NetworkMod



  • J'ai le @NetworkMod

    Voici ma classe principale

    
    package _fearZ.mod;
    
    import org.lwjgl.util.glu.Registry;
    
    import net.minecraft.block.Block;
    import net.minecraft.block.BlockChest;
    import net.minecraft.block.material.Material;
    import net.minecraft.creativetab.CreativeTabs;
    import _fearZ.mod.blocks.BlockPharmacie;
    import _fearZ.mod.common.CommonProxy;
    import _fearZ.mod.tileentity.TileEntityArmoirePh;
    import cpw.mods.fml.common.Mod;
    import cpw.mods.fml.common.Mod.EventHandler;
    import cpw.mods.fml.common.Mod.Init;
    import cpw.mods.fml.common.Mod.Instance;
    import cpw.mods.fml.common.Mod.PreInit;
    import cpw.mods.fml.common.SidedProxy;
    import cpw.mods.fml.common.event.FMLInitializationEvent;
    import cpw.mods.fml.common.event.FMLPostInitializationEvent;
    import cpw.mods.fml.common.event.FMLPreInitializationEvent;
    import cpw.mods.fml.common.network.NetworkMod;
    import cpw.mods.fml.common.network.NetworkMod.SidedPacketHandler;
    import cpw.mods.fml.common.network.NetworkRegistry;
    import cpw.mods.fml.common.registry.GameRegistry;
    import cpw.mods.fml.common.registry.LanguageRegistry;
    
    @Mod(modid = "fearz", name = "FearZ", version = "1.0.0")
    @NetworkMod(clientSideRequired = true, serverSideRequired = true)
    
    public class Mod_FearZ
    {
    @Instance("FearZMod")
    public static Mod_FearZ modInstance;
    @SidedProxy(clientSide="_fearZ.mod.client.ClientProxy", serverSide="_fearZ.mod.common.CommonProxy")
    public static CommonProxy proxy;
    
    /**blocks*/
    public static Block armoirePh;
    
    /**Items*/
    
    /**Creative Tabs*/
    public static final CreativeTabs onglet = new OngletCreatif(CreativeTabs.getNextID(), "FearZ");
    
    @EventHandler
    public void PreInit(FMLPreInitializationEvent event)
    {
    /**Blocks*/
    armoirePh = new BlockPharmacie (1800).setBlockUnbreakable().setHardness(10000f).setStepSound(Block.soundMetalFootstep).setUnlocalizedName("ArmoirePharmacie");
    GameRegistry.registerBlock(armoirePh, "armoirePh");
    
    }
    
    @EventHandler
    public void Init(FMLInitializationEvent event)
    {
    /**Mobs*/
    
    /**Render*/
    proxy.registerRender();
    proxy.registerTileEntityRender();
    
    /**NetWork*/
    
    /**Recipes*/
    
    /**TileEntityRegistry*/
    GameRegistry.registerTileEntity(TileEntityArmoirePh.class, "pharmacie");
    
    NetworkRegistry.instance().registerGuiHandler(this.modInstance, new GuiHandlerArmoirePh());
    
    }
    
    @EventHandler
    public void PostInit(FMLPostInitializationEvent event)
    {
    /**Integration avec les autres mods*/
    }
    }
    
    

  • Administrateurs

    Mauvaise instance, dans ton @Instance tu dois avoir ton modid :

    @Instance("fearz")
    public static Mod_FearZ modInstance;
    

    à la place de :

    @Instance("FearZMod")
    public static Mod_FearZ modInstance;
    


  • Merci beaucoup, ça marche nickel 🙂



  • Rebonjour. J'aimerais savoir si quelqu'un sais comment animer un bloc. j'ai déjà cherché sur google, fait des testes de mon côté, et même essayé de suivre cette page mais rien à faire. Je m'explique : j'aimerais que mon bloc fonctionne comme un coffre (qu'il s'ouvre et se ferme). Sauf que mon bloc ressemble plus à une armoire et qu'il a deux portes qui doivent s'ouvrir vers les côtés. Ce qui m’empêche de reprendre le code du coffre qui est d'ailleurs trop compliqué pour moi.

    J'aimerais donc savoir si quelqu'un saurais ce que je dois faire pour faire fonctionner mon bloc.

    J'ai remarqué dans le tutoriel la présence des fonction "oppenChest()" et "closeChest()". J'imagine bien que ça a un rapport. mais je ne parviens pas à me servir de ces fonctions.

    Je précise que c'est un bloc TileEntity.


  • Administrateurs

    Je n'es pas parlé des fonctions open et close Chest car elles ne servent pas dans le tutoriel, mais elles doivent normalement être dans ton code.
    J'ai encore jamais fait d'animation, mais je vais voir ce que je peux faire.



  • Merci bien. J'attends de voir ce que tu trouves 🙂


  • Administrateurs

    http://www.minecraftforgefrance.fr/showthread.php?tid=375
    Première partie terminé, il y a ce qu'il te faut.



  • Merci beaucoup, je vais voir ça de ce pas 🙂


  • Administrateurs

    Vérifie toutes les fonctions en rapport avec les tile entity, et envoie tes codes (de préférence via des liens pastebin pour ne pas spammer), on ne peut pas deviner tes codes !



  • Bonjour Robin,

    Je me permet de laisser un message d'une part pour vous remercier de vôtre tuto qui est très bien mais qui manque un poil d'explication (je débute c'est sans doute pour ça).

    Mais aussi car j'ai une erreur dans le code.
    J'ai relu mais je n'arrive pas à trouver mon erreur, voici mon problème :

    Quand j'ajoute

    NetworkRegistry.instance().registerGuiHandler(this.instance, new GuiHandlerPlacard());
    

    Il ne reconnait pas l'instance et la souligne en rouge.

    Pourriez-vous m'aider ? Merci pour vôtre aide, encore une fois pour vôtre/vos tutos qui m'aident vraiment.

    Bonne journée.


  • Administrateurs

    Dans ta classe principale, ajoute :

    @Instance("modid")
    public static NomDaTaClassePrincipale instance;
    

    Il faut bien suivre les tutoriels, c'est écrit dans un des premiers tutoriel : http://www.minecraftforgefrance.fr/showthread.php?tid=60

    Il est vrai que ce tutoriel n'est pas beaucoup détaillé, j'ai beaucoup "balancé des codes", étant donner que je peux tourner tranquillement maintenant (faut encore que je configure pas mal de truc sur mon ordinateur, et encore je pense que le processeur de cette ordinateur va avoir du mal), je vais pouvoir faire une version en vidéo en 1.7 avec plus de détail et d'explication.



  • C'est déjà fait

    @Instance("TAL")
    public static Devmain instance;
    

    J'ai remplacé votre code par :

    NetworkRegistry.instance().registerGuiHandler(NetworkRegistry.instance(), new GuiHandlerPlacard());
    

    Et ça marche. Donc je ne sais pas trop…

    Après une question plus personnel, j'ai suivis vôtre tuto pour faire un container particulier. Il ne suivrait pas la taille de l'inventaire ni d'un coffre "classic" mais serait de type 7 par 7 cases (Soit 2 case de moins que l'inventaire en longueur mais 1 ligne de cases en hauteur).

    Vous pouvez m'expliquer s'il vous plait comment construire ce code à moins qu'il est possible de modifier le code du coffre en lui même.

    Et puis ce sera l'occasion aux apprentis codeurs (comme moi) de pouvoir créer des containers indépendamment du code fourni par Mojang. Je ne vous oblige pas bien entendu et je comprendrais ce refus.

    Merci pour cette réponse rapide.
    Bonne journée.

    PS : Je viens de m'apercevoir d'un problème quand je veux placer un bloc à l'intérieur du bloc il disparaît...


  • Administrateurs

    NetworkRegistry.instance(), c'est pas bon, tu peux m'envoyer toutes tes classes via des liens pastebin ?

    Si tu veux modifier la taille, c'est dans le container qu'il faut changer ça. Il y a plusieurs boucle for, c'est celle-ci qui ajoute les slots :

    for(int i = 0; i < 6; i++)
    {
    for(int j = 0; j < 9; j++)
    {
    this.addSlotToContainer(new Slot(teChest, j + i * 9, 8 + j * 18, 18 + i * 18));
    }
    }
    

    C'est ce code qui génère les slots, 96 ici, si tu veux faire 77 il suffit d'adapter les boules for.

    Il te faut aussi adapter le container :

    private ItemStack[] inventory = new ItemStack[72];
    

    72 était le nombre total de slot, si tu as un nombre trop petit tu vas avoir un OutOfBoundException (et 9×6 ça fait que 54, je sais pas pourquoi j'ai mit 72 x), 54 devrait fonctionner) donc 49 pour toi comme tu veux mettre 7*7 slots.

    Il ne faut pas non plus oublier d'adapter l'image du gui.



  • Parfait, vous êtes exceptionnel !

    Je vous envoie mes classes par messages privés ne sachant le faire par des PasteBin.
    Merci encore pour les containers !


  • Administrateurs

    NetworkRegistry.instance().registerGuiHandler(this.instance, new GuiHandlerPlacard());
    doit être dans la classe principale, dans la fonction init et non dans le client proxy, ce qui explique l'erreur, et le problème de syncro client ? serveur.



  • Décidément j’enchaîne les problèmes sur ce sujet. J'ai créé un second block conteneur. Quand je l'ouvre, il fonctionne bien. Mais du coup, mon premier bloc ne s'ouvre plus. Il n'y a aucune réactions.