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