001    package net.minecraft.world;
002    
003    import cpw.mods.fml.relauncher.Side;
004    import cpw.mods.fml.relauncher.SideOnly;
005    import net.minecraft.block.Block;
006    import net.minecraft.block.BlockHalfSlab;
007    import net.minecraft.block.BlockStairs;
008    import net.minecraft.block.material.Material;
009    import net.minecraft.tileentity.TileEntity;
010    import net.minecraft.util.Vec3Pool;
011    import net.minecraft.world.biome.BiomeGenBase;
012    import net.minecraft.world.chunk.Chunk;
013    
014    public class ChunkCache implements IBlockAccess
015    {
016        private int chunkX;
017        private int chunkZ;
018        private Chunk[][] chunkArray;
019    
020        /** set by !chunk.getAreLevelsEmpty */
021        private boolean hasExtendedLevels;
022    
023        /** Reference to the World object. */
024        private World worldObj;
025    
026        public ChunkCache(World par1World, int par2, int par3, int par4, int par5, int par6, int par7)
027        {
028            this.worldObj = par1World;
029            this.chunkX = par2 >> 4;
030            this.chunkZ = par4 >> 4;
031            int var8 = par5 >> 4;
032            int var9 = par7 >> 4;
033            this.chunkArray = new Chunk[var8 - this.chunkX + 1][var9 - this.chunkZ + 1];
034            this.hasExtendedLevels = true;
035    
036            for (int var10 = this.chunkX; var10 <= var8; ++var10)
037            {
038                for (int var11 = this.chunkZ; var11 <= var9; ++var11)
039                {
040                    Chunk var12 = par1World.getChunkFromChunkCoords(var10, var11);
041    
042                    if (var12 != null)
043                    {
044                        this.chunkArray[var10 - this.chunkX][var11 - this.chunkZ] = var12;
045    
046                        if (!var12.getAreLevelsEmpty(par3, par6))
047                        {
048                            this.hasExtendedLevels = false;
049                        }
050                    }
051                }
052            }
053        }
054    
055        @SideOnly(Side.CLIENT)
056    
057        /**
058         * set by !chunk.getAreLevelsEmpty
059         */
060        public boolean extendedLevelsInChunkCache()
061        {
062            return this.hasExtendedLevels;
063        }
064    
065        /**
066         * Returns the block ID at coords x,y,z
067         */
068        public int getBlockId(int par1, int par2, int par3)
069        {
070            if (par2 < 0)
071            {
072                return 0;
073            }
074            else if (par2 >= 256)
075            {
076                return 0;
077            }
078            else
079            {
080                int var4 = (par1 >> 4) - this.chunkX;
081                int var5 = (par3 >> 4) - this.chunkZ;
082    
083                if (var4 >= 0 && var4 < this.chunkArray.length && var5 >= 0 && var5 < this.chunkArray[var4].length)
084                {
085                    Chunk var6 = this.chunkArray[var4][var5];
086                    return var6 == null ? 0 : var6.getBlockID(par1 & 15, par2, par3 & 15);
087                }
088                else
089                {
090                    return 0;
091                }
092            }
093        }
094    
095        /**
096         * Returns the TileEntity associated with a given block in X,Y,Z coordinates, or null if no TileEntity exists
097         */
098        public TileEntity getBlockTileEntity(int par1, int par2, int par3)
099        {
100            int var4 = (par1 >> 4) - this.chunkX;
101            int var5 = (par3 >> 4) - this.chunkZ;
102            if (var4 >= 0 && var4 < this.chunkArray.length && var5 >= 0 && var5 < this.chunkArray[var4].length)
103            {
104                Chunk var6 = this.chunkArray[var4][var5];
105                return var6 == null ? null : var6.getChunkBlockTileEntity(par1 & 15, par2, par3 & 15);
106            }
107            else
108            {
109                return null;
110            }
111        }
112    
113        @SideOnly(Side.CLIENT)
114        public float getBrightness(int par1, int par2, int par3, int par4)
115        {
116            int var5 = this.getLightValue(par1, par2, par3);
117    
118            if (var5 < par4)
119            {
120                var5 = par4;
121            }
122    
123            return this.worldObj.provider.lightBrightnessTable[var5];
124        }
125    
126        @SideOnly(Side.CLIENT)
127    
128        /**
129         * Any Light rendered on a 1.8 Block goes through here
130         */
131        public int getLightBrightnessForSkyBlocks(int par1, int par2, int par3, int par4)
132        {
133            int var5 = this.getSkyBlockTypeBrightness(EnumSkyBlock.Sky, par1, par2, par3);
134            int var6 = this.getSkyBlockTypeBrightness(EnumSkyBlock.Block, par1, par2, par3);
135    
136            if (var6 < par4)
137            {
138                var6 = par4;
139            }
140    
141            return var5 << 20 | var6 << 4;
142        }
143    
144        @SideOnly(Side.CLIENT)
145    
146        /**
147         * Returns how bright the block is shown as which is the block's light value looked up in a lookup table (light
148         * values aren't linear for brightness). Args: x, y, z
149         */
150        public float getLightBrightness(int par1, int par2, int par3)
151        {
152            return this.worldObj.provider.lightBrightnessTable[this.getLightValue(par1, par2, par3)];
153        }
154    
155        @SideOnly(Side.CLIENT)
156    
157        /**
158         * Gets the light value of the specified block coords. Args: x, y, z
159         */
160        public int getLightValue(int par1, int par2, int par3)
161        {
162            return this.getLightValueExt(par1, par2, par3, true);
163        }
164    
165        @SideOnly(Side.CLIENT)
166    
167        /**
168         * Get light value with flag
169         */
170        public int getLightValueExt(int par1, int par2, int par3, boolean par4)
171        {
172            if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 <= 30000000)
173            {
174                int var5;
175                int var6;
176    
177                if (par4)
178                {
179                    var5 = this.getBlockId(par1, par2, par3);
180    
181                    if (var5 == Block.stoneSingleSlab.blockID || var5 == Block.woodSingleSlab.blockID || var5 == Block.tilledField.blockID || var5 == Block.stairCompactPlanks.blockID || var5 == Block.stairCompactCobblestone.blockID)
182                    {
183                        var6 = this.getLightValueExt(par1, par2 + 1, par3, false);
184                        int var7 = this.getLightValueExt(par1 + 1, par2, par3, false);
185                        int var8 = this.getLightValueExt(par1 - 1, par2, par3, false);
186                        int var9 = this.getLightValueExt(par1, par2, par3 + 1, false);
187                        int var10 = this.getLightValueExt(par1, par2, par3 - 1, false);
188    
189                        if (var7 > var6)
190                        {
191                            var6 = var7;
192                        }
193    
194                        if (var8 > var6)
195                        {
196                            var6 = var8;
197                        }
198    
199                        if (var9 > var6)
200                        {
201                            var6 = var9;
202                        }
203    
204                        if (var10 > var6)
205                        {
206                            var6 = var10;
207                        }
208    
209                        return var6;
210                    }
211                }
212    
213                if (par2 < 0)
214                {
215                    return 0;
216                }
217                else if (par2 >= 256)
218                {
219                    var5 = 15 - this.worldObj.skylightSubtracted;
220    
221                    if (var5 < 0)
222                    {
223                        var5 = 0;
224                    }
225    
226                    return var5;
227                }
228                else
229                {
230                    var5 = (par1 >> 4) - this.chunkX;
231                    var6 = (par3 >> 4) - this.chunkZ;
232                    return this.chunkArray[var5][var6].getBlockLightValue(par1 & 15, par2, par3 & 15, this.worldObj.skylightSubtracted);
233                }
234            }
235            else
236            {
237                return 15;
238            }
239        }
240    
241        /**
242         * Returns the block metadata at coords x,y,z
243         */
244        public int getBlockMetadata(int par1, int par2, int par3)
245        {
246            if (par2 < 0)
247            {
248                return 0;
249            }
250            else if (par2 >= 256)
251            {
252                return 0;
253            }
254            else
255            {
256                int var4 = (par1 >> 4) - this.chunkX;
257                int var5 = (par3 >> 4) - this.chunkZ;
258                if (var4 >= 0 && var4 < this.chunkArray.length && var5 >= 0 && var5 < this.chunkArray[var4].length)
259                {
260                    Chunk var6 = this.chunkArray[var4][var5];
261                    return var6 == null ? 0 : var6.getBlockMetadata(par1 & 15, par2, par3 & 15);
262                }
263                return 0;
264            }
265        }
266    
267        /**
268         * Returns the block's material.
269         */
270        public Material getBlockMaterial(int par1, int par2, int par3)
271        {
272            int var4 = this.getBlockId(par1, par2, par3);
273            return var4 == 0 ? Material.air : Block.blocksList[var4].blockMaterial;
274        }
275    
276        @SideOnly(Side.CLIENT)
277    
278        /**
279         * Gets the biome for a given set of x/z coordinates
280         */
281        public BiomeGenBase getBiomeGenForCoords(int par1, int par2)
282        {
283            return this.worldObj.getBiomeGenForCoords(par1, par2);
284        }
285    
286        @SideOnly(Side.CLIENT)
287    
288        /**
289         * Returns true if the block at the specified coordinates is an opaque cube. Args: x, y, z
290         */
291        public boolean isBlockOpaqueCube(int par1, int par2, int par3)
292        {
293            Block var4 = Block.blocksList[this.getBlockId(par1, par2, par3)];
294            return var4 == null ? false : var4.isOpaqueCube();
295        }
296    
297        /**
298         * Indicate if a material is a normal solid opaque cube.
299         */
300        public boolean isBlockNormalCube(int par1, int par2, int par3)
301        {
302            Block var4 = Block.blocksList[this.getBlockId(par1, par2, par3)];
303            return var4 == null ? false : var4.blockMaterial.blocksMovement() && var4.renderAsNormalBlock();
304        }
305    
306        @SideOnly(Side.CLIENT)
307    
308        /**
309         * Returns true if the block at the given coordinate has a solid (buildable) top surface.
310         */
311        public boolean doesBlockHaveSolidTopSurface(int par1, int par2, int par3)
312        {
313            Block var4 = Block.blocksList[this.getBlockId(par1, par2, par3)];
314            return var4 == null ? false : (var4.blockMaterial.isOpaque() && var4.renderAsNormalBlock() ? true : (var4 instanceof BlockStairs ? (this.getBlockMetadata(par1, par2, par3) & 4) == 4 : (var4 instanceof BlockHalfSlab ? (this.getBlockMetadata(par1, par2, par3) & 8) == 8 : false)));
315        }
316    
317        /**
318         * Return the Vec3Pool object for this world.
319         */
320        public Vec3Pool getWorldVec3Pool()
321        {
322            return this.worldObj.getWorldVec3Pool();
323        }
324    
325        @SideOnly(Side.CLIENT)
326    
327        /**
328         * Returns true if the block at the specified coordinates is empty
329         */
330        public boolean isAirBlock(int par1, int par2, int par3)
331        {
332            Block var4 = Block.blocksList[this.getBlockId(par1, par2, par3)];
333            return var4 == null;
334        }
335    
336        @SideOnly(Side.CLIENT)
337    
338        /**
339         * Brightness for SkyBlock.Sky is clear white and (through color computing it is assumed) DEPENDENT ON DAYTIME.
340         * Brightness for SkyBlock.Block is yellowish and independent.
341         */
342        public int getSkyBlockTypeBrightness(EnumSkyBlock par1EnumSkyBlock, int par2, int par3, int par4)
343        {
344            if (par3 < 0)
345            {
346                par3 = 0;
347            }
348    
349            if (par3 >= 256)
350            {
351                par3 = 255;
352            }
353    
354            if (par3 >= 0 && par3 < 256 && par2 >= -30000000 && par4 >= -30000000 && par2 < 30000000 && par4 <= 30000000)
355            {
356                if (par1EnumSkyBlock == EnumSkyBlock.Sky && this.worldObj.provider.hasNoSky)
357                {
358                    return 0;
359                }
360                else
361                {
362                    int var5;
363                    int var6;
364    
365                    if (Block.useNeighborBrightness[this.getBlockId(par2, par3, par4)])
366                    {
367                        var5 = this.getSpecialBlockBrightness(par1EnumSkyBlock, par2, par3 + 1, par4);
368                        var6 = this.getSpecialBlockBrightness(par1EnumSkyBlock, par2 + 1, par3, par4);
369                        int var7 = this.getSpecialBlockBrightness(par1EnumSkyBlock, par2 - 1, par3, par4);
370                        int var8 = this.getSpecialBlockBrightness(par1EnumSkyBlock, par2, par3, par4 + 1);
371                        int var9 = this.getSpecialBlockBrightness(par1EnumSkyBlock, par2, par3, par4 - 1);
372    
373                        if (var6 > var5)
374                        {
375                            var5 = var6;
376                        }
377    
378                        if (var7 > var5)
379                        {
380                            var5 = var7;
381                        }
382    
383                        if (var8 > var5)
384                        {
385                            var5 = var8;
386                        }
387    
388                        if (var9 > var5)
389                        {
390                            var5 = var9;
391                        }
392    
393                        return var5;
394                    }
395                    else
396                    {
397                        var5 = (par2 >> 4) - this.chunkX;
398                        var6 = (par4 >> 4) - this.chunkZ;
399                        return this.chunkArray[var5][var6].getSavedLightValue(par1EnumSkyBlock, par2 & 15, par3, par4 & 15);
400                    }
401                }
402            }
403            else
404            {
405                return par1EnumSkyBlock.defaultLightValue;
406            }
407        }
408    
409        @SideOnly(Side.CLIENT)
410    
411        /**
412         * is only used on stairs and tilled fields
413         */
414        public int getSpecialBlockBrightness(EnumSkyBlock par1EnumSkyBlock, int par2, int par3, int par4)
415        {
416            if (par3 < 0)
417            {
418                par3 = 0;
419            }
420    
421            if (par3 >= 256)
422            {
423                par3 = 255;
424            }
425    
426            if (par3 >= 0 && par3 < 256 && par2 >= -30000000 && par4 >= -30000000 && par2 < 30000000 && par4 <= 30000000)
427            {
428                int var5 = (par2 >> 4) - this.chunkX;
429                int var6 = (par4 >> 4) - this.chunkZ;
430                return this.chunkArray[var5][var6].getSavedLightValue(par1EnumSkyBlock, par2 & 15, par3, par4 & 15);
431            }
432            else
433            {
434                return par1EnumSkyBlock.defaultLightValue;
435            }
436        }
437    
438        @SideOnly(Side.CLIENT)
439    
440        /**
441         * Returns current world height.
442         */
443        public int getHeight()
444        {
445            return 256;
446        }
447    
448        /**
449         * Is this block powering in the specified direction Args: x, y, z, direction
450         */
451        public boolean isBlockProvidingPowerTo(int par1, int par2, int par3, int par4)
452        {
453            int var5 = this.getBlockId(par1, par2, par3);
454            return var5 == 0 ? false : Block.blocksList[var5].isProvidingStrongPower(this, par1, par2, par3, par4);
455        }
456    }