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 }