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