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 TileEntity te = worldObj.getBlockTileEntity(var12, par2, var13); 711 if (te != null && te.shouldRefresh(var8, par4, var9, par5, worldObj, var12, par2, var13)) 712 { 713 this.worldObj.removeBlockTileEntity(var12, par2, var13); 714 } 715 } 716 } 717 718 if (var10.getExtBlockID(par1, par2 & 15, par3) != par4) 719 { 720 return false; 721 } 722 else 723 { 724 var10.setExtBlockMetadata(par1, par2 & 15, par3, par5); 725 726 if (var11) 727 { 728 this.generateSkylightMap(); 729 } 730 else 731 { 732 if (getBlockLightOpacity(par1, par2, par3) > 0) 733 { 734 if (par2 >= var7) 735 { 736 this.relightBlock(par1, par2 + 1, par3); 737 } 738 } 739 else if (par2 == var7 - 1) 740 { 741 this.relightBlock(par1, par2, par3); 742 } 743 744 this.propagateSkylightOcclusion(par1, par3); 745 } 746 747 TileEntity var14; 748 749 if (par4 != 0) 750 { 751 if (!this.worldObj.isRemote) 752 { 753 Block.blocksList[par4].onBlockAdded(this.worldObj, var12, par2, var13); 754 } 755 756 if (Block.blocksList[par4] != null && Block.blocksList[par4].hasTileEntity(par5)) 757 { 758 var14 = this.getChunkBlockTileEntity(par1, par2, par3); 759 760 if (var14 == null) 761 { 762 var14 = Block.blocksList[par4].createTileEntity(this.worldObj, par5); 763 this.worldObj.setBlockTileEntity(var12, par2, var13, var14); 764 } 765 766 if (var14 != null) 767 { 768 var14.updateContainingBlockInfo(); 769 var14.blockMetadata = par5; 770 } 771 } 772 } 773 774 this.isModified = true; 775 return true; 776 } 777 } 778 } 779 780 /** 781 * Set the metadata of a block in the chunk 782 */ 783 public boolean setBlockMetadata(int par1, int par2, int par3, int par4) 784 { 785 ExtendedBlockStorage var5 = (par2 >> 4 >= storageArrays.length || par2 >> 4 < 0 ? null : storageArrays[par2 >> 4]); 786 787 if (var5 == null) 788 { 789 return false; 790 } 791 else 792 { 793 int var6 = var5.getExtBlockMetadata(par1, par2 & 15, par3); 794 795 if (var6 == par4) 796 { 797 return false; 798 } 799 else 800 { 801 this.isModified = true; 802 var5.setExtBlockMetadata(par1, par2 & 15, par3, par4); 803 int var7 = var5.getExtBlockID(par1, par2 & 15, par3); 804 805 if (var7 > 0 && Block.blocksList[var7] != null && Block.blocksList[var7].hasTileEntity(par4)) 806 { 807 TileEntity var8 = this.getChunkBlockTileEntity(par1, par2, par3); 808 809 if (var8 != null) 810 { 811 var8.updateContainingBlockInfo(); 812 var8.blockMetadata = par4; 813 } 814 } 815 816 return true; 817 } 818 } 819 } 820 821 /** 822 * Gets the amount of light saved in this block (doesn't adjust for daylight) 823 */ 824 public int getSavedLightValue(EnumSkyBlock par1EnumSkyBlock, int par2, int par3, int par4) 825 { 826 ExtendedBlockStorage var5 = (par3 >> 4 >= storageArrays.length || par3 >> 4 < 0 ? null : storageArrays[par3 >> 4]); 827 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)); 828 } 829 830 /** 831 * Sets the light value at the coordinate. If enumskyblock is set to sky it sets it in the skylightmap and if its a 832 * block then into the blocklightmap. Args enumSkyBlock, x, y, z, lightValue 833 */ 834 public void setLightValue(EnumSkyBlock par1EnumSkyBlock, int par2, int par3, int par4, int par5) 835 { 836 if (par3 >> 4 >= storageArrays.length || par3 >> 4 < 0) 837 { 838 return; 839 } 840 841 ExtendedBlockStorage var6 = this.storageArrays[par3 >> 4]; 842 843 if (var6 == null) 844 { 845 var6 = this.storageArrays[par3 >> 4] = new ExtendedBlockStorage(par3 >> 4 << 4); 846 this.generateSkylightMap(); 847 } 848 849 this.isModified = true; 850 851 if (par1EnumSkyBlock == EnumSkyBlock.Sky) 852 { 853 if (!this.worldObj.provider.hasNoSky) 854 { 855 var6.setExtSkylightValue(par2, par3 & 15, par4, par5); 856 } 857 } 858 else if (par1EnumSkyBlock == EnumSkyBlock.Block) 859 { 860 var6.setExtBlocklightValue(par2, par3 & 15, par4, par5); 861 } 862 } 863 864 /** 865 * Gets the amount of light on a block taking into account sunlight 866 */ 867 public int getBlockLightValue(int par1, int par2, int par3, int par4) 868 { 869 ExtendedBlockStorage var5 = (par2 >> 4 >= storageArrays.length || par2 >> 4 < 0 ? null : storageArrays[par2 >> 4]); 870 871 if (var5 == null) 872 { 873 return !this.worldObj.provider.hasNoSky && par4 < EnumSkyBlock.Sky.defaultLightValue ? EnumSkyBlock.Sky.defaultLightValue - par4 : 0; 874 } 875 else 876 { 877 int var6 = this.worldObj.provider.hasNoSky ? 0 : var5.getExtSkylightValue(par1, par2 & 15, par3); 878 879 if (var6 > 0) 880 { 881 isLit = true; 882 } 883 884 var6 -= par4; 885 int var7 = var5.getExtBlocklightValue(par1, par2 & 15, par3); 886 887 if (var7 > var6) 888 { 889 var6 = var7; 890 } 891 892 return var6; 893 } 894 } 895 896 /** 897 * Adds an entity to the chunk. Args: entity 898 */ 899 public void addEntity(Entity par1Entity) 900 { 901 this.hasEntities = true; 902 int var2 = MathHelper.floor_double(par1Entity.posX / 16.0D); 903 int var3 = MathHelper.floor_double(par1Entity.posZ / 16.0D); 904 905 if (var2 != this.xPosition || var3 != this.zPosition) 906 { 907 System.out.println("Wrong location! " + par1Entity); 908 Thread.dumpStack(); 909 } 910 911 int var4 = MathHelper.floor_double(par1Entity.posY / 16.0D); 912 913 if (var4 < 0) 914 { 915 var4 = 0; 916 } 917 918 if (var4 >= this.entityLists.length) 919 { 920 var4 = this.entityLists.length - 1; 921 } 922 MinecraftForge.EVENT_BUS.post(new EntityEvent.EnteringChunk(par1Entity, this.xPosition, this.zPosition, par1Entity.chunkCoordX, par1Entity.chunkCoordZ)); 923 par1Entity.addedToChunk = true; 924 par1Entity.chunkCoordX = this.xPosition; 925 par1Entity.chunkCoordY = var4; 926 par1Entity.chunkCoordZ = this.zPosition; 927 this.entityLists[var4].add(par1Entity); 928 } 929 930 /** 931 * removes entity using its y chunk coordinate as its index 932 */ 933 public void removeEntity(Entity par1Entity) 934 { 935 this.removeEntityAtIndex(par1Entity, par1Entity.chunkCoordY); 936 } 937 938 /** 939 * Removes entity at the specified index from the entity array. 940 */ 941 public void removeEntityAtIndex(Entity par1Entity, int par2) 942 { 943 if (par2 < 0) 944 { 945 par2 = 0; 946 } 947 948 if (par2 >= this.entityLists.length) 949 { 950 par2 = this.entityLists.length - 1; 951 } 952 953 this.entityLists[par2].remove(par1Entity); 954 } 955 956 /** 957 * Returns whether is not a block above this one blocking sight to the sky (done via checking against the heightmap) 958 */ 959 public boolean canBlockSeeTheSky(int par1, int par2, int par3) 960 { 961 return par2 >= this.heightMap[par3 << 4 | par1]; 962 } 963 964 /** 965 * Gets the TileEntity for a given block in this chunk 966 */ 967 public TileEntity getChunkBlockTileEntity(int par1, int par2, int par3) 968 { 969 ChunkPosition var4 = new ChunkPosition(par1, par2, par3); 970 TileEntity var5 = (TileEntity)this.chunkTileEntityMap.get(var4); 971 972 if (var5 != null && var5.isInvalid()) 973 { 974 chunkTileEntityMap.remove(var4); 975 var5 = null; 976 } 977 978 if (var5 == null) 979 { 980 int var6 = this.getBlockID(par1, par2, par3); 981 982 int meta = this.getBlockMetadata(par1, par2, par3); 983 984 if (var6 <= 0 || !Block.blocksList[var6].hasTileEntity(meta)) 985 { 986 return null; 987 } 988 989 if (var5 == null) 990 { 991 var5 = Block.blocksList[var6].createTileEntity(this.worldObj, meta); 992 this.worldObj.setBlockTileEntity(this.xPosition * 16 + par1, par2, this.zPosition * 16 + par3, var5); 993 } 994 995 var5 = (TileEntity)this.chunkTileEntityMap.get(var4); 996 } 997 998 return var5; 999 } 1000 1001 /** 1002 * Adds a TileEntity to a chunk 1003 */ 1004 public void addTileEntity(TileEntity par1TileEntity) 1005 { 1006 int var2 = par1TileEntity.xCoord - this.xPosition * 16; 1007 int var3 = par1TileEntity.yCoord; 1008 int var4 = par1TileEntity.zCoord - this.zPosition * 16; 1009 this.setChunkBlockTileEntity(var2, var3, var4, par1TileEntity); 1010 1011 if (this.isChunkLoaded) 1012 { 1013 this.worldObj.addTileEntity(par1TileEntity); 1014 } 1015 } 1016 1017 /** 1018 * Sets the TileEntity for a given block in this chunk 1019 */ 1020 public void setChunkBlockTileEntity(int par1, int par2, int par3, TileEntity par4TileEntity) 1021 { 1022 ChunkPosition var5 = new ChunkPosition(par1, par2, par3); 1023 par4TileEntity.setWorldObj(this.worldObj); 1024 par4TileEntity.xCoord = this.xPosition * 16 + par1; 1025 par4TileEntity.yCoord = par2; 1026 par4TileEntity.zCoord = this.zPosition * 16 + par3; 1027 1028 Block block = Block.blocksList[getBlockID(par1, par2, par3)]; 1029 if (block != null && block.hasTileEntity(getBlockMetadata(par1, par2, par3))) 1030 { 1031 TileEntity old = (TileEntity)chunkTileEntityMap.get(var5); 1032 if (old != null) 1033 { 1034 old.invalidate(); 1035 } 1036 par4TileEntity.validate(); 1037 this.chunkTileEntityMap.put(var5, par4TileEntity); 1038 } 1039 } 1040 1041 /** 1042 * Removes the TileEntity for a given block in this chunk 1043 */ 1044 public void removeChunkBlockTileEntity(int par1, int par2, int par3) 1045 { 1046 ChunkPosition var4 = new ChunkPosition(par1, par2, par3); 1047 1048 if (this.isChunkLoaded) 1049 { 1050 TileEntity var5 = (TileEntity)this.chunkTileEntityMap.remove(var4); 1051 1052 if (var5 != null) 1053 { 1054 var5.invalidate(); 1055 } 1056 } 1057 } 1058 1059 /** 1060 * Called when this Chunk is loaded by the ChunkProvider 1061 */ 1062 public void onChunkLoad() 1063 { 1064 this.isChunkLoaded = true; 1065 this.worldObj.addTileEntity(this.chunkTileEntityMap.values()); 1066 1067 for (int var1 = 0; var1 < this.entityLists.length; ++var1) 1068 { 1069 this.worldObj.addLoadedEntities(this.entityLists[var1]); 1070 } 1071 MinecraftForge.EVENT_BUS.post(new ChunkEvent.Load(this)); 1072 } 1073 1074 /** 1075 * Called when this Chunk is unloaded by the ChunkProvider 1076 */ 1077 public void onChunkUnload() 1078 { 1079 this.isChunkLoaded = false; 1080 Iterator var1 = this.chunkTileEntityMap.values().iterator(); 1081 1082 while (var1.hasNext()) 1083 { 1084 TileEntity var2 = (TileEntity)var1.next(); 1085 this.worldObj.markTileEntityForDespawn(var2); 1086 } 1087 1088 for (int var3 = 0; var3 < this.entityLists.length; ++var3) 1089 { 1090 this.worldObj.unloadEntities(this.entityLists[var3]); 1091 } 1092 MinecraftForge.EVENT_BUS.post(new ChunkEvent.Unload(this)); 1093 } 1094 1095 /** 1096 * Sets the isModified flag for this Chunk 1097 */ 1098 public void setChunkModified() 1099 { 1100 this.isModified = true; 1101 } 1102 1103 /** 1104 * Fills the given list of all entities that intersect within the given bounding box that aren't the passed entity 1105 * Args: entity, aabb, listToFill 1106 */ 1107 public void getEntitiesWithinAABBForEntity(Entity par1Entity, AxisAlignedBB par2AxisAlignedBB, List par3List) 1108 { 1109 int var4 = MathHelper.floor_double((par2AxisAlignedBB.minY - World.MAX_ENTITY_RADIUS) / 16.0D); 1110 int var5 = MathHelper.floor_double((par2AxisAlignedBB.maxY + World.MAX_ENTITY_RADIUS) / 16.0D); 1111 1112 if (var4 < 0) 1113 { 1114 var4 = 0; 1115 } 1116 1117 if (var5 >= this.entityLists.length) 1118 { 1119 var5 = this.entityLists.length - 1; 1120 } 1121 1122 for (int var6 = var4; var6 <= var5; ++var6) 1123 { 1124 List var7 = this.entityLists[var6]; 1125 1126 for (int var8 = 0; var8 < var7.size(); ++var8) 1127 { 1128 Entity var9 = (Entity)var7.get(var8); 1129 1130 if (var9 != par1Entity && var9.boundingBox.intersectsWith(par2AxisAlignedBB)) 1131 { 1132 par3List.add(var9); 1133 Entity[] var10 = var9.getParts(); 1134 1135 if (var10 != null) 1136 { 1137 for (int var11 = 0; var11 < var10.length; ++var11) 1138 { 1139 var9 = var10[var11]; 1140 1141 if (var9 != par1Entity && var9.boundingBox.intersectsWith(par2AxisAlignedBB)) 1142 { 1143 par3List.add(var9); 1144 } 1145 } 1146 } 1147 } 1148 } 1149 } 1150 } 1151 1152 /** 1153 * Gets all entities that can be assigned to the specified class. Args: entityClass, aabb, listToFill 1154 */ 1155 public void getEntitiesOfTypeWithinAAAB(Class par1Class, AxisAlignedBB par2AxisAlignedBB, List par3List, IEntitySelector par4IEntitySelector) 1156 { 1157 int var5 = MathHelper.floor_double((par2AxisAlignedBB.minY - World.MAX_ENTITY_RADIUS) / 16.0D); 1158 int var6 = MathHelper.floor_double((par2AxisAlignedBB.maxY + World.MAX_ENTITY_RADIUS) / 16.0D); 1159 1160 if (var5 < 0) 1161 { 1162 var5 = 0; 1163 } 1164 else if (var5 >= this.entityLists.length) 1165 { 1166 var5 = this.entityLists.length - 1; 1167 } 1168 1169 if (var6 >= this.entityLists.length) 1170 { 1171 var6 = this.entityLists.length - 1; 1172 } 1173 else if (var6 < 0) 1174 { 1175 var6 = 0; 1176 } 1177 1178 for (int var7 = var5; var7 <= var6; ++var7) 1179 { 1180 List var8 = this.entityLists[var7]; 1181 1182 for (int var9 = 0; var9 < var8.size(); ++var9) 1183 { 1184 Entity var10 = (Entity)var8.get(var9); 1185 1186 if (par1Class.isAssignableFrom(var10.getClass()) && var10.boundingBox.intersectsWith(par2AxisAlignedBB) && (par4IEntitySelector == null || par4IEntitySelector.isEntityApplicable(var10))) 1187 { 1188 par3List.add(var10); 1189 } 1190 } 1191 } 1192 } 1193 1194 /** 1195 * Returns true if this Chunk needs to be saved 1196 */ 1197 public boolean needsSaving(boolean par1) 1198 { 1199 if (par1) 1200 { 1201 if (this.hasEntities && this.worldObj.getTotalWorldTime() != this.lastSaveTime) 1202 { 1203 return true; 1204 } 1205 } 1206 else if (this.hasEntities && this.worldObj.getTotalWorldTime() >= this.lastSaveTime + 600L) 1207 { 1208 return true; 1209 } 1210 1211 return this.isModified; 1212 } 1213 1214 public Random getRandomWithSeed(long par1) 1215 { 1216 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); 1217 } 1218 1219 public boolean isEmpty() 1220 { 1221 return false; 1222 } 1223 1224 public void populateChunk(IChunkProvider par1IChunkProvider, IChunkProvider par2IChunkProvider, int par3, int par4) 1225 { 1226 if (!this.isTerrainPopulated && par1IChunkProvider.chunkExists(par3 + 1, par4 + 1) && par1IChunkProvider.chunkExists(par3, par4 + 1) && par1IChunkProvider.chunkExists(par3 + 1, par4)) 1227 { 1228 par1IChunkProvider.populate(par2IChunkProvider, par3, par4); 1229 } 1230 1231 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)) 1232 { 1233 par1IChunkProvider.populate(par2IChunkProvider, par3 - 1, par4); 1234 } 1235 1236 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)) 1237 { 1238 par1IChunkProvider.populate(par2IChunkProvider, par3, par4 - 1); 1239 } 1240 1241 if (par1IChunkProvider.chunkExists(par3 - 1, par4 - 1) && !par1IChunkProvider.provideChunk(par3 - 1, par4 - 1).isTerrainPopulated && par1IChunkProvider.chunkExists(par3, par4 - 1) && par1IChunkProvider.chunkExists(par3 - 1, par4)) 1242 { 1243 par1IChunkProvider.populate(par2IChunkProvider, par3 - 1, par4 - 1); 1244 } 1245 } 1246 1247 /** 1248 * Gets the height to which rain/snow will fall. Calculates it if not already stored. 1249 */ 1250 public int getPrecipitationHeight(int par1, int par2) 1251 { 1252 int var3 = par1 | par2 << 4; 1253 int var4 = this.precipitationHeightMap[var3]; 1254 1255 if (var4 == -999) 1256 { 1257 int var5 = this.getTopFilledSegment() + 15; 1258 var4 = -1; 1259 1260 while (var5 > 0 && var4 == -1) 1261 { 1262 int var6 = this.getBlockID(par1, var5, par2); 1263 Material var7 = var6 == 0 ? Material.air : Block.blocksList[var6].blockMaterial; 1264 1265 if (!var7.blocksMovement() && !var7.isLiquid()) 1266 { 1267 --var5; 1268 } 1269 else 1270 { 1271 var4 = var5 + 1; 1272 } 1273 } 1274 1275 this.precipitationHeightMap[var3] = var4; 1276 } 1277 1278 return var4; 1279 } 1280 1281 /** 1282 * Checks whether skylight needs updated; if it does, calls updateSkylight_do 1283 */ 1284 public void updateSkylight() 1285 { 1286 if (this.isGapLightingUpdated && !this.worldObj.provider.hasNoSky) 1287 { 1288 this.updateSkylight_do(); 1289 } 1290 } 1291 1292 /** 1293 * Gets a ChunkCoordIntPair representing the Chunk's position. 1294 */ 1295 public ChunkCoordIntPair getChunkCoordIntPair() 1296 { 1297 return new ChunkCoordIntPair(this.xPosition, this.zPosition); 1298 } 1299 1300 /** 1301 * Returns whether the ExtendedBlockStorages containing levels (in blocks) from arg 1 to arg 2 are fully empty 1302 * (true) or not (false). 1303 */ 1304 public boolean getAreLevelsEmpty(int par1, int par2) 1305 { 1306 if (par1 < 0) 1307 { 1308 par1 = 0; 1309 } 1310 1311 if (par2 >= 256) 1312 { 1313 par2 = 255; 1314 } 1315 1316 for (int var3 = par1; var3 <= par2; var3 += 16) 1317 { 1318 ExtendedBlockStorage var4 = this.storageArrays[var3 >> 4]; 1319 1320 if (var4 != null && !var4.isEmpty()) 1321 { 1322 return false; 1323 } 1324 } 1325 1326 return true; 1327 } 1328 1329 public void setStorageArrays(ExtendedBlockStorage[] par1ArrayOfExtendedBlockStorage) 1330 { 1331 this.storageArrays = par1ArrayOfExtendedBlockStorage; 1332 } 1333 1334 @SideOnly(Side.CLIENT) 1335 1336 /** 1337 * Initialise this chunk with new binary data 1338 */ 1339 public void fillChunk(byte[] par1ArrayOfByte, int par2, int par3, boolean par4) 1340 { 1341 Iterator iterator = chunkTileEntityMap.values().iterator(); 1342 while(iterator.hasNext()) 1343 { 1344 TileEntity tileEntity = (TileEntity)iterator.next(); 1345 tileEntity.updateContainingBlockInfo(); 1346 tileEntity.getBlockMetadata(); 1347 tileEntity.getBlockType(); 1348 } 1349 1350 int var5 = 0; 1351 int var6; 1352 1353 for (var6 = 0; var6 < this.storageArrays.length; ++var6) 1354 { 1355 if ((par2 & 1 << var6) != 0) 1356 { 1357 if (this.storageArrays[var6] == null) 1358 { 1359 this.storageArrays[var6] = new ExtendedBlockStorage(var6 << 4); 1360 } 1361 1362 byte[] var7 = this.storageArrays[var6].getBlockLSBArray(); 1363 System.arraycopy(par1ArrayOfByte, var5, var7, 0, var7.length); 1364 var5 += var7.length; 1365 } 1366 else if (par4 && this.storageArrays[var6] != null) 1367 { 1368 this.storageArrays[var6] = null; 1369 } 1370 } 1371 1372 NibbleArray var8; 1373 1374 for (var6 = 0; var6 < this.storageArrays.length; ++var6) 1375 { 1376 if ((par2 & 1 << var6) != 0 && this.storageArrays[var6] != null) 1377 { 1378 var8 = this.storageArrays[var6].getMetadataArray(); 1379 System.arraycopy(par1ArrayOfByte, var5, var8.data, 0, var8.data.length); 1380 var5 += var8.data.length; 1381 } 1382 } 1383 1384 for (var6 = 0; var6 < this.storageArrays.length; ++var6) 1385 { 1386 if ((par2 & 1 << var6) != 0 && this.storageArrays[var6] != null) 1387 { 1388 var8 = this.storageArrays[var6].getBlocklightArray(); 1389 System.arraycopy(par1ArrayOfByte, var5, var8.data, 0, var8.data.length); 1390 var5 += var8.data.length; 1391 } 1392 } 1393 1394 for (var6 = 0; var6 < this.storageArrays.length; ++var6) 1395 { 1396 if ((par2 & 1 << var6) != 0 && this.storageArrays[var6] != null) 1397 { 1398 var8 = this.storageArrays[var6].getSkylightArray(); 1399 System.arraycopy(par1ArrayOfByte, var5, var8.data, 0, var8.data.length); 1400 var5 += var8.data.length; 1401 } 1402 } 1403 1404 for (var6 = 0; var6 < this.storageArrays.length; ++var6) 1405 { 1406 if ((par3 & 1 << var6) != 0) 1407 { 1408 if (this.storageArrays[var6] == null) 1409 { 1410 var5 += 2048; 1411 } 1412 else 1413 { 1414 var8 = this.storageArrays[var6].getBlockMSBArray(); 1415 1416 if (var8 == null) 1417 { 1418 var8 = this.storageArrays[var6].createBlockMSBArray(); 1419 } 1420 1421 System.arraycopy(par1ArrayOfByte, var5, var8.data, 0, var8.data.length); 1422 var5 += var8.data.length; 1423 } 1424 } 1425 else if (par4 && this.storageArrays[var6] != null && this.storageArrays[var6].getBlockMSBArray() != null) 1426 { 1427 this.storageArrays[var6].clearMSBArray(); 1428 } 1429 } 1430 1431 if (par4) 1432 { 1433 System.arraycopy(par1ArrayOfByte, var5, this.blockBiomeArray, 0, this.blockBiomeArray.length); 1434 int var10000 = var5 + this.blockBiomeArray.length; 1435 } 1436 1437 for (var6 = 0; var6 < this.storageArrays.length; ++var6) 1438 { 1439 if (this.storageArrays[var6] != null && (par2 & 1 << var6) != 0) 1440 { 1441 this.storageArrays[var6].removeInvalidBlocks(); 1442 } 1443 } 1444 1445 this.generateHeightMap(); 1446 1447 List<TileEntity> invalidList = new ArrayList<TileEntity>(); 1448 iterator = chunkTileEntityMap.values().iterator(); 1449 while (iterator.hasNext()) 1450 { 1451 TileEntity tileEntity = (TileEntity)iterator.next(); 1452 int x = tileEntity.xCoord & 15; 1453 int y = tileEntity.yCoord; 1454 int z = tileEntity.zCoord & 15; 1455 Block block = tileEntity.getBlockType(); 1456 if (block == null || block.blockID != getBlockID(x, y, z) || tileEntity.getBlockMetadata() != getBlockMetadata(x, y, z)) 1457 { 1458 invalidList.add(tileEntity); 1459 } 1460 tileEntity.updateContainingBlockInfo(); 1461 } 1462 1463 for (TileEntity tileEntity : invalidList) 1464 { 1465 tileEntity.invalidate(); 1466 } 1467 } 1468 1469 /** 1470 * This method retrieves the biome at a set of coordinates 1471 */ 1472 public BiomeGenBase getBiomeGenForWorldCoords(int par1, int par2, WorldChunkManager par3WorldChunkManager) 1473 { 1474 int var4 = this.blockBiomeArray[par2 << 4 | par1] & 255; 1475 1476 if (var4 == 255) 1477 { 1478 BiomeGenBase var5 = par3WorldChunkManager.getBiomeGenAt((this.xPosition << 4) + par1, (this.zPosition << 4) + par2); 1479 var4 = var5.biomeID; 1480 this.blockBiomeArray[par2 << 4 | par1] = (byte)(var4 & 255); 1481 } 1482 1483 return BiomeGenBase.biomeList[var4] == null ? BiomeGenBase.plains : BiomeGenBase.biomeList[var4]; 1484 } 1485 1486 /** 1487 * Returns an array containing a 16x16 mapping on the X/Z of block positions in this Chunk to biome IDs. 1488 */ 1489 public byte[] getBiomeArray() 1490 { 1491 return this.blockBiomeArray; 1492 } 1493 1494 /** 1495 * Accepts a 256-entry array that contains a 16x16 mapping on the X/Z plane of block positions in this Chunk to 1496 * biome IDs. 1497 */ 1498 public void setBiomeArray(byte[] par1ArrayOfByte) 1499 { 1500 this.blockBiomeArray = par1ArrayOfByte; 1501 } 1502 1503 /** 1504 * Resets the relight check index to 0 for this Chunk. 1505 */ 1506 public void resetRelightChecks() 1507 { 1508 this.queuedLightChecks = 0; 1509 } 1510 1511 /** 1512 * Called once-per-chunk-per-tick, and advances the round-robin relight check index per-storage-block by up to 8 1513 * blocks at a time. In a worst-case scenario, can potentially take up to 1.6 seconds, calculated via 1514 * (4096/(8*16))/20, to re-check all blocks in a chunk, which could explain both lagging light updates in certain 1515 * cases as well as Nether relight 1516 */ 1517 public void enqueueRelightChecks() 1518 { 1519 for (int var1 = 0; var1 < 8; ++var1) 1520 { 1521 if (this.queuedLightChecks >= 4096) 1522 { 1523 return; 1524 } 1525 1526 int var2 = this.queuedLightChecks % 16; 1527 int var3 = this.queuedLightChecks / 16 % 16; 1528 int var4 = this.queuedLightChecks / 256; 1529 ++this.queuedLightChecks; 1530 int var5 = (this.xPosition << 4) + var3; 1531 int var6 = (this.zPosition << 4) + var4; 1532 1533 for (int var7 = 0; var7 < 16; ++var7) 1534 { 1535 int var8 = (var2 << 4) + var7; 1536 1537 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) 1538 { 1539 if (Block.lightValue[this.worldObj.getBlockId(var5, var8 - 1, var6)] > 0) 1540 { 1541 this.worldObj.updateAllLightTypes(var5, var8 - 1, var6); 1542 } 1543 1544 if (Block.lightValue[this.worldObj.getBlockId(var5, var8 + 1, var6)] > 0) 1545 { 1546 this.worldObj.updateAllLightTypes(var5, var8 + 1, var6); 1547 } 1548 1549 if (Block.lightValue[this.worldObj.getBlockId(var5 - 1, var8, var6)] > 0) 1550 { 1551 this.worldObj.updateAllLightTypes(var5 - 1, var8, var6); 1552 } 1553 1554 if (Block.lightValue[this.worldObj.getBlockId(var5 + 1, var8, var6)] > 0) 1555 { 1556 this.worldObj.updateAllLightTypes(var5 + 1, var8, var6); 1557 } 1558 1559 if (Block.lightValue[this.worldObj.getBlockId(var5, var8, var6 - 1)] > 0) 1560 { 1561 this.worldObj.updateAllLightTypes(var5, var8, var6 - 1); 1562 } 1563 1564 if (Block.lightValue[this.worldObj.getBlockId(var5, var8, var6 + 1)] > 0) 1565 { 1566 this.worldObj.updateAllLightTypes(var5, var8, var6 + 1); 1567 } 1568 1569 this.worldObj.updateAllLightTypes(var5, var8, var6); 1570 } 1571 } 1572 } 1573 } 1574 1575 /** FORGE: Used to remove only invalid TileEntities */ 1576 public void cleanChunkBlockTileEntity(int x, int y, int z) 1577 { 1578 ChunkPosition position = new ChunkPosition(x, y, z); 1579 if (isChunkLoaded) 1580 { 1581 TileEntity entity = (TileEntity)chunkTileEntityMap.get(position); 1582 if (entity != null && entity.isInvalid()) 1583 { 1584 chunkTileEntityMap.remove(position); 1585 } 1586 } 1587 } 1588 }