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