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