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