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