30 juin 2013, 23:18

Vous avez sûrement remarqué que certains blocs ont des metadatas, ce qui donne un id du genre 5:1, 5:2 etc… Dans ce tutoriel vous allez apprendre à utiliser les metadatas classics, qui permettent d’avoir 16 metadata ( de :0 à :15). Pour plus de metadata, il faut utiliser des tileentity, le sujet sera traité dans un autre tutoriel.

Dans la classe principale

À la suite de vos déclarations de blocs déjà existants, ajoutez un nouveau bloc :

    public static Block BlockTutoriel, BlockTutorielMetadata;

Ensuite dans la partie @PreInit faite comme si c’était un bloc normal :

    BlockTutorielMetadata = new BlockTutorielMetadata(2001).setHardness(3.0F).setResistance(4.0F).setUnlocalizedName("BlockTutorielMetadata");

Dans la partie @Init, le code va être un peu différent :

    GameRegistry.registerBlock(BlockTutorielMetadata, ItemBlockTutorielMetadata.class, "TutorielMetadata");

ItemBlockTutorielMetadata est une nouvelle classe que nous allons créer après, c’est l’item qui correspond à votre bloc. Il faut savoir que quand vous créez un bloc, vous créez aussi un item qui va avec. Le bloc est ce qui est posé sur la map, et l’item est soit sous forme d’itemstack dans l’inventaire, soit sous forme d’entityItem si vous le jetez par terre. Quand on crée un bloc simple, l’itemblock utilisé est celui par défaut de Minecraft, mais lorsque l’on crée un bloc avec des metadata, nous avons besoin de créer notre propre itemblock.
“TutorielMetadata” est le nom du bloc, utiliser pour le système d’itemtracker de FML.

Pour le nom dans la classe principale, nous y reviendrons plus tard, car nous allons utiliser une autre méthode qui sera en rapport avec notre itemblock
Créez les deux classes “ItemBlockTutorielMetadata” et “BlockTutorielMetadata”

La classe du bloc

Suivez le tutoriel sur le bloc basique pour avoir un bloc déjà prêt.
Nous allons maintenant faire quelques modifications sur notre bloc :
Au-dessus du constructeur, ajoutez :

    public static String[] type = new String[]{"block1", "block2", "block3", "block4", "block5", "block6", "block7", "block8"};
    private Icon[] IconArray;

Ceci est un tableau de chaine de caractère, je l’ai appelé type, vous pouvez le nommer comme vous voulez. Nous allons utiliser ce tableau dans la méthode d’enregistrement de texture, et de nom.
En dessous, j’ai fait un tableau d’icône, il va servir pour les textures. (Importez net.minecraft.util.Icon)

Maintenant nous allons modifier la méthode d’enregistrement d’icône :

    public void registerIcons(IconRegister iconregister)
    {
        IconArray = new Icon[type.length];
        for(int i = 0; i < type.length; i++)
        {
            IconArray[i] = iconregister.registerIcon("ModTutoriel:" + type[i]);
        }
    }

On commence par indiquer la longueur du tableau “IconArray”, elle va être la même que notre tableau type. Ensuite, c’est une petite boucle for, elle va permettre d’enregistrer tous les icônes en fonction de la taille du tableau type. Ainsi, si vous souhaitez ajouter un bloc de plus, il vous suffit de l’ajoutez au tableau “type”.
Les textures seront dans le dossier mods/ModTutoriel/textures/blocks/ et auront le même nom que celui donné dans le tableau (block1, block2, block3, block4, block5, block6, block7, block8)

Maintenant il faut ajouter la fonction pour voir les blocs dans la table créative :

    @SideOnly(Side.CLIENT)
    public void getSubBlocks(int id, CreativeTabs creativeTabs, List list)
    {
        for(int metadata = 0; metadata < type.length; metadata++)
        {
            list.add(new ItemStack(id, 1, metadata));
        }
    }

À nouveau la boucle for nous simplifie la vie, le principe est le même qu’au-dessus.

Il ne nous reste plus qu’à finaliser la texture, car pour l’instant notre bloc utilise l’icône “blockIcon” comme il est extends Block. Nous allons donc ajouter la méthode getIcon dans notre bloc :

    @SideOnly(Side.CLIENT)
    public Icon getIcon(int side, int metadata)
    {
        return metadata < type.length && metadata >= 0 ? IconArray[metadata] : blockIcon;
    }

Pour ceux qui ont pas l’habitude des conditions ternaires, cela revient à faire ça :

if(metadata < type.length && metadata >= 0)
    return IconArray[metadata];
else
    return blockIcon;

En fait je vérifie que le metadata du bloc ne dépasse pas la taille du tableau “IconArray” car si je crée un bloc qui n’a que 5 metadata par exemple et que le joueur s’amuse à se give le bloc de metadata 6 ou supérieur (avec /give <pseudo><id><quantité>6), l’icone sera IconArray[6], or comme le tableau n’a que 5 case, le jeu va crasher avec un java.lang.ArrayIndexOutOfBoundsException, ce code est donc une prévention anti-crash 🙂

Une dernière fonction :

    public int damageDropped(int metadata)
    {
        return metadata;
    }

Elle est assez importante, si vous ne la mettez pas tous vos blocs vont dropper le metadata 0…

La classe de l’item bloc

La classe du bloc est fini, nous allons maintenant nous occuper de la classe de l’item bloc.
Commencez par ajouter extends ItemBlock, puis importez net.minecraft.item.ItemBlock
Ensuite, dans le constructeur, ajoutez this.setHasSubtypes(true);.
Ajoutez aussi cette fonction :

    public int getMetadata(int metadata)
    {
        return metadata;
    }

Par défaut dans Item.java cette fonction renvoie 0, c’est pour ça qu’il est important de la mettre, sinon même avec un bloc d’id <quelque chose>:1, lorsque vous le poserez, il deviendra un bloc de metadata 0. Donc si un jour vous avez ce problème, vous saurez que vous avez oublié de mettre cette fonction 😉 (je préviens, car ça m’est déjà arrivé).

Il reste encore à faire la fonction pour le nom, vous allez donc ajouter :

    public String getUnlocalizedName(ItemStack stack)
    {
        int metadata = stack.getItemDamage();
        if(metadata < BlockTutorielMetadata.type.length && metadata >= 0)
        {
            return super.getUnlocalizedName() + "." + BlockTutorielMetadata.type[metadata];
        }
        else
        {
            return getUnlocalizedName();
        }
    }

Comme avant, la condition if(stack.getItemDamage() < BlockTutorielMetadata.type.length) sert à éviter un java.lang.ArrayIndexOutOfBoundsException.
Cette fonction change le nom non localisé de votre bloc, à la place de “tile.<unlocalizedname>.name” il sera “tile.<unlocalizedname>.<nom dans le tableau type>.name”

Pour finir, encore la classe principale

Retournez donc dans votre classe principale et dans la partie @PostInit, ajoutez ceci :

    LanguageRegistry.instance().addStringLocalization("tile.BlockTutorielMetadata.block1.name", "Tutoriel metadata 1");
    LanguageRegistry.instance().addStringLocalization("tile.BlockTutorielMetadata.block2.name", "Tutoriel metadata 2");
    LanguageRegistry.instance().addStringLocalization("tile.BlockTutorielMetadata.block3.name", "Tutoriel metadata 3");
    LanguageRegistry.instance().addStringLocalization("tile.BlockTutorielMetadata.block4.name", "Tutoriel metadata 4");
    LanguageRegistry.instance().addStringLocalization("tile.BlockTutorielMetadata.block5.name", "Tutoriel metadata 5");
    LanguageRegistry.instance().addStringLocalization("tile.BlockTutorielMetadata.block6.name", "Tutoriel metadata 6");
    LanguageRegistry.instance().addStringLocalization("tile.BlockTutorielMetadata.block7.name", "Tutoriel metadata 7");
    LanguageRegistry.instance().addStringLocalization("tile.BlockTutorielMetadata.block8.name", "Tutoriel metadata 8");

Pour retrouver les noms, c’est simple, il faut mettre “tile.” puis votre nom non localisé (défini par ça : .setUnlocalizedName(“BlockTutorielMetadata”) dans le code du bloc) puis un “.” ensuite les noms que vous avez mis dans le String[] type dans la classe du bloc, puis “.name”
Si vous n’y arrivez toujours pas, vous pouvez utiliser le addname et nommer l’item stack comme ceci :

    LanguageRegistry.addName(new ItemStack(BlockTutorielMetadata, 1, 0), "Tutoriel metadata 1");
    LanguageRegistry.addName(new ItemStack(BlockTutorielMetadata, 1, 1), "Tutoriel metadata 2");
    //etc …

Mais cela oblige à créer des itemstack, ce qui est plus lourd, c’est pour ça que je vous encourage à utiliser la première méthode.

Voilà le tutoriel est fini, si vous avez eu du mal pour placer les codes, jetez un coup d’œil sur le rendu final.

Rendu final

Plusieurs blocs avec metadata

Classe principale :

package tutoriel.common;

import net.minecraft.block.Block;
import net.minecraft.item.ItemStack;

import tutoriel.proxy.TutoCommonProxy;

import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.Init;
import cpw.mods.fml.common.Mod.Instance;
import cpw.mods.fml.common.Mod.PostInit;
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.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;

@Mod(modid = "ModTutoriel", name = "Mod Tutoriel", version = "1.0.0", acceptedMinecraftVersions = "[1.5.2,)")
@NetworkMod(clientSideRequired = true, serverSideRequired = false)

public class ModTutoriel
{
    @SidedProxy(clientSide = "tutoriel.proxy.TutoClientProxy", serverSide = "tutoriel.proxy.TutoCommonProxy")
    public static TutoCommonProxy proxy;
    @Instance("ModTutoriel")
    public static ModTutoriel instance;

    //Blocks
    public static Block BlockTutoriel, BlockTutorielMetadata;

    @PreInit
    public void preload(FMLPreInitializationEvent event)
    {
        //Configuration

        //Blocks
        BlockTutoriel = new BlockTutoriel(2000).setHardness(2.0F).setResistance(4.0F).setUnlocalizedName("BlockTutoriel");
        BlockTutorielMetadata = new BlockTutorielMetadata(2001).setHardness(3.0F).setResistance(4.0F).setUnlocalizedName("BlockTutorielMetadata");

        //Items

        //Achievements
    }

    @Init
    public void load(FMLInitializationEvent event)
    {
        //Registry
        GameRegistry.registerBlock(BlockTutoriel, "BlockTutoriel");
        GameRegistry.registerBlock(BlockTutorielMetadata, ItemBlockTutorielMetadata.class, "TutorielMetadata");

        //Mobs

        //Render
        proxy.registerRender();
        //NetWork
    }

    @PostInit
    public void modloaded(FMLPostInitializationEvent event)
    {
        //Language
        LanguageRegistry.addName(BlockTutoriel, "Block Tutoriel");
        LanguageRegistry.instance().addStringLocalization("tile.BlockTutorielMetadata.block1.name", "Tutoriel metadata 1");
        LanguageRegistry.instance().addStringLocalization("tile.BlockTutorielMetadata.block2.name", "Tutoriel metadata 2");
        LanguageRegistry.instance().addStringLocalization("tile.BlockTutorielMetadata.block3.name", "Tutoriel metadata 3");
        LanguageRegistry.instance().addStringLocalization("tile.BlockTutorielMetadata.block4.name", "Tutoriel metadata 4");
        LanguageRegistry.instance().addStringLocalization("tile.BlockTutorielMetadata.block5.name", "Tutoriel metadata 5");
        LanguageRegistry.instance().addStringLocalization("tile.BlockTutorielMetadata.block6.name", "Tutoriel metadata 6");
        LanguageRegistry.instance().addStringLocalization("tile.BlockTutorielMetadata.block7.name", "Tutoriel metadata 7");
        LanguageRegistry.instance().addStringLocalization("tile.BlockTutorielMetadata.block8.name", "Tutoriel metadata 8");

        //Recipe

    }
}

Classe du bloc :

package tutoriel.common;

import java.util.List;

import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Icon;

public class BlockTutorielMetadata extends Block
{
    public static String[] type = new String[]{"block1", "block2", "block3", "block4", "block5", "block6", "block7", "block8"};
    private Icon[] IconArray;

    public BlockTutorielMetadata(int id)
    {
        super(id, Material.rock);
        this.setCreativeTab(CreativeTabs.tabBlock);
    }

    public void registerIcons(IconRegister iconregister)
    {
        IconArray = new Icon[type.length];
        for(int i = 0; i < type.length; i++)
        {
            IconArray[i] = iconregister.registerIcon("ModTutoriel:" + type[i]);
        }
    }

    @SideOnly(Side.CLIENT)
    public void getSubBlocks(int id, CreativeTabs creativeTabs, List list)
    {
        for(int metadata = 0; metadata < type.length; metadata++)
        {
            list.add(new ItemStack(id, 1, metadata));
        }
    }

    @SideOnly(Side.CLIENT)
    public Icon getIcon(int side, int metadata)
    {
        return metadata < type.length && metadata >= 0 ? IconArray[metadata] : blockIcon;
    }

    public int damageDropped(int metadata)
    {
        return metadata;
    }
}

Classe de l’item bloc :

package tutoriel.common;

import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;

public class ItemBlockTutorielMetadata extends ItemBlock
{
    public ItemBlockTutorielMetadata(int id)
    {
        super(id);
        this.setHasSubtypes(true);
    }

    public int getMetadata(int metadata)
    {
        return metadata;
    }

    public String getUnlocalizedName(ItemStack stack)
    {
        int metadata = stack.getItemDamage();
        if(metadata < BlockTutorielMetadata.type.length && metadata >= 0)
        {
            return super.getUnlocalizedName() + "." + BlockTutorielMetadata.type[metadata];
        }
        else
        {
            return getUnlocalizedName();
        }
    }
}