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