    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}