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