Créer une structure multiblocks


  • Rédacteurs

    Sommaire

    Introduction

    Nous allons voir comment créer une structure multi-block.
    Tout d'abord qu'est ce qu'une structure multi-block ? C'est un ensemble de bloc qui une fois disposés
    correctement, forment un ensemble.

    Pré-requis

    Code

    La classe principale :

    Déclarez votre bloc dans votre classe principale, pour ce tutoriel il s'appellera multiBlockTuto

        public static Block multiBlockTuto;
    

    Puis instanciez-le et enregistrez-le dans la fonction preInit

        multiBlockTuto = new BlockMultiBlockTuto();
        GameRegistry.registerBlock(multiBlockTuto, "multiblocktuto");
    

    Créez la classe BlockMultiBlockTuto.

    La classe du bloc :

    La classe du bloc devrait être extends Block, si ce n'est pas le cas, faites-le.
    Implémentez ensuite l'interface ITileEntityProvider

        public class BlockMultiBlockTuto extends Block implements ITileEntityProvider
    

    Définissez le constructeur comme pour un bloc normal.

    On ajoute maintenant la fonction permettant de créer le TileEntity

        @Override
        public TileEntity createNewTileEntity(World worldIn, int meta) {
            return new TileEntityMultiBlockTuto();
        }
    

    Créez la classe TileEntityMultiBlockTuto.

    La classe du TileEntity

    La structure que nous allons créer est une structure de 1 de hauteur, 3 de largeur, 3 de longueur,
    ce qui nous fait une structure composée de 331 = 9 blocs.

    Le concept sera le suivant, dans toute la structure il y aura un bloc qui sera,
    dit 'master' et les autres ne feront que vérifier que ce block existe. C'est dans ce master
    que toute les informations que vous voudrez enregistrer dans la structure devront se trouver.

    Chaque bloc, quelqu'il soit, aura 5 variables qui définira sont état :

    • Est-t-il oui ou non master (1 variable)
    • As-t-il oui ou non un master (1 variable)
    • Quels sont les coordonnées du master (3 variables x, y, z)
      Ainsi on déclare chaque variable et on les enregistres dans les NBT
        private boolean hasMaster = false;
        private boolean isMaster = false;
        private int masterX = 0;
        private int masterY = 0;
        private int masterZ = 0;
    
        @Override
        public void readFromNBT(NBTTagCompound compound)
        {
            super.readFromNBT(compound);
            this.hasMaster = compound.getBoolean("HasMaster");
            this.isMaster = compound.getBoolean("IsMaster");
            this.masterX = compound.getInteger("MasterX");
            this.masterY = compound.getInteger("MasterY");
            this.masterZ = compound.getInteger("MasterZ");
        }
    
        @Override
        public void writeToNBT(NBTTagCompound compound)
        {
            super.writeToNBT(compound);
            compound.setBoolean("HasMaster", hasMaster);
            compound.setBoolean("IsMaster", isMaster);
            compound.setInteger("MasterX", masterX);
            compound.setInteger("MasterY", masterY);
            compound.setInteger("MasterZ", masterZ);
        }
    

    Suite à ça ajoutons directement les getter et setter

        public boolean hasMaster()
        {
            return this.hasMaster;
        }
    
        public boolean isMaster()
        {
            return this.isMaster;
        }
    
        public int getMasterX()
        {
            return this.masterX;
        }
    
        public int getMasterY()
        {
            return this.masterY;
        }
    
        public int getMasterZ()
        {
            return this.masterZ;
        }
    
        public void setMaster(int x, int y, int z)
        {
            this.hasMaster = true;
            this.masterX = x;
            this.masterY = y;
            this.masterZ = z;
        }
    

    Nous allons maintenant créer une fonction afin de vérifier la présense
    d'une structure, chaque bloc va essayer de créer une structure dans il est
    master tant qu'il ne sera ou n'aura pas de master.
    Pour vérifier la structure on va se baser sur le bloc du milieux de notre
    carré de 3 par 3.

    private boolean checkStructure()
    {
        int n = 0;
        for(int x = this.pos.getX() - 1; x < this.pos.getX() + 2; x++)
        {
            for(int z = this.pos.getZ() - 1; z < this.pos.getZ() + 2; z++)
            {
                BlockPos position = new BlockPos(x, this.pos.getY(), z);
                TileEntity tile = worldObj.getTileEntity(position);
                if(tile != null && tile instanceof TileEntityMultiBlockTuto)
                {
                    TileEntityMultiBlockTuto t = (TileEntityMultiBlockTuto)tile;
                    if(t.hasMaster)
                    {
                        if(this.pos.getX() == t.getMasterX() && this.pos.getY() == t.getMasterY() && this.pos.getZ() == t.getMasterZ())
                        {
                            n++;
                        }
                    }
                    else
                    {
                        n++;
                    }
                }
            }
        }
    
        if(n == 9)
        {
            return true;
        }
        return false;
    }
    

    On compte le nombre de bloc qui n'ont pas de master ou qui ont pour master le bloc qui check.
    Si il est égal à 9, le nombre de bloc dans la structure alors c'est bon, dans ce cas on met
    en place la structure en indiquant à chaque bloc la place du master et le fait qu'il ai un master.

    private void setupStructure()
    {
        for(int x = this.pos.getX() - 1; x < this.pos.getX() + 2; x++)
        {
            for(int z = this.pos.getZ() - 1; z < this.pos.getZ() + 2; z++)
            {
                BlockPos position = new BlockPos(x, this.pos.getY(), z);
                TileEntity tile = worldObj.getTileEntity(position);
                if(tile != null && tile instanceof TileEntityMultiBlockTuto)
                {
                    TileEntityMultiBlockTuto t = (TileEntityMultiBlockTuto)tile;
                    t.setMaster(this.pos.getX(), this.pos.getY(), this.pos.getZ());
                    this.isMaster = true;
                }
            }
        }
    }
    

    Vous verrez que une fois la structure faite nous allons re-vérifier son intégrité, dans le cas
    où elle n'est plus correcte, il va falloir indiquer à chaque bloc que c'est fini, il n'y a plus
    de structure.
    Il faut donc une fonction qui reset la structure, qui sera exécutée par le master et une qui reset
    juste le bloc qui sera appelée dans la boucle pour reset la structure.

    private void resetStructure()
    {
        for(int x = this.pos.getX() - 1; x < this.pos.getX() + 2; x++)
        {
            for(int z = this.pos.getZ() - 1; z < this.pos.getZ() + 2; z++)
            {
                BlockPos position = new BlockPos(x, this.pos.getY(), z);
                TileEntity tile = worldObj.getTileEntity(position);
                if(tile != null && tile instanceof TileEntityMultiBlockTuto)
                {
                    TileEntityMultiBlockTuto t = (TileEntityMultiBlockTuto)tile;
                    t.reset();
                }
            }
        }
    }
    
    public void reset()
    {
        this.isMaster = false;
        this.hasMaster = false;
        this.masterX = 0;
        this.masterY = 0;
        this.masterZ = 0;
    }
    

    Dans le cas où le master est détruit, il ne pourra pas reset la structure, il faut alors que chaque
    bloc vérifie si le master existe encore

    private boolean checkForMaster()
    {
        BlockPos position = new BlockPos(masterX, masterY, masterZ);
        TileEntity tile = worldObj.getTileEntity(position);
        if(tile != null && tile instanceof TileEntityMultiBlockTuto)
        {
            TileEntityMultiBlockTuto t = (TileEntityMultiBlockTuto)tile;
            if(t.isMaster())
            {
                return true;
            }
        }
        return false;
    }
    

    Les deux fonctions concernant les packets

    @Override
    public Packet getDescriptionPacket()
    {
        NBTTagCompound nbttagcompound = new NBTTagCompound();
        this.writeToNBT(nbttagcompound);
        return new S35PacketUpdateTileEntity(this.getPos(), this.getBlockMetadata(), nbttagcompound);
    }
    
    @Override
    public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt)
    {
        this.readFromNBT(pkt.getNbtCompound());
        this.worldObj.markBlockRangeForRenderUpdate(this.pos, this.pos);
    }
    

    Implémentez la classe de l'interface IUpdatePlayerListBox
    La fonction update est appellée à chaque update du bloc, on y appeler nos fonctions,
    mais réfléchissons à la façon dont nous allons nous y prendre.

    public void update() {}
    

    Tout d'abord si le bloc est un master il va devoir vérifier la structure,
    si elle n'est plus correcte alors on la reset

    if(this.isMaster)
        {
            if(!this.checkStructure())
            {
                this.resetStructure();
            }
        }
    

    Sinon si il a un master, on doit vérifier si sont master est encore là,
    sinon on reset le bloc

    else if(this.hasMaster)
    {
        if(!checkForMaster())
        {
            this.reset();
        }
    }
    

    Sinon si il n'a pas de master alors il doit il va essayer de créer une structure

    else if(!this.hasMaster)
    {
        if(this.checkStructure())
        {
            this.setupStructure();
        }
    }
    

    La situation de notre bloc a changé, on le signal.

    this.markDirty();
    

    Voilà, tout fonctionne, les autres variables que vous voudriez enregistrer doivent êtres enregistrer dans le master
    seulement, mettez donc une condition dans les fonctions read et write et n'oubliez pas de reset les variables
    dans la fonction reset.

    Bonus

    Une idée ?

    Résultat

    Pour une plus grande clartée j'ai ajouté des blocstates, chaque situation
    à sa propre couleur, rouge si le bloc ne fait pas partie d'une structure,
    rose si il fait partie d'une structure mais qu'il n'est pas master, et
    jaune si il est master.

    0_1529311139345_multiblock-action.png



  • Tutoriel intéressant mais quelques problèmes dans le code : dans ta fonction checkStructure et setupStructure, d'où sort le "pos" ? Si c'est une variable de la TileEntity, mets un this.pos sinon on peut difficilement comprendre.

    De plus, à quoi sert le "else if (!t.hasMaster)" ? Un simple else suffit :

    if(t.hasMaster)
    {
    if(pos.getX() == t.getMasterX() && pos.getY() == t.getMasterY() && pos.getZ() == t.getMasterZ())
    {
    n++;
    }
    }
    else if(!t.hasMaster)
    {
    n++;
    }
    

  • Rédacteurs

    Efectivement pos est une variable de la classe TileEntity, je mettrai le this (le week-end prochain) et pour le else if pareil, c'est vrai qu'il ne sert à rien

    EDIT : mis à jour


  • Correcteurs

    Salut les gens, juste pour savoir, ce tuto marche-t-il aussi en 1.7.10?
    Des fonctions que j'ai pu voir logiquement oui, mais je ne suis pas certain.


  • Administrateurs

    Il faut adapter les blocs pos par x, y z et les block state par les metadata et normalement c'est bon.



  • pour l'ider tu pourrai four une structure mais avec un gui et fait une machine ?