    001package net.minecraft.world.chunk.storage;
    002
    003import cpw.mods.fml.relauncher.Side;
    004import cpw.mods.fml.relauncher.SideOnly;
    005import net.minecraft.block.Block;
    006import net.minecraft.world.chunk.NibbleArray;
    007
    008public class ExtendedBlockStorage
    009{
    010    /**
    011     * Contains the bottom-most Y block represented by this ExtendedBlockStorage. Typically a multiple of 16.
    012     */
    013    private int yBase;
    014
    015    /**
    016     * A total count of the number of non-air blocks in this block storage's Chunk.
    017     */
    018    private int blockRefCount;
    019
    020    /**
    021     * Contains the number of blocks in this block storage's parent chunk that require random ticking. Used to cull the
    022     * Chunk from random tick updates for performance reasons.
    023     */
    024    private int tickRefCount;
    025
    026    /**
    027     * Contains the least significant 8 bits of each block ID belonging to this block storage's parent Chunk.
    028     */
    029    private byte[] blockLSBArray;
    030
    031    /**
    032     * Contains the most significant 4 bits of each block ID belonging to this block storage's parent Chunk.
    033     */
    034    private NibbleArray blockMSBArray;
    035
    036    /**
    037     * Stores the metadata associated with blocks in this ExtendedBlockStorage.
    038     */
    039    private NibbleArray blockMetadataArray;
    040
    041    /** The NibbleArray containing a block of Block-light data. */
    042    private NibbleArray blocklightArray;
    043
    044    /** The NibbleArray containing a block of Sky-light data. */
    045    private NibbleArray skylightArray;
    046
    047    public ExtendedBlockStorage(int par1, boolean par2)
    048    {
    049        this.yBase = par1;
    050        this.blockLSBArray = new byte[4096];
    051        this.blockMetadataArray = new NibbleArray(this.blockLSBArray.length, 4);
    052        this.blocklightArray = new NibbleArray(this.blockLSBArray.length, 4);
    053
    054        if (par2)
    055        {
    056            this.skylightArray = new NibbleArray(this.blockLSBArray.length, 4);
    057        }
    058    }
    059
    060    /**
    061     * Returns the extended block ID for a location in a chunk, merged from a byte array and a NibbleArray to form a
    062     * full 12-bit block ID.
    063     */
    064    public int getExtBlockID(int par1, int par2, int par3)
    065    {
    066        int l = this.blockLSBArray[par2 << 8 | par3 << 4 | par1] & 255;
    067        return this.blockMSBArray != null ? this.blockMSBArray.get(par1, par2, par3) << 8 | l : l;
    068    }
    069
    070    /**
    071     * Sets the extended block ID for a location in a chunk, splitting bits 11..8 into a NibbleArray and bits 7..0 into
    072     * a byte array. Also performs reference counting to determine whether or not to broadly cull this Chunk from the
    073     * random-update tick list.
    074     */
    075    public void setExtBlockID(int par1, int par2, int par3, int par4)
    076    {
    077        int i1 = this.blockLSBArray[par2 << 8 | par3 << 4 | par1] & 255;
    078
    079        if (this.blockMSBArray != null)
    080        {
    081            i1 |= this.blockMSBArray.get(par1, par2, par3) << 8;
    082        }
    083
    084        if (i1 == 0 && par4 != 0)
    085        {
    086            ++this.blockRefCount;
    087
    088            if (Block.blocksList[par4] != null && Block.blocksList[par4].getTickRandomly())
    089            {
    090                ++this.tickRefCount;
    091            }
    092        }
    093        else if (i1 != 0 && par4 == 0)
    094        {
    095            --this.blockRefCount;
    096
    097            if (Block.blocksList[i1] != null && Block.blocksList[i1].getTickRandomly())
    098            {
    099                --this.tickRefCount;
    100            }
    101        }
    102        else if (Block.blocksList[i1] != null && Block.blocksList[i1].getTickRandomly() && (Block.blocksList[par4] == null || !Block.blocksList[par4].getTickRandomly()))
    103        {
    104            --this.tickRefCount;
    105        }
    106        else if ((Block.blocksList[i1] == null || !Block.blocksList[i1].getTickRandomly()) && Block.blocksList[par4] != null && Block.blocksList[par4].getTickRandomly())
    107        {
    108            ++this.tickRefCount;
    109        }
    110
    111        this.blockLSBArray[par2 << 8 | par3 << 4 | par1] = (byte)(par4 & 255);
    112
    113        if (par4 > 255)
    114        {
    115            if (this.blockMSBArray == null)
    116            {
    117                this.blockMSBArray = new NibbleArray(this.blockLSBArray.length, 4);
    118            }
    119
    120            this.blockMSBArray.set(par1, par2, par3, (par4 & 3840) >> 8);
    121        }
    122        else if (this.blockMSBArray != null)
    123        {
    124            this.blockMSBArray.set(par1, par2, par3, 0);
    125        }
    126    }
    127
    128    /**
    129     * Returns the metadata associated with the block at the given coordinates in this ExtendedBlockStorage.
    130     */
    131    public int getExtBlockMetadata(int par1, int par2, int par3)
    132    {
    133        return this.blockMetadataArray.get(par1, par2, par3);
    134    }
    135
    136    /**
    137     * Sets the metadata of the Block at the given coordinates in this ExtendedBlockStorage to the given metadata.
    138     */
    139    public void setExtBlockMetadata(int par1, int par2, int par3, int par4)
    140    {
    141        this.blockMetadataArray.set(par1, par2, par3, par4);
    142    }
    143
    144    /**
    145     * Returns whether or not this block storage's Chunk is fully empty, based on its internal reference count.
    146     */
    147    public boolean isEmpty()
    148    {
    149        return this.blockRefCount == 0;
    150    }
    151
    152    /**
    153     * Returns whether or not this block storage's Chunk will require random ticking, used to avoid looping through
    154     * random block ticks when there are no blocks that would randomly tick.
    155     */
    156    public boolean getNeedsRandomTick()
    157    {
    158        return this.tickRefCount > 0;
    159    }
    160
    161    /**
    162     * Returns the Y location of this ExtendedBlockStorage.
    163     */
    164    public int getYLocation()
    165    {
    166        return this.yBase;
    167    }
    168
    169    /**
    170     * Sets the saved Sky-light value in the extended block storage structure.
    171     */
    172    public void setExtSkylightValue(int par1, int par2, int par3, int par4)
    173    {
    174        this.skylightArray.set(par1, par2, par3, par4);
    175    }
    176
    177    /**
    178     * Gets the saved Sky-light value in the extended block storage structure.
    179     */
    180    public int getExtSkylightValue(int par1, int par2, int par3)
    181    {
    182        return this.skylightArray.get(par1, par2, par3);
    183    }
    184
    185    /**
    186     * Sets the saved Block-light value in the extended block storage structure.
    187     */
    188    public void setExtBlocklightValue(int par1, int par2, int par3, int par4)
    189    {
    190        this.blocklightArray.set(par1, par2, par3, par4);
    191    }
    192
    193    /**
    194     * Gets the saved Block-light value in the extended block storage structure.
    195     */
    196    public int getExtBlocklightValue(int par1, int par2, int par3)
    197    {
    198        return this.blocklightArray.get(par1, par2, par3);
    199    }
    200
    201    public void removeInvalidBlocks()
    202    {
    203        this.blockRefCount = 0;
    204        this.tickRefCount = 0;
    205
    206        for (int i = 0; i < 16; ++i)
    207        {
    208            for (int j = 0; j < 16; ++j)
    209            {
    210                for (int k = 0; k < 16; ++k)
    211                {
    212                    int l = this.getExtBlockID(i, j, k);
    213
    214                    if (l > 0)
    215                    {
    216                        if (Block.blocksList[l] == null)
    217                        {
    218                            this.blockLSBArray[j << 8 | k << 4 | i] = 0;
    219
    220                            if (this.blockMSBArray != null)
    221                            {
    222                                this.blockMSBArray.set(i, j, k, 0);
    223                            }
    224                        }
    225                        else
    226                        {
    227                            ++this.blockRefCount;
    228
    229                            if (Block.blocksList[l].getTickRandomly())
    230                            {
    231                                ++this.tickRefCount;
    232                            }
    233                        }
    234                    }
    235                }
    236            }
    237        }
    238    }
    239
    240    public byte[] getBlockLSBArray()
    241    {
    242        return this.blockLSBArray;
    243    }
    244
    245    @SideOnly(Side.CLIENT)
    246    public void clearMSBArray()
    247    {
    248        this.blockMSBArray = null;
    249    }
    250
    251    /**
    252     * Returns the block ID MSB (bits 11..8) array for this storage array's Chunk.
    253     */
    254    public NibbleArray getBlockMSBArray()
    255    {
    256        return this.blockMSBArray;
    257    }
    258
    259    public NibbleArray getMetadataArray()
    260    {
    261        return this.blockMetadataArray;
    262    }
    263
    264    /**
    265     * Returns the NibbleArray instance containing Block-light data.
    266     */
    267    public NibbleArray getBlocklightArray()
    268    {
    269        return this.blocklightArray;
    270    }
    271
    272    /**
    273     * Returns the NibbleArray instance containing Sky-light data.
    274     */
    275    public NibbleArray getSkylightArray()
    276    {
    277        return this.skylightArray;
    278    }
    279
    280    /**
    281     * Sets the array of block ID least significant bits for this ExtendedBlockStorage.
    282     */
    283    public void setBlockLSBArray(byte[] par1ArrayOfByte)
    284    {
    285        this.blockLSBArray = par1ArrayOfByte;
    286    }
    287
    288    /**
    289     * Sets the array of blockID most significant bits (blockMSBArray) for this ExtendedBlockStorage.
    290     */
    291    public void setBlockMSBArray(NibbleArray par1NibbleArray)
    292    {
    293        this.blockMSBArray = par1NibbleArray;
    294    }
    295
    296    /**
    297     * Sets the NibbleArray of block metadata (blockMetadataArray) for this ExtendedBlockStorage.
    298     */
    299    public void setBlockMetadataArray(NibbleArray par1NibbleArray)
    300    {
    301        this.blockMetadataArray = par1NibbleArray;
    302    }
    303
    304    /**
    305     * Sets the NibbleArray instance used for Block-light values in this particular storage block.
    306     */
    307    public void setBlocklightArray(NibbleArray par1NibbleArray)
    308    {
    309        this.blocklightArray = par1NibbleArray;
    310    }
    311
    312    /**
    313     * Sets the NibbleArray instance used for Sky-light values in this particular storage block.
    314     */
    315    public void setSkylightArray(NibbleArray par1NibbleArray)
    316    {
    317        this.skylightArray = par1NibbleArray;
    318    }
    319
    320    @SideOnly(Side.CLIENT)
    321
    322    /**
    323     * Called by a Chunk to initialize the MSB array if getBlockMSBArray returns null. Returns the newly-created
    324     * NibbleArray instance.
    325     */
    326    public NibbleArray createBlockMSBArray()
    327    {
    328        this.blockMSBArray = new NibbleArray(this.blockLSBArray.length, 4);
    329        return this.blockMSBArray;
    330    }
    331}