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