001 package net.minecraft.src; 002 003 import cpw.mods.fml.common.Side; 004 import cpw.mods.fml.common.asm.SideOnly; 005 import java.util.ArrayList; 006 import java.util.Arrays; 007 import java.util.HashMap; 008 import java.util.Iterator; 009 import java.util.List; 010 import java.util.Map; 011 import java.util.Random; 012 013 import net.minecraftforge.common.MinecraftForge; 014 import net.minecraftforge.event.entity.EntityEvent; 015 import net.minecraftforge.event.world.ChunkEvent; 016 017 public class Chunk 018 { 019 /** 020 * Determines if the chunk is lit or not at a light value greater than 0. 021 */ 022 public static boolean isLit; 023 024 /** 025 * Used to store block IDs, block MSBs, Sky-light maps, Block-light maps, and metadata. Each entry corresponds to a 026 * logical segment of 16x16x16 blocks, stacked vertically. 027 */ 028 private ExtendedBlockStorage[] storageArrays; 029 030 /** 031 * Contains a 16x16 mapping on the X/Z plane of the biome ID to which each colum belongs. 032 */ 033 private byte[] blockBiomeArray; 034 035 /** 036 * A map, similar to heightMap, that tracks how far down precipitation can fall. 037 */ 038 public int[] precipitationHeightMap; 039 040 /** Which columns need their skylightMaps updated. */ 041 public boolean[] updateSkylightColumns; 042 043 /** Whether or not this Chunk is currently loaded into the World */ 044 public boolean isChunkLoaded; 045 046 /** Reference to the World object. */ 047 public World worldObj; 048 public int[] heightMap; 049 050 /** The x coordinate of the chunk. */ 051 public final int xPosition; 052 053 /** The z coordinate of the chunk. */ 054 public final int zPosition; 055 private boolean isGapLightingUpdated; 056 057 /** A Map of ChunkPositions to TileEntities in this chunk */ 058 public Map chunkTileEntityMap; 059 060 /** 061 * Array of Lists containing the entities in this Chunk. Each List represents a 16 block subchunk. 062 */ 063 public List[] entityLists; 064 065 /** Boolean value indicating if the terrain is populated. */ 066 public boolean isTerrainPopulated; 067 068 /** 069 * Set to true if the chunk has been modified and needs to be updated internally. 070 */ 071 public boolean isModified; 072 073 /** 074 * Whether this Chunk has any Entities and thus requires saving on every tick 075 */ 076 public boolean hasEntities; 077 078 /** The time according to World.worldTime when this chunk was last saved */ 079 public long lastSaveTime; 080 public boolean deferRender; 081 public int field_82912_p; 082 083 /** 084 * Contains the current round-robin relight check index, and is implied as the relight check location as well. 085 */ 086 private int queuedLightChecks; 087 boolean field_76653_p; 088 089 public Chunk(World par1World, int par2, int par3) 090 { 091 this.storageArrays = new ExtendedBlockStorage[16]; 092 this.blockBiomeArray = new byte[256]; 093 this.precipitationHeightMap = new int[256]; 094 this.updateSkylightColumns = new boolean[256]; 095 this.isGapLightingUpdated = false; 096 this.chunkTileEntityMap = new HashMap(); 097 this.isTerrainPopulated = false; 098 this.isModified = false; 099 this.hasEntities = false; 100 this.lastSaveTime = 0L; 101 this.deferRender = false; 102 this.field_82912_p = 0; 103 this.queuedLightChecks = 4096; 104 this.field_76653_p = false; 105 this.entityLists = new List[16]; 106 this.worldObj = par1World; 107 this.xPosition = par2; 108 this.zPosition = par3; 109 this.heightMap = new int[256]; 110 111 for (int var4 = 0; var4 < this.entityLists.length; ++var4) 112 { 113 this.entityLists[var4] = new ArrayList(); 114 } 115 116 Arrays.fill(this.precipitationHeightMap, -999); 117 Arrays.fill(this.blockBiomeArray, (byte) - 1); 118 } 119 120 public Chunk(World par1World, byte[] par2ArrayOfByte, int par3, int par4) 121 { 122 this(par1World, par3, par4); 123 int var5 = par2ArrayOfByte.length / 256; 124 125 for (int var6 = 0; var6 < 16; ++var6) 126 { 127 for (int var7 = 0; var7 < 16; ++var7) 128 { 129 for (int var8 = 0; var8 < var5; ++var8) 130 { 131 /* FORGE: The following change, a cast from unsigned byte to int, 132 * fixes a vanilla bug when generating new chunks that contain a block ID > 127 */ 133 int var9 = par2ArrayOfByte[var6 << 11 | var7 << 7 | var8] & 0xFF; 134 135 if (var9 != 0) 136 { 137 int var10 = var8 >> 4; 138 139 if (this.storageArrays[var10] == null) 140 { 141 this.storageArrays[var10] = new ExtendedBlockStorage(var10 << 4); 142 } 143 144 this.storageArrays[var10].setExtBlockID(var6, var8 & 15, var7, var9); 145 } 146 } 147 } 148 } 149 } 150 151 /** 152 * Metadata sensitive Chunk constructor for use in new ChunkProviders that 153 * use metadata sensitive blocks during generation. 154 * 155 * @param world The world this chunk belongs to 156 * @param ids A ByteArray containing all the BlockID's to set this chunk to 157 * @param metadata A ByteArray containing all the metadata to set this chunk to 158 * @param chunkX The chunk's X position 159 * @param chunkZ The Chunk's Z position 160 */ 161 public Chunk(World world, byte[] ids, byte[] metadata, int chunkX, int chunkZ) 162 { 163 this(world, chunkX, chunkZ); 164 int var5 = ids.length / 256; 165 166 for (int x = 0; x < 16; ++x) 167 { 168 for (int z = 0; z < 16; ++z) 169 { 170 for (int y = 0; y < var5; ++y) 171 { 172 int idx = x << 11 | z << 7 | y; 173 int id = ids[idx] & 0xFF; 174 int meta = metadata[idx]; 175 176 if (id != 0) 177 { 178 int var10 = y >> 4; 179 180 if (this.storageArrays[var10] == null) 181 { 182 this.storageArrays[var10] = new ExtendedBlockStorage(var10 << 4); 183 } 184 185 this.storageArrays[var10].setExtBlockID(x, y & 15, z, id); 186 this.storageArrays[var10].setExtBlockMetadata(x, y & 15, z, meta); 187 } 188 } 189 } 190 } 191 } 192 193 /** 194 * A Chunk Constructor which handles shorts to allow block ids > 256 (full 4096 range) 195 * Meta data sensitive 196 * NOTE: The x,y,z order of the array is different from the native Chunk constructor to allow for generation > y127 197 * NOTE: This is possibly more efficient than the standard constructor due to less memory skipping 198 * 199 * @param world The world this chunk belongs to 200 * @param ids A ShortArray containing all the BlockID's to set this chunk to (x is low order, z is mid, y is high) 201 * @param metadata A ByteArray containing all the metadata to set this chunk to 202 * @param chunkX The chunk's X position 203 * @param chunkZ The Chunk's Z position 204 */ 205 public Chunk(World world, short[] ids, byte[] metadata, int chunkX, int chunkZ) 206 { 207 this(world, chunkX, chunkZ); 208 int max = ids.length / 256; 209 210 for (int y = 0; y < max; ++y) 211 { 212 for (int z = 0; z < 16; ++z) 213 { 214 for (int x = 0; x < 16; ++x) 215 { 216 int idx = y << 8 | z << 4 | x; 217 int id = ids[idx] & 0xFFFFFF; 218 int meta = metadata[idx]; 219 220 if (id != 0) { 221 int storageBlock = y >> 4; 222 223 if (this.storageArrays[storageBlock] == null) { 224 this.storageArrays[storageBlock] = new ExtendedBlockStorage(storageBlock << 4); 225 } 226 227 this.storageArrays[storageBlock].setExtBlockID(x, y & 15, z, id); 228 this.storageArrays[storageBlock].setExtBlockMetadata(x, y & 15, z, meta); 229 } 230 } 231 } 232 } 233 } 234 235 /** 236 * Checks whether the chunk is at the X/Z location specified 237 */ 238 public boolean isAtLocation(int par1, int par2) 239 { 240 return par1 == this.xPosition && par2 == this.zPosition; 241 } 242 243 /** 244 * Returns the value in the height map at this x, z coordinate in the chunk 245 */ 246 public int getHeightValue(int par1, int par2) 247 { 248 return this.heightMap[par2 << 4 | par1]; 249 } 250 251 /** 252 * Returns the topmost ExtendedBlockStorage instance for this Chunk that actually contains a block. 253 */ 254 public int getTopFilledSegment() 255 { 256 for (int var1 = this.storageArrays.length - 1; var1 >= 0; --var1) 257 { 258 if (this.storageArrays[var1] != null) 259 { 260 return this.storageArrays[var1].getYLocation(); 261 } 262 } 263 264 return 0; 265 } 266 267 /** 268 * Returns the ExtendedBlockStorage array for this Chunk. 269 */ 270 public ExtendedBlockStorage[] getBlockStorageArray() 271 { 272 return this.storageArrays; 273 } 274 275 @SideOnly(Side.CLIENT) 276 277 /** 278 * Generates the height map for a chunk from scratch 279 */ 280 public void generateHeightMap() 281 { 282 int var1 = this.getTopFilledSegment(); 283 284 for (int var2 = 0; var2 < 16; ++var2) 285 { 286 int var3 = 0; 287 288 while (var3 < 16) 289 { 290 this.precipitationHeightMap[var2 + (var3 << 4)] = -999; 291 int var4 = var1 + 16 - 1; 292 293 while (true) 294 { 295 if (var4 > 0) 296 { 297 int var5 = this.getBlockID(var2, var4 - 1, var3); 298 299 if (getBlockLightOpacity(var2, var4 - 1, var3) == 0) 300 { 301 --var4; 302 continue; 303 } 304 305 this.heightMap[var3 << 4 | var2] = var4; 306 } 307 308 ++var3; 309 break; 310 } 311 } 312 } 313 314 this.isModified = true; 315 } 316 317 /** 318 * Generates the initial skylight map for the chunk upon generation or load. 319 */ 320 public void generateSkylightMap() 321 { 322 int var1 = this.getTopFilledSegment(); 323 this.field_82912_p = Integer.MAX_VALUE; 324 int var2; 325 int var3; 326 327 for (var2 = 0; var2 < 16; ++var2) 328 { 329 var3 = 0; 330 331 while (var3 < 16) 332 { 333 this.precipitationHeightMap[var2 + (var3 << 4)] = -999; 334 int var4 = var1 + 16 - 1; 335 336 while (true) 337 { 338 if (var4 > 0) 339 { 340 if (this.getBlockLightOpacity(var2, var4 - 1, var3) == 0) 341 { 342 --var4; 343 continue; 344 } 345 346 this.heightMap[var3 << 4 | var2] = var4; 347 348 if (var4 < this.field_82912_p) 349 { 350 this.field_82912_p = var4; 351 } 352 } 353 354 if (!this.worldObj.provider.hasNoSky) 355 { 356 var4 = 15; 357 int var5 = var1 + 16 - 1; 358 359 do 360 { 361 var4 -= this.getBlockLightOpacity(var2, var5, var3); 362 363 if (var4 > 0) 364 { 365 ExtendedBlockStorage var6 = this.storageArrays[var5 >> 4]; 366 367 if (var6 != null) 368 { 369 var6.setExtSkylightValue(var2, var5 & 15, var3, var4); 370 this.worldObj.markBlockForRenderUpdate((this.xPosition << 4) + var2, var5, (this.zPosition << 4) + var3); 371 } 372 } 373 374 --var5; 375 } 376 while (var5 > 0 && var4 > 0); 377 } 378 379 ++var3; 380 break; 381 } 382 } 383 } 384 385 this.isModified = true; 386 387 for (var2 = 0; var2 < 16; ++var2) 388 { 389 for (var3 = 0; var3 < 16; ++var3) 390 { 391 this.propagateSkylightOcclusion(var2, var3); 392 } 393 } 394 } 395 396 /** 397 * Propagates a given sky-visible block's light value downward and upward to neighboring blocks as necessary. 398 */ 399 private void propagateSkylightOcclusion(int par1, int par2) 400 { 401 this.updateSkylightColumns[par1 + par2 * 16] = true; 402 this.isGapLightingUpdated = true; 403 } 404 405 /** 406 * Runs delayed skylight updates. 407 */ 408 private void updateSkylight_do() 409 { 410 this.worldObj.theProfiler.startSection("recheckGaps"); 411 412 if (this.worldObj.doChunksNearChunkExist(this.xPosition * 16 + 8, 0, this.zPosition * 16 + 8, 16)) 413 { 414 for (int var1 = 0; var1 < 16; ++var1) 415 { 416 for (int var2 = 0; var2 < 16; ++var2) 417 { 418 if (this.updateSkylightColumns[var1 + var2 * 16]) 419 { 420 this.updateSkylightColumns[var1 + var2 * 16] = false; 421 int var3 = this.getHeightValue(var1, var2); 422 int var4 = this.xPosition * 16 + var1; 423 int var5 = this.zPosition * 16 + var2; 424 int var6 = this.worldObj.func_82734_g(var4 - 1, var5); 425 int var7 = this.worldObj.func_82734_g(var4 + 1, var5); 426 int var8 = this.worldObj.func_82734_g(var4, var5 - 1); 427 int var9 = this.worldObj.func_82734_g(var4, var5 + 1); 428 429 if (var7 < var6) 430 { 431 var6 = var7; 432 } 433 434 if (var8 < var6) 435 { 436 var6 = var8; 437 } 438 439 if (var9 < var6) 440 { 441 var6 = var9; 442 } 443 444 this.checkSkylightNeighborHeight(var4, var5, var6); 445 this.checkSkylightNeighborHeight(var4 - 1, var5, var3); 446 this.checkSkylightNeighborHeight(var4 + 1, var5, var3); 447 this.checkSkylightNeighborHeight(var4, var5 - 1, var3); 448 this.checkSkylightNeighborHeight(var4, var5 + 1, var3); 449 } 450 } 451 } 452 453 this.isGapLightingUpdated = false; 454 } 455 456 this.worldObj.theProfiler.endSection(); 457 } 458 459 /** 460 * Checks the height of a block next to a sky-visible block and schedules a lighting update as necessary. 461 */ 462 private void checkSkylightNeighborHeight(int par1, int par2, int par3) 463 { 464 int var4 = this.worldObj.getHeightValue(par1, par2); 465 466 if (var4 > par3) 467 { 468 this.updateSkylightNeighborHeight(par1, par2, par3, var4 + 1); 469 } 470 else if (var4 < par3) 471 { 472 this.updateSkylightNeighborHeight(par1, par2, var4, par3 + 1); 473 } 474 } 475 476 private void updateSkylightNeighborHeight(int par1, int par2, int par3, int par4) 477 { 478 if (par4 > par3 && this.worldObj.doChunksNearChunkExist(par1, 0, par2, 16)) 479 { 480 for (int var5 = par3; var5 < par4; ++var5) 481 { 482 this.worldObj.updateLightByType(EnumSkyBlock.Sky, par1, var5, par2); 483 } 484 485 this.isModified = true; 486 } 487 } 488 489 /** 490 * Initiates the recalculation of both the block-light and sky-light for a given block inside a chunk. 491 */ 492 private void relightBlock(int par1, int par2, int par3) 493 { 494 int var4 = this.heightMap[par3 << 4 | par1] & 255; 495 int var5 = var4; 496 497 if (par2 > var4) 498 { 499 var5 = par2; 500 } 501 502 while (var5 > 0 && this.getBlockLightOpacity(par1, var5 - 1, par3) == 0) 503 { 504 --var5; 505 } 506 507 if (var5 != var4) 508 { 509 this.worldObj.markBlocksDirtyVertical(par1 + this.xPosition * 16, par3 + this.zPosition * 16, var5, var4); 510 this.heightMap[par3 << 4 | par1] = var5; 511 int var6 = this.xPosition * 16 + par1; 512 int var7 = this.zPosition * 16 + par3; 513 int var8; 514 int var12; 515 516 if (!this.worldObj.provider.hasNoSky) 517 { 518 ExtendedBlockStorage var9; 519 520 if (var5 < var4) 521 { 522 for (var8 = var5; var8 < var4; ++var8) 523 { 524 var9 = this.storageArrays[var8 >> 4]; 525 526 if (var9 != null) 527 { 528 var9.setExtSkylightValue(par1, var8 & 15, par3, 15); 529 this.worldObj.markBlockForRenderUpdate((this.xPosition << 4) + par1, var8, (this.zPosition << 4) + par3); 530 } 531 } 532 } 533 else 534 { 535 for (var8 = var4; var8 < var5; ++var8) 536 { 537 var9 = this.storageArrays[var8 >> 4]; 538 539 if (var9 != null) 540 { 541 var9.setExtSkylightValue(par1, var8 & 15, par3, 0); 542 this.worldObj.markBlockForRenderUpdate((this.xPosition << 4) + par1, var8, (this.zPosition << 4) + par3); 543 } 544 } 545 } 546 547 var8 = 15; 548 549 while (var5 > 0 && var8 > 0) 550 { 551 --var5; 552 var12 = this.getBlockLightOpacity(par1, var5, par3); 553 554 if (var12 == 0) 555 { 556 var12 = 1; 557 } 558 559 var8 -= var12; 560 561 if (var8 < 0) 562 { 563 var8 = 0; 564 } 565 566 ExtendedBlockStorage var10 = this.storageArrays[var5 >> 4]; 567 568 if (var10 != null) 569 { 570 var10.setExtSkylightValue(par1, var5 & 15, par3, var8); 571 } 572 } 573 } 574 575 var8 = this.heightMap[par3 << 4 | par1]; 576 var12 = var4; 577 int var13 = var8; 578 579 if (var8 < var4) 580 { 581 var12 = var8; 582 var13 = var4; 583 } 584 585 if (var8 < this.field_82912_p) 586 { 587 this.field_82912_p = var8; 588 } 589 590 if (!this.worldObj.provider.hasNoSky) 591 { 592 this.updateSkylightNeighborHeight(var6 - 1, var7, var12, var13); 593 this.updateSkylightNeighborHeight(var6 + 1, var7, var12, var13); 594 this.updateSkylightNeighborHeight(var6, var7 - 1, var12, var13); 595 this.updateSkylightNeighborHeight(var6, var7 + 1, var12, var13); 596 this.updateSkylightNeighborHeight(var6, var7, var12, var13); 597 } 598 599 this.isModified = true; 600 } 601 } 602 603 public int getBlockLightOpacity(int par1, int par2, int par3) 604 { 605 int x = (xPosition << 4) + par1; 606 int z = (zPosition << 4) + par3; 607 Block block = Block.blocksList[getBlockID(par1, par2, par3)]; 608 return (block == null ? 0 : block.getLightOpacity(worldObj, x, par2, z)); 609 } 610 611 /** 612 * Return the ID of a block in the chunk. 613 */ 614 public int getBlockID(int par1, int par2, int par3) 615 { 616 if (par2 >> 4 >= this.storageArrays.length || par2 >> 4 < 0) 617 { 618 return 0; 619 } 620 else 621 { 622 ExtendedBlockStorage var4 = this.storageArrays[par2 >> 4]; 623 return var4 != null ? var4.getExtBlockID(par1, par2 & 15, par3) : 0; 624 } 625 } 626 627 /** 628 * Return the metadata corresponding to the given coordinates inside a chunk. 629 */ 630 public int getBlockMetadata(int par1, int par2, int par3) 631 { 632 if (par2 >> 4 >= this.storageArrays.length || par2 >> 4 < 0) 633 { 634 return 0; 635 } 636 else 637 { 638 ExtendedBlockStorage var4 = this.storageArrays[par2 >> 4]; 639 return var4 != null ? var4.getExtBlockMetadata(par1, par2 & 15, par3) : 0; 640 } 641 } 642 643 /** 644 * Sets a blockID for a position in the chunk. Args: x, y, z, blockID 645 */ 646 public boolean setBlockID(int par1, int par2, int par3, int par4) 647 { 648 return this.setBlockIDWithMetadata(par1, par2, par3, par4, 0); 649 } 650 651 /** 652 * Sets a blockID of a position within a chunk with metadata. Args: x, y, z, blockID, metadata 653 */ 654 public boolean setBlockIDWithMetadata(int par1, int par2, int par3, int par4, int par5) 655 { 656 int var6 = par3 << 4 | par1; 657 658 if (par2 >= this.precipitationHeightMap[var6] - 1) 659 { 660 this.precipitationHeightMap[var6] = -999; 661 } 662 663 int var7 = this.heightMap[var6]; 664 int var8 = this.getBlockID(par1, par2, par3); 665 int var9 = this.getBlockMetadata(par1, par2, par3); 666 667 if (var8 == par4 && var9 == par5) 668 { 669 return false; 670 } 671 else 672 { 673 if (par2 >> 4 >= storageArrays.length || par2 >> 4 < 0) 674 { 675 return false; 676 } 677 678 ExtendedBlockStorage var10 = this.storageArrays[par2 >> 4]; 679 boolean var11 = false; 680 681 if (var10 == null) 682 { 683 if (par4 == 0) 684 { 685 return false; 686 } 687 688 var10 = this.storageArrays[par2 >> 4] = new ExtendedBlockStorage(par2 >> 4 << 4); 689 var11 = par2 >= var7; 690 } 691 692 int var12 = this.xPosition * 16 + par1; 693 int var13 = this.zPosition * 16 + par3; 694 695 if (var8 != 0 && !this.worldObj.isRemote) 696 { 697 Block.blocksList[var8].onSetBlockIDWithMetaData(this.worldObj, var12, par2, var13, var9); 698 } 699 700 var10.setExtBlockID(par1, par2 & 15, par3, par4); 701 702 if (var8 != 0) 703 { 704 if (!this.worldObj.isRemote) 705 { 706 Block.blocksList[var8].breakBlock(this.worldObj, var12, par2, var13, var8, var9); 707 } 708 else if (Block.blocksList[var8] != null && Block.blocksList[var8].hasTileEntity(var9)) 709 { 710 this.worldObj.removeBlockTileEntity(var12, par2, var13); 711 } 712 } 713 714 if (var10.getExtBlockID(par1, par2 & 15, par3) != par4) 715 { 716 return false; 717 } 718 else 719 { 720 var10.setExtBlockMetadata(par1, par2 & 15, par3, par5); 721 722 if (var11) 723 { 724 this.generateSkylightMap(); 725 } 726 else 727 { 728 if (getBlockLightOpacity(par1, par2, par3) > 0) 729 { 730 if (par2 >= var7) 731 { 732 this.relightBlock(par1, par2 + 1, par3); 733 } 734 } 735 else if (par2 == var7 - 1) 736 { 737 this.relightBlock(par1, par2, par3); 738 } 739 740 this.propagateSkylightOcclusion(par1, par3); 741 } 742 743 TileEntity var14; 744 745 if (par4 != 0) 746 { 747 if (!this.worldObj.isRemote) 748 { 749 Block.blocksList[par4].onBlockAdded(this.worldObj, var12, par2, var13); 750 } 751 752 if (Block.blocksList[par4] != null && Block.blocksList[par4].hasTileEntity(par5)) 753 { 754 var14 = this.getChunkBlockTileEntity(par1, par2, par3); 755 756 if (var14 == null) 757 { 758 var14 = Block.blocksList[par4].createTileEntity(this.worldObj, par5); 759 this.worldObj.setBlockTileEntity(var12, par2, var13, var14); 760 } 761 762 if (var14 != null) 763 { 764 var14.updateContainingBlockInfo(); 765 var14.blockMetadata = par5; 766 } 767 } 768 } 769 770 this.isModified = true; 771 return true; 772 } 773 } 774 } 775 776 /** 777 * Set the metadata of a block in the chunk 778 */ 779 public boolean setBlockMetadata(int par1, int par2, int par3, int par4) 780 { 781 ExtendedBlockStorage var5 = (par2 >> 4 >= storageArrays.length || par2 >> 4 < 0 ? null : storageArrays[par2 >> 4]); 782 783 if (var5 == null) 784 { 785 return false; 786 } 787 else 788 { 789 int var6 = var5.getExtBlockMetadata(par1, par2 & 15, par3); 790 791 if (var6 == par4) 792 { 793 return false; 794 } 795 else 796 { 797 this.isModified = true; 798 var5.setExtBlockMetadata(par1, par2 & 15, par3, par4); 799 int var7 = var5.getExtBlockID(par1, par2 & 15, par3); 800 801 if (var7 > 0 && Block.blocksList[var7] != null && Block.blocksList[var7].hasTileEntity(par4)) 802 { 803 TileEntity var8 = this.getChunkBlockTileEntity(par1, par2, par3); 804 805 if (var8 != null) 806 { 807 var8.updateContainingBlockInfo(); 808 var8.blockMetadata = par4; 809 } 810 } 811 812 return true; 813 } 814 } 815 } 816 817 /** 818 * Gets the amount of light saved in this block (doesn't adjust for daylight) 819 */ 820 public int getSavedLightValue(EnumSkyBlock par1EnumSkyBlock, int par2, int par3, int par4) 821 { 822 ExtendedBlockStorage var5 = (par3 >> 4 >= storageArrays.length || par3 >> 4 < 0 ? null : storageArrays[par3 >> 4]); 823 return var5 == null ? (this.canBlockSeeTheSky(par2, par3, par4) ? par1EnumSkyBlock.defaultLightValue : 0) : (par1EnumSkyBlock == EnumSkyBlock.Sky ? var5.getExtSkylightValue(par2, par3 & 15, par4) : (par1EnumSkyBlock == EnumSkyBlock.Block ? var5.getExtBlocklightValue(par2, par3 & 15, par4) : par1EnumSkyBlock.defaultLightValue)); 824 } 825 826 /** 827 * Sets the light value at the coordinate. If enumskyblock is set to sky it sets it in the skylightmap and if its a 828 * block then into the blocklightmap. Args enumSkyBlock, x, y, z, lightValue 829 */ 830 public void setLightValue(EnumSkyBlock par1EnumSkyBlock, int par2, int par3, int par4, int par5) 831 { 832 if (par3 >> 4 >= storageArrays.length || par3 >> 4 < 0) 833 { 834 return; 835 } 836 837 ExtendedBlockStorage var6 = this.storageArrays[par3 >> 4]; 838 839 if (var6 == null) 840 { 841 var6 = this.storageArrays[par3 >> 4] = new ExtendedBlockStorage(par3 >> 4 << 4); 842 this.generateSkylightMap(); 843 } 844 845 this.isModified = true; 846 847 if (par1EnumSkyBlock == EnumSkyBlock.Sky) 848 { 849 if (!this.worldObj.provider.hasNoSky) 850 { 851 var6.setExtSkylightValue(par2, par3 & 15, par4, par5); 852 } 853 } 854 else if (par1EnumSkyBlock == EnumSkyBlock.Block) 855 { 856 var6.setExtBlocklightValue(par2, par3 & 15, par4, par5); 857 } 858 } 859 860 /** 861 * Gets the amount of light on a block taking into account sunlight 862 */ 863 public int getBlockLightValue(int par1, int par2, int par3, int par4) 864 { 865 ExtendedBlockStorage var5 = (par2 >> 4 >= storageArrays.length || par2 >> 4 < 0 ? null : storageArrays[par2 >> 4]); 866 867 if (var5 == null) 868 { 869 return !this.worldObj.provider.hasNoSky && par4 < EnumSkyBlock.Sky.defaultLightValue ? EnumSkyBlock.Sky.defaultLightValue - par4 : 0; 870 } 871 else 872 { 873 int var6 = this.worldObj.provider.hasNoSky ? 0 : var5.getExtSkylightValue(par1, par2 & 15, par3); 874 875 if (var6 > 0) 876 { 877 isLit = true; 878 } 879 880 var6 -= par4; 881 int var7 = var5.getExtBlocklightValue(par1, par2 & 15, par3); 882 883 if (var7 > var6) 884 { 885 var6 = var7; 886 } 887 888 return var6; 889 } 890 } 891 892 /** 893 * Adds an entity to the chunk. Args: entity 894 */ 895 public void addEntity(Entity par1Entity) 896 { 897 this.hasEntities = true; 898 int var2 = MathHelper.floor_double(par1Entity.posX / 16.0D); 899 int var3 = MathHelper.floor_double(par1Entity.posZ / 16.0D); 900 901 if (var2 != this.xPosition || var3 != this.zPosition) 902 { 903 System.out.println("Wrong location! " + par1Entity); 904 Thread.dumpStack(); 905 } 906 907 int var4 = MathHelper.floor_double(par1Entity.posY / 16.0D); 908 909 if (var4 < 0) 910 { 911 var4 = 0; 912 } 913 914 if (var4 >= this.entityLists.length) 915 { 916 var4 = this.entityLists.length - 1; 917 } 918 MinecraftForge.EVENT_BUS.post(new EntityEvent.EnteringChunk(par1Entity, this.xPosition, this.zPosition, par1Entity.chunkCoordX, par1Entity.chunkCoordZ)); 919 par1Entity.addedToChunk = true; 920 par1Entity.chunkCoordX = this.xPosition; 921 par1Entity.chunkCoordY = var4; 922 par1Entity.chunkCoordZ = this.zPosition; 923 this.entityLists[var4].add(par1Entity); 924 } 925 926 /** 927 * removes entity using its y chunk coordinate as its index 928 */ 929 public void removeEntity(Entity par1Entity) 930 { 931 this.removeEntityAtIndex(par1Entity, par1Entity.chunkCoordY); 932 } 933 934 /** 935 * Removes entity at the specified index from the entity array. 936 */ 937 public void removeEntityAtIndex(Entity par1Entity, int par2) 938 { 939 if (par2 < 0) 940 { 941 par2 = 0; 942 } 943 944 if (par2 >= this.entityLists.length) 945 { 946 par2 = this.entityLists.length - 1; 947 } 948 949 this.entityLists[par2].remove(par1Entity); 950 } 951 952 /** 953 * Returns whether is not a block above this one blocking sight to the sky (done via checking against the heightmap) 954 */ 955 public boolean canBlockSeeTheSky(int par1, int par2, int par3) 956 { 957 return par2 >= this.heightMap[par3 << 4 | par1]; 958 } 959 960 /** 961 * Gets the TileEntity for a given block in this chunk 962 */ 963 public TileEntity getChunkBlockTileEntity(int par1, int par2, int par3) 964 { 965 ChunkPosition var4 = new ChunkPosition(par1, par2, par3); 966 TileEntity var5 = (TileEntity)this.chunkTileEntityMap.get(var4); 967 968 if (var5 != null && var5.isInvalid()) 969 { 970 chunkTileEntityMap.remove(var4); 971 var5 = null; 972 } 973 974 if (var5 == null) 975 { 976 int var6 = this.getBlockID(par1, par2, par3); 977 978 int meta = this.getBlockMetadata(par1, par2, par3); 979 980 if (var6 <= 0 || !Block.blocksList[var6].hasTileEntity(meta)) 981 { 982 return null; 983 } 984 985 if (var5 == null) 986 { 987 var5 = Block.blocksList[var6].createTileEntity(this.worldObj, meta); 988 this.worldObj.setBlockTileEntity(this.xPosition * 16 + par1, par2, this.zPosition * 16 + par3, var5); 989 } 990 991 var5 = (TileEntity)this.chunkTileEntityMap.get(var4); 992 } 993 994 return var5; 995 } 996 997 /** 998 * Adds a TileEntity to a chunk 999 */ 1000 public void addTileEntity(TileEntity par1TileEntity) 1001 { 1002 int var2 = par1TileEntity.xCoord - this.xPosition * 16; 1003 int var3 = par1TileEntity.yCoord; 1004 int var4 = par1TileEntity.zCoord - this.zPosition * 16; 1005 this.setChunkBlockTileEntity(var2, var3, var4, par1TileEntity); 1006 1007 if (this.isChunkLoaded) 1008 { 1009 this.worldObj.addTileEntity(par1TileEntity); 1010 } 1011 } 1012 1013 /** 1014 * Sets the TileEntity for a given block in this chunk 1015 */ 1016 public void setChunkBlockTileEntity(int par1, int par2, int par3, TileEntity par4TileEntity) 1017 { 1018 ChunkPosition var5 = new ChunkPosition(par1, par2, par3); 1019 par4TileEntity.setWorldObj(this.worldObj); 1020 par4TileEntity.xCoord = this.xPosition * 16 + par1; 1021 par4TileEntity.yCoord = par2; 1022 par4TileEntity.zCoord = this.zPosition * 16 + par3; 1023 1024 Block block = Block.blocksList[getBlockID(par1, par2, par3)]; 1025 if (block != null && block.hasTileEntity(getBlockMetadata(par1, par2, par3))) 1026 { 1027 TileEntity old = (TileEntity)chunkTileEntityMap.get(var5); 1028 if (old != null) 1029 { 1030 old.invalidate(); 1031 } 1032 par4TileEntity.validate(); 1033 this.chunkTileEntityMap.put(var5, par4TileEntity); 1034 } 1035 } 1036 1037 /** 1038 * Removes the TileEntity for a given block in this chunk 1039 */ 1040 public void removeChunkBlockTileEntity(int par1, int par2, int par3) 1041 { 1042 ChunkPosition var4 = new ChunkPosition(par1, par2, par3); 1043 1044 if (this.isChunkLoaded) 1045 { 1046 TileEntity var5 = (TileEntity)this.chunkTileEntityMap.remove(var4); 1047 1048 if (var5 != null) 1049 { 1050 var5.invalidate(); 1051 } 1052 } 1053 } 1054 1055 /** 1056 * Called when this Chunk is loaded by the ChunkProvider 1057 */ 1058 public void onChunkLoad() 1059 { 1060 this.isChunkLoaded = true; 1061 this.worldObj.addTileEntity(this.chunkTileEntityMap.values()); 1062 1063 for (int var1 = 0; var1 < this.entityLists.length; ++var1) 1064 { 1065 this.worldObj.addLoadedEntities(this.entityLists[var1]); 1066 } 1067 MinecraftForge.EVENT_BUS.post(new ChunkEvent.Load(this)); 1068 } 1069 1070 /** 1071 * Called when this Chunk is unloaded by the ChunkProvider 1072 */ 1073 public void onChunkUnload() 1074 { 1075 this.isChunkLoaded = false; 1076 Iterator var1 = this.chunkTileEntityMap.values().iterator(); 1077 1078 while (var1.hasNext()) 1079 { 1080 TileEntity var2 = (TileEntity)var1.next(); 1081 this.worldObj.markTileEntityForDespawn(var2); 1082 } 1083 1084 for (int var3 = 0; var3 < this.entityLists.length; ++var3) 1085 { 1086 this.worldObj.unloadEntities(this.entityLists[var3]); 1087 } 1088 MinecraftForge.EVENT_BUS.post(new ChunkEvent.Unload(this)); 1089 } 1090 1091 /** 1092 * Sets the isModified flag for this Chunk 1093 */ 1094 public void setChunkModified() 1095 { 1096 this.isModified = true; 1097 } 1098 1099 /** 1100 * Fills the given list of all entities that intersect within the given bounding box that aren't the passed entity 1101 * Args: entity, aabb, listToFill 1102 */ 1103 public void getEntitiesWithinAABBForEntity(Entity par1Entity, AxisAlignedBB par2AxisAlignedBB, List par3List) 1104 { 1105 int var4 = MathHelper.floor_double((par2AxisAlignedBB.minY - World.MAX_ENTITY_RADIUS) / 16.0D); 1106 int var5 = MathHelper.floor_double((par2AxisAlignedBB.maxY + World.MAX_ENTITY_RADIUS) / 16.0D); 1107 1108 if (var4 < 0) 1109 { 1110 var4 = 0; 1111 } 1112 1113 if (var5 >= this.entityLists.length) 1114 { 1115 var5 = this.entityLists.length - 1; 1116 } 1117 1118 for (int var6 = var4; var6 <= var5; ++var6) 1119 { 1120 List var7 = this.entityLists[var6]; 1121 1122 for (int var8 = 0; var8 < var7.size(); ++var8) 1123 { 1124 Entity var9 = (Entity)var7.get(var8); 1125 1126 if (var9 != par1Entity && var9.boundingBox.intersectsWith(par2AxisAlignedBB)) 1127 { 1128 par3List.add(var9); 1129 Entity[] var10 = var9.getParts(); 1130 1131 if (var10 != null) 1132 { 1133 for (int var11 = 0; var11 < var10.length; ++var11) 1134 { 1135 var9 = var10[var11]; 1136 1137 if (var9 != par1Entity && var9.boundingBox.intersectsWith(par2AxisAlignedBB)) 1138 { 1139 par3List.add(var9); 1140 } 1141 } 1142 } 1143 } 1144 } 1145 } 1146 } 1147 1148 /** 1149 * Gets all entities that can be assigned to the specified class. Args: entityClass, aabb, listToFill 1150 */ 1151 public void getEntitiesOfTypeWithinAAAB(Class par1Class, AxisAlignedBB par2AxisAlignedBB, List par3List, IEntitySelector par4IEntitySelector) 1152 { 1153 int var5 = MathHelper.floor_double((par2AxisAlignedBB.minY - World.MAX_ENTITY_RADIUS) / 16.0D); 1154 int var6 = MathHelper.floor_double((par2AxisAlignedBB.maxY + World.MAX_ENTITY_RADIUS) / 16.0D); 1155 1156 if (var5 < 0) 1157 { 1158 var5 = 0; 1159 } 1160 else if (var5 >= this.entityLists.length) 1161 { 1162 var5 = this.entityLists.length - 1; 1163 } 1164 1165 if (var6 >= this.entityLists.length) 1166 { 1167 var6 = this.entityLists.length - 1; 1168 } 1169 else if (var6 < 0) 1170 { 1171 var6 = 0; 1172 } 1173 1174 for (int var7 = var5; var7 <= var6; ++var7) 1175 { 1176 List var8 = this.entityLists[var7]; 1177 1178 for (int var9 = 0; var9 < var8.size(); ++var9) 1179 { 1180 Entity var10 = (Entity)var8.get(var9); 1181 1182 if (par1Class.isAssignableFrom(var10.getClass()) && var10.boundingBox.intersectsWith(par2AxisAlignedBB) && (par4IEntitySelector == null || par4IEntitySelector.isEntityApplicable(var10))) 1183 { 1184 par3List.add(var10); 1185 } 1186 } 1187 } 1188 } 1189 1190 /** 1191 * Returns true if this Chunk needs to be saved 1192 */ 1193 public boolean needsSaving(boolean par1) 1194 { 1195 if (par1) 1196 { 1197 if (this.hasEntities && this.worldObj.getTotalWorldTime() != this.lastSaveTime) 1198 { 1199 return true; 1200 } 1201 } 1202 else if (this.hasEntities && this.worldObj.getTotalWorldTime() >= this.lastSaveTime + 600L) 1203 { 1204 return true; 1205 } 1206 1207 return this.isModified; 1208 } 1209 1210 public Random getRandomWithSeed(long par1) 1211 { 1212 return new Random(this.worldObj.getSeed() + (long)(this.xPosition * this.xPosition * 4987142) + (long)(this.xPosition * 5947611) + (long)(this.zPosition * this.zPosition) * 4392871L + (long)(this.zPosition * 389711) ^ par1); 1213 } 1214 1215 public boolean isEmpty() 1216 { 1217 return false; 1218 } 1219 1220 public void populateChunk(IChunkProvider par1IChunkProvider, IChunkProvider par2IChunkProvider, int par3, int par4) 1221 { 1222 if (!this.isTerrainPopulated && par1IChunkProvider.chunkExists(par3 + 1, par4 + 1) && par1IChunkProvider.chunkExists(par3, par4 + 1) && par1IChunkProvider.chunkExists(par3 + 1, par4)) 1223 { 1224 par1IChunkProvider.populate(par2IChunkProvider, par3, par4); 1225 } 1226 1227 if (par1IChunkProvider.chunkExists(par3 - 1, par4) && !par1IChunkProvider.provideChunk(par3 - 1, par4).isTerrainPopulated && par1IChunkProvider.chunkExists(par3 - 1, par4 + 1) && par1IChunkProvider.chunkExists(par3, par4 + 1) && par1IChunkProvider.chunkExists(par3 - 1, par4 + 1)) 1228 { 1229 par1IChunkProvider.populate(par2IChunkProvider, par3 - 1, par4); 1230 } 1231 1232 if (par1IChunkProvider.chunkExists(par3, par4 - 1) && !par1IChunkProvider.provideChunk(par3, par4 - 1).isTerrainPopulated && par1IChunkProvider.chunkExists(par3 + 1, par4 - 1) && par1IChunkProvider.chunkExists(par3 + 1, par4 - 1) && par1IChunkProvider.chunkExists(par3 + 1, par4)) 1233 { 1234 par1IChunkProvider.populate(par2IChunkProvider, par3, par4 - 1); 1235 } 1236 1237 if (par1IChunkProvider.chunkExists(par3 - 1, par4 - 1) && !par1IChunkProvider.provideChunk(par3 - 1, par4 - 1).isTerrainPopulated && par1IChunkProvider.chunkExists(par3, par4 - 1) && par1IChunkProvider.chunkExists(par3 - 1, par4)) 1238 { 1239 par1IChunkProvider.populate(par2IChunkProvider, par3 - 1, par4 - 1); 1240 } 1241 } 1242 1243 /** 1244 * Gets the height to which rain/snow will fall. Calculates it if not already stored. 1245 */ 1246 public int getPrecipitationHeight(int par1, int par2) 1247 { 1248 int var3 = par1 | par2 << 4; 1249 int var4 = this.precipitationHeightMap[var3]; 1250 1251 if (var4 == -999) 1252 { 1253 int var5 = this.getTopFilledSegment() + 15; 1254 var4 = -1; 1255 1256 while (var5 > 0 && var4 == -1) 1257 { 1258 int var6 = this.getBlockID(par1, var5, par2); 1259 Material var7 = var6 == 0 ? Material.air : Block.blocksList[var6].blockMaterial; 1260 1261 if (!var7.blocksMovement() && !var7.isLiquid()) 1262 { 1263 --var5; 1264 } 1265 else 1266 { 1267 var4 = var5 + 1; 1268 } 1269 } 1270 1271 this.precipitationHeightMap[var3] = var4; 1272 } 1273 1274 return var4; 1275 } 1276 1277 /** 1278 * Checks whether skylight needs updated; if it does, calls updateSkylight_do 1279 */ 1280 public void updateSkylight() 1281 { 1282 if (this.isGapLightingUpdated && !this.worldObj.provider.hasNoSky) 1283 { 1284 this.updateSkylight_do(); 1285 } 1286 } 1287 1288 /** 1289 * Gets a ChunkCoordIntPair representing the Chunk's position. 1290 */ 1291 public ChunkCoordIntPair getChunkCoordIntPair() 1292 { 1293 return new ChunkCoordIntPair(this.xPosition, this.zPosition); 1294 } 1295 1296 /** 1297 * Returns whether the ExtendedBlockStorages containing levels (in blocks) from arg 1 to arg 2 are fully empty 1298 * (true) or not (false). 1299 */ 1300 public boolean getAreLevelsEmpty(int par1, int par2) 1301 { 1302 if (par1 < 0) 1303 { 1304 par1 = 0; 1305 } 1306 1307 if (par2 >= 256) 1308 { 1309 par2 = 255; 1310 } 1311 1312 for (int var3 = par1; var3 <= par2; var3 += 16) 1313 { 1314 ExtendedBlockStorage var4 = this.storageArrays[var3 >> 4]; 1315 1316 if (var4 != null && !var4.isEmpty()) 1317 { 1318 return false; 1319 } 1320 } 1321 1322 return true; 1323 } 1324 1325 public void setStorageArrays(ExtendedBlockStorage[] par1ArrayOfExtendedBlockStorage) 1326 { 1327 this.storageArrays = par1ArrayOfExtendedBlockStorage; 1328 } 1329 1330 @SideOnly(Side.CLIENT) 1331 1332 /** 1333 * Initialise this chunk with new binary data 1334 */ 1335 public void fillChunk(byte[] par1ArrayOfByte, int par2, int par3, boolean par4) 1336 { 1337 Iterator iterator = chunkTileEntityMap.values().iterator(); 1338 while(iterator.hasNext()) 1339 { 1340 TileEntity tileEntity = (TileEntity)iterator.next(); 1341 tileEntity.updateContainingBlockInfo(); 1342 tileEntity.getBlockMetadata(); 1343 tileEntity.getBlockType(); 1344 } 1345 1346 int var5 = 0; 1347 int var6; 1348 1349 for (var6 = 0; var6 < this.storageArrays.length; ++var6) 1350 { 1351 if ((par2 & 1 << var6) != 0) 1352 { 1353 if (this.storageArrays[var6] == null) 1354 { 1355 this.storageArrays[var6] = new ExtendedBlockStorage(var6 << 4); 1356 } 1357 1358 byte[] var7 = this.storageArrays[var6].getBlockLSBArray(); 1359 System.arraycopy(par1ArrayOfByte, var5, var7, 0, var7.length); 1360 var5 += var7.length; 1361 } 1362 else if (par4 && this.storageArrays[var6] != null) 1363 { 1364 this.storageArrays[var6] = null; 1365 } 1366 } 1367 1368 NibbleArray var8; 1369 1370 for (var6 = 0; var6 < this.storageArrays.length; ++var6) 1371 { 1372 if ((par2 & 1 << var6) != 0 && this.storageArrays[var6] != null) 1373 { 1374 var8 = this.storageArrays[var6].getMetadataArray(); 1375 System.arraycopy(par1ArrayOfByte, var5, var8.data, 0, var8.data.length); 1376 var5 += var8.data.length; 1377 } 1378 } 1379 1380 for (var6 = 0; var6 < this.storageArrays.length; ++var6) 1381 { 1382 if ((par2 & 1 << var6) != 0 && this.storageArrays[var6] != null) 1383 { 1384 var8 = this.storageArrays[var6].getBlocklightArray(); 1385 System.arraycopy(par1ArrayOfByte, var5, var8.data, 0, var8.data.length); 1386 var5 += var8.data.length; 1387 } 1388 } 1389 1390 for (var6 = 0; var6 < this.storageArrays.length; ++var6) 1391 { 1392 if ((par2 & 1 << var6) != 0 && this.storageArrays[var6] != null) 1393 { 1394 var8 = this.storageArrays[var6].getSkylightArray(); 1395 System.arraycopy(par1ArrayOfByte, var5, var8.data, 0, var8.data.length); 1396 var5 += var8.data.length; 1397 } 1398 } 1399 1400 for (var6 = 0; var6 < this.storageArrays.length; ++var6) 1401 { 1402 if ((par3 & 1 << var6) != 0) 1403 { 1404 if (this.storageArrays[var6] == null) 1405 { 1406 var5 += 2048; 1407 } 1408 else 1409 { 1410 var8 = this.storageArrays[var6].getBlockMSBArray(); 1411 1412 if (var8 == null) 1413 { 1414 var8 = this.storageArrays[var6].createBlockMSBArray(); 1415 } 1416 1417 System.arraycopy(par1ArrayOfByte, var5, var8.data, 0, var8.data.length); 1418 var5 += var8.data.length; 1419 } 1420 } 1421 else if (par4 && this.storageArrays[var6] != null && this.storageArrays[var6].getBlockMSBArray() != null) 1422 { 1423 this.storageArrays[var6].clearMSBArray(); 1424 } 1425 } 1426 1427 if (par4) 1428 { 1429 System.arraycopy(par1ArrayOfByte, var5, this.blockBiomeArray, 0, this.blockBiomeArray.length); 1430 int var10000 = var5 + this.blockBiomeArray.length; 1431 } 1432 1433 for (var6 = 0; var6 < this.storageArrays.length; ++var6) 1434 { 1435 if (this.storageArrays[var6] != null && (par2 & 1 << var6) != 0) 1436 { 1437 this.storageArrays[var6].removeInvalidBlocks(); 1438 } 1439 } 1440 1441 this.generateHeightMap(); 1442 1443 List<TileEntity> invalidList = new ArrayList<TileEntity>(); 1444 iterator = chunkTileEntityMap.values().iterator(); 1445 while (iterator.hasNext()) 1446 { 1447 TileEntity tileEntity = (TileEntity)iterator.next(); 1448 int x = tileEntity.xCoord & 15; 1449 int y = tileEntity.yCoord; 1450 int z = tileEntity.zCoord & 15; 1451 Block block = tileEntity.getBlockType(); 1452 if (block == null || block.blockID != getBlockID(x, y, z) || tileEntity.getBlockMetadata() != getBlockMetadata(x, y, z)) 1453 { 1454 invalidList.add(tileEntity); 1455 } 1456 tileEntity.updateContainingBlockInfo(); 1457 } 1458 1459 for (TileEntity tileEntity : invalidList) 1460 { 1461 tileEntity.invalidate(); 1462 } 1463 } 1464 1465 /** 1466 * This method retrieves the biome at a set of coordinates 1467 */ 1468 public BiomeGenBase getBiomeGenForWorldCoords(int par1, int par2, WorldChunkManager par3WorldChunkManager) 1469 { 1470 int var4 = this.blockBiomeArray[par2 << 4 | par1] & 255; 1471 1472 if (var4 == 255) 1473 { 1474 BiomeGenBase var5 = par3WorldChunkManager.getBiomeGenAt((this.xPosition << 4) + par1, (this.zPosition << 4) + par2); 1475 var4 = var5.biomeID; 1476 this.blockBiomeArray[par2 << 4 | par1] = (byte)(var4 & 255); 1477 } 1478 1479 return BiomeGenBase.biomeList[var4] == null ? BiomeGenBase.plains : BiomeGenBase.biomeList[var4]; 1480 } 1481 1482 /** 1483 * Returns an array containing a 16x16 mapping on the X/Z of block positions in this Chunk to biome IDs. 1484 */ 1485 public byte[] getBiomeArray() 1486 { 1487 return this.blockBiomeArray; 1488 } 1489 1490 /** 1491 * Accepts a 256-entry array that contains a 16x16 mapping on the X/Z plane of block positions in this Chunk to 1492 * biome IDs. 1493 */ 1494 public void setBiomeArray(byte[] par1ArrayOfByte) 1495 { 1496 this.blockBiomeArray = par1ArrayOfByte; 1497 } 1498 1499 /** 1500 * Resets the relight check index to 0 for this Chunk. 1501 */ 1502 public void resetRelightChecks() 1503 { 1504 this.queuedLightChecks = 0; 1505 } 1506 1507 /** 1508 * Called once-per-chunk-per-tick, and advances the round-robin relight check index per-storage-block by up to 8 1509 * blocks at a time. In a worst-case scenario, can potentially take up to 1.6 seconds, calculated via 1510 * (4096/(8*16))/20, to re-check all blocks in a chunk, which could explain both lagging light updates in certain 1511 * cases as well as Nether relight 1512 */ 1513 public void enqueueRelightChecks() 1514 { 1515 for (int var1 = 0; var1 < 8; ++var1) 1516 { 1517 if (this.queuedLightChecks >= 4096) 1518 { 1519 return; 1520 } 1521 1522 int var2 = this.queuedLightChecks % 16; 1523 int var3 = this.queuedLightChecks / 16 % 16; 1524 int var4 = this.queuedLightChecks / 256; 1525 ++this.queuedLightChecks; 1526 int var5 = (this.xPosition << 4) + var3; 1527 int var6 = (this.zPosition << 4) + var4; 1528 1529 for (int var7 = 0; var7 < 16; ++var7) 1530 { 1531 int var8 = (var2 << 4) + var7; 1532 1533 if (this.storageArrays[var2] == null && (var7 == 0 || var7 == 15 || var3 == 0 || var3 == 15 || var4 == 0 || var4 == 15) || this.storageArrays[var2] != null && this.storageArrays[var2].getExtBlockID(var3, var7, var4) == 0) 1534 { 1535 if (Block.lightValue[this.worldObj.getBlockId(var5, var8 - 1, var6)] > 0) 1536 { 1537 this.worldObj.updateAllLightTypes(var5, var8 - 1, var6); 1538 } 1539 1540 if (Block.lightValue[this.worldObj.getBlockId(var5, var8 + 1, var6)] > 0) 1541 { 1542 this.worldObj.updateAllLightTypes(var5, var8 + 1, var6); 1543 } 1544 1545 if (Block.lightValue[this.worldObj.getBlockId(var5 - 1, var8, var6)] > 0) 1546 { 1547 this.worldObj.updateAllLightTypes(var5 - 1, var8, var6); 1548 } 1549 1550 if (Block.lightValue[this.worldObj.getBlockId(var5 + 1, var8, var6)] > 0) 1551 { 1552 this.worldObj.updateAllLightTypes(var5 + 1, var8, var6); 1553 } 1554 1555 if (Block.lightValue[this.worldObj.getBlockId(var5, var8, var6 - 1)] > 0) 1556 { 1557 this.worldObj.updateAllLightTypes(var5, var8, var6 - 1); 1558 } 1559 1560 if (Block.lightValue[this.worldObj.getBlockId(var5, var8, var6 + 1)] > 0) 1561 { 1562 this.worldObj.updateAllLightTypes(var5, var8, var6 + 1); 1563 } 1564 1565 this.worldObj.updateAllLightTypes(var5, var8, var6); 1566 } 1567 } 1568 } 1569 } 1570 1571 /** FORGE: Used to remove only invalid TileEntities */ 1572 public void cleanChunkBlockTileEntity(int x, int y, int z) 1573 { 1574 ChunkPosition position = new ChunkPosition(x, y, z); 1575 if (isChunkLoaded) 1576 { 1577 TileEntity entity = (TileEntity)chunkTileEntityMap.get(position); 1578 if (entity != null && entity.isInvalid()) 1579 { 1580 chunkTileEntityMap.remove(position); 1581 } 1582 } 1583 } 1584 }