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 1021 for (int var1 = 0; var1 < this.entityLists.length; ++var1) 1022 { 1023 this.worldObj.addLoadedEntities(this.entityLists[var1]); 1024 } 1025 MinecraftForge.EVENT_BUS.post(new ChunkEvent.Load(this)); 1026 } 1027 1028 /** 1029 * Called when this Chunk is unloaded by the ChunkProvider 1030 */ 1031 public void onChunkUnload() 1032 { 1033 this.isChunkLoaded = false; 1034 Iterator var1 = this.chunkTileEntityMap.values().iterator(); 1035 1036 while (var1.hasNext()) 1037 { 1038 TileEntity var2 = (TileEntity)var1.next(); 1039 this.worldObj.markTileEntityForDespawn(var2); 1040 } 1041 1042 for (int var3 = 0; var3 < this.entityLists.length; ++var3) 1043 { 1044 this.worldObj.unloadEntities(this.entityLists[var3]); 1045 } 1046 MinecraftForge.EVENT_BUS.post(new ChunkEvent.Unload(this)); 1047 } 1048 1049 /** 1050 * Sets the isModified flag for this Chunk 1051 */ 1052 public void setChunkModified() 1053 { 1054 this.isModified = true; 1055 } 1056 1057 /** 1058 * Fills the given list of all entities that intersect within the given bounding box that aren't the passed entity 1059 * Args: entity, aabb, listToFill 1060 */ 1061 public void getEntitiesWithinAABBForEntity(Entity par1Entity, AxisAlignedBB par2AxisAlignedBB, List par3List) 1062 { 1063 int var4 = MathHelper.floor_double((par2AxisAlignedBB.minY - World.MAX_ENTITY_RADIUS) / 16.0D); 1064 int var5 = MathHelper.floor_double((par2AxisAlignedBB.maxY + World.MAX_ENTITY_RADIUS) / 16.0D); 1065 1066 if (var4 < 0) 1067 { 1068 var4 = 0; 1069 } 1070 1071 if (var5 >= this.entityLists.length) 1072 { 1073 var5 = this.entityLists.length - 1; 1074 } 1075 1076 for (int var6 = var4; var6 <= var5; ++var6) 1077 { 1078 List var7 = this.entityLists[var6]; 1079 1080 for (int var8 = 0; var8 < var7.size(); ++var8) 1081 { 1082 Entity var9 = (Entity)var7.get(var8); 1083 1084 if (var9 != par1Entity && var9.boundingBox.intersectsWith(par2AxisAlignedBB)) 1085 { 1086 par3List.add(var9); 1087 Entity[] var10 = var9.getParts(); 1088 1089 if (var10 != null) 1090 { 1091 for (int var11 = 0; var11 < var10.length; ++var11) 1092 { 1093 var9 = var10[var11]; 1094 1095 if (var9 != par1Entity && var9.boundingBox.intersectsWith(par2AxisAlignedBB)) 1096 { 1097 par3List.add(var9); 1098 } 1099 } 1100 } 1101 } 1102 } 1103 } 1104 } 1105 1106 /** 1107 * Gets all entities that can be assigned to the specified class. Args: entityClass, aabb, listToFill 1108 */ 1109 public void getEntitiesOfTypeWithinAAAB(Class par1Class, AxisAlignedBB par2AxisAlignedBB, List par3List, IEntitySelector par4IEntitySelector) 1110 { 1111 int var5 = MathHelper.floor_double((par2AxisAlignedBB.minY - World.MAX_ENTITY_RADIUS) / 16.0D); 1112 int var6 = MathHelper.floor_double((par2AxisAlignedBB.maxY + World.MAX_ENTITY_RADIUS) / 16.0D); 1113 1114 if (var5 < 0) 1115 { 1116 var5 = 0; 1117 } 1118 else if (var5 >= this.entityLists.length) 1119 { 1120 var5 = this.entityLists.length - 1; 1121 } 1122 1123 if (var6 >= this.entityLists.length) 1124 { 1125 var6 = this.entityLists.length - 1; 1126 } 1127 else if (var6 < 0) 1128 { 1129 var6 = 0; 1130 } 1131 1132 for (int var7 = var5; var7 <= var6; ++var7) 1133 { 1134 List var8 = this.entityLists[var7]; 1135 1136 for (int var9 = 0; var9 < var8.size(); ++var9) 1137 { 1138 Entity var10 = (Entity)var8.get(var9); 1139 1140 if (par1Class.isAssignableFrom(var10.getClass()) && var10.boundingBox.intersectsWith(par2AxisAlignedBB) && (par4IEntitySelector == null || par4IEntitySelector.isEntityApplicable(var10))) 1141 { 1142 par3List.add(var10); 1143 } 1144 } 1145 } 1146 } 1147 1148 /** 1149 * Returns true if this Chunk needs to be saved 1150 */ 1151 public boolean needsSaving(boolean par1) 1152 { 1153 if (par1) 1154 { 1155 if (this.hasEntities && this.worldObj.getTotalWorldTime() != this.lastSaveTime) 1156 { 1157 return true; 1158 } 1159 } 1160 else if (this.hasEntities && this.worldObj.getTotalWorldTime() >= this.lastSaveTime + 600L) 1161 { 1162 return true; 1163 } 1164 1165 return this.isModified; 1166 } 1167 1168 public Random getRandomWithSeed(long par1) 1169 { 1170 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); 1171 } 1172 1173 public boolean isEmpty() 1174 { 1175 return false; 1176 } 1177 1178 public void populateChunk(IChunkProvider par1IChunkProvider, IChunkProvider par2IChunkProvider, int par3, int par4) 1179 { 1180 if (!this.isTerrainPopulated && par1IChunkProvider.chunkExists(par3 + 1, par4 + 1) && par1IChunkProvider.chunkExists(par3, par4 + 1) && par1IChunkProvider.chunkExists(par3 + 1, par4)) 1181 { 1182 par1IChunkProvider.populate(par2IChunkProvider, par3, par4); 1183 } 1184 1185 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)) 1186 { 1187 par1IChunkProvider.populate(par2IChunkProvider, par3 - 1, par4); 1188 } 1189 1190 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)) 1191 { 1192 par1IChunkProvider.populate(par2IChunkProvider, par3, par4 - 1); 1193 } 1194 1195 if (par1IChunkProvider.chunkExists(par3 - 1, par4 - 1) && !par1IChunkProvider.provideChunk(par3 - 1, par4 - 1).isTerrainPopulated && par1IChunkProvider.chunkExists(par3, par4 - 1) && par1IChunkProvider.chunkExists(par3 - 1, par4)) 1196 { 1197 par1IChunkProvider.populate(par2IChunkProvider, par3 - 1, par4 - 1); 1198 } 1199 } 1200 1201 /** 1202 * Gets the height to which rain/snow will fall. Calculates it if not already stored. 1203 */ 1204 public int getPrecipitationHeight(int par1, int par2) 1205 { 1206 int var3 = par1 | par2 << 4; 1207 int var4 = this.precipitationHeightMap[var3]; 1208 1209 if (var4 == -999) 1210 { 1211 int var5 = this.getTopFilledSegment() + 15; 1212 var4 = -1; 1213 1214 while (var5 > 0 && var4 == -1) 1215 { 1216 int var6 = this.getBlockID(par1, var5, par2); 1217 Material var7 = var6 == 0 ? Material.air : Block.blocksList[var6].blockMaterial; 1218 1219 if (!var7.blocksMovement() && !var7.isLiquid()) 1220 { 1221 --var5; 1222 } 1223 else 1224 { 1225 var4 = var5 + 1; 1226 } 1227 } 1228 1229 this.precipitationHeightMap[var3] = var4; 1230 } 1231 1232 return var4; 1233 } 1234 1235 /** 1236 * Checks whether skylight needs updated; if it does, calls updateSkylight_do 1237 */ 1238 public void updateSkylight() 1239 { 1240 if (this.isGapLightingUpdated && !this.worldObj.provider.hasNoSky) 1241 { 1242 this.updateSkylight_do(); 1243 } 1244 } 1245 1246 /** 1247 * Gets a ChunkCoordIntPair representing the Chunk's position. 1248 */ 1249 public ChunkCoordIntPair getChunkCoordIntPair() 1250 { 1251 return new ChunkCoordIntPair(this.xPosition, this.zPosition); 1252 } 1253 1254 /** 1255 * Returns whether the ExtendedBlockStorages containing levels (in blocks) from arg 1 to arg 2 are fully empty 1256 * (true) or not (false). 1257 */ 1258 public boolean getAreLevelsEmpty(int par1, int par2) 1259 { 1260 if (par1 < 0) 1261 { 1262 par1 = 0; 1263 } 1264 1265 if (par2 >= 256) 1266 { 1267 par2 = 255; 1268 } 1269 1270 for (int var3 = par1; var3 <= par2; var3 += 16) 1271 { 1272 ExtendedBlockStorage var4 = this.storageArrays[var3 >> 4]; 1273 1274 if (var4 != null && !var4.isEmpty()) 1275 { 1276 return false; 1277 } 1278 } 1279 1280 return true; 1281 } 1282 1283 public void setStorageArrays(ExtendedBlockStorage[] par1ArrayOfExtendedBlockStorage) 1284 { 1285 this.storageArrays = par1ArrayOfExtendedBlockStorage; 1286 } 1287 1288 @SideOnly(Side.CLIENT) 1289 1290 /** 1291 * Initialise this chunk with new binary data 1292 */ 1293 public void fillChunk(byte[] par1ArrayOfByte, int par2, int par3, boolean par4) 1294 { 1295 Iterator iterator = chunkTileEntityMap.values().iterator(); 1296 while(iterator.hasNext()) 1297 { 1298 TileEntity tileEntity = (TileEntity)iterator.next(); 1299 tileEntity.updateContainingBlockInfo(); 1300 tileEntity.getBlockMetadata(); 1301 tileEntity.getBlockType(); 1302 } 1303 1304 int var5 = 0; 1305 int var6; 1306 1307 for (var6 = 0; var6 < this.storageArrays.length; ++var6) 1308 { 1309 if ((par2 & 1 << var6) != 0) 1310 { 1311 if (this.storageArrays[var6] == null) 1312 { 1313 this.storageArrays[var6] = new ExtendedBlockStorage(var6 << 4); 1314 } 1315 1316 byte[] var7 = this.storageArrays[var6].getBlockLSBArray(); 1317 System.arraycopy(par1ArrayOfByte, var5, var7, 0, var7.length); 1318 var5 += var7.length; 1319 } 1320 else if (par4 && this.storageArrays[var6] != null) 1321 { 1322 this.storageArrays[var6] = null; 1323 } 1324 } 1325 1326 NibbleArray var8; 1327 1328 for (var6 = 0; var6 < this.storageArrays.length; ++var6) 1329 { 1330 if ((par2 & 1 << var6) != 0 && this.storageArrays[var6] != null) 1331 { 1332 var8 = this.storageArrays[var6].getMetadataArray(); 1333 System.arraycopy(par1ArrayOfByte, var5, var8.data, 0, var8.data.length); 1334 var5 += var8.data.length; 1335 } 1336 } 1337 1338 for (var6 = 0; var6 < this.storageArrays.length; ++var6) 1339 { 1340 if ((par2 & 1 << var6) != 0 && this.storageArrays[var6] != null) 1341 { 1342 var8 = this.storageArrays[var6].getBlocklightArray(); 1343 System.arraycopy(par1ArrayOfByte, var5, var8.data, 0, var8.data.length); 1344 var5 += var8.data.length; 1345 } 1346 } 1347 1348 for (var6 = 0; var6 < this.storageArrays.length; ++var6) 1349 { 1350 if ((par2 & 1 << var6) != 0 && this.storageArrays[var6] != null) 1351 { 1352 var8 = this.storageArrays[var6].getSkylightArray(); 1353 System.arraycopy(par1ArrayOfByte, var5, var8.data, 0, var8.data.length); 1354 var5 += var8.data.length; 1355 } 1356 } 1357 1358 for (var6 = 0; var6 < this.storageArrays.length; ++var6) 1359 { 1360 if ((par3 & 1 << var6) != 0) 1361 { 1362 if (this.storageArrays[var6] == null) 1363 { 1364 var5 += 2048; 1365 } 1366 else 1367 { 1368 var8 = this.storageArrays[var6].getBlockMSBArray(); 1369 1370 if (var8 == null) 1371 { 1372 var8 = this.storageArrays[var6].createBlockMSBArray(); 1373 } 1374 1375 System.arraycopy(par1ArrayOfByte, var5, var8.data, 0, var8.data.length); 1376 var5 += var8.data.length; 1377 } 1378 } 1379 else if (par4 && this.storageArrays[var6] != null && this.storageArrays[var6].getBlockMSBArray() != null) 1380 { 1381 this.storageArrays[var6].clearMSBArray(); 1382 } 1383 } 1384 1385 if (par4) 1386 { 1387 System.arraycopy(par1ArrayOfByte, var5, this.blockBiomeArray, 0, this.blockBiomeArray.length); 1388 int var10000 = var5 + this.blockBiomeArray.length; 1389 } 1390 1391 for (var6 = 0; var6 < this.storageArrays.length; ++var6) 1392 { 1393 if (this.storageArrays[var6] != null && (par2 & 1 << var6) != 0) 1394 { 1395 this.storageArrays[var6].removeInvalidBlocks(); 1396 } 1397 } 1398 1399 this.generateHeightMap(); 1400 1401 List<TileEntity> invalidList = new ArrayList<TileEntity>(); 1402 iterator = chunkTileEntityMap.values().iterator(); 1403 while (iterator.hasNext()) 1404 { 1405 TileEntity tileEntity = (TileEntity)iterator.next(); 1406 int x = tileEntity.xCoord & 15; 1407 int y = tileEntity.yCoord; 1408 int z = tileEntity.zCoord & 15; 1409 Block block = tileEntity.getBlockType(); 1410 if (block == null || block.blockID != getBlockID(x, y, z) || tileEntity.getBlockMetadata() != getBlockMetadata(x, y, z)) 1411 { 1412 invalidList.add(tileEntity); 1413 } 1414 tileEntity.updateContainingBlockInfo(); 1415 } 1416 1417 for (TileEntity tileEntity : invalidList) 1418 { 1419 tileEntity.invalidate(); 1420 } 1421 } 1422 1423 /** 1424 * This method retrieves the biome at a set of coordinates 1425 */ 1426 public BiomeGenBase getBiomeGenForWorldCoords(int par1, int par2, WorldChunkManager par3WorldChunkManager) 1427 { 1428 int var4 = this.blockBiomeArray[par2 << 4 | par1] & 255; 1429 1430 if (var4 == 255) 1431 { 1432 BiomeGenBase var5 = par3WorldChunkManager.getBiomeGenAt((this.xPosition << 4) + par1, (this.zPosition << 4) + par2); 1433 var4 = var5.biomeID; 1434 this.blockBiomeArray[par2 << 4 | par1] = (byte)(var4 & 255); 1435 } 1436 1437 return BiomeGenBase.biomeList[var4] == null ? BiomeGenBase.plains : BiomeGenBase.biomeList[var4]; 1438 } 1439 1440 /** 1441 * Returns an array containing a 16x16 mapping on the X/Z of block positions in this Chunk to biome IDs. 1442 */ 1443 public byte[] getBiomeArray() 1444 { 1445 return this.blockBiomeArray; 1446 } 1447 1448 /** 1449 * Accepts a 256-entry array that contains a 16x16 mapping on the X/Z plane of block positions in this Chunk to 1450 * biome IDs. 1451 */ 1452 public void setBiomeArray(byte[] par1ArrayOfByte) 1453 { 1454 this.blockBiomeArray = par1ArrayOfByte; 1455 } 1456 1457 /** 1458 * Resets the relight check index to 0 for this Chunk. 1459 */ 1460 public void resetRelightChecks() 1461 { 1462 this.queuedLightChecks = 0; 1463 } 1464 1465 /** 1466 * Called once-per-chunk-per-tick, and advances the round-robin relight check index per-storage-block by up to 8 1467 * blocks at a time. In a worst-case scenario, can potentially take up to 1.6 seconds, calculated via 1468 * (4096/(8*16))/20, to re-check all blocks in a chunk, which could explain both lagging light updates in certain 1469 * cases as well as Nether relight 1470 */ 1471 public void enqueueRelightChecks() 1472 { 1473 for (int var1 = 0; var1 < 8; ++var1) 1474 { 1475 if (this.queuedLightChecks >= 4096) 1476 { 1477 return; 1478 } 1479 1480 int var2 = this.queuedLightChecks % 16; 1481 int var3 = this.queuedLightChecks / 16 % 16; 1482 int var4 = this.queuedLightChecks / 256; 1483 ++this.queuedLightChecks; 1484 int var5 = (this.xPosition << 4) + var3; 1485 int var6 = (this.zPosition << 4) + var4; 1486 1487 for (int var7 = 0; var7 < 16; ++var7) 1488 { 1489 int var8 = (var2 << 4) + var7; 1490 1491 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) 1492 { 1493 if (Block.lightValue[this.worldObj.getBlockId(var5, var8 - 1, var6)] > 0) 1494 { 1495 this.worldObj.updateAllLightTypes(var5, var8 - 1, var6); 1496 } 1497 1498 if (Block.lightValue[this.worldObj.getBlockId(var5, var8 + 1, var6)] > 0) 1499 { 1500 this.worldObj.updateAllLightTypes(var5, var8 + 1, var6); 1501 } 1502 1503 if (Block.lightValue[this.worldObj.getBlockId(var5 - 1, var8, var6)] > 0) 1504 { 1505 this.worldObj.updateAllLightTypes(var5 - 1, var8, var6); 1506 } 1507 1508 if (Block.lightValue[this.worldObj.getBlockId(var5 + 1, var8, var6)] > 0) 1509 { 1510 this.worldObj.updateAllLightTypes(var5 + 1, var8, var6); 1511 } 1512 1513 if (Block.lightValue[this.worldObj.getBlockId(var5, var8, var6 - 1)] > 0) 1514 { 1515 this.worldObj.updateAllLightTypes(var5, var8, var6 - 1); 1516 } 1517 1518 if (Block.lightValue[this.worldObj.getBlockId(var5, var8, var6 + 1)] > 0) 1519 { 1520 this.worldObj.updateAllLightTypes(var5, var8, var6 + 1); 1521 } 1522 1523 this.worldObj.updateAllLightTypes(var5, var8, var6); 1524 } 1525 } 1526 } 1527 } 1528 1529 /** FORGE: Used to remove only invalid TileEntities */ 1530 public void cleanChunkBlockTileEntity(int x, int y, int z) 1531 { 1532 ChunkPosition position = new ChunkPosition(x, y, z); 1533 if (isChunkLoaded) 1534 { 1535 TileEntity entity = (TileEntity)chunkTileEntityMap.get(position); 1536 if (entity != null && entity.isInvalid()) 1537 { 1538 chunkTileEntityMap.remove(position); 1539 } 1540 } 1541 } 1542 }