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.Collection;
007 import java.util.HashSet;
008 import java.util.Iterator;
009 import java.util.List;
010 import java.util.Random;
011 import java.util.Set;
012
013 import com.google.common.collect.SetMultimap;
014
015 import net.minecraftforge.common.ForgeChunkManager;
016 import net.minecraftforge.common.ForgeChunkManager.Ticket;
017 import net.minecraftforge.common.ForgeHooks;
018 import net.minecraftforge.common.MinecraftForge;
019 import net.minecraftforge.common.ForgeDirection;
020 import net.minecraftforge.event.entity.EntityEvent;
021 import net.minecraftforge.event.entity.EntityJoinWorldEvent;
022 import net.minecraftforge.event.world.WorldEvent;
023 import net.minecraftforge.event.entity.PlaySoundAtEntityEvent;
024
025 public abstract class World implements IBlockAccess
026 {
027 /**
028 * Used in the getEntitiesWithinAABB functions to expand the search area for entities.
029 * Modders should change this variable to a higher value if it is less then the radius
030 * of one of there entities.
031 */
032 public static double MAX_ENTITY_RADIUS = 2.0D;
033
034 /**
035 * boolean; if true updates scheduled by scheduleBlockUpdate happen immediately
036 */
037 public boolean scheduledUpdatesAreImmediate = false;
038
039 /** A list of all Entities in all currently-loaded chunks */
040 public List loadedEntityList = new ArrayList();
041 protected List unloadedEntityList = new ArrayList();
042
043 /** A list of all TileEntities in all currently-loaded chunks */
044 public List loadedTileEntityList = new ArrayList();
045 private List addedTileEntityList = new ArrayList();
046
047 /** Entities marked for removal. */
048 private List entityRemoval = new ArrayList();
049
050 /** Array list of players in the world. */
051 public List playerEntities = new ArrayList();
052
053 /** a list of all the lightning entities */
054 public List weatherEffects = new ArrayList();
055 private long cloudColour = 16777215L;
056
057 /** How much light is subtracted from full daylight */
058 public int skylightSubtracted = 0;
059
060 /**
061 * Contains the current Linear Congruential Generator seed for block updates. Used with an A value of 3 and a C
062 * value of 0x3c6ef35f, producing a highly planar series of values ill-suited for choosing random blocks in a
063 * 16x128x16 field.
064 */
065 protected int updateLCG = (new Random()).nextInt();
066
067 /**
068 * magic number used to generate fast random numbers for 3d distribution within a chunk
069 */
070 protected final int DIST_HASH_MAGIC = 1013904223;
071 protected float prevRainingStrength;
072 protected float rainingStrength;
073 protected float prevThunderingStrength;
074 protected float thunderingStrength;
075
076 /**
077 * Set to 2 whenever a lightning bolt is generated in SSP. Decrements if > 0 in updateWeather(). Value appears to be
078 * unused.
079 */
080 protected int lastLightningBolt = 0;
081
082 /**
083 * If > 0, the sky and skylight colors are illuminated by a lightning flash
084 */
085 public int lightningFlash = 0;
086
087 /** true while the world is editing blocks */
088 public boolean editingBlocks = false;
089
090 /** Option > Difficulty setting (0 - 3) */
091 public int difficultySetting;
092
093 /** RNG for World. */
094 public Random rand = new Random();
095
096 /** The WorldProvider instance that World uses. */
097 public final WorldProvider provider;
098 protected List worldAccesses = new ArrayList();
099
100 /** Handles chunk operations and caching */
101 protected IChunkProvider chunkProvider;
102 protected final ISaveHandler saveHandler;
103
104 /**
105 * holds information about a world (size on disk, time, spawn point, seed, ...)
106 */
107 protected WorldInfo worldInfo;
108
109 /** Boolean that is set to true when trying to find a spawn point */
110 public boolean findingSpawnPoint;
111 public MapStorage mapStorage;
112 public VillageCollection villageCollectionObj;
113 protected final VillageSiege villageSiegeObj = new VillageSiege(this);
114 public final Profiler theProfiler;
115 private final Vec3Pool field_82741_K = new Vec3Pool(300, 2000);
116 private ArrayList collidingBoundingBoxes = new ArrayList();
117 private boolean scanningTileEntities;
118
119 /** indicates if enemies are spawned or not */
120 protected boolean spawnHostileMobs = true;
121
122 /** A flag indicating whether we should spawn peaceful mobs. */
123 protected boolean spawnPeacefulMobs = true;
124
125 /** Positions to update */
126 protected Set activeChunkSet = new HashSet();
127
128 /** number of ticks until the next random ambients play */
129 private int ambientTickCountdown;
130
131 /**
132 * is a temporary list of blocks and light values used when updating light levels. Holds up to 32x32x32 blocks (the
133 * maximum influence of a light source.) Every element is a packed bit value: 0000000000LLLLzzzzzzyyyyyyxxxxxx. The
134 * 4-bit L is a light level used when darkening blocks. 6-bit numbers x, y and z represent the block's offset from
135 * the original block, plus 32 (i.e. value of 31 would mean a -1 offset
136 */
137 int[] lightUpdateBlockList;
138
139 /**
140 * entities within AxisAlignedBB excluding one, set and returned in getEntitiesWithinAABBExcludingEntity(Entity
141 * var1, AxisAlignedBB var2)
142 */
143 private List entitiesWithinAABBExcludingEntity;
144
145 /**
146 * This is set to true when you are a client connected to a multiplayer world, false otherwise. As of Minecraft 1.3
147 * and the integrated server, this will always return true.
148 */
149 public boolean isRemote;
150
151 /**
152 * Gets the biome for a given set of x/z coordinates
153 */
154 public BiomeGenBase getBiomeGenForCoords(int par1, int par2)
155 {
156 return provider.getBiomeGenForCoords(par1, par2);
157 }
158
159 public BiomeGenBase getBiomeGenForCoordsBody(int par1, int par2)
160 {
161 if (this.blockExists(par1, 0, par2))
162 {
163 Chunk var3 = this.getChunkFromBlockCoords(par1, par2);
164
165 if (var3 != null)
166 {
167 return var3.getBiomeGenForWorldCoords(par1 & 15, par2 & 15, this.provider.worldChunkMgr);
168 }
169 }
170
171 return this.provider.worldChunkMgr.getBiomeGenAt(par1, par2);
172 }
173
174 public WorldChunkManager getWorldChunkManager()
175 {
176 return this.provider.worldChunkMgr;
177 }
178
179 @SideOnly(Side.CLIENT)
180 public World(ISaveHandler par1ISaveHandler, String par2Str, WorldProvider par3WorldProvider, WorldSettings par4WorldSettings, Profiler par5Profiler)
181 {
182 this.ambientTickCountdown = this.rand.nextInt(12000);
183 this.lightUpdateBlockList = new int[32768];
184 this.entitiesWithinAABBExcludingEntity = new ArrayList();
185 this.isRemote = false;
186 this.saveHandler = par1ISaveHandler;
187 this.theProfiler = par5Profiler;
188 this.worldInfo = new WorldInfo(par4WorldSettings, par2Str);
189 this.provider = par3WorldProvider;
190 }
191
192 // Broken up so that the WorldClient gets the chance to set the mapstorage object before the dimension initializes
193 @SideOnly(Side.CLIENT)
194 protected void finishSetup()
195 {
196 this.provider.registerWorld(this);
197
198 this.mapStorage = new MapStorage(saveHandler);
199 VillageCollection var6 = (VillageCollection)this.mapStorage.loadData(VillageCollection.class, "villages");
200
201 if (var6 == null)
202 {
203 this.villageCollectionObj = new VillageCollection(this);
204 this.mapStorage.setData("villages", this.villageCollectionObj);
205 }
206 else
207 {
208 this.villageCollectionObj = var6;
209 this.villageCollectionObj.func_82566_a(this);
210 }
211
212 this.provider.registerWorld(this);
213 this.chunkProvider = this.createChunkProvider();
214 this.calculateInitialSkylight();
215 this.calculateInitialWeather();
216 }
217
218 public World(ISaveHandler par1ISaveHandler, String par2Str, WorldSettings par3WorldSettings, WorldProvider par4WorldProvider, Profiler par5Profiler)
219 {
220 this.ambientTickCountdown = this.rand.nextInt(12000);
221 this.lightUpdateBlockList = new int[32768];
222 this.entitiesWithinAABBExcludingEntity = new ArrayList();
223 this.isRemote = false;
224 this.saveHandler = par1ISaveHandler;
225 this.theProfiler = par5Profiler;
226 this.mapStorage = getMapStorage(par1ISaveHandler);
227 this.worldInfo = par1ISaveHandler.loadWorldInfo();
228
229 if (par4WorldProvider != null)
230 {
231 this.provider = par4WorldProvider;
232 }
233 else if (this.worldInfo != null && this.worldInfo.getDimension() != 0)
234 {
235 this.provider = WorldProvider.getProviderForDimension(this.worldInfo.getDimension());
236 }
237 else
238 {
239 this.provider = WorldProvider.getProviderForDimension(0);
240 }
241
242 if (this.worldInfo == null)
243 {
244 this.worldInfo = new WorldInfo(par3WorldSettings, par2Str);
245 }
246 else
247 {
248 this.worldInfo.setWorldName(par2Str);
249 }
250
251 this.provider.registerWorld(this);
252 this.chunkProvider = this.createChunkProvider();
253
254 if (!this.worldInfo.isInitialized())
255 {
256 this.initialize(par3WorldSettings);
257 this.worldInfo.setServerInitialized(true);
258 }
259
260 VillageCollection var6 = (VillageCollection)this.mapStorage.loadData(VillageCollection.class, "villages");
261
262 if (var6 == null)
263 {
264 this.villageCollectionObj = new VillageCollection(this);
265 this.mapStorage.setData("villages", this.villageCollectionObj);
266 }
267 else
268 {
269 this.villageCollectionObj = var6;
270 this.villageCollectionObj.func_82566_a(this);
271 }
272
273 this.calculateInitialSkylight();
274 this.calculateInitialWeather();
275 }
276
277 private static MapStorage s_mapStorage;
278 private static ISaveHandler s_savehandler;
279 //Provides a solution for different worlds getting different copies of the same data, potentially rewriting the data or causing race conditions/stale data
280 //Buildcraft has suffered from the issue this fixes. If you load the same data from two different worlds they can get two different copies of the same object, thus the last saved gets final say.
281 private MapStorage getMapStorage(ISaveHandler savehandler)
282 {
283 if (s_savehandler != savehandler || s_mapStorage == null) {
284 s_mapStorage = new MapStorage(savehandler);
285 s_savehandler = savehandler;
286 }
287 return s_mapStorage;
288 }
289
290 /**
291 * Creates the chunk provider for this world. Called in the constructor. Retrieves provider from worldProvider?
292 */
293 protected abstract IChunkProvider createChunkProvider();
294
295 protected void initialize(WorldSettings par1WorldSettings)
296 {
297 this.worldInfo.setServerInitialized(true);
298 }
299
300 @SideOnly(Side.CLIENT)
301
302 /**
303 * Sets a new spawn location by finding an uncovered block at a random (x,z) location in the chunk.
304 */
305 public void setSpawnLocation()
306 {
307 this.setSpawnLocation(8, 64, 8);
308 }
309
310 /**
311 * Returns the block ID of the first block at this (x,z) location with air above it, searching from sea level
312 * upwards.
313 */
314 public int getFirstUncoveredBlock(int par1, int par2)
315 {
316 int var3;
317
318 for (var3 = 63; !this.isAirBlock(par1, var3 + 1, par2); ++var3)
319 {
320 ;
321 }
322
323 return this.getBlockId(par1, var3, par2);
324 }
325
326 /**
327 * Returns the block ID at coords x,y,z
328 */
329 public int getBlockId(int par1, int par2, int par3)
330 {
331 return par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000 ? (par2 < 0 ? 0 : (par2 >= 256 ? 0 : this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4).getBlockID(par1 & 15, par2, par3 & 15))) : 0;
332 }
333
334 public int getBlockLightOpacity(int par1, int par2, int par3)
335 {
336 return par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000 ? (par2 < 0 ? 0 : (par2 >= 256 ? 0 : this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4).getBlockLightOpacity(par1 & 15, par2, par3 & 15))) : 0;
337 }
338
339 /**
340 * Returns true if the block at the specified coordinates is empty
341 */
342 public boolean isAirBlock(int par1, int par2, int par3)
343 {
344 int id = getBlockId(par1, par2, par3);
345 return id == 0 || Block.blocksList[id] == null || Block.blocksList[id].isAirBlock(this, par1, par2, par3);
346 }
347
348 /**
349 * Checks if a block at a given position should have a tile entity.
350 */
351 public boolean blockHasTileEntity(int par1, int par2, int par3)
352 {
353 int var4 = this.getBlockId(par1, par2, par3);
354 int meta = this.getBlockMetadata(par1, par2, par3);
355 return Block.blocksList[var4] != null && Block.blocksList[var4].hasTileEntity(meta);
356 }
357
358 /**
359 * Returns whether a block exists at world coordinates x, y, z
360 */
361 public boolean blockExists(int par1, int par2, int par3)
362 {
363 return par2 >= 0 && par2 < 256 ? this.chunkExists(par1 >> 4, par3 >> 4) : false;
364 }
365
366 /**
367 * Checks if any of the chunks within distance (argument 4) blocks of the given block exist
368 */
369 public boolean doChunksNearChunkExist(int par1, int par2, int par3, int par4)
370 {
371 return this.checkChunksExist(par1 - par4, par2 - par4, par3 - par4, par1 + par4, par2 + par4, par3 + par4);
372 }
373
374 /**
375 * Checks between a min and max all the chunks inbetween actually exist. Args: minX, minY, minZ, maxX, maxY, maxZ
376 */
377 public boolean checkChunksExist(int par1, int par2, int par3, int par4, int par5, int par6)
378 {
379 if (par5 >= 0 && par2 < 256)
380 {
381 par1 >>= 4;
382 par3 >>= 4;
383 par4 >>= 4;
384 par6 >>= 4;
385
386 for (int var7 = par1; var7 <= par4; ++var7)
387 {
388 for (int var8 = par3; var8 <= par6; ++var8)
389 {
390 if (!this.chunkExists(var7, var8))
391 {
392 return false;
393 }
394 }
395 }
396
397 return true;
398 }
399 else
400 {
401 return false;
402 }
403 }
404
405 /**
406 * Returns whether a chunk exists at chunk coordinates x, y
407 */
408 protected boolean chunkExists(int par1, int par2)
409 {
410 return this.chunkProvider.chunkExists(par1, par2);
411 }
412
413 /**
414 * Returns a chunk looked up by block coordinates. Args: x, z
415 */
416 public Chunk getChunkFromBlockCoords(int par1, int par2)
417 {
418 return this.getChunkFromChunkCoords(par1 >> 4, par2 >> 4);
419 }
420
421 /**
422 * Returns back a chunk looked up by chunk coordinates Args: x, y
423 */
424 public Chunk getChunkFromChunkCoords(int par1, int par2)
425 {
426 return this.chunkProvider.provideChunk(par1, par2);
427 }
428
429 /**
430 * Sets the block ID and metadata of a block in global coordinates
431 */
432 public boolean setBlockAndMetadata(int par1, int par2, int par3, int par4, int par5)
433 {
434 return this.setBlockAndMetadataWithUpdate(par1, par2, par3, par4, par5, true);
435 }
436
437 /**
438 * Sets the block ID and metadata of a block, optionally marking it as needing update. Args: X,Y,Z, blockID,
439 * metadata, needsUpdate
440 */
441 public boolean setBlockAndMetadataWithUpdate(int par1, int par2, int par3, int par4, int par5, boolean par6)
442 {
443 if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000)
444 {
445 if (par2 < 0)
446 {
447 return false;
448 }
449 else if (par2 >= 256)
450 {
451 return false;
452 }
453 else
454 {
455 Chunk var7 = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
456 boolean var8 = var7.setBlockIDWithMetadata(par1 & 15, par2, par3 & 15, par4, par5);
457 this.theProfiler.startSection("checkLight");
458 this.updateAllLightTypes(par1, par2, par3);
459 this.theProfiler.endSection();
460
461 if (par6 && var8 && (this.isRemote || var7.deferRender))
462 {
463 this.markBlockNeedsUpdate(par1, par2, par3);
464 }
465
466 return var8;
467 }
468 }
469 else
470 {
471 return false;
472 }
473 }
474
475 /**
476 * Sets the block to the specified blockID at the block coordinates Args x, y, z, blockID
477 */
478 public boolean setBlock(int par1, int par2, int par3, int par4)
479 {
480 if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000)
481 {
482 if (par2 < 0)
483 {
484 return false;
485 }
486 else if (par2 >= 256)
487 {
488 return false;
489 }
490 else
491 {
492 Chunk var5 = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
493 boolean var6 = var5.setBlockID(par1 & 15, par2, par3 & 15, par4);
494 this.theProfiler.startSection("checkLight");
495 this.updateAllLightTypes(par1, par2, par3);
496 this.theProfiler.endSection();
497
498 if (var6 && (this.isRemote || var5.deferRender))
499 {
500 this.markBlockNeedsUpdate(par1, par2, par3);
501 }
502
503 return var6;
504 }
505 }
506 else
507 {
508 return false;
509 }
510 }
511
512 /**
513 * Returns the block's material.
514 */
515 public Material getBlockMaterial(int par1, int par2, int par3)
516 {
517 int var4 = this.getBlockId(par1, par2, par3);
518 return var4 == 0 ? Material.air : Block.blocksList[var4].blockMaterial;
519 }
520
521 /**
522 * Returns the block metadata at coords x,y,z
523 */
524 public int getBlockMetadata(int par1, int par2, int par3)
525 {
526 if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000)
527 {
528 if (par2 < 0)
529 {
530 return 0;
531 }
532 else if (par2 >= 256)
533 {
534 return 0;
535 }
536 else
537 {
538 Chunk var4 = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
539 par1 &= 15;
540 par3 &= 15;
541 return var4.getBlockMetadata(par1, par2, par3);
542 }
543 }
544 else
545 {
546 return 0;
547 }
548 }
549
550 /**
551 * Sets the blocks metadata and if set will then notify blocks that this block changed. Args: x, y, z, metadata
552 */
553 public void setBlockMetadataWithNotify(int par1, int par2, int par3, int par4)
554 {
555 if (this.setBlockMetadata(par1, par2, par3, par4))
556 {
557 this.notifyBlockChange(par1, par2, par3, this.getBlockId(par1, par2, par3));
558 }
559 }
560
561 /**
562 * Set the metadata of a block in global coordinates
563 */
564 public boolean setBlockMetadata(int par1, int par2, int par3, int par4)
565 {
566 if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000)
567 {
568 if (par2 < 0)
569 {
570 return false;
571 }
572 else if (par2 >= 256)
573 {
574 return false;
575 }
576 else
577 {
578 Chunk var5 = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
579 int var6 = par1 & 15;
580 int var7 = par3 & 15;
581 boolean var8 = var5.setBlockMetadata(var6, par2, var7, par4);
582
583 if (var8 && (this.isRemote || var5.deferRender && Block.requiresSelfNotify[var5.getBlockID(var6, par2, var7) & 4095]))
584 {
585 this.markBlockNeedsUpdate(par1, par2, par3);
586 }
587
588 return var8;
589 }
590 }
591 else
592 {
593 return false;
594 }
595 }
596
597 /**
598 * Sets a block and notifies relevant systems with the block change Args: x, y, z, blockID
599 */
600 public boolean setBlockWithNotify(int par1, int par2, int par3, int par4)
601 {
602 if (this.setBlock(par1, par2, par3, par4))
603 {
604 this.notifyBlockChange(par1, par2, par3, par4);
605 return true;
606 }
607 else
608 {
609 return false;
610 }
611 }
612
613 /**
614 * Sets the block ID and metadata, then notifies neighboring blocks of the change Params: x, y, z, BlockID, Metadata
615 */
616 public boolean setBlockAndMetadataWithNotify(int par1, int par2, int par3, int par4, int par5)
617 {
618 if (this.setBlockAndMetadata(par1, par2, par3, par4, par5))
619 {
620 this.notifyBlockChange(par1, par2, par3, par4);
621 return true;
622 }
623 else
624 {
625 return false;
626 }
627 }
628
629 /**
630 * Marks the block as needing an update with the renderer. Args: x, y, z
631 */
632 public void markBlockNeedsUpdate(int par1, int par2, int par3)
633 {
634 Iterator var4 = this.worldAccesses.iterator();
635
636 while (var4.hasNext())
637 {
638 IWorldAccess var5 = (IWorldAccess)var4.next();
639 var5.markBlockNeedsUpdate(par1, par2, par3);
640 }
641 }
642
643 /**
644 * The block type change and need to notify other systems Args: x, y, z, blockID
645 */
646 public void notifyBlockChange(int par1, int par2, int par3, int par4)
647 {
648 this.notifyBlocksOfNeighborChange(par1, par2, par3, par4);
649 }
650
651 /**
652 * marks a vertical line of blocks as dirty
653 */
654 public void markBlocksDirtyVertical(int par1, int par2, int par3, int par4)
655 {
656 int var5;
657
658 if (par3 > par4)
659 {
660 var5 = par4;
661 par4 = par3;
662 par3 = var5;
663 }
664
665 if (!this.provider.hasNoSky)
666 {
667 for (var5 = par3; var5 <= par4; ++var5)
668 {
669 this.updateLightByType(EnumSkyBlock.Sky, par1, var5, par2);
670 }
671 }
672
673 this.markBlocksDirty(par1, par3, par2, par1, par4, par2);
674 }
675
676 /**
677 * calls the 'MarkBlockAsNeedsUpdate' in all block accesses in this world
678 */
679 public void markBlockAsNeedsUpdate(int par1, int par2, int par3)
680 {
681 Iterator var4 = this.worldAccesses.iterator();
682
683 while (var4.hasNext())
684 {
685 IWorldAccess var5 = (IWorldAccess)var4.next();
686 var5.markBlockRangeNeedsUpdate(par1, par2, par3, par1, par2, par3);
687 }
688 }
689
690 public void markBlocksDirty(int par1, int par2, int par3, int par4, int par5, int par6)
691 {
692 Iterator var7 = this.worldAccesses.iterator();
693
694 while (var7.hasNext())
695 {
696 IWorldAccess var8 = (IWorldAccess)var7.next();
697 var8.markBlockRangeNeedsUpdate(par1, par2, par3, par4, par5, par6);
698 }
699 }
700
701 /**
702 * Notifies neighboring blocks that this specified block changed Args: x, y, z, blockID
703 */
704 public void notifyBlocksOfNeighborChange(int par1, int par2, int par3, int par4)
705 {
706 this.notifyBlockOfNeighborChange(par1 - 1, par2, par3, par4);
707 this.notifyBlockOfNeighborChange(par1 + 1, par2, par3, par4);
708 this.notifyBlockOfNeighborChange(par1, par2 - 1, par3, par4);
709 this.notifyBlockOfNeighborChange(par1, par2 + 1, par3, par4);
710 this.notifyBlockOfNeighborChange(par1, par2, par3 - 1, par4);
711 this.notifyBlockOfNeighborChange(par1, par2, par3 + 1, par4);
712 }
713
714 /**
715 * Notifies a block that one of its neighbor change to the specified type Args: x, y, z, blockID
716 */
717 private void notifyBlockOfNeighborChange(int par1, int par2, int par3, int par4)
718 {
719 if (!this.editingBlocks && !this.isRemote)
720 {
721 Block var5 = Block.blocksList[this.getBlockId(par1, par2, par3)];
722
723 if (var5 != null)
724 {
725 var5.onNeighborBlockChange(this, par1, par2, par3, par4);
726 }
727 }
728 }
729
730 /**
731 * Checks if the specified block is able to see the sky
732 */
733 public boolean canBlockSeeTheSky(int par1, int par2, int par3)
734 {
735 return this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4).canBlockSeeTheSky(par1 & 15, par2, par3 & 15);
736 }
737
738 /**
739 * Does the same as getBlockLightValue_do but without checking if its not a normal block
740 */
741 public int getFullBlockLightValue(int par1, int par2, int par3)
742 {
743 if (par2 < 0)
744 {
745 return 0;
746 }
747 else
748 {
749 if (par2 >= 256)
750 {
751 par2 = 255;
752 }
753
754 return this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4).getBlockLightValue(par1 & 15, par2, par3 & 15, 0);
755 }
756 }
757
758 /**
759 * Gets the light value of a block location
760 */
761 public int getBlockLightValue(int par1, int par2, int par3)
762 {
763 return this.getBlockLightValue_do(par1, par2, par3, true);
764 }
765
766 /**
767 * Gets the light value of a block location. This is the actual function that gets the value and has a bool flag
768 * that indicates if its a half step block to get the maximum light value of a direct neighboring block (left,
769 * right, forward, back, and up)
770 */
771 public int getBlockLightValue_do(int par1, int par2, int par3, boolean par4)
772 {
773 if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000)
774 {
775 if (par4)
776 {
777 int var5 = this.getBlockId(par1, par2, par3);
778
779 if (var5 == Block.stoneSingleSlab.blockID || var5 == Block.woodSingleSlab.blockID || var5 == Block.tilledField.blockID || var5 == Block.stairCompactCobblestone.blockID || var5 == Block.stairCompactPlanks.blockID)
780 {
781 int var6 = this.getBlockLightValue_do(par1, par2 + 1, par3, false);
782 int var7 = this.getBlockLightValue_do(par1 + 1, par2, par3, false);
783 int var8 = this.getBlockLightValue_do(par1 - 1, par2, par3, false);
784 int var9 = this.getBlockLightValue_do(par1, par2, par3 + 1, false);
785 int var10 = this.getBlockLightValue_do(par1, par2, par3 - 1, false);
786
787 if (var7 > var6)
788 {
789 var6 = var7;
790 }
791
792 if (var8 > var6)
793 {
794 var6 = var8;
795 }
796
797 if (var9 > var6)
798 {
799 var6 = var9;
800 }
801
802 if (var10 > var6)
803 {
804 var6 = var10;
805 }
806
807 return var6;
808 }
809 }
810
811 if (par2 < 0)
812 {
813 return 0;
814 }
815 else
816 {
817 if (par2 >= 256)
818 {
819 par2 = 255;
820 }
821
822 Chunk var11 = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
823 par1 &= 15;
824 par3 &= 15;
825 return var11.getBlockLightValue(par1, par2, par3, this.skylightSubtracted);
826 }
827 }
828 else
829 {
830 return 15;
831 }
832 }
833
834 /**
835 * Returns the y coordinate with a block in it at this x, z coordinate
836 */
837 public int getHeightValue(int par1, int par2)
838 {
839 if (par1 >= -30000000 && par2 >= -30000000 && par1 < 30000000 && par2 < 30000000)
840 {
841 if (!this.chunkExists(par1 >> 4, par2 >> 4))
842 {
843 return 0;
844 }
845 else
846 {
847 Chunk var3 = this.getChunkFromChunkCoords(par1 >> 4, par2 >> 4);
848 return var3.getHeightValue(par1 & 15, par2 & 15);
849 }
850 }
851 else
852 {
853 return 0;
854 }
855 }
856
857 public int func_82734_g(int par1, int par2)
858 {
859 if (par1 >= -30000000 && par2 >= -30000000 && par1 < 30000000 && par2 < 30000000)
860 {
861 if (!this.chunkExists(par1 >> 4, par2 >> 4))
862 {
863 return 0;
864 }
865 else
866 {
867 Chunk var3 = this.getChunkFromChunkCoords(par1 >> 4, par2 >> 4);
868 return var3.field_82912_p;
869 }
870 }
871 else
872 {
873 return 0;
874 }
875 }
876
877 @SideOnly(Side.CLIENT)
878
879 /**
880 * Brightness for SkyBlock.Sky is clear white and (through color computing it is assumed) DEPENDENT ON DAYTIME.
881 * Brightness for SkyBlock.Block is yellowish and independent.
882 */
883 public int getSkyBlockTypeBrightness(EnumSkyBlock par1EnumSkyBlock, int par2, int par3, int par4)
884 {
885 if (this.provider.hasNoSky && par1EnumSkyBlock == EnumSkyBlock.Sky)
886 {
887 return 0;
888 }
889 else
890 {
891 if (par3 < 0)
892 {
893 par3 = 0;
894 }
895
896 if (par3 >= 256)
897 {
898 return par1EnumSkyBlock.defaultLightValue;
899 }
900 else if (par2 >= -30000000 && par4 >= -30000000 && par2 < 30000000 && par4 < 30000000)
901 {
902 int var5 = par2 >> 4;
903 int var6 = par4 >> 4;
904
905 if (!this.chunkExists(var5, var6))
906 {
907 return par1EnumSkyBlock.defaultLightValue;
908 }
909 else if (Block.useNeighborBrightness[this.getBlockId(par2, par3, par4)])
910 {
911 int var12 = this.getSavedLightValue(par1EnumSkyBlock, par2, par3 + 1, par4);
912 int var8 = this.getSavedLightValue(par1EnumSkyBlock, par2 + 1, par3, par4);
913 int var9 = this.getSavedLightValue(par1EnumSkyBlock, par2 - 1, par3, par4);
914 int var10 = this.getSavedLightValue(par1EnumSkyBlock, par2, par3, par4 + 1);
915 int var11 = this.getSavedLightValue(par1EnumSkyBlock, par2, par3, par4 - 1);
916
917 if (var8 > var12)
918 {
919 var12 = var8;
920 }
921
922 if (var9 > var12)
923 {
924 var12 = var9;
925 }
926
927 if (var10 > var12)
928 {
929 var12 = var10;
930 }
931
932 if (var11 > var12)
933 {
934 var12 = var11;
935 }
936
937 return var12;
938 }
939 else
940 {
941 Chunk var7 = this.getChunkFromChunkCoords(var5, var6);
942 return var7.getSavedLightValue(par1EnumSkyBlock, par2 & 15, par3, par4 & 15);
943 }
944 }
945 else
946 {
947 return par1EnumSkyBlock.defaultLightValue;
948 }
949 }
950 }
951
952 /**
953 * Returns saved light value without taking into account the time of day. Either looks in the sky light map or
954 * block light map based on the enumSkyBlock arg.
955 */
956 public int getSavedLightValue(EnumSkyBlock par1EnumSkyBlock, int par2, int par3, int par4)
957 {
958 if (par3 < 0)
959 {
960 par3 = 0;
961 }
962
963 if (par3 >= 256)
964 {
965 par3 = 255;
966 }
967
968 if (par2 >= -30000000 && par4 >= -30000000 && par2 < 30000000 && par4 < 30000000)
969 {
970 int var5 = par2 >> 4;
971 int var6 = par4 >> 4;
972
973 if (!this.chunkExists(var5, var6))
974 {
975 return par1EnumSkyBlock.defaultLightValue;
976 }
977 else
978 {
979 Chunk var7 = this.getChunkFromChunkCoords(var5, var6);
980 return var7.getSavedLightValue(par1EnumSkyBlock, par2 & 15, par3, par4 & 15);
981 }
982 }
983 else
984 {
985 return par1EnumSkyBlock.defaultLightValue;
986 }
987 }
988
989 /**
990 * Sets the light value either into the sky map or block map depending on if enumSkyBlock is set to sky or block.
991 * Args: enumSkyBlock, x, y, z, lightValue
992 */
993 public void setLightValue(EnumSkyBlock par1EnumSkyBlock, int par2, int par3, int par4, int par5)
994 {
995 if (par2 >= -30000000 && par4 >= -30000000 && par2 < 30000000 && par4 < 30000000)
996 {
997 if (par3 >= 0)
998 {
999 if (par3 < 256)
1000 {
1001 if (this.chunkExists(par2 >> 4, par4 >> 4))
1002 {
1003 Chunk var6 = this.getChunkFromChunkCoords(par2 >> 4, par4 >> 4);
1004 var6.setLightValue(par1EnumSkyBlock, par2 & 15, par3, par4 & 15, par5);
1005 Iterator var7 = this.worldAccesses.iterator();
1006
1007 while (var7.hasNext())
1008 {
1009 IWorldAccess var8 = (IWorldAccess)var7.next();
1010 var8.markBlockNeedsUpdate2(par2, par3, par4);
1011 }
1012 }
1013 }
1014 }
1015 }
1016 }
1017
1018 /**
1019 * all WorldAcceses mark this block as dirty
1020 */
1021 public void markBlockNeedsUpdateForAll(int par1, int par2, int par3)
1022 {
1023 Iterator var4 = this.worldAccesses.iterator();
1024
1025 while (var4.hasNext())
1026 {
1027 IWorldAccess var5 = (IWorldAccess)var4.next();
1028 var5.markBlockNeedsUpdate2(par1, par2, par3);
1029 }
1030 }
1031
1032 @SideOnly(Side.CLIENT)
1033
1034 /**
1035 * Any Light rendered on a 1.8 Block goes through here
1036 */
1037 public int getLightBrightnessForSkyBlocks(int par1, int par2, int par3, int par4)
1038 {
1039 int var5 = this.getSkyBlockTypeBrightness(EnumSkyBlock.Sky, par1, par2, par3);
1040 int var6 = this.getSkyBlockTypeBrightness(EnumSkyBlock.Block, par1, par2, par3);
1041
1042 if (var6 < par4)
1043 {
1044 var6 = par4;
1045 }
1046
1047 return var5 << 20 | var6 << 4;
1048 }
1049
1050 @SideOnly(Side.CLIENT)
1051 public float getBrightness(int par1, int par2, int par3, int par4)
1052 {
1053 int var5 = this.getBlockLightValue(par1, par2, par3);
1054
1055 if (var5 < par4)
1056 {
1057 var5 = par4;
1058 }
1059
1060 return this.provider.lightBrightnessTable[var5];
1061 }
1062
1063 /**
1064 * Returns how bright the block is shown as which is the block's light value looked up in a lookup table (light
1065 * values aren't linear for brightness). Args: x, y, z
1066 */
1067 public float getLightBrightness(int par1, int par2, int par3)
1068 {
1069 return this.provider.lightBrightnessTable[this.getBlockLightValue(par1, par2, par3)];
1070 }
1071
1072 /**
1073 * Checks whether its daytime by seeing if the light subtracted from the skylight is less than 4
1074 */
1075 public boolean isDaytime()
1076 {
1077 return provider.isDaytime();
1078 }
1079
1080 /**
1081 * ray traces all blocks, including non-collideable ones
1082 */
1083 public MovingObjectPosition rayTraceBlocks(Vec3 par1Vec3, Vec3 par2Vec3)
1084 {
1085 return this.rayTraceBlocks_do_do(par1Vec3, par2Vec3, false, false);
1086 }
1087
1088 public MovingObjectPosition rayTraceBlocks_do(Vec3 par1Vec3, Vec3 par2Vec3, boolean par3)
1089 {
1090 return this.rayTraceBlocks_do_do(par1Vec3, par2Vec3, par3, false);
1091 }
1092
1093 public MovingObjectPosition rayTraceBlocks_do_do(Vec3 par1Vec3, Vec3 par2Vec3, boolean par3, boolean par4)
1094 {
1095 if (!Double.isNaN(par1Vec3.xCoord) && !Double.isNaN(par1Vec3.yCoord) && !Double.isNaN(par1Vec3.zCoord))
1096 {
1097 if (!Double.isNaN(par2Vec3.xCoord) && !Double.isNaN(par2Vec3.yCoord) && !Double.isNaN(par2Vec3.zCoord))
1098 {
1099 int var5 = MathHelper.floor_double(par2Vec3.xCoord);
1100 int var6 = MathHelper.floor_double(par2Vec3.yCoord);
1101 int var7 = MathHelper.floor_double(par2Vec3.zCoord);
1102 int var8 = MathHelper.floor_double(par1Vec3.xCoord);
1103 int var9 = MathHelper.floor_double(par1Vec3.yCoord);
1104 int var10 = MathHelper.floor_double(par1Vec3.zCoord);
1105 int var11 = this.getBlockId(var8, var9, var10);
1106 int var12 = this.getBlockMetadata(var8, var9, var10);
1107 Block var13 = Block.blocksList[var11];
1108
1109 if (var13 != null && (!par4 || var13 == null || var13.getCollisionBoundingBoxFromPool(this, var8, var9, var10) != null) && var11 > 0 && var13.canCollideCheck(var12, par3))
1110 {
1111 MovingObjectPosition var14 = var13.collisionRayTrace(this, var8, var9, var10, par1Vec3, par2Vec3);
1112
1113 if (var14 != null)
1114 {
1115 return var14;
1116 }
1117 }
1118
1119 var11 = 200;
1120
1121 while (var11-- >= 0)
1122 {
1123 if (Double.isNaN(par1Vec3.xCoord) || Double.isNaN(par1Vec3.yCoord) || Double.isNaN(par1Vec3.zCoord))
1124 {
1125 return null;
1126 }
1127
1128 if (var8 == var5 && var9 == var6 && var10 == var7)
1129 {
1130 return null;
1131 }
1132
1133 boolean var39 = true;
1134 boolean var40 = true;
1135 boolean var41 = true;
1136 double var15 = 999.0D;
1137 double var17 = 999.0D;
1138 double var19 = 999.0D;
1139
1140 if (var5 > var8)
1141 {
1142 var15 = (double)var8 + 1.0D;
1143 }
1144 else if (var5 < var8)
1145 {
1146 var15 = (double)var8 + 0.0D;
1147 }
1148 else
1149 {
1150 var39 = false;
1151 }
1152
1153 if (var6 > var9)
1154 {
1155 var17 = (double)var9 + 1.0D;
1156 }
1157 else if (var6 < var9)
1158 {
1159 var17 = (double)var9 + 0.0D;
1160 }
1161 else
1162 {
1163 var40 = false;
1164 }
1165
1166 if (var7 > var10)
1167 {
1168 var19 = (double)var10 + 1.0D;
1169 }
1170 else if (var7 < var10)
1171 {
1172 var19 = (double)var10 + 0.0D;
1173 }
1174 else
1175 {
1176 var41 = false;
1177 }
1178
1179 double var21 = 999.0D;
1180 double var23 = 999.0D;
1181 double var25 = 999.0D;
1182 double var27 = par2Vec3.xCoord - par1Vec3.xCoord;
1183 double var29 = par2Vec3.yCoord - par1Vec3.yCoord;
1184 double var31 = par2Vec3.zCoord - par1Vec3.zCoord;
1185
1186 if (var39)
1187 {
1188 var21 = (var15 - par1Vec3.xCoord) / var27;
1189 }
1190
1191 if (var40)
1192 {
1193 var23 = (var17 - par1Vec3.yCoord) / var29;
1194 }
1195
1196 if (var41)
1197 {
1198 var25 = (var19 - par1Vec3.zCoord) / var31;
1199 }
1200
1201 boolean var33 = false;
1202 byte var42;
1203
1204 if (var21 < var23 && var21 < var25)
1205 {
1206 if (var5 > var8)
1207 {
1208 var42 = 4;
1209 }
1210 else
1211 {
1212 var42 = 5;
1213 }
1214
1215 par1Vec3.xCoord = var15;
1216 par1Vec3.yCoord += var29 * var21;
1217 par1Vec3.zCoord += var31 * var21;
1218 }
1219 else if (var23 < var25)
1220 {
1221 if (var6 > var9)
1222 {
1223 var42 = 0;
1224 }
1225 else
1226 {
1227 var42 = 1;
1228 }
1229
1230 par1Vec3.xCoord += var27 * var23;
1231 par1Vec3.yCoord = var17;
1232 par1Vec3.zCoord += var31 * var23;
1233 }
1234 else
1235 {
1236 if (var7 > var10)
1237 {
1238 var42 = 2;
1239 }
1240 else
1241 {
1242 var42 = 3;
1243 }
1244
1245 par1Vec3.xCoord += var27 * var25;
1246 par1Vec3.yCoord += var29 * var25;
1247 par1Vec3.zCoord = var19;
1248 }
1249
1250 Vec3 var34 = this.func_82732_R().getVecFromPool(par1Vec3.xCoord, par1Vec3.yCoord, par1Vec3.zCoord);
1251 var8 = (int)(var34.xCoord = (double)MathHelper.floor_double(par1Vec3.xCoord));
1252
1253 if (var42 == 5)
1254 {
1255 --var8;
1256 ++var34.xCoord;
1257 }
1258
1259 var9 = (int)(var34.yCoord = (double)MathHelper.floor_double(par1Vec3.yCoord));
1260
1261 if (var42 == 1)
1262 {
1263 --var9;
1264 ++var34.yCoord;
1265 }
1266
1267 var10 = (int)(var34.zCoord = (double)MathHelper.floor_double(par1Vec3.zCoord));
1268
1269 if (var42 == 3)
1270 {
1271 --var10;
1272 ++var34.zCoord;
1273 }
1274
1275 int var35 = this.getBlockId(var8, var9, var10);
1276 int var36 = this.getBlockMetadata(var8, var9, var10);
1277 Block var37 = Block.blocksList[var35];
1278
1279 if ((!par4 || var37 == null || var37.getCollisionBoundingBoxFromPool(this, var8, var9, var10) != null) && var35 > 0 && var37.canCollideCheck(var36, par3))
1280 {
1281 MovingObjectPosition var38 = var37.collisionRayTrace(this, var8, var9, var10, par1Vec3, par2Vec3);
1282
1283 if (var38 != null)
1284 {
1285 return var38;
1286 }
1287 }
1288 }
1289
1290 return null;
1291 }
1292 else
1293 {
1294 return null;
1295 }
1296 }
1297 else
1298 {
1299 return null;
1300 }
1301 }
1302
1303 /**
1304 * Plays a sound at the entity's position. Args: entity, sound, volume (relative to 1.0), and frequency (or pitch,
1305 * also relative to 1.0).
1306 */
1307 public void playSoundAtEntity(Entity par1Entity, String par2Str, float par3, float par4)
1308 {
1309 PlaySoundAtEntityEvent event = new PlaySoundAtEntityEvent(par1Entity, par2Str, par3, par4);
1310 if (MinecraftForge.EVENT_BUS.post(event))
1311 {
1312 return;
1313 }
1314 par2Str = event.name;
1315 if (par1Entity != null && par2Str != null)
1316 {
1317 Iterator var5 = this.worldAccesses.iterator();
1318
1319 while (var5.hasNext())
1320 {
1321 IWorldAccess var6 = (IWorldAccess)var5.next();
1322 var6.playSound(par2Str, par1Entity.posX, par1Entity.posY - (double)par1Entity.yOffset, par1Entity.posZ, par3, par4);
1323 }
1324 }
1325 }
1326
1327 /**
1328 * Play a sound effect. Many many parameters for this function. Not sure what they do, but a classic call is :
1329 * (double)i + 0.5D, (double)j + 0.5D, (double)k + 0.5D, 'random.door_open', 1.0F, world.rand.nextFloat() * 0.1F +
1330 * 0.9F with i,j,k position of the block.
1331 */
1332 public void playSoundEffect(double par1, double par3, double par5, String par7Str, float par8, float par9)
1333 {
1334 if (par7Str != null)
1335 {
1336 Iterator var10 = this.worldAccesses.iterator();
1337
1338 while (var10.hasNext())
1339 {
1340 IWorldAccess var11 = (IWorldAccess)var10.next();
1341 var11.playSound(par7Str, par1, par3, par5, par8, par9);
1342 }
1343 }
1344 }
1345
1346 /**
1347 * par8 is loudness, all pars passed to minecraftInstance.sndManager.playSound
1348 */
1349 public void playSound(double par1, double par3, double par5, String par7Str, float par8, float par9) {}
1350
1351 /**
1352 * Plays a record at the specified coordinates of the specified name. Args: recordName, x, y, z
1353 */
1354 public void playRecord(String par1Str, int par2, int par3, int par4)
1355 {
1356 Iterator var5 = this.worldAccesses.iterator();
1357
1358 while (var5.hasNext())
1359 {
1360 IWorldAccess var6 = (IWorldAccess)var5.next();
1361 var6.playRecord(par1Str, par2, par3, par4);
1362 }
1363 }
1364
1365 /**
1366 * Spawns a particle. Args particleName, x, y, z, velX, velY, velZ
1367 */
1368 public void spawnParticle(String par1Str, double par2, double par4, double par6, double par8, double par10, double par12)
1369 {
1370 Iterator var14 = this.worldAccesses.iterator();
1371
1372 while (var14.hasNext())
1373 {
1374 IWorldAccess var15 = (IWorldAccess)var14.next();
1375 var15.spawnParticle(par1Str, par2, par4, par6, par8, par10, par12);
1376 }
1377 }
1378
1379 /**
1380 * adds a lightning bolt to the list of lightning bolts in this world.
1381 */
1382 public boolean addWeatherEffect(Entity par1Entity)
1383 {
1384 this.weatherEffects.add(par1Entity);
1385 return true;
1386 }
1387
1388 /**
1389 * Called to place all entities as part of a world
1390 */
1391 public boolean spawnEntityInWorld(Entity par1Entity)
1392 {
1393 int var2 = MathHelper.floor_double(par1Entity.posX / 16.0D);
1394 int var3 = MathHelper.floor_double(par1Entity.posZ / 16.0D);
1395 boolean var4 = false;
1396
1397 if (par1Entity instanceof EntityPlayer)
1398 {
1399 var4 = true;
1400 }
1401
1402 if (!var4 && !this.chunkExists(var2, var3))
1403 {
1404 return false;
1405 }
1406 else
1407 {
1408 if (par1Entity instanceof EntityPlayer)
1409 {
1410 EntityPlayer var5 = (EntityPlayer)par1Entity;
1411 this.playerEntities.add(var5);
1412 this.updateAllPlayersSleepingFlag();
1413 }
1414
1415 if (!var4 && MinecraftForge.EVENT_BUS.post(new EntityJoinWorldEvent(par1Entity, this)))
1416 {
1417 return false;
1418 }
1419
1420 this.getChunkFromChunkCoords(var2, var3).addEntity(par1Entity);
1421 this.loadedEntityList.add(par1Entity);
1422 this.obtainEntitySkin(par1Entity);
1423 return true;
1424 }
1425 }
1426
1427 /**
1428 * Start the skin for this entity downloading, if necessary, and increment its reference counter
1429 */
1430 protected void obtainEntitySkin(Entity par1Entity)
1431 {
1432 Iterator var2 = this.worldAccesses.iterator();
1433
1434 while (var2.hasNext())
1435 {
1436 IWorldAccess var3 = (IWorldAccess)var2.next();
1437 var3.obtainEntitySkin(par1Entity);
1438 }
1439 }
1440
1441 /**
1442 * Decrement the reference counter for this entity's skin image data
1443 */
1444 protected void releaseEntitySkin(Entity par1Entity)
1445 {
1446 Iterator var2 = this.worldAccesses.iterator();
1447
1448 while (var2.hasNext())
1449 {
1450 IWorldAccess var3 = (IWorldAccess)var2.next();
1451 var3.releaseEntitySkin(par1Entity);
1452 }
1453 }
1454
1455 /**
1456 * Dismounts the entity (and anything riding the entity), sets the dead flag, and removes the player entity from the
1457 * player entity list. Called by the playerLoggedOut function.
1458 */
1459 public void setEntityDead(Entity par1Entity)
1460 {
1461 if (par1Entity.riddenByEntity != null)
1462 {
1463 par1Entity.riddenByEntity.mountEntity((Entity)null);
1464 }
1465
1466 if (par1Entity.ridingEntity != null)
1467 {
1468 par1Entity.mountEntity((Entity)null);
1469 }
1470
1471 par1Entity.setDead();
1472
1473 if (par1Entity instanceof EntityPlayer)
1474 {
1475 this.playerEntities.remove(par1Entity);
1476 this.updateAllPlayersSleepingFlag();
1477 }
1478 }
1479
1480 /**
1481 * remove dat player from dem servers
1482 */
1483 public void removeEntity(Entity par1Entity)
1484 {
1485 par1Entity.setDead();
1486
1487 if (par1Entity instanceof EntityPlayer)
1488 {
1489 this.playerEntities.remove(par1Entity);
1490 this.updateAllPlayersSleepingFlag();
1491 }
1492
1493 int var2 = par1Entity.chunkCoordX;
1494 int var3 = par1Entity.chunkCoordZ;
1495
1496 if (par1Entity.addedToChunk && this.chunkExists(var2, var3))
1497 {
1498 this.getChunkFromChunkCoords(var2, var3).removeEntity(par1Entity);
1499 }
1500
1501 this.loadedEntityList.remove(par1Entity);
1502 this.releaseEntitySkin(par1Entity);
1503 }
1504
1505 /**
1506 * Adds a IWorldAccess to the list of worldAccesses
1507 */
1508 public void addWorldAccess(IWorldAccess par1IWorldAccess)
1509 {
1510 this.worldAccesses.add(par1IWorldAccess);
1511 }
1512
1513 /**
1514 * Returns a list of bounding boxes that collide with aabb excluding the passed in entity's collision. Args: entity,
1515 * aabb
1516 */
1517 public List getCollidingBoundingBoxes(Entity par1Entity, AxisAlignedBB par2AxisAlignedBB)
1518 {
1519 this.collidingBoundingBoxes.clear();
1520 int var3 = MathHelper.floor_double(par2AxisAlignedBB.minX);
1521 int var4 = MathHelper.floor_double(par2AxisAlignedBB.maxX + 1.0D);
1522 int var5 = MathHelper.floor_double(par2AxisAlignedBB.minY);
1523 int var6 = MathHelper.floor_double(par2AxisAlignedBB.maxY + 1.0D);
1524 int var7 = MathHelper.floor_double(par2AxisAlignedBB.minZ);
1525 int var8 = MathHelper.floor_double(par2AxisAlignedBB.maxZ + 1.0D);
1526
1527 for (int var9 = var3; var9 < var4; ++var9)
1528 {
1529 for (int var10 = var7; var10 < var8; ++var10)
1530 {
1531 if (this.blockExists(var9, 64, var10))
1532 {
1533 for (int var11 = var5 - 1; var11 < var6; ++var11)
1534 {
1535 Block var12 = Block.blocksList[this.getBlockId(var9, var11, var10)];
1536
1537 if (var12 != null)
1538 {
1539 var12.addCollidingBlockToList(this, var9, var11, var10, par2AxisAlignedBB, this.collidingBoundingBoxes, par1Entity);
1540 }
1541 }
1542 }
1543 }
1544 }
1545
1546 double var15 = 0.25D;
1547 List var17 = this.getEntitiesWithinAABBExcludingEntity(par1Entity, par2AxisAlignedBB.expand(var15, var15, var15));
1548 Iterator var16 = var17.iterator();
1549
1550 while (var16.hasNext())
1551 {
1552 Entity var13 = (Entity)var16.next();
1553 AxisAlignedBB var14 = var13.getBoundingBox();
1554
1555 if (var14 != null && var14.intersectsWith(par2AxisAlignedBB))
1556 {
1557 this.collidingBoundingBoxes.add(var14);
1558 }
1559
1560 var14 = par1Entity.getCollisionBox(var13);
1561
1562 if (var14 != null && var14.intersectsWith(par2AxisAlignedBB))
1563 {
1564 this.collidingBoundingBoxes.add(var14);
1565 }
1566 }
1567
1568 return this.collidingBoundingBoxes;
1569 }
1570
1571 /**
1572 * calculates and returns a list of colliding bounding boxes within a given AABB
1573 */
1574 public List getAllCollidingBoundingBoxes(AxisAlignedBB par1AxisAlignedBB)
1575 {
1576 this.collidingBoundingBoxes.clear();
1577 int var2 = MathHelper.floor_double(par1AxisAlignedBB.minX);
1578 int var3 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
1579 int var4 = MathHelper.floor_double(par1AxisAlignedBB.minY);
1580 int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
1581 int var6 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
1582 int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
1583
1584 for (int var8 = var2; var8 < var3; ++var8)
1585 {
1586 for (int var9 = var6; var9 < var7; ++var9)
1587 {
1588 if (this.blockExists(var8, 64, var9))
1589 {
1590 for (int var10 = var4 - 1; var10 < var5; ++var10)
1591 {
1592 Block var11 = Block.blocksList[this.getBlockId(var8, var10, var9)];
1593
1594 if (var11 != null)
1595 {
1596 var11.addCollidingBlockToList(this, var8, var10, var9, par1AxisAlignedBB, this.collidingBoundingBoxes, (Entity)null);
1597 }
1598 }
1599 }
1600 }
1601 }
1602
1603 return this.collidingBoundingBoxes;
1604 }
1605
1606 /**
1607 * Returns the amount of skylight subtracted for the current time
1608 */
1609 public int calculateSkylightSubtracted(float par1)
1610 {
1611 float var2 = this.getCelestialAngle(par1);
1612 float var3 = 1.0F - (MathHelper.cos(var2 * (float)Math.PI * 2.0F) * 2.0F + 0.5F);
1613
1614 if (var3 < 0.0F)
1615 {
1616 var3 = 0.0F;
1617 }
1618
1619 if (var3 > 1.0F)
1620 {
1621 var3 = 1.0F;
1622 }
1623
1624 var3 = 1.0F - var3;
1625 var3 = (float)((double)var3 * (1.0D - (double)(this.getRainStrength(par1) * 5.0F) / 16.0D));
1626 var3 = (float)((double)var3 * (1.0D - (double)(this.getWeightedThunderStrength(par1) * 5.0F) / 16.0D));
1627 var3 = 1.0F - var3;
1628 return (int)(var3 * 11.0F);
1629 }
1630
1631 @SideOnly(Side.CLIENT)
1632
1633 /**
1634 * Removes a worldAccess from the worldAccesses object
1635 */
1636 public void removeWorldAccess(IWorldAccess par1IWorldAccess)
1637 {
1638 this.worldAccesses.remove(par1IWorldAccess);
1639 }
1640
1641 @SideOnly(Side.CLIENT)
1642 public float func_72971_b(float par1)
1643 {
1644 float var2 = this.getCelestialAngle(par1);
1645 float var3 = 1.0F - (MathHelper.cos(var2 * (float)Math.PI * 2.0F) * 2.0F + 0.2F);
1646
1647 if (var3 < 0.0F)
1648 {
1649 var3 = 0.0F;
1650 }
1651
1652 if (var3 > 1.0F)
1653 {
1654 var3 = 1.0F;
1655 }
1656
1657 var3 = 1.0F - var3;
1658 var3 = (float)((double)var3 * (1.0D - (double)(this.getRainStrength(par1) * 5.0F) / 16.0D));
1659 var3 = (float)((double)var3 * (1.0D - (double)(this.getWeightedThunderStrength(par1) * 5.0F) / 16.0D));
1660 return var3 * 0.8F + 0.2F;
1661 }
1662
1663 @SideOnly(Side.CLIENT)
1664
1665 /**
1666 * Calculates the color for the skybox
1667 */
1668 public Vec3 getSkyColor(Entity par1Entity, float par2)
1669 {
1670 return provider.getSkyColor(par1Entity, par2);
1671 }
1672
1673 @SideOnly(Side.CLIENT)
1674 public Vec3 getSkyColorBody(Entity par1Entity, float par2)
1675 {
1676 float var3 = this.getCelestialAngle(par2);
1677 float var4 = MathHelper.cos(var3 * (float)Math.PI * 2.0F) * 2.0F + 0.5F;
1678
1679 if (var4 < 0.0F)
1680 {
1681 var4 = 0.0F;
1682 }
1683
1684 if (var4 > 1.0F)
1685 {
1686 var4 = 1.0F;
1687 }
1688
1689 int var5 = MathHelper.floor_double(par1Entity.posX);
1690 int var6 = MathHelper.floor_double(par1Entity.posZ);
1691 BiomeGenBase var7 = this.getBiomeGenForCoords(var5, var6);
1692 float var8 = var7.getFloatTemperature();
1693 int var9 = var7.getSkyColorByTemp(var8);
1694 float var10 = (float)(var9 >> 16 & 255) / 255.0F;
1695 float var11 = (float)(var9 >> 8 & 255) / 255.0F;
1696 float var12 = (float)(var9 & 255) / 255.0F;
1697 var10 *= var4;
1698 var11 *= var4;
1699 var12 *= var4;
1700 float var13 = this.getRainStrength(par2);
1701 float var14;
1702 float var15;
1703
1704 if (var13 > 0.0F)
1705 {
1706 var14 = (var10 * 0.3F + var11 * 0.59F + var12 * 0.11F) * 0.6F;
1707 var15 = 1.0F - var13 * 0.75F;
1708 var10 = var10 * var15 + var14 * (1.0F - var15);
1709 var11 = var11 * var15 + var14 * (1.0F - var15);
1710 var12 = var12 * var15 + var14 * (1.0F - var15);
1711 }
1712
1713 var14 = this.getWeightedThunderStrength(par2);
1714
1715 if (var14 > 0.0F)
1716 {
1717 var15 = (var10 * 0.3F + var11 * 0.59F + var12 * 0.11F) * 0.2F;
1718 float var16 = 1.0F - var14 * 0.75F;
1719 var10 = var10 * var16 + var15 * (1.0F - var16);
1720 var11 = var11 * var16 + var15 * (1.0F - var16);
1721 var12 = var12 * var16 + var15 * (1.0F - var16);
1722 }
1723
1724 if (this.lightningFlash > 0)
1725 {
1726 var15 = (float)this.lightningFlash - par2;
1727
1728 if (var15 > 1.0F)
1729 {
1730 var15 = 1.0F;
1731 }
1732
1733 var15 *= 0.45F;
1734 var10 = var10 * (1.0F - var15) + 0.8F * var15;
1735 var11 = var11 * (1.0F - var15) + 0.8F * var15;
1736 var12 = var12 * (1.0F - var15) + 1.0F * var15;
1737 }
1738
1739 return this.func_82732_R().getVecFromPool((double)var10, (double)var11, (double)var12);
1740 }
1741
1742 /**
1743 * calls calculateCelestialAngle
1744 */
1745 public float getCelestialAngle(float par1)
1746 {
1747 return this.provider.calculateCelestialAngle(this.worldInfo.getWorldTime(), par1);
1748 }
1749
1750 @SideOnly(Side.CLIENT)
1751 public int getMoonPhase(float par1)
1752 {
1753 return this.provider.getMoonPhase(this.worldInfo.getWorldTime(), par1);
1754 }
1755
1756 @SideOnly(Side.CLIENT)
1757
1758 /**
1759 * Return getCelestialAngle()*2*PI
1760 */
1761 public float getCelestialAngleRadians(float par1)
1762 {
1763 float var2 = this.getCelestialAngle(par1);
1764 return var2 * (float)Math.PI * 2.0F;
1765 }
1766
1767 @SideOnly(Side.CLIENT)
1768 public Vec3 drawClouds(float par1)
1769 {
1770 return provider.drawClouds(par1);
1771 }
1772
1773 @SideOnly(Side.CLIENT)
1774 public Vec3 drawCloudsBody(float par1)
1775 {
1776 float var2 = this.getCelestialAngle(par1);
1777 float var3 = MathHelper.cos(var2 * (float)Math.PI * 2.0F) * 2.0F + 0.5F;
1778
1779 if (var3 < 0.0F)
1780 {
1781 var3 = 0.0F;
1782 }
1783
1784 if (var3 > 1.0F)
1785 {
1786 var3 = 1.0F;
1787 }
1788
1789 float var4 = (float)(this.cloudColour >> 16 & 255L) / 255.0F;
1790 float var5 = (float)(this.cloudColour >> 8 & 255L) / 255.0F;
1791 float var6 = (float)(this.cloudColour & 255L) / 255.0F;
1792 float var7 = this.getRainStrength(par1);
1793 float var8;
1794 float var9;
1795
1796 if (var7 > 0.0F)
1797 {
1798 var8 = (var4 * 0.3F + var5 * 0.59F + var6 * 0.11F) * 0.6F;
1799 var9 = 1.0F - var7 * 0.95F;
1800 var4 = var4 * var9 + var8 * (1.0F - var9);
1801 var5 = var5 * var9 + var8 * (1.0F - var9);
1802 var6 = var6 * var9 + var8 * (1.0F - var9);
1803 }
1804
1805 var4 *= var3 * 0.9F + 0.1F;
1806 var5 *= var3 * 0.9F + 0.1F;
1807 var6 *= var3 * 0.85F + 0.15F;
1808 var8 = this.getWeightedThunderStrength(par1);
1809
1810 if (var8 > 0.0F)
1811 {
1812 var9 = (var4 * 0.3F + var5 * 0.59F + var6 * 0.11F) * 0.2F;
1813 float var10 = 1.0F - var8 * 0.95F;
1814 var4 = var4 * var10 + var9 * (1.0F - var10);
1815 var5 = var5 * var10 + var9 * (1.0F - var10);
1816 var6 = var6 * var10 + var9 * (1.0F - var10);
1817 }
1818
1819 return this.func_82732_R().getVecFromPool((double)var4, (double)var5, (double)var6);
1820 }
1821
1822 @SideOnly(Side.CLIENT)
1823
1824 /**
1825 * Returns vector(ish) with R/G/B for fog
1826 */
1827 public Vec3 getFogColor(float par1)
1828 {
1829 float var2 = this.getCelestialAngle(par1);
1830 return this.provider.getFogColor(var2, par1);
1831 }
1832
1833 /**
1834 * Gets the height to which rain/snow will fall. Calculates it if not already stored.
1835 */
1836 public int getPrecipitationHeight(int par1, int par2)
1837 {
1838 return this.getChunkFromBlockCoords(par1, par2).getPrecipitationHeight(par1 & 15, par2 & 15);
1839 }
1840
1841 /**
1842 * Finds the highest block on the x, z coordinate that is solid and returns its y coord. Args x, z
1843 */
1844 public int getTopSolidOrLiquidBlock(int par1, int par2)
1845 {
1846 Chunk var3 = this.getChunkFromBlockCoords(par1, par2);
1847 int var4 = var3.getTopFilledSegment() + 15;
1848 par1 &= 15;
1849
1850 for (par2 &= 15; var4 > 0; --var4)
1851 {
1852 int var5 = var3.getBlockID(par1, var4, par2);
1853
1854 if (var5 != 0 && Block.blocksList[var5].blockMaterial.blocksMovement() && Block.blocksList[var5].blockMaterial != Material.leaves && !Block.blocksList[var5].isBlockFoliage(this, par1, var4, par2))
1855 {
1856 return var4 + 1;
1857 }
1858 }
1859
1860 return -1;
1861 }
1862
1863 @SideOnly(Side.CLIENT)
1864
1865 /**
1866 * How bright are stars in the sky
1867 */
1868 public float getStarBrightness(float par1)
1869 {
1870 return provider.getStarBrightness(par1);
1871 }
1872
1873 @SideOnly(Side.CLIENT)
1874 public float getStarBrightnessBody(float par1)
1875 {
1876 float var2 = this.getCelestialAngle(par1);
1877 float var3 = 1.0F - (MathHelper.cos(var2 * (float)Math.PI * 2.0F) * 2.0F + 0.25F);
1878
1879 if (var3 < 0.0F)
1880 {
1881 var3 = 0.0F;
1882 }
1883
1884 if (var3 > 1.0F)
1885 {
1886 var3 = 1.0F;
1887 }
1888
1889 return var3 * var3 * 0.5F;
1890 }
1891
1892 /**
1893 * Schedules a tick to a block with a delay (Most commonly the tick rate)
1894 */
1895 public void scheduleBlockUpdate(int par1, int par2, int par3, int par4, int par5) {}
1896
1897 public void func_82740_a(int par1, int par2, int par3, int par4, int par5, int par6) {}
1898
1899 /**
1900 * Schedules a block update from the saved information in a chunk. Called when the chunk is loaded.
1901 */
1902 public void scheduleBlockUpdateFromLoad(int par1, int par2, int par3, int par4, int par5) {}
1903
1904 /**
1905 * Updates (and cleans up) entities and tile entities
1906 */
1907 public void updateEntities()
1908 {
1909 this.theProfiler.startSection("entities");
1910 this.theProfiler.startSection("global");
1911 int var1;
1912 Entity var2;
1913
1914 for (var1 = 0; var1 < this.weatherEffects.size(); ++var1)
1915 {
1916 var2 = (Entity)this.weatherEffects.get(var1);
1917 var2.onUpdate();
1918
1919 if (var2.isDead)
1920 {
1921 this.weatherEffects.remove(var1--);
1922 }
1923 }
1924
1925 this.theProfiler.endStartSection("remove");
1926 this.loadedEntityList.removeAll(this.unloadedEntityList);
1927 Iterator var5 = this.unloadedEntityList.iterator();
1928 int var3;
1929 int var4;
1930
1931 while (var5.hasNext())
1932 {
1933 var2 = (Entity)var5.next();
1934 var3 = var2.chunkCoordX;
1935 var4 = var2.chunkCoordZ;
1936
1937 if (var2.addedToChunk && this.chunkExists(var3, var4))
1938 {
1939 this.getChunkFromChunkCoords(var3, var4).removeEntity(var2);
1940 }
1941 }
1942
1943 var5 = this.unloadedEntityList.iterator();
1944
1945 while (var5.hasNext())
1946 {
1947 var2 = (Entity)var5.next();
1948 this.releaseEntitySkin(var2);
1949 }
1950
1951 this.unloadedEntityList.clear();
1952 this.theProfiler.endStartSection("regular");
1953
1954 for (var1 = 0; var1 < this.loadedEntityList.size(); ++var1)
1955 {
1956 var2 = (Entity)this.loadedEntityList.get(var1);
1957
1958 if (var2.ridingEntity != null)
1959 {
1960 if (!var2.ridingEntity.isDead && var2.ridingEntity.riddenByEntity == var2)
1961 {
1962 continue;
1963 }
1964
1965 var2.ridingEntity.riddenByEntity = null;
1966 var2.ridingEntity = null;
1967 }
1968
1969 this.theProfiler.startSection("tick");
1970
1971 if (!var2.isDead)
1972 {
1973 this.updateEntity(var2);
1974 }
1975
1976 this.theProfiler.endSection();
1977 this.theProfiler.startSection("remove");
1978
1979 if (var2.isDead)
1980 {
1981 var3 = var2.chunkCoordX;
1982 var4 = var2.chunkCoordZ;
1983
1984 if (var2.addedToChunk && this.chunkExists(var3, var4))
1985 {
1986 this.getChunkFromChunkCoords(var3, var4).removeEntity(var2);
1987 }
1988
1989 this.loadedEntityList.remove(var1--);
1990 this.releaseEntitySkin(var2);
1991 }
1992
1993 this.theProfiler.endSection();
1994 }
1995
1996 this.theProfiler.endStartSection("tileEntities");
1997 this.scanningTileEntities = true;
1998 var5 = this.loadedTileEntityList.iterator();
1999
2000 while (var5.hasNext())
2001 {
2002 TileEntity var6 = (TileEntity)var5.next();
2003
2004 if (!var6.isInvalid() && var6.func_70309_m() && this.blockExists(var6.xCoord, var6.yCoord, var6.zCoord))
2005 {
2006 var6.updateEntity();
2007 }
2008
2009 if (var6.isInvalid())
2010 {
2011 var5.remove();
2012
2013 if (this.chunkExists(var6.xCoord >> 4, var6.zCoord >> 4))
2014 {
2015 Chunk var8 = this.getChunkFromChunkCoords(var6.xCoord >> 4, var6.zCoord >> 4);
2016
2017 if (var8 != null)
2018 {
2019 var8.cleanChunkBlockTileEntity(var6.xCoord & 15, var6.yCoord, var6.zCoord & 15);
2020 }
2021 }
2022 }
2023 }
2024
2025 this.scanningTileEntities = false;
2026
2027 if (!this.entityRemoval.isEmpty())
2028 {
2029 for (Object tile : entityRemoval)
2030 {
2031 ((TileEntity)tile).onChunkUnload();
2032 }
2033 this.loadedTileEntityList.removeAll(this.entityRemoval);
2034 this.entityRemoval.clear();
2035 }
2036
2037 this.theProfiler.endStartSection("pendingTileEntities");
2038
2039 if (!this.addedTileEntityList.isEmpty())
2040 {
2041 Iterator var7 = this.addedTileEntityList.iterator();
2042
2043 while (var7.hasNext())
2044 {
2045 TileEntity var9 = (TileEntity)var7.next();
2046
2047 if (!var9.isInvalid())
2048 {
2049 if (!this.loadedTileEntityList.contains(var9))
2050 {
2051 this.loadedTileEntityList.add(var9);
2052 }
2053 }
2054 else
2055 {
2056 if (this.chunkExists(var9.xCoord >> 4, var9.zCoord >> 4))
2057 {
2058 Chunk var10 = this.getChunkFromChunkCoords(var9.xCoord >> 4, var9.zCoord >> 4);
2059
2060 if (var10 != null)
2061 {
2062 var10.setChunkBlockTileEntity(var9.xCoord & 15, var9.yCoord, var9.zCoord & 15, var9);
2063 }
2064 }
2065 }
2066 }
2067
2068 this.addedTileEntityList.clear();
2069 }
2070
2071 this.theProfiler.endSection();
2072 this.theProfiler.endSection();
2073 }
2074
2075 public void addTileEntity(Collection par1Collection)
2076 {
2077 List dest = scanningTileEntities ? addedTileEntityList : loadedTileEntityList;
2078 for(Object entity : par1Collection)
2079 {
2080 if(((TileEntity)entity).canUpdate())
2081 {
2082 dest.add(entity);
2083 }
2084 }
2085 }
2086
2087 /**
2088 * Will update the entity in the world if the chunk the entity is in is currently loaded. Args: entity
2089 */
2090 public void updateEntity(Entity par1Entity)
2091 {
2092 this.updateEntityWithOptionalForce(par1Entity, true);
2093 }
2094
2095 /**
2096 * Will update the entity in the world if the chunk the entity is in is currently loaded or its forced to update.
2097 * Args: entity, forceUpdate
2098 */
2099 public void updateEntityWithOptionalForce(Entity par1Entity, boolean par2)
2100 {
2101 int var3 = MathHelper.floor_double(par1Entity.posX);
2102 int var4 = MathHelper.floor_double(par1Entity.posZ);
2103
2104 boolean isForced = getPersistentChunks().containsKey(new ChunkCoordIntPair(var3 >> 4, var4 >> 4));
2105 byte var5 = isForced ? (byte)0 : 32;
2106 boolean canUpdate = !par2 || this.checkChunksExist(var3 - var5, 0, var4 - var5, var3 + var5, 0, var4 + var5);
2107 if (!canUpdate)
2108 {
2109 EntityEvent.CanUpdate event = new EntityEvent.CanUpdate(par1Entity);
2110 MinecraftForge.EVENT_BUS.post(event);
2111 canUpdate = event.canUpdate;
2112 }
2113 if (canUpdate)
2114 {
2115 par1Entity.lastTickPosX = par1Entity.posX;
2116 par1Entity.lastTickPosY = par1Entity.posY;
2117 par1Entity.lastTickPosZ = par1Entity.posZ;
2118 par1Entity.prevRotationYaw = par1Entity.rotationYaw;
2119 par1Entity.prevRotationPitch = par1Entity.rotationPitch;
2120
2121 if (par2 && par1Entity.addedToChunk)
2122 {
2123 if (par1Entity.ridingEntity != null)
2124 {
2125 par1Entity.updateRidden();
2126 }
2127 else
2128 {
2129 par1Entity.onUpdate();
2130 }
2131 }
2132
2133 this.theProfiler.startSection("chunkCheck");
2134
2135 if (Double.isNaN(par1Entity.posX) || Double.isInfinite(par1Entity.posX))
2136 {
2137 par1Entity.posX = par1Entity.lastTickPosX;
2138 }
2139
2140 if (Double.isNaN(par1Entity.posY) || Double.isInfinite(par1Entity.posY))
2141 {
2142 par1Entity.posY = par1Entity.lastTickPosY;
2143 }
2144
2145 if (Double.isNaN(par1Entity.posZ) || Double.isInfinite(par1Entity.posZ))
2146 {
2147 par1Entity.posZ = par1Entity.lastTickPosZ;
2148 }
2149
2150 if (Double.isNaN((double)par1Entity.rotationPitch) || Double.isInfinite((double)par1Entity.rotationPitch))
2151 {
2152 par1Entity.rotationPitch = par1Entity.prevRotationPitch;
2153 }
2154
2155 if (Double.isNaN((double)par1Entity.rotationYaw) || Double.isInfinite((double)par1Entity.rotationYaw))
2156 {
2157 par1Entity.rotationYaw = par1Entity.prevRotationYaw;
2158 }
2159
2160 int var6 = MathHelper.floor_double(par1Entity.posX / 16.0D);
2161 int var7 = MathHelper.floor_double(par1Entity.posY / 16.0D);
2162 int var8 = MathHelper.floor_double(par1Entity.posZ / 16.0D);
2163
2164 if (!par1Entity.addedToChunk || par1Entity.chunkCoordX != var6 || par1Entity.chunkCoordY != var7 || par1Entity.chunkCoordZ != var8)
2165 {
2166 if (par1Entity.addedToChunk && this.chunkExists(par1Entity.chunkCoordX, par1Entity.chunkCoordZ))
2167 {
2168 this.getChunkFromChunkCoords(par1Entity.chunkCoordX, par1Entity.chunkCoordZ).removeEntityAtIndex(par1Entity, par1Entity.chunkCoordY);
2169 }
2170
2171 if (this.chunkExists(var6, var8))
2172 {
2173 par1Entity.addedToChunk = true;
2174 this.getChunkFromChunkCoords(var6, var8).addEntity(par1Entity);
2175 }
2176 else
2177 {
2178 par1Entity.addedToChunk = false;
2179 }
2180 }
2181
2182 this.theProfiler.endSection();
2183
2184 if (par2 && par1Entity.addedToChunk && par1Entity.riddenByEntity != null)
2185 {
2186 if (!par1Entity.riddenByEntity.isDead && par1Entity.riddenByEntity.ridingEntity == par1Entity)
2187 {
2188 this.updateEntity(par1Entity.riddenByEntity);
2189 }
2190 else
2191 {
2192 par1Entity.riddenByEntity.ridingEntity = null;
2193 par1Entity.riddenByEntity = null;
2194 }
2195 }
2196 }
2197 }
2198
2199 /**
2200 * Returns true if there are no solid, live entities in the specified AxisAlignedBB
2201 */
2202 public boolean checkIfAABBIsClear(AxisAlignedBB par1AxisAlignedBB)
2203 {
2204 return this.checkIfAABBIsClearExcludingEntity(par1AxisAlignedBB, (Entity)null);
2205 }
2206
2207 /**
2208 * Returns true if there are no solid, live entities in the specified AxisAlignedBB, excluding the given entity
2209 */
2210 public boolean checkIfAABBIsClearExcludingEntity(AxisAlignedBB par1AxisAlignedBB, Entity par2Entity)
2211 {
2212 List var3 = this.getEntitiesWithinAABBExcludingEntity((Entity)null, par1AxisAlignedBB);
2213 Iterator var4 = var3.iterator();
2214 Entity var5;
2215
2216 do
2217 {
2218 if (!var4.hasNext())
2219 {
2220 return true;
2221 }
2222
2223 var5 = (Entity)var4.next();
2224 }
2225 while (var5.isDead || !var5.preventEntitySpawning || var5 == par2Entity);
2226
2227 return false;
2228 }
2229
2230 /**
2231 * Returns true if there are any blocks in the region constrained by an AxisAlignedBB
2232 */
2233 public boolean isAABBNonEmpty(AxisAlignedBB par1AxisAlignedBB)
2234 {
2235 int var2 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2236 int var3 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2237 int var4 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2238 int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2239 int var6 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2240 int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2241
2242 if (par1AxisAlignedBB.minX < 0.0D)
2243 {
2244 --var2;
2245 }
2246
2247 if (par1AxisAlignedBB.minY < 0.0D)
2248 {
2249 --var4;
2250 }
2251
2252 if (par1AxisAlignedBB.minZ < 0.0D)
2253 {
2254 --var6;
2255 }
2256
2257 for (int var8 = var2; var8 < var3; ++var8)
2258 {
2259 for (int var9 = var4; var9 < var5; ++var9)
2260 {
2261 for (int var10 = var6; var10 < var7; ++var10)
2262 {
2263 Block var11 = Block.blocksList[this.getBlockId(var8, var9, var10)];
2264
2265 if (var11 != null)
2266 {
2267 return true;
2268 }
2269 }
2270 }
2271 }
2272
2273 return false;
2274 }
2275
2276 /**
2277 * Returns if any of the blocks within the aabb are liquids. Args: aabb
2278 */
2279 public boolean isAnyLiquid(AxisAlignedBB par1AxisAlignedBB)
2280 {
2281 int var2 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2282 int var3 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2283 int var4 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2284 int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2285 int var6 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2286 int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2287
2288 if (par1AxisAlignedBB.minX < 0.0D)
2289 {
2290 --var2;
2291 }
2292
2293 if (par1AxisAlignedBB.minY < 0.0D)
2294 {
2295 --var4;
2296 }
2297
2298 if (par1AxisAlignedBB.minZ < 0.0D)
2299 {
2300 --var6;
2301 }
2302
2303 for (int var8 = var2; var8 < var3; ++var8)
2304 {
2305 for (int var9 = var4; var9 < var5; ++var9)
2306 {
2307 for (int var10 = var6; var10 < var7; ++var10)
2308 {
2309 Block var11 = Block.blocksList[this.getBlockId(var8, var9, var10)];
2310
2311 if (var11 != null && var11.blockMaterial.isLiquid())
2312 {
2313 return true;
2314 }
2315 }
2316 }
2317 }
2318
2319 return false;
2320 }
2321
2322 /**
2323 * Returns whether or not the given bounding box is on fire or not
2324 */
2325 public boolean isBoundingBoxBurning(AxisAlignedBB par1AxisAlignedBB)
2326 {
2327 int var2 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2328 int var3 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2329 int var4 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2330 int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2331 int var6 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2332 int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2333
2334 if (this.checkChunksExist(var2, var4, var6, var3, var5, var7))
2335 {
2336 for (int var8 = var2; var8 < var3; ++var8)
2337 {
2338 for (int var9 = var4; var9 < var5; ++var9)
2339 {
2340 for (int var10 = var6; var10 < var7; ++var10)
2341 {
2342 int var11 = this.getBlockId(var8, var9, var10);
2343
2344 if (var11 == Block.fire.blockID || var11 == Block.lavaMoving.blockID || var11 == Block.lavaStill.blockID)
2345 {
2346 return true;
2347 }
2348 else
2349 {
2350 Block block = Block.blocksList[var11];
2351 if (block != null && block.isBlockBurning(this, var8, var9, var10))
2352 {
2353 return true;
2354 }
2355 }
2356 }
2357 }
2358 }
2359 }
2360
2361 return false;
2362 }
2363
2364 /**
2365 * handles the acceleration of an object whilst in water. Not sure if it is used elsewhere.
2366 */
2367 public boolean handleMaterialAcceleration(AxisAlignedBB par1AxisAlignedBB, Material par2Material, Entity par3Entity)
2368 {
2369 int var4 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2370 int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2371 int var6 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2372 int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2373 int var8 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2374 int var9 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2375
2376 if (!this.checkChunksExist(var4, var6, var8, var5, var7, var9))
2377 {
2378 return false;
2379 }
2380 else
2381 {
2382 boolean var10 = false;
2383 Vec3 var11 = this.func_82732_R().getVecFromPool(0.0D, 0.0D, 0.0D);
2384
2385 for (int var12 = var4; var12 < var5; ++var12)
2386 {
2387 for (int var13 = var6; var13 < var7; ++var13)
2388 {
2389 for (int var14 = var8; var14 < var9; ++var14)
2390 {
2391 Block var15 = Block.blocksList[this.getBlockId(var12, var13, var14)];
2392
2393 if (var15 != null && var15.blockMaterial == par2Material)
2394 {
2395 double var16 = (double)((float)(var13 + 1) - BlockFluid.getFluidHeightPercent(this.getBlockMetadata(var12, var13, var14)));
2396
2397 if ((double)var7 >= var16)
2398 {
2399 var10 = true;
2400 var15.velocityToAddToEntity(this, var12, var13, var14, par3Entity, var11);
2401 }
2402 }
2403 }
2404 }
2405 }
2406
2407 if (var11.lengthVector() > 0.0D)
2408 {
2409 var11 = var11.normalize();
2410 double var18 = 0.014D;
2411 par3Entity.motionX += var11.xCoord * var18;
2412 par3Entity.motionY += var11.yCoord * var18;
2413 par3Entity.motionZ += var11.zCoord * var18;
2414 }
2415
2416 return var10;
2417 }
2418 }
2419
2420 /**
2421 * Returns true if the given bounding box contains the given material
2422 */
2423 public boolean isMaterialInBB(AxisAlignedBB par1AxisAlignedBB, Material par2Material)
2424 {
2425 int var3 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2426 int var4 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2427 int var5 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2428 int var6 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2429 int var7 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2430 int var8 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2431
2432 for (int var9 = var3; var9 < var4; ++var9)
2433 {
2434 for (int var10 = var5; var10 < var6; ++var10)
2435 {
2436 for (int var11 = var7; var11 < var8; ++var11)
2437 {
2438 Block var12 = Block.blocksList[this.getBlockId(var9, var10, var11)];
2439
2440 if (var12 != null && var12.blockMaterial == par2Material)
2441 {
2442 return true;
2443 }
2444 }
2445 }
2446 }
2447
2448 return false;
2449 }
2450
2451 /**
2452 * checks if the given AABB is in the material given. Used while swimming.
2453 */
2454 public boolean isAABBInMaterial(AxisAlignedBB par1AxisAlignedBB, Material par2Material)
2455 {
2456 int var3 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2457 int var4 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2458 int var5 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2459 int var6 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2460 int var7 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2461 int var8 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2462
2463 for (int var9 = var3; var9 < var4; ++var9)
2464 {
2465 for (int var10 = var5; var10 < var6; ++var10)
2466 {
2467 for (int var11 = var7; var11 < var8; ++var11)
2468 {
2469 Block var12 = Block.blocksList[this.getBlockId(var9, var10, var11)];
2470
2471 if (var12 != null && var12.blockMaterial == par2Material)
2472 {
2473 int var13 = this.getBlockMetadata(var9, var10, var11);
2474 double var14 = (double)(var10 + 1);
2475
2476 if (var13 < 8)
2477 {
2478 var14 = (double)(var10 + 1) - (double)var13 / 8.0D;
2479 }
2480
2481 if (var14 >= par1AxisAlignedBB.minY)
2482 {
2483 return true;
2484 }
2485 }
2486 }
2487 }
2488 }
2489
2490 return false;
2491 }
2492
2493 /**
2494 * Creates an explosion. Args: entity, x, y, z, strength
2495 */
2496 public Explosion createExplosion(Entity var1, double var2, double var4, double var6, float var8, boolean var9)
2497 {
2498 return this.newExplosion(var1, var2, var4, var6, var8, false, var9);
2499 }
2500
2501 /**
2502 * returns a new explosion. Does initiation (at time of writing Explosion is not finished)
2503 */
2504 public Explosion newExplosion(Entity var1, double var2, double var4, double var6, float var8, boolean var9, boolean var10)
2505 {
2506 Explosion var11 = new Explosion(this, var1, var2, var4, var6, var8);
2507 var11.isFlaming = var9;
2508 var11.field_82755_b = var10;
2509 var11.doExplosionA();
2510 var11.doExplosionB(true);
2511 return var11;
2512 }
2513
2514 /**
2515 * Gets the percentage of real blocks within within a bounding box, along a specified vector.
2516 */
2517 public float getBlockDensity(Vec3 par1Vec3, AxisAlignedBB par2AxisAlignedBB)
2518 {
2519 double var3 = 1.0D / ((par2AxisAlignedBB.maxX - par2AxisAlignedBB.minX) * 2.0D + 1.0D);
2520 double var5 = 1.0D / ((par2AxisAlignedBB.maxY - par2AxisAlignedBB.minY) * 2.0D + 1.0D);
2521 double var7 = 1.0D / ((par2AxisAlignedBB.maxZ - par2AxisAlignedBB.minZ) * 2.0D + 1.0D);
2522 int var9 = 0;
2523 int var10 = 0;
2524
2525 for (float var11 = 0.0F; var11 <= 1.0F; var11 = (float)((double)var11 + var3))
2526 {
2527 for (float var12 = 0.0F; var12 <= 1.0F; var12 = (float)((double)var12 + var5))
2528 {
2529 for (float var13 = 0.0F; var13 <= 1.0F; var13 = (float)((double)var13 + var7))
2530 {
2531 double var14 = par2AxisAlignedBB.minX + (par2AxisAlignedBB.maxX - par2AxisAlignedBB.minX) * (double)var11;
2532 double var16 = par2AxisAlignedBB.minY + (par2AxisAlignedBB.maxY - par2AxisAlignedBB.minY) * (double)var12;
2533 double var18 = par2AxisAlignedBB.minZ + (par2AxisAlignedBB.maxZ - par2AxisAlignedBB.minZ) * (double)var13;
2534
2535 if (this.rayTraceBlocks(this.func_82732_R().getVecFromPool(var14, var16, var18), par1Vec3) == null)
2536 {
2537 ++var9;
2538 }
2539
2540 ++var10;
2541 }
2542 }
2543 }
2544
2545 return (float)var9 / (float)var10;
2546 }
2547
2548 /**
2549 * If the block in the given direction of the given coordinate is fire, extinguish it. Args: Player, X,Y,Z,
2550 * blockDirection
2551 */
2552 public boolean extinguishFire(EntityPlayer par1EntityPlayer, int par2, int par3, int par4, int par5)
2553 {
2554 if (par5 == 0)
2555 {
2556 --par3;
2557 }
2558
2559 if (par5 == 1)
2560 {
2561 ++par3;
2562 }
2563
2564 if (par5 == 2)
2565 {
2566 --par4;
2567 }
2568
2569 if (par5 == 3)
2570 {
2571 ++par4;
2572 }
2573
2574 if (par5 == 4)
2575 {
2576 --par2;
2577 }
2578
2579 if (par5 == 5)
2580 {
2581 ++par2;
2582 }
2583
2584 if (this.getBlockId(par2, par3, par4) == Block.fire.blockID)
2585 {
2586 this.playAuxSFXAtEntity(par1EntityPlayer, 1004, par2, par3, par4, 0);
2587 this.setBlockWithNotify(par2, par3, par4, 0);
2588 return true;
2589 }
2590 else
2591 {
2592 return false;
2593 }
2594 }
2595
2596 @SideOnly(Side.CLIENT)
2597
2598 /**
2599 * This string is 'All: (number of loaded entities)' Viewable by press ing F3
2600 */
2601 public String getDebugLoadedEntities()
2602 {
2603 return "All: " + this.loadedEntityList.size();
2604 }
2605
2606 @SideOnly(Side.CLIENT)
2607
2608 /**
2609 * Returns the name of the current chunk provider, by calling chunkprovider.makeString()
2610 */
2611 public String getProviderName()
2612 {
2613 return this.chunkProvider.makeString();
2614 }
2615
2616 /**
2617 * Returns the TileEntity associated with a given block in X,Y,Z coordinates, or null if no TileEntity exists
2618 */
2619 public TileEntity getBlockTileEntity(int par1, int par2, int par3)
2620 {
2621 if (par2 >= 256)
2622 {
2623 return null;
2624 }
2625 else
2626 {
2627 Chunk var4 = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
2628
2629 if (var4 == null)
2630 {
2631 return null;
2632 }
2633 else
2634 {
2635 TileEntity var5 = var4.getChunkBlockTileEntity(par1 & 15, par2, par3 & 15);
2636
2637 if (var5 == null)
2638 {
2639 Iterator var6 = this.addedTileEntityList.iterator();
2640
2641 while (var6.hasNext())
2642 {
2643 TileEntity var7 = (TileEntity)var6.next();
2644
2645 if (!var7.isInvalid() && var7.xCoord == par1 && var7.yCoord == par2 && var7.zCoord == par3)
2646 {
2647 var5 = var7;
2648 break;
2649 }
2650 }
2651 }
2652
2653 return var5;
2654 }
2655 }
2656 }
2657
2658 /**
2659 * Sets the TileEntity for a given block in X, Y, Z coordinates
2660 */
2661 public void setBlockTileEntity(int par1, int par2, int par3, TileEntity par4TileEntity)
2662 {
2663 if (par4TileEntity == null || par4TileEntity.isInvalid())
2664 {
2665 return;
2666 }
2667
2668 if (par4TileEntity.canUpdate())
2669 {
2670 List dest = scanningTileEntities ? addedTileEntityList : loadedTileEntityList;
2671 dest.add(par4TileEntity);
2672 }
2673
2674 Chunk chunk = getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
2675 if (chunk != null)
2676 {
2677 chunk.setChunkBlockTileEntity(par1 & 15, par2, par3 & 15, par4TileEntity);
2678 }
2679 }
2680
2681 /**
2682 * Removes the TileEntity for a given block in X,Y,Z coordinates
2683 */
2684 public void removeBlockTileEntity(int par1, int par2, int par3)
2685 {
2686 Chunk chunk = getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
2687 if (chunk != null)
2688 {
2689 chunk.removeChunkBlockTileEntity(par1 & 15, par2, par3 & 15);
2690 }
2691 }
2692
2693 /**
2694 * adds tile entity to despawn list (renamed from markEntityForDespawn)
2695 */
2696 public void markTileEntityForDespawn(TileEntity par1TileEntity)
2697 {
2698 this.entityRemoval.add(par1TileEntity);
2699 }
2700
2701 /**
2702 * Returns true if the block at the specified coordinates is an opaque cube. Args: x, y, z
2703 */
2704 public boolean isBlockOpaqueCube(int par1, int par2, int par3)
2705 {
2706 Block var4 = Block.blocksList[this.getBlockId(par1, par2, par3)];
2707 return var4 == null ? false : var4.isOpaqueCube();
2708 }
2709
2710 /**
2711 * Indicate if a material is a normal solid opaque cube.
2712 */
2713 public boolean isBlockNormalCube(int par1, int par2, int par3)
2714 {
2715 Block block = Block.blocksList[getBlockId(par1, par2, par3)];
2716 return block != null && block.isBlockNormalCube(this, par1, par2, par3);
2717 }
2718
2719 /**
2720 * Returns true if the block at the given coordinate has a solid (buildable) top surface.
2721 */
2722 public boolean doesBlockHaveSolidTopSurface(int par1, int par2, int par3)
2723 {
2724 return isBlockSolidOnSide(par1, par2, par3, ForgeDirection.UP);
2725 }
2726
2727 /**
2728 * Checks if the block is a solid, normal cube. If the chunk does not exist, or is not loaded, it returns the
2729 * boolean parameter.
2730 */
2731 public boolean isBlockNormalCubeDefault(int par1, int par2, int par3, boolean par4)
2732 {
2733 if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000)
2734 {
2735 Chunk var5 = this.chunkProvider.provideChunk(par1 >> 4, par3 >> 4);
2736
2737 if (var5 != null && !var5.isEmpty())
2738 {
2739 Block var6 = Block.blocksList[this.getBlockId(par1, par2, par3)];
2740 return var6 == null ? false : isBlockNormalCube(par1, par2, par3);
2741 }
2742 else
2743 {
2744 return par4;
2745 }
2746 }
2747 else
2748 {
2749 return par4;
2750 }
2751 }
2752
2753 /**
2754 * Called on construction of the World class to setup the initial skylight values
2755 */
2756 public void calculateInitialSkylight()
2757 {
2758 int var1 = this.calculateSkylightSubtracted(1.0F);
2759
2760 if (var1 != this.skylightSubtracted)
2761 {
2762 this.skylightSubtracted = var1;
2763 }
2764 }
2765
2766 /**
2767 * Set which types of mobs are allowed to spawn (peaceful vs hostile).
2768 */
2769 public void setAllowedSpawnTypes(boolean par1, boolean par2)
2770 {
2771 provider.setAllowedSpawnTypes(par1, par2);
2772 }
2773
2774 /**
2775 * Runs a single tick for the world
2776 */
2777 public void tick()
2778 {
2779 this.updateWeather();
2780 }
2781
2782 /**
2783 * Called from World constructor to set rainingStrength and thunderingStrength
2784 */
2785 private void calculateInitialWeather()
2786 {
2787 provider.calculateInitialWeather();
2788 }
2789
2790 public void calculateInitialWeatherBody()
2791 {
2792 if (this.worldInfo.isRaining())
2793 {
2794 this.rainingStrength = 1.0F;
2795
2796 if (this.worldInfo.isThundering())
2797 {
2798 this.thunderingStrength = 1.0F;
2799 }
2800 }
2801 }
2802
2803 /**
2804 * Updates all weather states.
2805 */
2806 protected void updateWeather()
2807 {
2808 provider.updateWeather();
2809 }
2810
2811 public void updateWeatherBody()
2812 {
2813 if (!this.provider.hasNoSky)
2814 {
2815 if (this.lastLightningBolt > 0)
2816 {
2817 --this.lastLightningBolt;
2818 }
2819
2820 int var1 = this.worldInfo.getThunderTime();
2821
2822 if (var1 <= 0)
2823 {
2824 if (this.worldInfo.isThundering())
2825 {
2826 this.worldInfo.setThunderTime(this.rand.nextInt(12000) + 3600);
2827 }
2828 else
2829 {
2830 this.worldInfo.setThunderTime(this.rand.nextInt(168000) + 12000);
2831 }
2832 }
2833 else
2834 {
2835 --var1;
2836 this.worldInfo.setThunderTime(var1);
2837
2838 if (var1 <= 0)
2839 {
2840 this.worldInfo.setThundering(!this.worldInfo.isThundering());
2841 }
2842 }
2843
2844 int var2 = this.worldInfo.getRainTime();
2845
2846 if (var2 <= 0)
2847 {
2848 if (this.worldInfo.isRaining())
2849 {
2850 this.worldInfo.setRainTime(this.rand.nextInt(12000) + 12000);
2851 }
2852 else
2853 {
2854 this.worldInfo.setRainTime(this.rand.nextInt(168000) + 12000);
2855 }
2856 }
2857 else
2858 {
2859 --var2;
2860 this.worldInfo.setRainTime(var2);
2861
2862 if (var2 <= 0)
2863 {
2864 this.worldInfo.setRaining(!this.worldInfo.isRaining());
2865 }
2866 }
2867
2868 this.prevRainingStrength = this.rainingStrength;
2869
2870 if (this.worldInfo.isRaining())
2871 {
2872 this.rainingStrength = (float)((double)this.rainingStrength + 0.01D);
2873 }
2874 else
2875 {
2876 this.rainingStrength = (float)((double)this.rainingStrength - 0.01D);
2877 }
2878
2879 if (this.rainingStrength < 0.0F)
2880 {
2881 this.rainingStrength = 0.0F;
2882 }
2883
2884 if (this.rainingStrength > 1.0F)
2885 {
2886 this.rainingStrength = 1.0F;
2887 }
2888
2889 this.prevThunderingStrength = this.thunderingStrength;
2890
2891 if (this.worldInfo.isThundering())
2892 {
2893 this.thunderingStrength = (float)((double)this.thunderingStrength + 0.01D);
2894 }
2895 else
2896 {
2897 this.thunderingStrength = (float)((double)this.thunderingStrength - 0.01D);
2898 }
2899
2900 if (this.thunderingStrength < 0.0F)
2901 {
2902 this.thunderingStrength = 0.0F;
2903 }
2904
2905 if (this.thunderingStrength > 1.0F)
2906 {
2907 this.thunderingStrength = 1.0F;
2908 }
2909 }
2910 }
2911
2912 public void toggleRain()
2913 {
2914 provider.toggleRain();
2915 }
2916
2917 protected void setActivePlayerChunksAndCheckLight()
2918 {
2919 this.activeChunkSet.clear();
2920 this.activeChunkSet.addAll(getPersistentChunks().keySet());
2921
2922 this.theProfiler.startSection("buildList");
2923 int var1;
2924 EntityPlayer var2;
2925 int var3;
2926 int var4;
2927
2928 for (var1 = 0; var1 < this.playerEntities.size(); ++var1)
2929 {
2930 var2 = (EntityPlayer)this.playerEntities.get(var1);
2931 var3 = MathHelper.floor_double(var2.posX / 16.0D);
2932 var4 = MathHelper.floor_double(var2.posZ / 16.0D);
2933 byte var5 = 7;
2934
2935 for (int var6 = -var5; var6 <= var5; ++var6)
2936 {
2937 for (int var7 = -var5; var7 <= var5; ++var7)
2938 {
2939 this.activeChunkSet.add(new ChunkCoordIntPair(var6 + var3, var7 + var4));
2940 }
2941 }
2942 }
2943
2944 this.theProfiler.endSection();
2945
2946 if (this.ambientTickCountdown > 0)
2947 {
2948 --this.ambientTickCountdown;
2949 }
2950
2951 this.theProfiler.startSection("playerCheckLight");
2952
2953 if (!this.playerEntities.isEmpty())
2954 {
2955 var1 = this.rand.nextInt(this.playerEntities.size());
2956 var2 = (EntityPlayer)this.playerEntities.get(var1);
2957 var3 = MathHelper.floor_double(var2.posX) + this.rand.nextInt(11) - 5;
2958 var4 = MathHelper.floor_double(var2.posY) + this.rand.nextInt(11) - 5;
2959 int var8 = MathHelper.floor_double(var2.posZ) + this.rand.nextInt(11) - 5;
2960 this.updateAllLightTypes(var3, var4, var8);
2961 }
2962
2963 this.theProfiler.endSection();
2964 }
2965
2966 protected void moodSoundAndLightCheck(int par1, int par2, Chunk par3Chunk)
2967 {
2968 this.theProfiler.endStartSection("moodSound");
2969
2970 if (this.ambientTickCountdown == 0 && !this.isRemote)
2971 {
2972 this.updateLCG = this.updateLCG * 3 + 1013904223;
2973 int var4 = this.updateLCG >> 2;
2974 int var5 = var4 & 15;
2975 int var6 = var4 >> 8 & 15;
2976 int var7 = var4 >> 16 & 127;
2977 int var8 = par3Chunk.getBlockID(var5, var7, var6);
2978 var5 += par1;
2979 var6 += par2;
2980
2981 if (var8 == 0 && this.getFullBlockLightValue(var5, var7, var6) <= this.rand.nextInt(8) && this.getSavedLightValue(EnumSkyBlock.Sky, var5, var7, var6) <= 0)
2982 {
2983 EntityPlayer var9 = this.getClosestPlayer((double)var5 + 0.5D, (double)var7 + 0.5D, (double)var6 + 0.5D, 8.0D);
2984
2985 if (var9 != null && var9.getDistanceSq((double)var5 + 0.5D, (double)var7 + 0.5D, (double)var6 + 0.5D) > 4.0D)
2986 {
2987 this.playSoundEffect((double)var5 + 0.5D, (double)var7 + 0.5D, (double)var6 + 0.5D, "ambient.cave.cave", 0.7F, 0.8F + this.rand.nextFloat() * 0.2F);
2988 this.ambientTickCountdown = this.rand.nextInt(12000) + 6000;
2989 }
2990 }
2991 }
2992
2993 this.theProfiler.endStartSection("checkLight");
2994 par3Chunk.enqueueRelightChecks();
2995 }
2996
2997 /**
2998 * plays random cave ambient sounds and runs updateTick on random blocks within each chunk in the vacinity of a
2999 * player
3000 */
3001 protected void tickBlocksAndAmbiance()
3002 {
3003 this.setActivePlayerChunksAndCheckLight();
3004 }
3005
3006 /**
3007 * checks to see if a given block is both water and is cold enough to freeze
3008 */
3009 public boolean isBlockFreezable(int par1, int par2, int par3)
3010 {
3011 return this.canBlockFreeze(par1, par2, par3, false);
3012 }
3013
3014 /**
3015 * checks to see if a given block is both water and has at least one immediately adjacent non-water block
3016 */
3017 public boolean isBlockFreezableNaturally(int par1, int par2, int par3)
3018 {
3019 return this.canBlockFreeze(par1, par2, par3, true);
3020 }
3021
3022 /**
3023 * checks to see if a given block is both water, and cold enough to freeze - if the par4 boolean is set, this will
3024 * only return true if there is a non-water block immediately adjacent to the specified block
3025 */
3026 public boolean canBlockFreeze(int par1, int par2, int par3, boolean par4)
3027 {
3028 return provider.canBlockFreeze(par1, par2, par3, par4);
3029 }
3030
3031 public boolean canBlockFreezeBody(int par1, int par2, int par3, boolean par4)
3032 {
3033 BiomeGenBase var5 = this.getBiomeGenForCoords(par1, par3);
3034 float var6 = var5.getFloatTemperature();
3035
3036 if (var6 > 0.15F)
3037 {
3038 return false;
3039 }
3040 else
3041 {
3042 if (par2 >= 0 && par2 < 256 && this.getSavedLightValue(EnumSkyBlock.Block, par1, par2, par3) < 10)
3043 {
3044 int var7 = this.getBlockId(par1, par2, par3);
3045
3046 if ((var7 == Block.waterStill.blockID || var7 == Block.waterMoving.blockID) && this.getBlockMetadata(par1, par2, par3) == 0)
3047 {
3048 if (!par4)
3049 {
3050 return true;
3051 }
3052
3053 boolean var8 = true;
3054
3055 if (var8 && this.getBlockMaterial(par1 - 1, par2, par3) != Material.water)
3056 {
3057 var8 = false;
3058 }
3059
3060 if (var8 && this.getBlockMaterial(par1 + 1, par2, par3) != Material.water)
3061 {
3062 var8 = false;
3063 }
3064
3065 if (var8 && this.getBlockMaterial(par1, par2, par3 - 1) != Material.water)
3066 {
3067 var8 = false;
3068 }
3069
3070 if (var8 && this.getBlockMaterial(par1, par2, par3 + 1) != Material.water)
3071 {
3072 var8 = false;
3073 }
3074
3075 if (!var8)
3076 {
3077 return true;
3078 }
3079 }
3080 }
3081
3082 return false;
3083 }
3084 }
3085
3086 /**
3087 * Tests whether or not snow can be placed at a given location
3088 */
3089 public boolean canSnowAt(int par1, int par2, int par3)
3090 {
3091 return provider.canSnowAt(par1, par2, par3);
3092 }
3093
3094 public boolean canSnowAtBody(int par1, int par2, int par3)
3095 {
3096 BiomeGenBase var4 = this.getBiomeGenForCoords(par1, par3);
3097 float var5 = var4.getFloatTemperature();
3098
3099 if (var5 > 0.15F)
3100 {
3101 return false;
3102 }
3103 else
3104 {
3105 if (par2 >= 0 && par2 < 256 && this.getSavedLightValue(EnumSkyBlock.Block, par1, par2, par3) < 10)
3106 {
3107 int var6 = this.getBlockId(par1, par2 - 1, par3);
3108 int var7 = this.getBlockId(par1, par2, par3);
3109
3110 if (var7 == 0 && Block.snow.canPlaceBlockAt(this, par1, par2, par3) && var6 != 0 && var6 != Block.ice.blockID && Block.blocksList[var6].blockMaterial.blocksMovement())
3111 {
3112 return true;
3113 }
3114 }
3115
3116 return false;
3117 }
3118 }
3119
3120 public void updateAllLightTypes(int par1, int par2, int par3)
3121 {
3122 if (!this.provider.hasNoSky)
3123 {
3124 this.updateLightByType(EnumSkyBlock.Sky, par1, par2, par3);
3125 }
3126
3127 this.updateLightByType(EnumSkyBlock.Block, par1, par2, par3);
3128 }
3129
3130 private int computeSkyLightValue(int par1, int par2, int par3, int par4, int par5, int par6)
3131 {
3132 int var7 = 0;
3133
3134 if (this.canBlockSeeTheSky(par2, par3, par4))
3135 {
3136 var7 = 15;
3137 }
3138 else
3139 {
3140 if (par6 == 0)
3141 {
3142 par6 = 1;
3143 }
3144
3145 int var8 = this.getSavedLightValue(EnumSkyBlock.Sky, par2 - 1, par3, par4) - par6;
3146 int var9 = this.getSavedLightValue(EnumSkyBlock.Sky, par2 + 1, par3, par4) - par6;
3147 int var10 = this.getSavedLightValue(EnumSkyBlock.Sky, par2, par3 - 1, par4) - par6;
3148 int var11 = this.getSavedLightValue(EnumSkyBlock.Sky, par2, par3 + 1, par4) - par6;
3149 int var12 = this.getSavedLightValue(EnumSkyBlock.Sky, par2, par3, par4 - 1) - par6;
3150 int var13 = this.getSavedLightValue(EnumSkyBlock.Sky, par2, par3, par4 + 1) - par6;
3151
3152 if (var8 > var7)
3153 {
3154 var7 = var8;
3155 }
3156
3157 if (var9 > var7)
3158 {
3159 var7 = var9;
3160 }
3161
3162 if (var10 > var7)
3163 {
3164 var7 = var10;
3165 }
3166
3167 if (var11 > var7)
3168 {
3169 var7 = var11;
3170 }
3171
3172 if (var12 > var7)
3173 {
3174 var7 = var12;
3175 }
3176
3177 if (var13 > var7)
3178 {
3179 var7 = var13;
3180 }
3181 }
3182
3183 return var7;
3184 }
3185
3186 private int computeBlockLightValue(int par1, int par2, int par3, int par4, int par5, int par6)
3187 {
3188 int var7 = (par5 == 0 || Block.blocksList[par5] == null ? 0 : Block.blocksList[par5].getLightValue(this, par2, par3, par4));
3189 int var8 = this.getSavedLightValue(EnumSkyBlock.Block, par2 - 1, par3, par4) - par6;
3190 int var9 = this.getSavedLightValue(EnumSkyBlock.Block, par2 + 1, par3, par4) - par6;
3191 int var10 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3 - 1, par4) - par6;
3192 int var11 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3 + 1, par4) - par6;
3193 int var12 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3, par4 - 1) - par6;
3194 int var13 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3, par4 + 1) - par6;
3195
3196 if (var8 > var7)
3197 {
3198 var7 = var8;
3199 }
3200
3201 if (var9 > var7)
3202 {
3203 var7 = var9;
3204 }
3205
3206 if (var10 > var7)
3207 {
3208 var7 = var10;
3209 }
3210
3211 if (var11 > var7)
3212 {
3213 var7 = var11;
3214 }
3215
3216 if (var12 > var7)
3217 {
3218 var7 = var12;
3219 }
3220
3221 if (var13 > var7)
3222 {
3223 var7 = var13;
3224 }
3225
3226 return var7;
3227 }
3228
3229 public void updateLightByType(EnumSkyBlock par1EnumSkyBlock, int par2, int par3, int par4)
3230 {
3231 if (this.doChunksNearChunkExist(par2, par3, par4, 17))
3232 {
3233 int var5 = 0;
3234 int var6 = 0;
3235 this.theProfiler.startSection("getBrightness");
3236 int var7 = this.getSavedLightValue(par1EnumSkyBlock, par2, par3, par4);
3237 boolean var8 = false;
3238 int var9 = this.getBlockId(par2, par3, par4);
3239 int var10 = this.getBlockLightOpacity(par2, par3, par4);
3240
3241 if (var10 == 0)
3242 {
3243 var10 = 1;
3244 }
3245
3246 boolean var11 = false;
3247 int var24;
3248
3249 if (par1EnumSkyBlock == EnumSkyBlock.Sky)
3250 {
3251 var24 = this.computeSkyLightValue(var7, par2, par3, par4, var9, var10);
3252 }
3253 else
3254 {
3255 var24 = this.computeBlockLightValue(var7, par2, par3, par4, var9, var10);
3256 }
3257
3258 int var12;
3259 int var13;
3260 int var14;
3261 int var15;
3262 int var17;
3263 int var16;
3264 int var19;
3265 int var18;
3266
3267 if (var24 > var7)
3268 {
3269 this.lightUpdateBlockList[var6++] = 133152;
3270 }
3271 else if (var24 < var7)
3272 {
3273 if (par1EnumSkyBlock != EnumSkyBlock.Block)
3274 {
3275 ;
3276 }
3277
3278 this.lightUpdateBlockList[var6++] = 133152 + (var7 << 18);
3279
3280 while (var5 < var6)
3281 {
3282 var9 = this.lightUpdateBlockList[var5++];
3283 var10 = (var9 & 63) - 32 + par2;
3284 var24 = (var9 >> 6 & 63) - 32 + par3;
3285 var12 = (var9 >> 12 & 63) - 32 + par4;
3286 var13 = var9 >> 18 & 15;
3287 var14 = this.getSavedLightValue(par1EnumSkyBlock, var10, var24, var12);
3288
3289 if (var14 == var13)
3290 {
3291 this.setLightValue(par1EnumSkyBlock, var10, var24, var12, 0);
3292
3293 if (var13 > 0)
3294 {
3295 var15 = var10 - par2;
3296 var16 = var24 - par3;
3297 var17 = var12 - par4;
3298
3299 if (var15 < 0)
3300 {
3301 var15 = -var15;
3302 }
3303
3304 if (var16 < 0)
3305 {
3306 var16 = -var16;
3307 }
3308
3309 if (var17 < 0)
3310 {
3311 var17 = -var17;
3312 }
3313
3314 if (var15 + var16 + var17 < 17)
3315 {
3316 for (var18 = 0; var18 < 6; ++var18)
3317 {
3318 var19 = var18 % 2 * 2 - 1;
3319 int var20 = var10 + var18 / 2 % 3 / 2 * var19;
3320 int var21 = var24 + (var18 / 2 + 1) % 3 / 2 * var19;
3321 int var22 = var12 + (var18 / 2 + 2) % 3 / 2 * var19;
3322 var14 = this.getSavedLightValue(par1EnumSkyBlock, var20, var21, var22);
3323 int var23 = this.getBlockLightOpacity(var20, var21, var22);
3324
3325 if (var23 == 0)
3326 {
3327 var23 = 1;
3328 }
3329
3330 if (var14 == var13 - var23 && var6 < this.lightUpdateBlockList.length)
3331 {
3332 this.lightUpdateBlockList[var6++] = var20 - par2 + 32 + (var21 - par3 + 32 << 6) + (var22 - par4 + 32 << 12) + (var13 - var23 << 18);
3333 }
3334 }
3335 }
3336 }
3337 }
3338 }
3339
3340 var5 = 0;
3341 }
3342
3343 this.theProfiler.endSection();
3344 this.theProfiler.startSection("checkedPosition < toCheckCount");
3345
3346 while (var5 < var6)
3347 {
3348 var9 = this.lightUpdateBlockList[var5++];
3349 var10 = (var9 & 63) - 32 + par2;
3350 var24 = (var9 >> 6 & 63) - 32 + par3;
3351 var12 = (var9 >> 12 & 63) - 32 + par4;
3352 var13 = this.getSavedLightValue(par1EnumSkyBlock, var10, var24, var12);
3353 var14 = this.getBlockId(var10, var24, var12);
3354 var15 = this.getBlockLightOpacity(var10, var24, var12);
3355
3356 if (var15 == 0)
3357 {
3358 var15 = 1;
3359 }
3360
3361 boolean var25 = false;
3362
3363 if (par1EnumSkyBlock == EnumSkyBlock.Sky)
3364 {
3365 var16 = this.computeSkyLightValue(var13, var10, var24, var12, var14, var15);
3366 }
3367 else
3368 {
3369 var16 = this.computeBlockLightValue(var13, var10, var24, var12, var14, var15);
3370 }
3371
3372 if (var16 != var13)
3373 {
3374 this.setLightValue(par1EnumSkyBlock, var10, var24, var12, var16);
3375
3376 if (var16 > var13)
3377 {
3378 var17 = var10 - par2;
3379 var18 = var24 - par3;
3380 var19 = var12 - par4;
3381
3382 if (var17 < 0)
3383 {
3384 var17 = -var17;
3385 }
3386
3387 if (var18 < 0)
3388 {
3389 var18 = -var18;
3390 }
3391
3392 if (var19 < 0)
3393 {
3394 var19 = -var19;
3395 }
3396
3397 if (var17 + var18 + var19 < 17 && var6 < this.lightUpdateBlockList.length - 6)
3398 {
3399 if (this.getSavedLightValue(par1EnumSkyBlock, var10 - 1, var24, var12) < var16)
3400 {
3401 this.lightUpdateBlockList[var6++] = var10 - 1 - par2 + 32 + (var24 - par3 + 32 << 6) + (var12 - par4 + 32 << 12);
3402 }
3403
3404 if (this.getSavedLightValue(par1EnumSkyBlock, var10 + 1, var24, var12) < var16)
3405 {
3406 this.lightUpdateBlockList[var6++] = var10 + 1 - par2 + 32 + (var24 - par3 + 32 << 6) + (var12 - par4 + 32 << 12);
3407 }
3408
3409 if (this.getSavedLightValue(par1EnumSkyBlock, var10, var24 - 1, var12) < var16)
3410 {
3411 this.lightUpdateBlockList[var6++] = var10 - par2 + 32 + (var24 - 1 - par3 + 32 << 6) + (var12 - par4 + 32 << 12);
3412 }
3413
3414 if (this.getSavedLightValue(par1EnumSkyBlock, var10, var24 + 1, var12) < var16)
3415 {
3416 this.lightUpdateBlockList[var6++] = var10 - par2 + 32 + (var24 + 1 - par3 + 32 << 6) + (var12 - par4 + 32 << 12);
3417 }
3418
3419 if (this.getSavedLightValue(par1EnumSkyBlock, var10, var24, var12 - 1) < var16)
3420 {
3421 this.lightUpdateBlockList[var6++] = var10 - par2 + 32 + (var24 - par3 + 32 << 6) + (var12 - 1 - par4 + 32 << 12);
3422 }
3423
3424 if (this.getSavedLightValue(par1EnumSkyBlock, var10, var24, var12 + 1) < var16)
3425 {
3426 this.lightUpdateBlockList[var6++] = var10 - par2 + 32 + (var24 - par3 + 32 << 6) + (var12 + 1 - par4 + 32 << 12);
3427 }
3428 }
3429 }
3430 }
3431 }
3432
3433 this.theProfiler.endSection();
3434 }
3435 }
3436
3437 /**
3438 * Runs through the list of updates to run and ticks them
3439 */
3440 public boolean tickUpdates(boolean par1)
3441 {
3442 return false;
3443 }
3444
3445 public List getPendingBlockUpdates(Chunk par1Chunk, boolean par2)
3446 {
3447 return null;
3448 }
3449
3450 /**
3451 * Will get all entities within the specified AABB excluding the one passed into it. Args: entityToExclude, aabb
3452 */
3453 public List getEntitiesWithinAABBExcludingEntity(Entity par1Entity, AxisAlignedBB par2AxisAlignedBB)
3454 {
3455 this.entitiesWithinAABBExcludingEntity.clear();
3456 int var3 = MathHelper.floor_double((par2AxisAlignedBB.minX - MAX_ENTITY_RADIUS) / 16.0D);
3457 int var4 = MathHelper.floor_double((par2AxisAlignedBB.maxX + MAX_ENTITY_RADIUS) / 16.0D);
3458 int var5 = MathHelper.floor_double((par2AxisAlignedBB.minZ - MAX_ENTITY_RADIUS) / 16.0D);
3459 int var6 = MathHelper.floor_double((par2AxisAlignedBB.maxZ + MAX_ENTITY_RADIUS) / 16.0D);
3460
3461 for (int var7 = var3; var7 <= var4; ++var7)
3462 {
3463 for (int var8 = var5; var8 <= var6; ++var8)
3464 {
3465 if (this.chunkExists(var7, var8))
3466 {
3467 this.getChunkFromChunkCoords(var7, var8).getEntitiesWithinAABBForEntity(par1Entity, par2AxisAlignedBB, this.entitiesWithinAABBExcludingEntity);
3468 }
3469 }
3470 }
3471
3472 return this.entitiesWithinAABBExcludingEntity;
3473 }
3474
3475 /**
3476 * Returns all entities of the specified class type which intersect with the AABB. Args: entityClass, aabb
3477 */
3478 public List getEntitiesWithinAABB(Class par1Class, AxisAlignedBB par2AxisAlignedBB)
3479 {
3480 return this.func_82733_a(par1Class, par2AxisAlignedBB, (IEntitySelector)null);
3481 }
3482
3483 public List func_82733_a(Class par1Class, AxisAlignedBB par2AxisAlignedBB, IEntitySelector par3IEntitySelector)
3484 {
3485 int var4 = MathHelper.floor_double((par2AxisAlignedBB.minX - MAX_ENTITY_RADIUS) / 16.0D);
3486 int var5 = MathHelper.floor_double((par2AxisAlignedBB.maxX + MAX_ENTITY_RADIUS) / 16.0D);
3487 int var6 = MathHelper.floor_double((par2AxisAlignedBB.minZ - MAX_ENTITY_RADIUS) / 16.0D);
3488 int var7 = MathHelper.floor_double((par2AxisAlignedBB.maxZ + MAX_ENTITY_RADIUS) / 16.0D);
3489 ArrayList var8 = new ArrayList();
3490
3491 for (int var9 = var4; var9 <= var5; ++var9)
3492 {
3493 for (int var10 = var6; var10 <= var7; ++var10)
3494 {
3495 if (this.chunkExists(var9, var10))
3496 {
3497 this.getChunkFromChunkCoords(var9, var10).getEntitiesOfTypeWithinAAAB(par1Class, par2AxisAlignedBB, var8, par3IEntitySelector);
3498 }
3499 }
3500 }
3501
3502 return var8;
3503 }
3504
3505 public Entity findNearestEntityWithinAABB(Class par1Class, AxisAlignedBB par2AxisAlignedBB, Entity par3Entity)
3506 {
3507 List var4 = this.getEntitiesWithinAABB(par1Class, par2AxisAlignedBB);
3508 Entity var5 = null;
3509 double var6 = Double.MAX_VALUE;
3510 Iterator var8 = var4.iterator();
3511
3512 while (var8.hasNext())
3513 {
3514 Entity var9 = (Entity)var8.next();
3515
3516 if (var9 != par3Entity)
3517 {
3518 double var10 = par3Entity.getDistanceSqToEntity(var9);
3519
3520 if (var10 <= var6)
3521 {
3522 var5 = var9;
3523 var6 = var10;
3524 }
3525 }
3526 }
3527
3528 return var5;
3529 }
3530
3531 /**
3532 * Returns the Entity with the given ID, or null if it doesn't exist in this World.
3533 */
3534 public abstract Entity getEntityByID(int var1);
3535
3536 @SideOnly(Side.CLIENT)
3537
3538 /**
3539 * Accessor for world Loaded Entity List
3540 */
3541 public List getLoadedEntityList()
3542 {
3543 return this.loadedEntityList;
3544 }
3545
3546 /**
3547 * marks the chunk that contains this tilentity as modified and then calls worldAccesses.doNothingWithTileEntity
3548 */
3549 public void updateTileEntityChunkAndDoNothing(int par1, int par2, int par3, TileEntity par4TileEntity)
3550 {
3551 if (this.blockExists(par1, par2, par3))
3552 {
3553 this.getChunkFromBlockCoords(par1, par3).setChunkModified();
3554 }
3555 }
3556
3557 /**
3558 * Counts how many entities of an entity class exist in the world. Args: entityClass
3559 */
3560 public int countEntities(Class par1Class)
3561 {
3562 int var2 = 0;
3563
3564 for (int var3 = 0; var3 < this.loadedEntityList.size(); ++var3)
3565 {
3566 Entity var4 = (Entity)this.loadedEntityList.get(var3);
3567
3568 if (par1Class.isAssignableFrom(var4.getClass()))
3569 {
3570 ++var2;
3571 }
3572 }
3573
3574 return var2;
3575 }
3576
3577 /**
3578 * adds entities to the loaded entities list, and loads thier skins.
3579 */
3580 public void addLoadedEntities(List par1List)
3581 {
3582 for (int var2 = 0; var2 < par1List.size(); ++var2)
3583 {
3584 Entity entity = (Entity)par1List.get(var2);
3585 if (!MinecraftForge.EVENT_BUS.post(new EntityJoinWorldEvent(entity, this)))
3586 {
3587 loadedEntityList.add(entity);
3588 this.obtainEntitySkin(entity);
3589 }
3590 }
3591 }
3592
3593 /**
3594 * Adds a list of entities to be unloaded on the next pass of World.updateEntities()
3595 */
3596 public void unloadEntities(List par1List)
3597 {
3598 this.unloadedEntityList.addAll(par1List);
3599 }
3600
3601 /**
3602 * Returns true if the given Entity can be placed on the given side of the given block position.
3603 */
3604 public boolean canPlaceEntityOnSide(int par1, int par2, int par3, int par4, boolean par5, int par6, Entity par7Entity)
3605 {
3606 int var8 = this.getBlockId(par2, par3, par4);
3607 Block var9 = Block.blocksList[var8];
3608 Block var10 = Block.blocksList[par1];
3609 AxisAlignedBB var11 = var10.getCollisionBoundingBoxFromPool(this, par2, par3, par4);
3610
3611 if (par5)
3612 {
3613 var11 = null;
3614 }
3615
3616 if (var11 != null && !this.checkIfAABBIsClearExcludingEntity(var11, par7Entity))
3617 {
3618 return false;
3619 }
3620 else
3621 {
3622 if (var9 != null && (var9 == Block.waterMoving || var9 == Block.waterStill || var9 == Block.lavaMoving || var9 == Block.lavaStill || var9 == Block.fire || var9.blockMaterial.isGroundCover()))
3623 {
3624 var9 = null;
3625 }
3626
3627 if (var9 != null && var9.isBlockReplaceable(this, par2, par3, par4))
3628 {
3629 var9 = null;
3630 }
3631
3632 return var9 != null && var9.blockMaterial == Material.circuits && var10 == Block.field_82510_ck ? true : par1 > 0 && var9 == null && var10.canPlaceBlockOnSide(this, par2, par3, par4, par6);
3633 }
3634 }
3635
3636 public PathEntity getPathEntityToEntity(Entity par1Entity, Entity par2Entity, float par3, boolean par4, boolean par5, boolean par6, boolean par7)
3637 {
3638 this.theProfiler.startSection("pathfind");
3639 int var8 = MathHelper.floor_double(par1Entity.posX);
3640 int var9 = MathHelper.floor_double(par1Entity.posY + 1.0D);
3641 int var10 = MathHelper.floor_double(par1Entity.posZ);
3642 int var11 = (int)(par3 + 16.0F);
3643 int var12 = var8 - var11;
3644 int var13 = var9 - var11;
3645 int var14 = var10 - var11;
3646 int var15 = var8 + var11;
3647 int var16 = var9 + var11;
3648 int var17 = var10 + var11;
3649 ChunkCache var18 = new ChunkCache(this, var12, var13, var14, var15, var16, var17);
3650 PathEntity var19 = (new PathFinder(var18, par4, par5, par6, par7)).createEntityPathTo(par1Entity, par2Entity, par3);
3651 this.theProfiler.endSection();
3652 return var19;
3653 }
3654
3655 public PathEntity getEntityPathToXYZ(Entity par1Entity, int par2, int par3, int par4, float par5, boolean par6, boolean par7, boolean par8, boolean par9)
3656 {
3657 this.theProfiler.startSection("pathfind");
3658 int var10 = MathHelper.floor_double(par1Entity.posX);
3659 int var11 = MathHelper.floor_double(par1Entity.posY);
3660 int var12 = MathHelper.floor_double(par1Entity.posZ);
3661 int var13 = (int)(par5 + 8.0F);
3662 int var14 = var10 - var13;
3663 int var15 = var11 - var13;
3664 int var16 = var12 - var13;
3665 int var17 = var10 + var13;
3666 int var18 = var11 + var13;
3667 int var19 = var12 + var13;
3668 ChunkCache var20 = new ChunkCache(this, var14, var15, var16, var17, var18, var19);
3669 PathEntity var21 = (new PathFinder(var20, par6, par7, par8, par9)).createEntityPathTo(par1Entity, par2, par3, par4, par5);
3670 this.theProfiler.endSection();
3671 return var21;
3672 }
3673
3674 /**
3675 * Is this block powering in the specified direction Args: x, y, z, direction
3676 */
3677 public boolean isBlockProvidingPowerTo(int par1, int par2, int par3, int par4)
3678 {
3679 int var5 = this.getBlockId(par1, par2, par3);
3680 return var5 == 0 ? false : Block.blocksList[var5].isIndirectlyPoweringTo(this, par1, par2, par3, par4);
3681 }
3682
3683 /**
3684 * Whether one of the neighboring blocks is putting power into this block. Args: x, y, z
3685 */
3686 public boolean isBlockGettingPowered(int par1, int par2, int par3)
3687 {
3688 return this.isBlockProvidingPowerTo(par1, par2 - 1, par3, 0) ? true : (this.isBlockProvidingPowerTo(par1, par2 + 1, par3, 1) ? true : (this.isBlockProvidingPowerTo(par1, par2, par3 - 1, 2) ? true : (this.isBlockProvidingPowerTo(par1, par2, par3 + 1, 3) ? true : (this.isBlockProvidingPowerTo(par1 - 1, par2, par3, 4) ? true : this.isBlockProvidingPowerTo(par1 + 1, par2, par3, 5)))));
3689 }
3690
3691 /**
3692 * Is a block next to you getting powered (if its an attachable block) or is it providing power directly to you.
3693 * Args: x, y, z, direction
3694 */
3695 public boolean isBlockIndirectlyProvidingPowerTo(int par1, int par2, int par3, int par4)
3696 {
3697 if (this.isBlockNormalCube(par1, par2, par3))
3698 {
3699 return this.isBlockGettingPowered(par1, par2, par3);
3700 }
3701 else
3702 {
3703 int var5 = this.getBlockId(par1, par2, par3);
3704 return var5 == 0 ? false : Block.blocksList[var5].isPoweringTo(this, par1, par2, par3, par4);
3705 }
3706 }
3707
3708 /**
3709 * Used to see if one of the blocks next to you or your block is getting power from a neighboring block. Used by
3710 * items like TNT or Doors so they don't have redstone going straight into them. Args: x, y, z
3711 */
3712 public boolean isBlockIndirectlyGettingPowered(int par1, int par2, int par3)
3713 {
3714 return this.isBlockIndirectlyProvidingPowerTo(par1, par2 - 1, par3, 0) ? true : (this.isBlockIndirectlyProvidingPowerTo(par1, par2 + 1, par3, 1) ? true : (this.isBlockIndirectlyProvidingPowerTo(par1, par2, par3 - 1, 2) ? true : (this.isBlockIndirectlyProvidingPowerTo(par1, par2, par3 + 1, 3) ? true : (this.isBlockIndirectlyProvidingPowerTo(par1 - 1, par2, par3, 4) ? true : this.isBlockIndirectlyProvidingPowerTo(par1 + 1, par2, par3, 5)))));
3715 }
3716
3717 /**
3718 * Gets the closest player to the entity within the specified distance (if distance is less than 0 then ignored).
3719 * Args: entity, dist
3720 */
3721 public EntityPlayer getClosestPlayerToEntity(Entity par1Entity, double par2)
3722 {
3723 return this.getClosestPlayer(par1Entity.posX, par1Entity.posY, par1Entity.posZ, par2);
3724 }
3725
3726 /**
3727 * Gets the closest player to the point within the specified distance (distance can be set to less than 0 to not
3728 * limit the distance). Args: x, y, z, dist
3729 */
3730 public EntityPlayer getClosestPlayer(double par1, double par3, double par5, double par7)
3731 {
3732 double var9 = -1.0D;
3733 EntityPlayer var11 = null;
3734
3735 for (int var12 = 0; var12 < this.playerEntities.size(); ++var12)
3736 {
3737 EntityPlayer var13 = (EntityPlayer)this.playerEntities.get(var12);
3738 double var14 = var13.getDistanceSq(par1, par3, par5);
3739
3740 if ((par7 < 0.0D || var14 < par7 * par7) && (var9 == -1.0D || var14 < var9))
3741 {
3742 var9 = var14;
3743 var11 = var13;
3744 }
3745 }
3746
3747 return var11;
3748 }
3749
3750 /**
3751 * Returns the closest vulnerable player to this entity within the given radius, or null if none is found
3752 */
3753 public EntityPlayer getClosestVulnerablePlayerToEntity(Entity par1Entity, double par2)
3754 {
3755 return this.getClosestVulnerablePlayer(par1Entity.posX, par1Entity.posY, par1Entity.posZ, par2);
3756 }
3757
3758 /**
3759 * Returns the closest vulnerable player within the given radius, or null if none is found.
3760 */
3761 public EntityPlayer getClosestVulnerablePlayer(double par1, double par3, double par5, double par7)
3762 {
3763 double var9 = -1.0D;
3764 EntityPlayer var11 = null;
3765
3766 for (int var12 = 0; var12 < this.playerEntities.size(); ++var12)
3767 {
3768 EntityPlayer var13 = (EntityPlayer)this.playerEntities.get(var12);
3769
3770 if (!var13.capabilities.disableDamage)
3771 {
3772 double var14 = var13.getDistanceSq(par1, par3, par5);
3773 double var16 = par7;
3774
3775 if (var13.isSneaking())
3776 {
3777 var16 = par7 * 0.800000011920929D;
3778 }
3779
3780 if (var13.func_82150_aj())
3781 {
3782 float var18 = var13.func_82243_bO();
3783
3784 if (var18 < 0.1F)
3785 {
3786 var18 = 0.1F;
3787 }
3788
3789 var16 *= (double)(0.7F * var18);
3790 }
3791
3792 if ((par7 < 0.0D || var14 < var16 * var16) && (var9 == -1.0D || var14 < var9))
3793 {
3794 var9 = var14;
3795 var11 = var13;
3796 }
3797 }
3798 }
3799
3800 return var11;
3801 }
3802
3803 /**
3804 * Find a player by name in this world.
3805 */
3806 public EntityPlayer getPlayerEntityByName(String par1Str)
3807 {
3808 for (int var2 = 0; var2 < this.playerEntities.size(); ++var2)
3809 {
3810 if (par1Str.equals(((EntityPlayer)this.playerEntities.get(var2)).username))
3811 {
3812 return (EntityPlayer)this.playerEntities.get(var2);
3813 }
3814 }
3815
3816 return null;
3817 }
3818
3819 @SideOnly(Side.CLIENT)
3820
3821 /**
3822 * If on MP, sends a quitting packet.
3823 */
3824 public void sendQuittingDisconnectingPacket() {}
3825
3826 /**
3827 * Checks whether the session lock file was modified by another process
3828 */
3829 public void checkSessionLock() throws MinecraftException
3830 {
3831 this.saveHandler.checkSessionLock();
3832 }
3833
3834 @SideOnly(Side.CLIENT)
3835 public void func_82738_a(long par1)
3836 {
3837 this.worldInfo.func_82572_b(par1);
3838 }
3839
3840 /**
3841 * Retrieve the world seed from level.dat
3842 */
3843 public long getSeed()
3844 {
3845 return provider.getSeed();
3846 }
3847
3848 public long func_82737_E()
3849 {
3850 return this.worldInfo.func_82573_f();
3851 }
3852
3853 public long getWorldTime()
3854 {
3855 return provider.getWorldTime();
3856 }
3857
3858 /**
3859 * Sets the world time.
3860 */
3861 public void setWorldTime(long par1)
3862 {
3863 provider.setWorldTime(par1);
3864 }
3865
3866 /**
3867 * Returns the coordinates of the spawn point
3868 */
3869 public ChunkCoordinates getSpawnPoint()
3870 {
3871 return provider.getSpawnPoint();
3872 }
3873
3874 @SideOnly(Side.CLIENT)
3875 public void setSpawnLocation(int par1, int par2, int par3)
3876 {
3877 provider.setSpawnPoint(par1, par2, par3);
3878 }
3879
3880 @SideOnly(Side.CLIENT)
3881
3882 /**
3883 * spwans an entity and loads surrounding chunks
3884 */
3885 public void joinEntityInSurroundings(Entity par1Entity)
3886 {
3887 int var2 = MathHelper.floor_double(par1Entity.posX / 16.0D);
3888 int var3 = MathHelper.floor_double(par1Entity.posZ / 16.0D);
3889 byte var4 = 2;
3890
3891 for (int var5 = var2 - var4; var5 <= var2 + var4; ++var5)
3892 {
3893 for (int var6 = var3 - var4; var6 <= var3 + var4; ++var6)
3894 {
3895 this.getChunkFromChunkCoords(var5, var6);
3896 }
3897 }
3898
3899 if (!this.loadedEntityList.contains(par1Entity))
3900 {
3901 if (!MinecraftForge.EVENT_BUS.post(new EntityJoinWorldEvent(par1Entity, this)))
3902 {
3903 loadedEntityList.add(par1Entity);
3904 }
3905 }
3906 }
3907
3908 /**
3909 * Called when checking if a certain block can be mined or not. The 'spawn safe zone' check is located here.
3910 */
3911 public boolean canMineBlock(EntityPlayer par1EntityPlayer, int par2, int par3, int par4)
3912 {
3913 return provider.canMineBlock(par1EntityPlayer, par2, par3, par4);
3914 }
3915
3916 public boolean canMineBlockBody(EntityPlayer par1EntityPlayer, int par2, int par3, int par4)
3917 {
3918 return true;
3919 }
3920
3921 /**
3922 * sends a Packet 38 (Entity Status) to all tracked players of that entity
3923 */
3924 public void setEntityState(Entity par1Entity, byte par2) {}
3925
3926 /**
3927 * gets the IChunkProvider this world uses.
3928 */
3929 public IChunkProvider getChunkProvider()
3930 {
3931 return this.chunkProvider;
3932 }
3933
3934 /**
3935 * Adds a block event with the given Args to the blockEventCache. During the next tick(), the block specified will
3936 * have its onBlockEvent handler called with the given parameters. Args: X,Y,Z, BlockID, EventID, EventParameter
3937 */
3938 public void addBlockEvent(int par1, int par2, int par3, int par4, int par5, int par6)
3939 {
3940 if (par4 > 0)
3941 {
3942 Block.blocksList[par4].onBlockEventReceived(this, par1, par2, par3, par5, par6);
3943 }
3944 }
3945
3946 /**
3947 * Returns this world's current save handler
3948 */
3949 public ISaveHandler getSaveHandler()
3950 {
3951 return this.saveHandler;
3952 }
3953
3954 /**
3955 * Gets the World's WorldInfo instance
3956 */
3957 public WorldInfo getWorldInfo()
3958 {
3959 return this.worldInfo;
3960 }
3961
3962 public GameRules func_82736_K()
3963 {
3964 return this.worldInfo.func_82574_x();
3965 }
3966
3967 /**
3968 * Updates the flag that indicates whether or not all players in the world are sleeping.
3969 */
3970 public void updateAllPlayersSleepingFlag() {}
3971
3972 public float getWeightedThunderStrength(float par1)
3973 {
3974 return (this.prevThunderingStrength + (this.thunderingStrength - this.prevThunderingStrength) * par1) * this.getRainStrength(par1);
3975 }
3976
3977 /**
3978 * Not sure about this actually. Reverting this one myself.
3979 */
3980 public float getRainStrength(float par1)
3981 {
3982 return this.prevRainingStrength + (this.rainingStrength - this.prevRainingStrength) * par1;
3983 }
3984
3985 @SideOnly(Side.CLIENT)
3986 public void setRainStrength(float par1)
3987 {
3988 this.prevRainingStrength = par1;
3989 this.rainingStrength = par1;
3990 }
3991
3992 /**
3993 * Returns true if the current thunder strength (weighted with the rain strength) is greater than 0.9
3994 */
3995 public boolean isThundering()
3996 {
3997 return (double)this.getWeightedThunderStrength(1.0F) > 0.9D;
3998 }
3999
4000 /**
4001 * Returns true if the current rain strength is greater than 0.2
4002 */
4003 public boolean isRaining()
4004 {
4005 return (double)this.getRainStrength(1.0F) > 0.2D;
4006 }
4007
4008 public boolean canLightningStrikeAt(int par1, int par2, int par3)
4009 {
4010 if (!this.isRaining())
4011 {
4012 return false;
4013 }
4014 else if (!this.canBlockSeeTheSky(par1, par2, par3))
4015 {
4016 return false;
4017 }
4018 else if (this.getPrecipitationHeight(par1, par3) > par2)
4019 {
4020 return false;
4021 }
4022 else
4023 {
4024 BiomeGenBase var4 = this.getBiomeGenForCoords(par1, par3);
4025 return var4.getEnableSnow() ? false : var4.canSpawnLightningBolt();
4026 }
4027 }
4028
4029 /**
4030 * Checks to see if the biome rainfall values for a given x,y,z coordinate set are extremely high
4031 */
4032 public boolean isBlockHighHumidity(int par1, int par2, int par3)
4033 {
4034 return provider.isBlockHighHumidity(par1, par2, par3);
4035 }
4036
4037 /**
4038 * Assigns the given String id to the given MapDataBase using the MapStorage, removing any existing ones of the same
4039 * id.
4040 */
4041 public void setItemData(String par1Str, WorldSavedData par2WorldSavedData)
4042 {
4043 this.mapStorage.setData(par1Str, par2WorldSavedData);
4044 }
4045
4046 /**
4047 * Loads an existing MapDataBase corresponding to the given String id from disk using the MapStorage, instantiating
4048 * the given Class, or returns null if none such file exists. args: Class to instantiate, String dataid
4049 */
4050 public WorldSavedData loadItemData(Class par1Class, String par2Str)
4051 {
4052 return this.mapStorage.loadData(par1Class, par2Str);
4053 }
4054
4055 /**
4056 * Returns an unique new data id from the MapStorage for the given prefix and saves the idCounts map to the
4057 * 'idcounts' file.
4058 */
4059 public int getUniqueDataId(String par1Str)
4060 {
4061 return this.mapStorage.getUniqueDataId(par1Str);
4062 }
4063
4064 public void func_82739_e(int par1, int par2, int par3, int par4, int par5)
4065 {
4066 for (int var6 = 0; var6 < this.worldAccesses.size(); ++var6)
4067 {
4068 ((IWorldAccess)this.worldAccesses.get(var6)).func_82746_a(par1, par2, par3, par4, par5);
4069 }
4070 }
4071
4072 /**
4073 * See description for playAuxSFX.
4074 */
4075 public void playAuxSFX(int par1, int par2, int par3, int par4, int par5)
4076 {
4077 this.playAuxSFXAtEntity((EntityPlayer)null, par1, par2, par3, par4, par5);
4078 }
4079
4080 /**
4081 * See description for playAuxSFX.
4082 */
4083 public void playAuxSFXAtEntity(EntityPlayer par1EntityPlayer, int par2, int par3, int par4, int par5, int par6)
4084 {
4085 for (int var7 = 0; var7 < this.worldAccesses.size(); ++var7)
4086 {
4087 ((IWorldAccess)this.worldAccesses.get(var7)).playAuxSFX(par1EntityPlayer, par2, par3, par4, par5, par6);
4088 }
4089 }
4090
4091 /**
4092 * Returns current world height.
4093 */
4094 public int getHeight()
4095 {
4096 return provider.getHeight();
4097 }
4098
4099 /**
4100 * Returns current world height.
4101 */
4102 public int getActualHeight()
4103 {
4104 return provider.getActualHeight();
4105 }
4106
4107 public IUpdatePlayerListBox func_82735_a(EntityMinecart par1EntityMinecart)
4108 {
4109 return null;
4110 }
4111
4112 /**
4113 * puts the World Random seed to a specific state dependant on the inputs
4114 */
4115 public Random setRandomSeed(int par1, int par2, int par3)
4116 {
4117 long var4 = (long)par1 * 341873128712L + (long)par2 * 132897987541L + this.getWorldInfo().getSeed() + (long)par3;
4118 this.rand.setSeed(var4);
4119 return this.rand;
4120 }
4121
4122 /**
4123 * Returns the location of the closest structure of the specified type. If not found returns null.
4124 */
4125 public ChunkPosition findClosestStructure(String par1Str, int par2, int par3, int par4)
4126 {
4127 return this.getChunkProvider().findClosestStructure(this, par1Str, par2, par3, par4);
4128 }
4129
4130 @SideOnly(Side.CLIENT)
4131
4132 /**
4133 * set by !chunk.getAreLevelsEmpty
4134 */
4135 public boolean extendedLevelsInChunkCache()
4136 {
4137 return false;
4138 }
4139
4140 @SideOnly(Side.CLIENT)
4141
4142 /**
4143 * Returns horizon height for use in rendering the sky.
4144 */
4145 public double getHorizon()
4146 {
4147 return provider.getHorizon();
4148 }
4149
4150 /**
4151 * Adds some basic stats of the world to the given crash report.
4152 */
4153 public CrashReport addWorldInfoToCrashReport(CrashReport par1CrashReport)
4154 {
4155 par1CrashReport.addCrashSectionCallable("World " + this.worldInfo.getWorldName() + " Entities", new CallableLvl1(this));
4156 par1CrashReport.addCrashSectionCallable("World " + this.worldInfo.getWorldName() + " Players", new CallableLvl2(this));
4157 par1CrashReport.addCrashSectionCallable("World " + this.worldInfo.getWorldName() + " Chunk Stats", new CallableLvl3(this));
4158 return par1CrashReport;
4159 }
4160
4161 /**
4162 * Starts (or continues) destroying a block with given ID at the given coordinates for the given partially destroyed
4163 * value
4164 */
4165 public void destroyBlockInWorldPartially(int par1, int par2, int par3, int par4, int par5)
4166 {
4167 Iterator var6 = this.worldAccesses.iterator();
4168
4169 while (var6.hasNext())
4170 {
4171 IWorldAccess var7 = (IWorldAccess)var6.next();
4172 var7.destroyBlockPartially(par1, par2, par3, par4, par5);
4173 }
4174 }
4175
4176 public Vec3Pool func_82732_R()
4177 {
4178 return this.field_82741_K;
4179 }
4180
4181 /**
4182 * Adds a single TileEntity to the world.
4183 * @param entity The TileEntity to be added.
4184 */
4185 public void addTileEntity(TileEntity entity)
4186 {
4187 List dest = scanningTileEntities ? addedTileEntityList : loadedTileEntityList;
4188 if(entity.canUpdate())
4189 {
4190 dest.add(entity);
4191 }
4192 }
4193
4194 /**
4195 * Determine if the given block is considered solid on the
4196 * specified side. Used by placement logic.
4197 *
4198 * @param X Block X Position
4199 * @param Y Block Y Position
4200 * @param Z Block Z Position
4201 * @param side The Side in question
4202 * @return True if the side is solid
4203 */
4204 public boolean isBlockSolidOnSide(int X, int Y, int Z, ForgeDirection side)
4205 {
4206 return isBlockSolidOnSide(X, Y, Z, side, false);
4207 }
4208
4209 /**
4210 * Determine if the given block is considered solid on the
4211 * specified side. Used by placement logic.
4212 *
4213 * @param X Block X Position
4214 * @param Y Block Y Position
4215 * @param Z Block Z Position
4216 * @param side The Side in question
4217 * @param _default The defult to return if the block doesn't exist.
4218 * @return True if the side is solid
4219 */
4220 public boolean isBlockSolidOnSide(int X, int Y, int Z, ForgeDirection side, boolean _default)
4221 {
4222 if (X < -30000000 || Z < -30000000 || X >= 30000000 || Z >= 30000000)
4223 {
4224 return _default;
4225 }
4226
4227 Chunk var5 = this.chunkProvider.provideChunk(X >> 4, Z >> 4);
4228 if (var5 == null || var5.isEmpty())
4229 {
4230 return _default;
4231 }
4232
4233 Block block = Block.blocksList[getBlockId(X, Y, Z)];
4234 if(block == null)
4235 {
4236 return false;
4237 }
4238
4239 return block.isBlockSolidOnSide(this, X, Y, Z, side);
4240 }
4241
4242 /**
4243 * Get the persistent chunks for this world
4244 *
4245 * @return
4246 */
4247 SetMultimap<ChunkCoordIntPair, Ticket> getPersistentChunks()
4248 {
4249 return ForgeChunkManager.getPersistentChunksFor(this);
4250 }
4251 }