001package net.minecraft.world;
002
003import cpw.mods.fml.relauncher.Side;
004import cpw.mods.fml.relauncher.SideOnly;
005import net.minecraft.block.Block;
006import net.minecraft.block.BlockHalfSlab;
007import net.minecraft.block.BlockStairs;
008import net.minecraft.block.material.Material;
009import net.minecraft.tileentity.TileEntity;
010import net.minecraft.util.Vec3Pool;
011import net.minecraft.world.biome.BiomeGenBase;
012import net.minecraft.world.chunk.Chunk;
013
014public 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    public 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}