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 var4 = this.blockLSBArray[par2 << 8 | par3 << 4 | par1] & 255;
067        return this.blockMSBArray != null ? this.blockMSBArray.get(par1, par2, par3) << 8 | var4 : var4;
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 var5 = this.blockLSBArray[par2 << 8 | par3 << 4 | par1] & 255;
078
079        if (this.blockMSBArray != null)
080        {
081            var5 |= this.blockMSBArray.get(par1, par2, par3) << 8;
082        }
083
084        if (var5 == 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 (var5 != 0 && par4 == 0)
094        {
095            --this.blockRefCount;
096
097            if (Block.blocksList[var5] != null && Block.blocksList[var5].getTickRandomly())
098            {
099                --this.tickRefCount;
100            }
101        }
102        else if (Block.blocksList[var5] != null && Block.blocksList[var5].getTickRandomly() && (Block.blocksList[par4] == null || !Block.blocksList[par4].getTickRandomly()))
103        {
104            --this.tickRefCount;
105        }
106        else if ((Block.blocksList[var5] == null || !Block.blocksList[var5].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 var1 = 0; var1 < 16; ++var1)
207        {
208            for (int var2 = 0; var2 < 16; ++var2)
209            {
210                for (int var3 = 0; var3 < 16; ++var3)
211                {
212                    int var4 = this.getExtBlockID(var1, var2, var3);
213
214                    if (var4 > 0)
215                    {
216                        if (Block.blocksList[var4] == null)
217                        {
218                            this.blockLSBArray[var2 << 8 | var3 << 4 | var1] = 0;
219
220                            if (this.blockMSBArray != null)
221                            {
222                                this.blockMSBArray.set(var1, var2, var3, 0);
223                            }
224                        }
225                        else
226                        {
227                            ++this.blockRefCount;
228
229                            if (Block.blocksList[var4].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}