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}