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