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        public void func_72902_n(int par1, int par2, int par3)
943        {
944            Iterator var4 = this.worldAccesses.iterator();
945    
946            while (var4.hasNext())
947            {
948                IWorldAccess var5 = (IWorldAccess)var4.next();
949                var5.markBlockNeedsUpdate2(par1, par2, par3);
950            }
951        }
952    
953        @SideOnly(Side.CLIENT)
954    
955        /**
956         * Any Light rendered on a 1.8 Block goes through here
957         */
958        public int getLightBrightnessForSkyBlocks(int par1, int par2, int par3, int par4)
959        {
960            int var5 = this.getSkyBlockTypeBrightness(EnumSkyBlock.Sky, par1, par2, par3);
961            int var6 = this.getSkyBlockTypeBrightness(EnumSkyBlock.Block, par1, par2, par3);
962    
963            if (var6 < par4)
964            {
965                var6 = par4;
966            }
967    
968            return var5 << 20 | var6 << 4;
969        }
970    
971        @SideOnly(Side.CLIENT)
972        public float getBrightness(int par1, int par2, int par3, int par4)
973        {
974            int var5 = this.getBlockLightValue(par1, par2, par3);
975    
976            if (var5 < par4)
977            {
978                var5 = par4;
979            }
980    
981            return this.provider.lightBrightnessTable[var5];
982        }
983    
984        /**
985         * Returns how bright the block is shown as which is the block's light value looked up in a lookup table (light
986         * values aren't linear for brightness). Args: x, y, z
987         */
988        public float getLightBrightness(int par1, int par2, int par3)
989        {
990            return this.provider.lightBrightnessTable[this.getBlockLightValue(par1, par2, par3)];
991        }
992    
993        /**
994         * Checks whether its daytime by seeing if the light subtracted from the skylight is less than 4
995         */
996        public boolean isDaytime()
997        {
998            return this.skylightSubtracted < 4;
999        }
1000    
1001        /**
1002         * ray traces all blocks, including non-collideable ones
1003         */
1004        public MovingObjectPosition rayTraceBlocks(Vec3 par1Vec3, Vec3 par2Vec3)
1005        {
1006            return this.rayTraceBlocks_do_do(par1Vec3, par2Vec3, false, false);
1007        }
1008    
1009        public MovingObjectPosition rayTraceBlocks_do(Vec3 par1Vec3, Vec3 par2Vec3, boolean par3)
1010        {
1011            return this.rayTraceBlocks_do_do(par1Vec3, par2Vec3, par3, false);
1012        }
1013    
1014        public MovingObjectPosition rayTraceBlocks_do_do(Vec3 par1Vec3, Vec3 par2Vec3, boolean par3, boolean par4)
1015        {
1016            if (!Double.isNaN(par1Vec3.xCoord) && !Double.isNaN(par1Vec3.yCoord) && !Double.isNaN(par1Vec3.zCoord))
1017            {
1018                if (!Double.isNaN(par2Vec3.xCoord) && !Double.isNaN(par2Vec3.yCoord) && !Double.isNaN(par2Vec3.zCoord))
1019                {
1020                    int var5 = MathHelper.floor_double(par2Vec3.xCoord);
1021                    int var6 = MathHelper.floor_double(par2Vec3.yCoord);
1022                    int var7 = MathHelper.floor_double(par2Vec3.zCoord);
1023                    int var8 = MathHelper.floor_double(par1Vec3.xCoord);
1024                    int var9 = MathHelper.floor_double(par1Vec3.yCoord);
1025                    int var10 = MathHelper.floor_double(par1Vec3.zCoord);
1026                    int var11 = this.getBlockId(var8, var9, var10);
1027                    int var12 = this.getBlockMetadata(var8, var9, var10);
1028                    Block var13 = Block.blocksList[var11];
1029    
1030                    if (var13 != null && (!par4 || var13 == null || var13.getCollisionBoundingBoxFromPool(this, var8, var9, var10) != null) && var11 > 0 && var13.canCollideCheck(var12, par3))
1031                    {
1032                        MovingObjectPosition var14 = var13.collisionRayTrace(this, var8, var9, var10, par1Vec3, par2Vec3);
1033    
1034                        if (var14 != null)
1035                        {
1036                            return var14;
1037                        }
1038                    }
1039    
1040                    var11 = 200;
1041    
1042                    while (var11-- >= 0)
1043                    {
1044                        if (Double.isNaN(par1Vec3.xCoord) || Double.isNaN(par1Vec3.yCoord) || Double.isNaN(par1Vec3.zCoord))
1045                        {
1046                            return null;
1047                        }
1048    
1049                        if (var8 == var5 && var9 == var6 && var10 == var7)
1050                        {
1051                            return null;
1052                        }
1053    
1054                        boolean var39 = true;
1055                        boolean var40 = true;
1056                        boolean var41 = true;
1057                        double var15 = 999.0D;
1058                        double var17 = 999.0D;
1059                        double var19 = 999.0D;
1060    
1061                        if (var5 > var8)
1062                        {
1063                            var15 = (double)var8 + 1.0D;
1064                        }
1065                        else if (var5 < var8)
1066                        {
1067                            var15 = (double)var8 + 0.0D;
1068                        }
1069                        else
1070                        {
1071                            var39 = false;
1072                        }
1073    
1074                        if (var6 > var9)
1075                        {
1076                            var17 = (double)var9 + 1.0D;
1077                        }
1078                        else if (var6 < var9)
1079                        {
1080                            var17 = (double)var9 + 0.0D;
1081                        }
1082                        else
1083                        {
1084                            var40 = false;
1085                        }
1086    
1087                        if (var7 > var10)
1088                        {
1089                            var19 = (double)var10 + 1.0D;
1090                        }
1091                        else if (var7 < var10)
1092                        {
1093                            var19 = (double)var10 + 0.0D;
1094                        }
1095                        else
1096                        {
1097                            var41 = false;
1098                        }
1099    
1100                        double var21 = 999.0D;
1101                        double var23 = 999.0D;
1102                        double var25 = 999.0D;
1103                        double var27 = par2Vec3.xCoord - par1Vec3.xCoord;
1104                        double var29 = par2Vec3.yCoord - par1Vec3.yCoord;
1105                        double var31 = par2Vec3.zCoord - par1Vec3.zCoord;
1106    
1107                        if (var39)
1108                        {
1109                            var21 = (var15 - par1Vec3.xCoord) / var27;
1110                        }
1111    
1112                        if (var40)
1113                        {
1114                            var23 = (var17 - par1Vec3.yCoord) / var29;
1115                        }
1116    
1117                        if (var41)
1118                        {
1119                            var25 = (var19 - par1Vec3.zCoord) / var31;
1120                        }
1121    
1122                        boolean var33 = false;
1123                        byte var42;
1124    
1125                        if (var21 < var23 && var21 < var25)
1126                        {
1127                            if (var5 > var8)
1128                            {
1129                                var42 = 4;
1130                            }
1131                            else
1132                            {
1133                                var42 = 5;
1134                            }
1135    
1136                            par1Vec3.xCoord = var15;
1137                            par1Vec3.yCoord += var29 * var21;
1138                            par1Vec3.zCoord += var31 * var21;
1139                        }
1140                        else if (var23 < var25)
1141                        {
1142                            if (var6 > var9)
1143                            {
1144                                var42 = 0;
1145                            }
1146                            else
1147                            {
1148                                var42 = 1;
1149                            }
1150    
1151                            par1Vec3.xCoord += var27 * var23;
1152                            par1Vec3.yCoord = var17;
1153                            par1Vec3.zCoord += var31 * var23;
1154                        }
1155                        else
1156                        {
1157                            if (var7 > var10)
1158                            {
1159                                var42 = 2;
1160                            }
1161                            else
1162                            {
1163                                var42 = 3;
1164                            }
1165    
1166                            par1Vec3.xCoord += var27 * var25;
1167                            par1Vec3.yCoord += var29 * var25;
1168                            par1Vec3.zCoord = var19;
1169                        }
1170    
1171                        Vec3 var34 = Vec3.getVec3Pool().getVecFromPool(par1Vec3.xCoord, par1Vec3.yCoord, par1Vec3.zCoord);
1172                        var8 = (int)(var34.xCoord = (double)MathHelper.floor_double(par1Vec3.xCoord));
1173    
1174                        if (var42 == 5)
1175                        {
1176                            --var8;
1177                            ++var34.xCoord;
1178                        }
1179    
1180                        var9 = (int)(var34.yCoord = (double)MathHelper.floor_double(par1Vec3.yCoord));
1181    
1182                        if (var42 == 1)
1183                        {
1184                            --var9;
1185                            ++var34.yCoord;
1186                        }
1187    
1188                        var10 = (int)(var34.zCoord = (double)MathHelper.floor_double(par1Vec3.zCoord));
1189    
1190                        if (var42 == 3)
1191                        {
1192                            --var10;
1193                            ++var34.zCoord;
1194                        }
1195    
1196                        int var35 = this.getBlockId(var8, var9, var10);
1197                        int var36 = this.getBlockMetadata(var8, var9, var10);
1198                        Block var37 = Block.blocksList[var35];
1199    
1200                        if ((!par4 || var37 == null || var37.getCollisionBoundingBoxFromPool(this, var8, var9, var10) != null) && var35 > 0 && var37.canCollideCheck(var36, par3))
1201                        {
1202                            MovingObjectPosition var38 = var37.collisionRayTrace(this, var8, var9, var10, par1Vec3, par2Vec3);
1203    
1204                            if (var38 != null)
1205                            {
1206                                return var38;
1207                            }
1208                        }
1209                    }
1210    
1211                    return null;
1212                }
1213                else
1214                {
1215                    return null;
1216                }
1217            }
1218            else
1219            {
1220                return null;
1221            }
1222        }
1223    
1224        /**
1225         * Plays a sound at the entity's position. Args: entity, sound, volume (relative to 1.0), and frequency (or pitch,
1226         * also relative to 1.0).
1227         */
1228        public void playSoundAtEntity(Entity par1Entity, String par2Str, float par3, float par4)
1229        {
1230            PlaySoundAtEntityEvent event = new PlaySoundAtEntityEvent(par1Entity, par2Str, par3, par4);
1231            if (MinecraftForge.EVENT_BUS.post(event))
1232            {
1233                return;
1234            }
1235            par2Str = event.name;
1236            if (par1Entity != null && par2Str != null)
1237            {
1238                Iterator var5 = this.worldAccesses.iterator();
1239    
1240                while (var5.hasNext())
1241                {
1242                    IWorldAccess var6 = (IWorldAccess)var5.next();
1243                    var6.playSound(par2Str, par1Entity.posX, par1Entity.posY - (double)par1Entity.yOffset, par1Entity.posZ, par3, par4);
1244                }
1245            }
1246        }
1247    
1248        /**
1249         * Play a sound effect. Many many parameters for this function. Not sure what they do, but a classic call is :
1250         * (double)i + 0.5D, (double)j + 0.5D, (double)k + 0.5D, 'random.door_open', 1.0F, world.rand.nextFloat() * 0.1F +
1251         * 0.9F with i,j,k position of the block.
1252         */
1253        public void playSoundEffect(double par1, double par3, double par5, String par7Str, float par8, float par9)
1254        {
1255            if (par7Str != null)
1256            {
1257                Iterator var10 = this.worldAccesses.iterator();
1258    
1259                while (var10.hasNext())
1260                {
1261                    IWorldAccess var11 = (IWorldAccess)var10.next();
1262                    var11.playSound(par7Str, par1, par3, par5, par8, par9);
1263                }
1264            }
1265        }
1266    
1267        /**
1268         * Plays a record at the specified coordinates of the specified name. Args: recordName, x, y, z
1269         */
1270        public void playRecord(String par1Str, int par2, int par3, int par4)
1271        {
1272            Iterator var5 = this.worldAccesses.iterator();
1273    
1274            while (var5.hasNext())
1275            {
1276                IWorldAccess var6 = (IWorldAccess)var5.next();
1277                var6.playRecord(par1Str, par2, par3, par4);
1278            }
1279        }
1280    
1281        /**
1282         * Spawns a particle.  Args particleName, x, y, z, velX, velY, velZ
1283         */
1284        public void spawnParticle(String par1Str, double par2, double par4, double par6, double par8, double par10, double par12)
1285        {
1286            Iterator var14 = this.worldAccesses.iterator();
1287    
1288            while (var14.hasNext())
1289            {
1290                IWorldAccess var15 = (IWorldAccess)var14.next();
1291                var15.spawnParticle(par1Str, par2, par4, par6, par8, par10, par12);
1292            }
1293        }
1294    
1295        @SideOnly(Side.CLIENT)
1296    
1297        /**
1298         * par8 is loudness, all pars passed to minecraftInstance.sndManager.playSound
1299         */
1300        public void playSound(double par1, double par3, double par5, String par7Str, float par8, float par9) {}
1301    
1302        /**
1303         * adds a lightning bolt to the list of lightning bolts in this world.
1304         */
1305        public boolean addWeatherEffect(Entity par1Entity)
1306        {
1307            this.weatherEffects.add(par1Entity);
1308            return true;
1309        }
1310    
1311        /**
1312         * Called to place all entities as part of a world
1313         */
1314        public boolean spawnEntityInWorld(Entity par1Entity)
1315        {
1316            int var2 = MathHelper.floor_double(par1Entity.posX / 16.0D);
1317            int var3 = MathHelper.floor_double(par1Entity.posZ / 16.0D);
1318            boolean var4 = false;
1319    
1320            if (par1Entity instanceof EntityPlayer)
1321            {
1322                var4 = true;
1323            }
1324    
1325            if (!var4 && !this.chunkExists(var2, var3))
1326            {
1327                return false;
1328            }
1329            else
1330            {
1331                if (par1Entity instanceof EntityPlayer)
1332                {
1333                    EntityPlayer var5 = (EntityPlayer)par1Entity;
1334                    this.playerEntities.add(var5);
1335                    this.updateAllPlayersSleepingFlag();
1336                }
1337    
1338                if (!var4 && MinecraftForge.EVENT_BUS.post(new EntityJoinWorldEvent(par1Entity, this)))
1339                {
1340                    return false;
1341                }
1342    
1343                this.getChunkFromChunkCoords(var2, var3).addEntity(par1Entity);
1344                this.loadedEntityList.add(par1Entity);
1345                this.obtainEntitySkin(par1Entity);
1346                return true;
1347            }
1348        }
1349    
1350        /**
1351         * Start the skin for this entity downloading, if necessary, and increment its reference counter
1352         */
1353        protected void obtainEntitySkin(Entity par1Entity)
1354        {
1355            Iterator var2 = this.worldAccesses.iterator();
1356    
1357            while (var2.hasNext())
1358            {
1359                IWorldAccess var3 = (IWorldAccess)var2.next();
1360                var3.obtainEntitySkin(par1Entity);
1361            }
1362        }
1363    
1364        /**
1365         * Decrement the reference counter for this entity's skin image data
1366         */
1367        protected void releaseEntitySkin(Entity par1Entity)
1368        {
1369            Iterator var2 = this.worldAccesses.iterator();
1370    
1371            while (var2.hasNext())
1372            {
1373                IWorldAccess var3 = (IWorldAccess)var2.next();
1374                var3.releaseEntitySkin(par1Entity);
1375            }
1376        }
1377    
1378        /**
1379         * Dismounts the entity (and anything riding the entity), sets the dead flag, and removes the player entity from the
1380         * player entity list. Called by the playerLoggedOut function.
1381         */
1382        public void setEntityDead(Entity par1Entity)
1383        {
1384            if (par1Entity.riddenByEntity != null)
1385            {
1386                par1Entity.riddenByEntity.mountEntity((Entity)null);
1387            }
1388    
1389            if (par1Entity.ridingEntity != null)
1390            {
1391                par1Entity.mountEntity((Entity)null);
1392            }
1393    
1394            par1Entity.setDead();
1395    
1396            if (par1Entity instanceof EntityPlayer)
1397            {
1398                this.playerEntities.remove(par1Entity);
1399                this.updateAllPlayersSleepingFlag();
1400            }
1401        }
1402    
1403        public void removeEntity(Entity par1Entity)
1404        {
1405            par1Entity.setDead();
1406    
1407            if (par1Entity instanceof EntityPlayer)
1408            {
1409                this.playerEntities.remove(par1Entity);
1410                this.updateAllPlayersSleepingFlag();
1411            }
1412    
1413            int var2 = par1Entity.chunkCoordX;
1414            int var3 = par1Entity.chunkCoordZ;
1415    
1416            if (par1Entity.addedToChunk && this.chunkExists(var2, var3))
1417            {
1418                this.getChunkFromChunkCoords(var2, var3).removeEntity(par1Entity);
1419            }
1420    
1421            this.loadedEntityList.remove(par1Entity);
1422            this.releaseEntitySkin(par1Entity);
1423        }
1424    
1425        /**
1426         * Adds a IWorldAccess to the list of worldAccesses
1427         */
1428        public void addWorldAccess(IWorldAccess par1IWorldAccess)
1429        {
1430            this.worldAccesses.add(par1IWorldAccess);
1431        }
1432    
1433        /**
1434         * Returns a list of bounding boxes that collide with aabb excluding the passed in entity's collision. Args: entity,
1435         * aabb
1436         */
1437        public List getCollidingBoundingBoxes(Entity par1Entity, AxisAlignedBB par2AxisAlignedBB)
1438        {
1439            this.collidingBoundingBoxes.clear();
1440            int var3 = MathHelper.floor_double(par2AxisAlignedBB.minX);
1441            int var4 = MathHelper.floor_double(par2AxisAlignedBB.maxX + 1.0D);
1442            int var5 = MathHelper.floor_double(par2AxisAlignedBB.minY);
1443            int var6 = MathHelper.floor_double(par2AxisAlignedBB.maxY + 1.0D);
1444            int var7 = MathHelper.floor_double(par2AxisAlignedBB.minZ);
1445            int var8 = MathHelper.floor_double(par2AxisAlignedBB.maxZ + 1.0D);
1446    
1447            for (int var9 = var3; var9 < var4; ++var9)
1448            {
1449                for (int var10 = var7; var10 < var8; ++var10)
1450                {
1451                    if (this.blockExists(var9, 64, var10))
1452                    {
1453                        for (int var11 = var5 - 1; var11 < var6; ++var11)
1454                        {
1455                            Block var12 = Block.blocksList[this.getBlockId(var9, var11, var10)];
1456    
1457                            if (var12 != null)
1458                            {
1459                                var12.addCollidingBlockToList(this, var9, var11, var10, par2AxisAlignedBB, this.collidingBoundingBoxes, par1Entity);
1460                            }
1461                        }
1462                    }
1463                }
1464            }
1465    
1466            double var15 = 0.25D;
1467            List var17 = this.getEntitiesWithinAABBExcludingEntity(par1Entity, par2AxisAlignedBB.expand(var15, var15, var15));
1468            Iterator var16 = var17.iterator();
1469    
1470            while (var16.hasNext())
1471            {
1472                Entity var13 = (Entity)var16.next();
1473                AxisAlignedBB var14 = var13.getBoundingBox();
1474    
1475                if (var14 != null && var14.intersectsWith(par2AxisAlignedBB))
1476                {
1477                    this.collidingBoundingBoxes.add(var14);
1478                }
1479    
1480                var14 = par1Entity.getCollisionBox(var13);
1481    
1482                if (var14 != null && var14.intersectsWith(par2AxisAlignedBB))
1483                {
1484                    this.collidingBoundingBoxes.add(var14);
1485                }
1486            }
1487    
1488            return this.collidingBoundingBoxes;
1489        }
1490    
1491        /**
1492         * calculates and returns a list of colliding bounding boxes within a given AABB
1493         */
1494        public List getAllCollidingBoundingBoxes(AxisAlignedBB par1AxisAlignedBB)
1495        {
1496            this.collidingBoundingBoxes.clear();
1497            int var2 = MathHelper.floor_double(par1AxisAlignedBB.minX);
1498            int var3 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
1499            int var4 = MathHelper.floor_double(par1AxisAlignedBB.minY);
1500            int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
1501            int var6 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
1502            int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
1503    
1504            for (int var8 = var2; var8 < var3; ++var8)
1505            {
1506                for (int var9 = var6; var9 < var7; ++var9)
1507                {
1508                    if (this.blockExists(var8, 64, var9))
1509                    {
1510                        for (int var10 = var4 - 1; var10 < var5; ++var10)
1511                        {
1512                            Block var11 = Block.blocksList[this.getBlockId(var8, var10, var9)];
1513    
1514                            if (var11 != null)
1515                            {
1516                                var11.addCollidingBlockToList(this, var8, var10, var9, par1AxisAlignedBB, this.collidingBoundingBoxes, (Entity)null);
1517                            }
1518                        }
1519                    }
1520                }
1521            }
1522    
1523            return this.collidingBoundingBoxes;
1524        }
1525    
1526        /**
1527         * Returns the amount of skylight subtracted for the current time
1528         */
1529        public int calculateSkylightSubtracted(float par1)
1530        {
1531            float var2 = this.getCelestialAngle(par1);
1532            float var3 = 1.0F - (MathHelper.cos(var2 * (float)Math.PI * 2.0F) * 2.0F + 0.5F);
1533    
1534            if (var3 < 0.0F)
1535            {
1536                var3 = 0.0F;
1537            }
1538    
1539            if (var3 > 1.0F)
1540            {
1541                var3 = 1.0F;
1542            }
1543    
1544            var3 = 1.0F - var3;
1545            var3 = (float)((double)var3 * (1.0D - (double)(this.getRainStrength(par1) * 5.0F) / 16.0D));
1546            var3 = (float)((double)var3 * (1.0D - (double)(this.getWeightedThunderStrength(par1) * 5.0F) / 16.0D));
1547            var3 = 1.0F - var3;
1548            return (int)(var3 * 11.0F);
1549        }
1550    
1551        @SideOnly(Side.CLIENT)
1552    
1553        /**
1554         * Removes a worldAccess from the worldAccesses object
1555         */
1556        public void removeWorldAccess(IWorldAccess par1IWorldAccess)
1557        {
1558            this.worldAccesses.remove(par1IWorldAccess);
1559        }
1560    
1561        @SideOnly(Side.CLIENT)
1562        public float func_72971_b(float par1)
1563        {
1564            float var2 = this.getCelestialAngle(par1);
1565            float var3 = 1.0F - (MathHelper.cos(var2 * (float)Math.PI * 2.0F) * 2.0F + 0.2F);
1566    
1567            if (var3 < 0.0F)
1568            {
1569                var3 = 0.0F;
1570            }
1571    
1572            if (var3 > 1.0F)
1573            {
1574                var3 = 1.0F;
1575            }
1576    
1577            var3 = 1.0F - var3;
1578            var3 = (float)((double)var3 * (1.0D - (double)(this.getRainStrength(par1) * 5.0F) / 16.0D));
1579            var3 = (float)((double)var3 * (1.0D - (double)(this.getWeightedThunderStrength(par1) * 5.0F) / 16.0D));
1580            return var3 * 0.8F + 0.2F;
1581        }
1582    
1583        @SideOnly(Side.CLIENT)
1584    
1585        /**
1586         * Calculates the color for the skybox
1587         */
1588        public Vec3 getSkyColor(Entity par1Entity, float par2)
1589        {
1590            float var3 = this.getCelestialAngle(par2);
1591            float var4 = MathHelper.cos(var3 * (float)Math.PI * 2.0F) * 2.0F + 0.5F;
1592    
1593            if (var4 < 0.0F)
1594            {
1595                var4 = 0.0F;
1596            }
1597    
1598            if (var4 > 1.0F)
1599            {
1600                var4 = 1.0F;
1601            }
1602    
1603            int var5 = MathHelper.floor_double(par1Entity.posX);
1604            int var6 = MathHelper.floor_double(par1Entity.posZ);
1605            BiomeGenBase var7 = this.getBiomeGenForCoords(var5, var6);
1606            float var8 = var7.getFloatTemperature();
1607            int var9 = var7.getSkyColorByTemp(var8);
1608            float var10 = (float)(var9 >> 16 & 255) / 255.0F;
1609            float var11 = (float)(var9 >> 8 & 255) / 255.0F;
1610            float var12 = (float)(var9 & 255) / 255.0F;
1611            var10 *= var4;
1612            var11 *= var4;
1613            var12 *= var4;
1614            float var13 = this.getRainStrength(par2);
1615            float var14;
1616            float var15;
1617    
1618            if (var13 > 0.0F)
1619            {
1620                var14 = (var10 * 0.3F + var11 * 0.59F + var12 * 0.11F) * 0.6F;
1621                var15 = 1.0F - var13 * 0.75F;
1622                var10 = var10 * var15 + var14 * (1.0F - var15);
1623                var11 = var11 * var15 + var14 * (1.0F - var15);
1624                var12 = var12 * var15 + var14 * (1.0F - var15);
1625            }
1626    
1627            var14 = this.getWeightedThunderStrength(par2);
1628    
1629            if (var14 > 0.0F)
1630            {
1631                var15 = (var10 * 0.3F + var11 * 0.59F + var12 * 0.11F) * 0.2F;
1632                float var16 = 1.0F - var14 * 0.75F;
1633                var10 = var10 * var16 + var15 * (1.0F - var16);
1634                var11 = var11 * var16 + var15 * (1.0F - var16);
1635                var12 = var12 * var16 + var15 * (1.0F - var16);
1636            }
1637    
1638            if (this.lightningFlash > 0)
1639            {
1640                var15 = (float)this.lightningFlash - par2;
1641    
1642                if (var15 > 1.0F)
1643                {
1644                    var15 = 1.0F;
1645                }
1646    
1647                var15 *= 0.45F;
1648                var10 = var10 * (1.0F - var15) + 0.8F * var15;
1649                var11 = var11 * (1.0F - var15) + 0.8F * var15;
1650                var12 = var12 * (1.0F - var15) + 1.0F * var15;
1651            }
1652    
1653            return Vec3.getVec3Pool().getVecFromPool((double)var10, (double)var11, (double)var12);
1654        }
1655    
1656        /**
1657         * calls calculateCelestialAngle
1658         */
1659        public float getCelestialAngle(float par1)
1660        {
1661            return this.provider.calculateCelestialAngle(this.worldInfo.getWorldTime(), par1);
1662        }
1663    
1664        @SideOnly(Side.CLIENT)
1665        public int getMoonPhase(float par1)
1666        {
1667            return this.provider.getMoonPhase(this.worldInfo.getWorldTime(), par1);
1668        }
1669    
1670        @SideOnly(Side.CLIENT)
1671    
1672        /**
1673         * Return getCelestialAngle()*2*PI
1674         */
1675        public float getCelestialAngleRadians(float par1)
1676        {
1677            float var2 = this.getCelestialAngle(par1);
1678            return var2 * (float)Math.PI * 2.0F;
1679        }
1680    
1681        @SideOnly(Side.CLIENT)
1682        public Vec3 drawClouds(float par1)
1683        {
1684            float var2 = this.getCelestialAngle(par1);
1685            float var3 = MathHelper.cos(var2 * (float)Math.PI * 2.0F) * 2.0F + 0.5F;
1686    
1687            if (var3 < 0.0F)
1688            {
1689                var3 = 0.0F;
1690            }
1691    
1692            if (var3 > 1.0F)
1693            {
1694                var3 = 1.0F;
1695            }
1696    
1697            float var4 = (float)(this.cloudColour >> 16 & 255L) / 255.0F;
1698            float var5 = (float)(this.cloudColour >> 8 & 255L) / 255.0F;
1699            float var6 = (float)(this.cloudColour & 255L) / 255.0F;
1700            float var7 = this.getRainStrength(par1);
1701            float var8;
1702            float var9;
1703    
1704            if (var7 > 0.0F)
1705            {
1706                var8 = (var4 * 0.3F + var5 * 0.59F + var6 * 0.11F) * 0.6F;
1707                var9 = 1.0F - var7 * 0.95F;
1708                var4 = var4 * var9 + var8 * (1.0F - var9);
1709                var5 = var5 * var9 + var8 * (1.0F - var9);
1710                var6 = var6 * var9 + var8 * (1.0F - var9);
1711            }
1712    
1713            var4 *= var3 * 0.9F + 0.1F;
1714            var5 *= var3 * 0.9F + 0.1F;
1715            var6 *= var3 * 0.85F + 0.15F;
1716            var8 = this.getWeightedThunderStrength(par1);
1717    
1718            if (var8 > 0.0F)
1719            {
1720                var9 = (var4 * 0.3F + var5 * 0.59F + var6 * 0.11F) * 0.2F;
1721                float var10 = 1.0F - var8 * 0.95F;
1722                var4 = var4 * var10 + var9 * (1.0F - var10);
1723                var5 = var5 * var10 + var9 * (1.0F - var10);
1724                var6 = var6 * var10 + var9 * (1.0F - var10);
1725            }
1726    
1727            return Vec3.getVec3Pool().getVecFromPool((double)var4, (double)var5, (double)var6);
1728        }
1729    
1730        @SideOnly(Side.CLIENT)
1731    
1732        /**
1733         * Returns vector(ish) with R/G/B for fog
1734         */
1735        public Vec3 getFogColor(float par1)
1736        {
1737            float var2 = this.getCelestialAngle(par1);
1738            return this.provider.getFogColor(var2, par1);
1739        }
1740    
1741        /**
1742         * Gets the height to which rain/snow will fall. Calculates it if not already stored.
1743         */
1744        public int getPrecipitationHeight(int par1, int par2)
1745        {
1746            return this.getChunkFromBlockCoords(par1, par2).getPrecipitationHeight(par1 & 15, par2 & 15);
1747        }
1748    
1749        /**
1750         * Finds the highest block on the x, z coordinate that is solid and returns its y coord. Args x, z
1751         */
1752        public int getTopSolidOrLiquidBlock(int par1, int par2)
1753        {
1754            Chunk var3 = this.getChunkFromBlockCoords(par1, par2);
1755            int var4 = var3.getTopFilledSegment() + 15;
1756            par1 &= 15;
1757    
1758            for (par2 &= 15; var4 > 0; --var4)
1759            {
1760                int var5 = var3.getBlockID(par1, var4, par2);
1761    
1762                if (var5 != 0 && Block.blocksList[var5].blockMaterial.blocksMovement() && Block.blocksList[var5].blockMaterial != Material.leaves && !Block.blocksList[var5].isBlockFoliage(this, par1, var4, par2))
1763                {
1764                    return var4 + 1;
1765                }
1766            }
1767    
1768            return -1;
1769        }
1770    
1771        @SideOnly(Side.CLIENT)
1772    
1773        /**
1774         * How bright are stars in the sky
1775         */
1776        public float getStarBrightness(float par1)
1777        {
1778            float var2 = this.getCelestialAngle(par1);
1779            float var3 = 1.0F - (MathHelper.cos(var2 * (float)Math.PI * 2.0F) * 2.0F + 0.25F);
1780    
1781            if (var3 < 0.0F)
1782            {
1783                var3 = 0.0F;
1784            }
1785    
1786            if (var3 > 1.0F)
1787            {
1788                var3 = 1.0F;
1789            }
1790    
1791            return var3 * var3 * 0.5F;
1792        }
1793    
1794        /**
1795         * Schedules a tick to a block with a delay (Most commonly the tick rate)
1796         */
1797        public void scheduleBlockUpdate(int par1, int par2, int par3, int par4, int par5) {}
1798    
1799        /**
1800         * Schedules a block update from the saved information in a chunk. Called when the chunk is loaded.
1801         */
1802        public void scheduleBlockUpdateFromLoad(int par1, int par2, int par3, int par4, int par5) {}
1803    
1804        /**
1805         * Updates (and cleans up) entities and tile entities
1806         */
1807        public void updateEntities()
1808        {
1809            this.theProfiler.startSection("entities");
1810            this.theProfiler.startSection("global");
1811            int var1;
1812            Entity var2;
1813    
1814            for (var1 = 0; var1 < this.weatherEffects.size(); ++var1)
1815            {
1816                var2 = (Entity)this.weatherEffects.get(var1);
1817                var2.onUpdate();
1818    
1819                if (var2.isDead)
1820                {
1821                    this.weatherEffects.remove(var1--);
1822                }
1823            }
1824    
1825            this.theProfiler.endStartSection("remove");
1826            this.loadedEntityList.removeAll(this.unloadedEntityList);
1827            Iterator var5 = this.unloadedEntityList.iterator();
1828            int var3;
1829            int var4;
1830    
1831            while (var5.hasNext())
1832            {
1833                var2 = (Entity)var5.next();
1834                var3 = var2.chunkCoordX;
1835                var4 = var2.chunkCoordZ;
1836    
1837                if (var2.addedToChunk && this.chunkExists(var3, var4))
1838                {
1839                    this.getChunkFromChunkCoords(var3, var4).removeEntity(var2);
1840                }
1841            }
1842    
1843            var5 = this.unloadedEntityList.iterator();
1844    
1845            while (var5.hasNext())
1846            {
1847                var2 = (Entity)var5.next();
1848                this.releaseEntitySkin(var2);
1849            }
1850    
1851            this.unloadedEntityList.clear();
1852            this.theProfiler.endStartSection("regular");
1853    
1854            for (var1 = 0; var1 < this.loadedEntityList.size(); ++var1)
1855            {
1856                var2 = (Entity)this.loadedEntityList.get(var1);
1857    
1858                if (var2.ridingEntity != null)
1859                {
1860                    if (!var2.ridingEntity.isDead && var2.ridingEntity.riddenByEntity == var2)
1861                    {
1862                        continue;
1863                    }
1864    
1865                    var2.ridingEntity.riddenByEntity = null;
1866                    var2.ridingEntity = null;
1867                }
1868    
1869                this.theProfiler.startSection("tick");
1870    
1871                if (!var2.isDead)
1872                {
1873                    this.updateEntity(var2);
1874                }
1875    
1876                this.theProfiler.endSection();
1877                this.theProfiler.startSection("remove");
1878    
1879                if (var2.isDead)
1880                {
1881                    var3 = var2.chunkCoordX;
1882                    var4 = var2.chunkCoordZ;
1883    
1884                    if (var2.addedToChunk && this.chunkExists(var3, var4))
1885                    {
1886                        this.getChunkFromChunkCoords(var3, var4).removeEntity(var2);
1887                    }
1888    
1889                    this.loadedEntityList.remove(var1--);
1890                    this.releaseEntitySkin(var2);
1891                }
1892    
1893                this.theProfiler.endSection();
1894            }
1895    
1896            this.theProfiler.endStartSection("tileEntities");
1897            this.scanningTileEntities = true;
1898            var5 = this.loadedTileEntityList.iterator();
1899    
1900            while (var5.hasNext())
1901            {
1902                TileEntity var6 = (TileEntity)var5.next();
1903    
1904                if (!var6.isInvalid() && var6.func_70309_m() && this.blockExists(var6.xCoord, var6.yCoord, var6.zCoord))
1905                {
1906                    var6.updateEntity();
1907                }
1908    
1909                if (var6.isInvalid())
1910                {
1911                    var5.remove();
1912    
1913                    if (this.chunkExists(var6.xCoord >> 4, var6.zCoord >> 4))
1914                    {
1915                        Chunk var8 = this.getChunkFromChunkCoords(var6.xCoord >> 4, var6.zCoord >> 4);
1916    
1917                        if (var8 != null)
1918                        {
1919                            var8.cleanChunkBlockTileEntity(var6.xCoord & 15, var6.yCoord, var6.zCoord & 15);
1920                        }
1921                    }
1922                }
1923            }
1924    
1925            this.scanningTileEntities = false;
1926    
1927            if (!this.entityRemoval.isEmpty())
1928            {
1929                for (Object tile : entityRemoval)
1930                {
1931                   ((TileEntity)tile).onChunkUnload(); 
1932                }
1933                this.loadedTileEntityList.removeAll(this.entityRemoval);
1934                this.entityRemoval.clear();
1935            }
1936    
1937            this.theProfiler.endStartSection("pendingTileEntities");
1938    
1939            if (!this.addedTileEntityList.isEmpty())
1940            {
1941                Iterator var7 = this.addedTileEntityList.iterator();
1942    
1943                while (var7.hasNext())
1944                {
1945                    TileEntity var9 = (TileEntity)var7.next();
1946    
1947                    if (!var9.isInvalid())
1948                    {
1949                        if (!this.loadedTileEntityList.contains(var9))
1950                        {
1951                            this.loadedTileEntityList.add(var9);
1952                        }
1953                    }
1954                    else
1955                    {
1956                        if (this.chunkExists(var9.xCoord >> 4, var9.zCoord >> 4))
1957                        {
1958                            Chunk var10 = this.getChunkFromChunkCoords(var9.xCoord >> 4, var9.zCoord >> 4);
1959    
1960                            if (var10 != null)
1961                            {
1962                                var10.setChunkBlockTileEntity(var9.xCoord & 15, var9.yCoord, var9.zCoord & 15, var9);
1963                            }
1964                        }
1965                    }
1966                }
1967    
1968                this.addedTileEntityList.clear();
1969            }
1970    
1971            this.theProfiler.endSection();
1972            this.theProfiler.endSection();
1973        }
1974    
1975        public void addTileEntity(Collection par1Collection)
1976        {
1977            List dest = scanningTileEntities ? addedTileEntityList : loadedTileEntityList;
1978            for(Object entity : par1Collection)
1979            {
1980                if(((TileEntity)entity).canUpdate())
1981                {
1982                    dest.add(entity);
1983                }
1984            }
1985        }
1986    
1987        /**
1988         * Will update the entity in the world if the chunk the entity is in is currently loaded. Args: entity
1989         */
1990        public void updateEntity(Entity par1Entity)
1991        {
1992            this.updateEntityWithOptionalForce(par1Entity, true);
1993        }
1994    
1995        /**
1996         * Will update the entity in the world if the chunk the entity is in is currently loaded or its forced to update.
1997         * Args: entity, forceUpdate
1998         */
1999        public void updateEntityWithOptionalForce(Entity par1Entity, boolean par2)
2000        {
2001            int var3 = MathHelper.floor_double(par1Entity.posX);
2002            int var4 = MathHelper.floor_double(par1Entity.posZ);
2003            byte var5 = 32;
2004            boolean canUpdate = !par2 || this.checkChunksExist(var3 - var5, 0, var4 - var5, var3 + var5, 0, var4 + var5);
2005            if (!canUpdate)
2006            {
2007                EntityEvent.CanUpdate event = new EntityEvent.CanUpdate(par1Entity);
2008                MinecraftForge.EVENT_BUS.post(event);
2009                canUpdate = event.canUpdate;
2010            }
2011            if (canUpdate)
2012            {
2013                par1Entity.lastTickPosX = par1Entity.posX;
2014                par1Entity.lastTickPosY = par1Entity.posY;
2015                par1Entity.lastTickPosZ = par1Entity.posZ;
2016                par1Entity.prevRotationYaw = par1Entity.rotationYaw;
2017                par1Entity.prevRotationPitch = par1Entity.rotationPitch;
2018    
2019                if (par2 && par1Entity.addedToChunk)
2020                {
2021                    if (par1Entity.ridingEntity != null)
2022                    {
2023                        par1Entity.updateRidden();
2024                    }
2025                    else
2026                    {
2027                        par1Entity.onUpdate();
2028                    }
2029                }
2030    
2031                this.theProfiler.startSection("chunkCheck");
2032    
2033                if (Double.isNaN(par1Entity.posX) || Double.isInfinite(par1Entity.posX))
2034                {
2035                    par1Entity.posX = par1Entity.lastTickPosX;
2036                }
2037    
2038                if (Double.isNaN(par1Entity.posY) || Double.isInfinite(par1Entity.posY))
2039                {
2040                    par1Entity.posY = par1Entity.lastTickPosY;
2041                }
2042    
2043                if (Double.isNaN(par1Entity.posZ) || Double.isInfinite(par1Entity.posZ))
2044                {
2045                    par1Entity.posZ = par1Entity.lastTickPosZ;
2046                }
2047    
2048                if (Double.isNaN((double)par1Entity.rotationPitch) || Double.isInfinite((double)par1Entity.rotationPitch))
2049                {
2050                    par1Entity.rotationPitch = par1Entity.prevRotationPitch;
2051                }
2052    
2053                if (Double.isNaN((double)par1Entity.rotationYaw) || Double.isInfinite((double)par1Entity.rotationYaw))
2054                {
2055                    par1Entity.rotationYaw = par1Entity.prevRotationYaw;
2056                }
2057    
2058                int var6 = MathHelper.floor_double(par1Entity.posX / 16.0D);
2059                int var7 = MathHelper.floor_double(par1Entity.posY / 16.0D);
2060                int var8 = MathHelper.floor_double(par1Entity.posZ / 16.0D);
2061    
2062                if (!par1Entity.addedToChunk || par1Entity.chunkCoordX != var6 || par1Entity.chunkCoordY != var7 || par1Entity.chunkCoordZ != var8)
2063                {
2064                    if (par1Entity.addedToChunk && this.chunkExists(par1Entity.chunkCoordX, par1Entity.chunkCoordZ))
2065                    {
2066                        this.getChunkFromChunkCoords(par1Entity.chunkCoordX, par1Entity.chunkCoordZ).removeEntityAtIndex(par1Entity, par1Entity.chunkCoordY);
2067                    }
2068    
2069                    if (this.chunkExists(var6, var8))
2070                    {
2071                        par1Entity.addedToChunk = true;
2072                        this.getChunkFromChunkCoords(var6, var8).addEntity(par1Entity);
2073                    }
2074                    else
2075                    {
2076                        par1Entity.addedToChunk = false;
2077                    }
2078                }
2079    
2080                this.theProfiler.endSection();
2081    
2082                if (par2 && par1Entity.addedToChunk && par1Entity.riddenByEntity != null)
2083                {
2084                    if (!par1Entity.riddenByEntity.isDead && par1Entity.riddenByEntity.ridingEntity == par1Entity)
2085                    {
2086                        this.updateEntity(par1Entity.riddenByEntity);
2087                    }
2088                    else
2089                    {
2090                        par1Entity.riddenByEntity.ridingEntity = null;
2091                        par1Entity.riddenByEntity = null;
2092                    }
2093                }
2094            }
2095        }
2096    
2097        /**
2098         * Returns true if there are no solid, live entities in the specified AxisAlignedBB
2099         */
2100        public boolean checkIfAABBIsClear(AxisAlignedBB par1AxisAlignedBB)
2101        {
2102            return this.checkIfAABBIsClearExcludingEntity(par1AxisAlignedBB, (Entity)null);
2103        }
2104    
2105        /**
2106         * Returns true if there are no solid, live entities in the specified AxisAlignedBB, excluding the given entity
2107         */
2108        public boolean checkIfAABBIsClearExcludingEntity(AxisAlignedBB par1AxisAlignedBB, Entity par2Entity)
2109        {
2110            List var3 = this.getEntitiesWithinAABBExcludingEntity((Entity)null, par1AxisAlignedBB);
2111            Iterator var4 = var3.iterator();
2112            Entity var5;
2113    
2114            do
2115            {
2116                if (!var4.hasNext())
2117                {
2118                    return true;
2119                }
2120    
2121                var5 = (Entity)var4.next();
2122            }
2123            while (var5.isDead || !var5.preventEntitySpawning || var5 == par2Entity);
2124    
2125            return false;
2126        }
2127    
2128        /**
2129         * Returns true if there are any blocks in the region constrained by an AxisAlignedBB
2130         */
2131        public boolean isAABBNonEmpty(AxisAlignedBB par1AxisAlignedBB)
2132        {
2133            int var2 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2134            int var3 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2135            int var4 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2136            int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2137            int var6 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2138            int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2139    
2140            if (par1AxisAlignedBB.minX < 0.0D)
2141            {
2142                --var2;
2143            }
2144    
2145            if (par1AxisAlignedBB.minY < 0.0D)
2146            {
2147                --var4;
2148            }
2149    
2150            if (par1AxisAlignedBB.minZ < 0.0D)
2151            {
2152                --var6;
2153            }
2154    
2155            for (int var8 = var2; var8 < var3; ++var8)
2156            {
2157                for (int var9 = var4; var9 < var5; ++var9)
2158                {
2159                    for (int var10 = var6; var10 < var7; ++var10)
2160                    {
2161                        Block var11 = Block.blocksList[this.getBlockId(var8, var9, var10)];
2162    
2163                        if (var11 != null)
2164                        {
2165                            return true;
2166                        }
2167                    }
2168                }
2169            }
2170    
2171            return false;
2172        }
2173    
2174        /**
2175         * Returns if any of the blocks within the aabb are liquids. Args: aabb
2176         */
2177        public boolean isAnyLiquid(AxisAlignedBB par1AxisAlignedBB)
2178        {
2179            int var2 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2180            int var3 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2181            int var4 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2182            int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2183            int var6 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2184            int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2185    
2186            if (par1AxisAlignedBB.minX < 0.0D)
2187            {
2188                --var2;
2189            }
2190    
2191            if (par1AxisAlignedBB.minY < 0.0D)
2192            {
2193                --var4;
2194            }
2195    
2196            if (par1AxisAlignedBB.minZ < 0.0D)
2197            {
2198                --var6;
2199            }
2200    
2201            for (int var8 = var2; var8 < var3; ++var8)
2202            {
2203                for (int var9 = var4; var9 < var5; ++var9)
2204                {
2205                    for (int var10 = var6; var10 < var7; ++var10)
2206                    {
2207                        Block var11 = Block.blocksList[this.getBlockId(var8, var9, var10)];
2208    
2209                        if (var11 != null && var11.blockMaterial.isLiquid())
2210                        {
2211                            return true;
2212                        }
2213                    }
2214                }
2215            }
2216    
2217            return false;
2218        }
2219    
2220        /**
2221         * Returns whether or not the given bounding box is on fire or not
2222         */
2223        public boolean isBoundingBoxBurning(AxisAlignedBB par1AxisAlignedBB)
2224        {
2225            int var2 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2226            int var3 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2227            int var4 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2228            int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2229            int var6 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2230            int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2231    
2232            if (this.checkChunksExist(var2, var4, var6, var3, var5, var7))
2233            {
2234                for (int var8 = var2; var8 < var3; ++var8)
2235                {
2236                    for (int var9 = var4; var9 < var5; ++var9)
2237                    {
2238                        for (int var10 = var6; var10 < var7; ++var10)
2239                        {
2240                            int var11 = this.getBlockId(var8, var9, var10);
2241    
2242                            if (var11 == Block.fire.blockID || var11 == Block.lavaMoving.blockID || var11 == Block.lavaStill.blockID)
2243                            {
2244                                return true;
2245                            }
2246                            else
2247                            {
2248                                Block block = Block.blocksList[var11];
2249                                if (block != null && block.isBlockBurning(this, var8, var9, var10))
2250                                {
2251                                    return true;
2252                                }
2253                            }
2254                        }
2255                    }
2256                }
2257            }
2258    
2259            return false;
2260        }
2261    
2262        /**
2263         * handles the acceleration of an object whilst in water. Not sure if it is used elsewhere.
2264         */
2265        public boolean handleMaterialAcceleration(AxisAlignedBB par1AxisAlignedBB, Material par2Material, Entity par3Entity)
2266        {
2267            int var4 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2268            int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2269            int var6 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2270            int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2271            int var8 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2272            int var9 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2273    
2274            if (!this.checkChunksExist(var4, var6, var8, var5, var7, var9))
2275            {
2276                return false;
2277            }
2278            else
2279            {
2280                boolean var10 = false;
2281                Vec3 var11 = Vec3.getVec3Pool().getVecFromPool(0.0D, 0.0D, 0.0D);
2282    
2283                for (int var12 = var4; var12 < var5; ++var12)
2284                {
2285                    for (int var13 = var6; var13 < var7; ++var13)
2286                    {
2287                        for (int var14 = var8; var14 < var9; ++var14)
2288                        {
2289                            Block var15 = Block.blocksList[this.getBlockId(var12, var13, var14)];
2290    
2291                            if (var15 != null && var15.blockMaterial == par2Material)
2292                            {
2293                                double var16 = (double)((float)(var13 + 1) - BlockFluid.getFluidHeightPercent(this.getBlockMetadata(var12, var13, var14)));
2294    
2295                                if ((double)var7 >= var16)
2296                                {
2297                                    var10 = true;
2298                                    var15.velocityToAddToEntity(this, var12, var13, var14, par3Entity, var11);
2299                                }
2300                            }
2301                        }
2302                    }
2303                }
2304    
2305                if (var11.lengthVector() > 0.0D)
2306                {
2307                    var11 = var11.normalize();
2308                    double var18 = 0.014D;
2309                    par3Entity.motionX += var11.xCoord * var18;
2310                    par3Entity.motionY += var11.yCoord * var18;
2311                    par3Entity.motionZ += var11.zCoord * var18;
2312                }
2313    
2314                return var10;
2315            }
2316        }
2317    
2318        /**
2319         * Returns true if the given bounding box contains the given material
2320         */
2321        public boolean isMaterialInBB(AxisAlignedBB par1AxisAlignedBB, Material par2Material)
2322        {
2323            int var3 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2324            int var4 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2325            int var5 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2326            int var6 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2327            int var7 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2328            int var8 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2329    
2330            for (int var9 = var3; var9 < var4; ++var9)
2331            {
2332                for (int var10 = var5; var10 < var6; ++var10)
2333                {
2334                    for (int var11 = var7; var11 < var8; ++var11)
2335                    {
2336                        Block var12 = Block.blocksList[this.getBlockId(var9, var10, var11)];
2337    
2338                        if (var12 != null && var12.blockMaterial == par2Material)
2339                        {
2340                            return true;
2341                        }
2342                    }
2343                }
2344            }
2345    
2346            return false;
2347        }
2348    
2349        /**
2350         * checks if the given AABB is in the material given. Used while swimming.
2351         */
2352        public boolean isAABBInMaterial(AxisAlignedBB par1AxisAlignedBB, Material par2Material)
2353        {
2354            int var3 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2355            int var4 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2356            int var5 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2357            int var6 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2358            int var7 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2359            int var8 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2360    
2361            for (int var9 = var3; var9 < var4; ++var9)
2362            {
2363                for (int var10 = var5; var10 < var6; ++var10)
2364                {
2365                    for (int var11 = var7; var11 < var8; ++var11)
2366                    {
2367                        Block var12 = Block.blocksList[this.getBlockId(var9, var10, var11)];
2368    
2369                        if (var12 != null && var12.blockMaterial == par2Material)
2370                        {
2371                            int var13 = this.getBlockMetadata(var9, var10, var11);
2372                            double var14 = (double)(var10 + 1);
2373    
2374                            if (var13 < 8)
2375                            {
2376                                var14 = (double)(var10 + 1) - (double)var13 / 8.0D;
2377                            }
2378    
2379                            if (var14 >= par1AxisAlignedBB.minY)
2380                            {
2381                                return true;
2382                            }
2383                        }
2384                    }
2385                }
2386            }
2387    
2388            return false;
2389        }
2390    
2391        /**
2392         * Creates an explosion. Args: entity, x, y, z, strength
2393         */
2394        public Explosion createExplosion(Entity par1Entity, double par2, double par4, double par6, float par8)
2395        {
2396            return this.newExplosion(par1Entity, par2, par4, par6, par8, false);
2397        }
2398    
2399        /**
2400         * returns a new explosion. Does initiation (at time of writing Explosion is not finished)
2401         */
2402        public Explosion newExplosion(Entity par1Entity, double par2, double par4, double par6, float par8, boolean par9)
2403        {
2404            Explosion var10 = new Explosion(this, par1Entity, par2, par4, par6, par8);
2405            var10.isFlaming = par9;
2406            var10.doExplosionA();
2407            var10.doExplosionB(true);
2408            return var10;
2409        }
2410    
2411        /**
2412         * Gets the percentage of real blocks within within a bounding box, along a specified vector.
2413         */
2414        public float getBlockDensity(Vec3 par1Vec3, AxisAlignedBB par2AxisAlignedBB)
2415        {
2416            double var3 = 1.0D / ((par2AxisAlignedBB.maxX - par2AxisAlignedBB.minX) * 2.0D + 1.0D);
2417            double var5 = 1.0D / ((par2AxisAlignedBB.maxY - par2AxisAlignedBB.minY) * 2.0D + 1.0D);
2418            double var7 = 1.0D / ((par2AxisAlignedBB.maxZ - par2AxisAlignedBB.minZ) * 2.0D + 1.0D);
2419            int var9 = 0;
2420            int var10 = 0;
2421    
2422            for (float var11 = 0.0F; var11 <= 1.0F; var11 = (float)((double)var11 + var3))
2423            {
2424                for (float var12 = 0.0F; var12 <= 1.0F; var12 = (float)((double)var12 + var5))
2425                {
2426                    for (float var13 = 0.0F; var13 <= 1.0F; var13 = (float)((double)var13 + var7))
2427                    {
2428                        double var14 = par2AxisAlignedBB.minX + (par2AxisAlignedBB.maxX - par2AxisAlignedBB.minX) * (double)var11;
2429                        double var16 = par2AxisAlignedBB.minY + (par2AxisAlignedBB.maxY - par2AxisAlignedBB.minY) * (double)var12;
2430                        double var18 = par2AxisAlignedBB.minZ + (par2AxisAlignedBB.maxZ - par2AxisAlignedBB.minZ) * (double)var13;
2431    
2432                        if (this.rayTraceBlocks(Vec3.getVec3Pool().getVecFromPool(var14, var16, var18), par1Vec3) == null)
2433                        {
2434                            ++var9;
2435                        }
2436    
2437                        ++var10;
2438                    }
2439                }
2440            }
2441    
2442            return (float)var9 / (float)var10;
2443        }
2444    
2445        /**
2446         * If the block in the given direction of the given coordinate is fire, extinguish it. Args: Player, X,Y,Z,
2447         * blockDirection
2448         */
2449        public boolean extinguishFire(EntityPlayer par1EntityPlayer, int par2, int par3, int par4, int par5)
2450        {
2451            if (par5 == 0)
2452            {
2453                --par3;
2454            }
2455    
2456            if (par5 == 1)
2457            {
2458                ++par3;
2459            }
2460    
2461            if (par5 == 2)
2462            {
2463                --par4;
2464            }
2465    
2466            if (par5 == 3)
2467            {
2468                ++par4;
2469            }
2470    
2471            if (par5 == 4)
2472            {
2473                --par2;
2474            }
2475    
2476            if (par5 == 5)
2477            {
2478                ++par2;
2479            }
2480    
2481            if (this.getBlockId(par2, par3, par4) == Block.fire.blockID)
2482            {
2483                this.playAuxSFXAtEntity(par1EntityPlayer, 1004, par2, par3, par4, 0);
2484                this.setBlockWithNotify(par2, par3, par4, 0);
2485                return true;
2486            }
2487            else
2488            {
2489                return false;
2490            }
2491        }
2492    
2493        @SideOnly(Side.CLIENT)
2494    
2495        /**
2496         * This string is 'All: (number of loaded entities)' Viewable by press ing F3
2497         */
2498        public String getDebugLoadedEntities()
2499        {
2500            return "All: " + this.loadedEntityList.size();
2501        }
2502    
2503        @SideOnly(Side.CLIENT)
2504    
2505        /**
2506         * Returns the name of the current chunk provider, by calling chunkprovider.makeString()
2507         */
2508        public String getProviderName()
2509        {
2510            return this.chunkProvider.makeString();
2511        }
2512    
2513        /**
2514         * Returns the TileEntity associated with a given block in X,Y,Z coordinates, or null if no TileEntity exists
2515         */
2516        public TileEntity getBlockTileEntity(int par1, int par2, int par3)
2517        {
2518            if (par2 >= 256)
2519            {
2520                return null;
2521            }
2522            else
2523            {
2524                Chunk var4 = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
2525    
2526                if (var4 == null)
2527                {
2528                    return null;
2529                }
2530                else
2531                {
2532                    TileEntity var5 = var4.getChunkBlockTileEntity(par1 & 15, par2, par3 & 15);
2533    
2534                    if (var5 == null)
2535                    {
2536                        Iterator var6 = this.addedTileEntityList.iterator();
2537    
2538                        while (var6.hasNext())
2539                        {
2540                            TileEntity var7 = (TileEntity)var6.next();
2541    
2542                            if (!var7.isInvalid() && var7.xCoord == par1 && var7.yCoord == par2 && var7.zCoord == par3)
2543                            {
2544                                var5 = var7;
2545                                break;
2546                            }
2547                        }
2548                    }
2549    
2550                    return var5;
2551                }
2552            }
2553        }
2554    
2555        /**
2556         * Sets the TileEntity for a given block in X, Y, Z coordinates
2557         */
2558        public void setBlockTileEntity(int par1, int par2, int par3, TileEntity par4TileEntity)
2559        {
2560            if (par4TileEntity == null || par4TileEntity.isInvalid())
2561            {
2562                return;
2563            }
2564    
2565            if (par4TileEntity.canUpdate())
2566            {
2567                List dest = scanningTileEntities ? addedTileEntityList : loadedTileEntityList;
2568                dest.add(par4TileEntity);
2569            }
2570    
2571            Chunk chunk = getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
2572            if (chunk != null)
2573            {
2574                chunk.setChunkBlockTileEntity(par1 & 15, par2, par3 & 15, par4TileEntity);
2575            }
2576        }
2577    
2578        /**
2579         * Removes the TileEntity for a given block in X,Y,Z coordinates
2580         */
2581        public void removeBlockTileEntity(int par1, int par2, int par3)
2582        {
2583            Chunk chunk = getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
2584            if (chunk != null)
2585            {
2586                chunk.removeChunkBlockTileEntity(par1 & 15, par2, par3 & 15);
2587            }
2588        }
2589    
2590        /**
2591         * adds tile entity to despawn list (renamed from markEntityForDespawn)
2592         */
2593        public void markTileEntityForDespawn(TileEntity par1TileEntity)
2594        {
2595            this.entityRemoval.add(par1TileEntity);
2596        }
2597    
2598        /**
2599         * Returns true if the block at the specified coordinates is an opaque cube. Args: x, y, z
2600         */
2601        public boolean isBlockOpaqueCube(int par1, int par2, int par3)
2602        {
2603            Block var4 = Block.blocksList[this.getBlockId(par1, par2, par3)];
2604            return var4 == null ? false : var4.isOpaqueCube();
2605        }
2606    
2607        /**
2608         * Indicate if a material is a normal solid opaque cube.
2609         */
2610        public boolean isBlockNormalCube(int par1, int par2, int par3)
2611        {
2612            Block block = Block.blocksList[getBlockId(par1, par2, par3)];
2613            return block != null && block.isBlockNormalCube(this, par1, par2, par3);
2614        }
2615    
2616        /**
2617         * Returns true if the block at the given coordinate has a solid (buildable) top surface.
2618         */
2619        public boolean doesBlockHaveSolidTopSurface(int par1, int par2, int par3)
2620        {
2621            return isBlockSolidOnSide(par1, par2, par3, ForgeDirection.UP);
2622        }
2623    
2624        /**
2625         * Checks if the block is a solid, normal cube. If the chunk does not exist, or is not loaded, it returns the
2626         * boolean parameter.
2627         */
2628        public boolean isBlockNormalCubeDefault(int par1, int par2, int par3, boolean par4)
2629        {
2630            if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000)
2631            {
2632                Chunk var5 = this.chunkProvider.provideChunk(par1 >> 4, par3 >> 4);
2633    
2634                if (var5 != null && !var5.isEmpty())
2635                {
2636                    Block var6 = Block.blocksList[this.getBlockId(par1, par2, par3)];
2637                    return var6 == null ? false : isBlockNormalCube(par1, par2, par3);
2638                }
2639                else
2640                {
2641                    return par4;
2642                }
2643            }
2644            else
2645            {
2646                return par4;
2647            }
2648        }
2649    
2650        /**
2651         * Called on construction of the World class to setup the initial skylight values
2652         */
2653        public void calculateInitialSkylight()
2654        {
2655            int var1 = this.calculateSkylightSubtracted(1.0F);
2656    
2657            if (var1 != this.skylightSubtracted)
2658            {
2659                this.skylightSubtracted = var1;
2660            }
2661        }
2662    
2663        /**
2664         * Set which types of mobs are allowed to spawn (peaceful vs hostile).
2665         */
2666        public void setAllowedSpawnTypes(boolean par1, boolean par2)
2667        {
2668            this.spawnHostileMobs = par1;
2669            this.spawnPeacefulMobs = par2;
2670        }
2671    
2672        /**
2673         * Runs a single tick for the world
2674         */
2675        public void tick()
2676        {
2677            this.updateWeather();
2678        }
2679    
2680        /**
2681         * Called from World constructor to set rainingStrength and thunderingStrength
2682         */
2683        private void calculateInitialWeather()
2684        {
2685            if (this.worldInfo.isRaining())
2686            {
2687                this.rainingStrength = 1.0F;
2688    
2689                if (this.worldInfo.isThundering())
2690                {
2691                    this.thunderingStrength = 1.0F;
2692                }
2693            }
2694        }
2695    
2696        /**
2697         * Updates all weather states.
2698         */
2699        protected void updateWeather()
2700        {
2701            if (!this.provider.hasNoSky)
2702            {
2703                if (this.lastLightningBolt > 0)
2704                {
2705                    --this.lastLightningBolt;
2706                }
2707    
2708                int var1 = this.worldInfo.getThunderTime();
2709    
2710                if (var1 <= 0)
2711                {
2712                    if (this.worldInfo.isThundering())
2713                    {
2714                        this.worldInfo.setThunderTime(this.rand.nextInt(12000) + 3600);
2715                    }
2716                    else
2717                    {
2718                        this.worldInfo.setThunderTime(this.rand.nextInt(168000) + 12000);
2719                    }
2720                }
2721                else
2722                {
2723                    --var1;
2724                    this.worldInfo.setThunderTime(var1);
2725    
2726                    if (var1 <= 0)
2727                    {
2728                        this.worldInfo.setThundering(!this.worldInfo.isThundering());
2729                    }
2730                }
2731    
2732                int var2 = this.worldInfo.getRainTime();
2733    
2734                if (var2 <= 0)
2735                {
2736                    if (this.worldInfo.isRaining())
2737                    {
2738                        this.worldInfo.setRainTime(this.rand.nextInt(12000) + 12000);
2739                    }
2740                    else
2741                    {
2742                        this.worldInfo.setRainTime(this.rand.nextInt(168000) + 12000);
2743                    }
2744                }
2745                else
2746                {
2747                    --var2;
2748                    this.worldInfo.setRainTime(var2);
2749    
2750                    if (var2 <= 0)
2751                    {
2752                        this.worldInfo.setRaining(!this.worldInfo.isRaining());
2753                    }
2754                }
2755    
2756                this.prevRainingStrength = this.rainingStrength;
2757    
2758                if (this.worldInfo.isRaining())
2759                {
2760                    this.rainingStrength = (float)((double)this.rainingStrength + 0.01D);
2761                }
2762                else
2763                {
2764                    this.rainingStrength = (float)((double)this.rainingStrength - 0.01D);
2765                }
2766    
2767                if (this.rainingStrength < 0.0F)
2768                {
2769                    this.rainingStrength = 0.0F;
2770                }
2771    
2772                if (this.rainingStrength > 1.0F)
2773                {
2774                    this.rainingStrength = 1.0F;
2775                }
2776    
2777                this.prevThunderingStrength = this.thunderingStrength;
2778    
2779                if (this.worldInfo.isThundering())
2780                {
2781                    this.thunderingStrength = (float)((double)this.thunderingStrength + 0.01D);
2782                }
2783                else
2784                {
2785                    this.thunderingStrength = (float)((double)this.thunderingStrength - 0.01D);
2786                }
2787    
2788                if (this.thunderingStrength < 0.0F)
2789                {
2790                    this.thunderingStrength = 0.0F;
2791                }
2792    
2793                if (this.thunderingStrength > 1.0F)
2794                {
2795                    this.thunderingStrength = 1.0F;
2796                }
2797            }
2798        }
2799    
2800        public void toggleRain()
2801        {
2802            this.worldInfo.setRainTime(1);
2803        }
2804    
2805        protected void setActivePlayerChunksAndCheckLight()
2806        {
2807            this.activeChunkSet.clear();
2808            this.theProfiler.startSection("buildList");
2809            int var1;
2810            EntityPlayer var2;
2811            int var3;
2812            int var4;
2813    
2814            for (var1 = 0; var1 < this.playerEntities.size(); ++var1)
2815            {
2816                var2 = (EntityPlayer)this.playerEntities.get(var1);
2817                var3 = MathHelper.floor_double(var2.posX / 16.0D);
2818                var4 = MathHelper.floor_double(var2.posZ / 16.0D);
2819                byte var5 = 7;
2820    
2821                for (int var6 = -var5; var6 <= var5; ++var6)
2822                {
2823                    for (int var7 = -var5; var7 <= var5; ++var7)
2824                    {
2825                        this.activeChunkSet.add(new ChunkCoordIntPair(var6 + var3, var7 + var4));
2826                    }
2827                }
2828            }
2829    
2830            this.theProfiler.endSection();
2831    
2832            if (this.ambientTickCountdown > 0)
2833            {
2834                --this.ambientTickCountdown;
2835            }
2836    
2837            this.theProfiler.startSection("playerCheckLight");
2838    
2839            if (!this.playerEntities.isEmpty())
2840            {
2841                var1 = this.rand.nextInt(this.playerEntities.size());
2842                var2 = (EntityPlayer)this.playerEntities.get(var1);
2843                var3 = MathHelper.floor_double(var2.posX) + this.rand.nextInt(11) - 5;
2844                var4 = MathHelper.floor_double(var2.posY) + this.rand.nextInt(11) - 5;
2845                int var8 = MathHelper.floor_double(var2.posZ) + this.rand.nextInt(11) - 5;
2846                this.updateAllLightTypes(var3, var4, var8);
2847            }
2848    
2849            this.theProfiler.endSection();
2850        }
2851    
2852        protected void moodSoundAndLightCheck(int par1, int par2, Chunk par3Chunk)
2853        {
2854            this.theProfiler.endStartSection("moodSound");
2855    
2856            if (this.ambientTickCountdown == 0)
2857            {
2858                this.updateLCG = this.updateLCG * 3 + 1013904223;
2859                int var4 = this.updateLCG >> 2;
2860                int var5 = var4 & 15;
2861                int var6 = var4 >> 8 & 15;
2862                int var7 = var4 >> 16 & 127;
2863                int var8 = par3Chunk.getBlockID(var5, var7, var6);
2864                var5 += par1;
2865                var6 += par2;
2866    
2867                if (var8 == 0 && this.getFullBlockLightValue(var5, var7, var6) <= this.rand.nextInt(8) && this.getSavedLightValue(EnumSkyBlock.Sky, var5, var7, var6) <= 0)
2868                {
2869                    EntityPlayer var9 = this.getClosestPlayer((double)var5 + 0.5D, (double)var7 + 0.5D, (double)var6 + 0.5D, 8.0D);
2870    
2871                    if (var9 != null && var9.getDistanceSq((double)var5 + 0.5D, (double)var7 + 0.5D, (double)var6 + 0.5D) > 4.0D)
2872                    {
2873                        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);
2874                        this.ambientTickCountdown = this.rand.nextInt(12000) + 6000;
2875                    }
2876                }
2877            }
2878    
2879            this.theProfiler.endStartSection("checkLight");
2880            par3Chunk.enqueueRelightChecks();
2881        }
2882    
2883        /**
2884         * plays random cave ambient sounds and runs updateTick on random blocks within each chunk in the vacinity of a
2885         * player
2886         */
2887        protected void tickBlocksAndAmbiance()
2888        {
2889            this.setActivePlayerChunksAndCheckLight();
2890        }
2891    
2892        /**
2893         * checks to see if a given block is both water and is cold enough to freeze
2894         */
2895        public boolean isBlockFreezable(int par1, int par2, int par3)
2896        {
2897            return this.canBlockFreeze(par1, par2, par3, false);
2898        }
2899    
2900        /**
2901         * checks to see if a given block is both water and has at least one immediately adjacent non-water block
2902         */
2903        public boolean isBlockFreezableNaturally(int par1, int par2, int par3)
2904        {
2905            return this.canBlockFreeze(par1, par2, par3, true);
2906        }
2907    
2908        /**
2909         * checks to see if a given block is both water, and cold enough to freeze - if the par4 boolean is set, this will
2910         * only return true if there is a non-water block immediately adjacent to the specified block
2911         */
2912        public boolean canBlockFreeze(int par1, int par2, int par3, boolean par4)
2913        {
2914            BiomeGenBase var5 = this.getBiomeGenForCoords(par1, par3);
2915            float var6 = var5.getFloatTemperature();
2916    
2917            if (var6 > 0.15F)
2918            {
2919                return false;
2920            }
2921            else
2922            {
2923                if (par2 >= 0 && par2 < 256 && this.getSavedLightValue(EnumSkyBlock.Block, par1, par2, par3) < 10)
2924                {
2925                    int var7 = this.getBlockId(par1, par2, par3);
2926    
2927                    if ((var7 == Block.waterStill.blockID || var7 == Block.waterMoving.blockID) && this.getBlockMetadata(par1, par2, par3) == 0)
2928                    {
2929                        if (!par4)
2930                        {
2931                            return true;
2932                        }
2933    
2934                        boolean var8 = true;
2935    
2936                        if (var8 && this.getBlockMaterial(par1 - 1, par2, par3) != Material.water)
2937                        {
2938                            var8 = false;
2939                        }
2940    
2941                        if (var8 && this.getBlockMaterial(par1 + 1, par2, par3) != Material.water)
2942                        {
2943                            var8 = false;
2944                        }
2945    
2946                        if (var8 && this.getBlockMaterial(par1, par2, par3 - 1) != Material.water)
2947                        {
2948                            var8 = false;
2949                        }
2950    
2951                        if (var8 && this.getBlockMaterial(par1, par2, par3 + 1) != Material.water)
2952                        {
2953                            var8 = false;
2954                        }
2955    
2956                        if (!var8)
2957                        {
2958                            return true;
2959                        }
2960                    }
2961                }
2962    
2963                return false;
2964            }
2965        }
2966    
2967        /**
2968         * Tests whether or not snow can be placed at a given location
2969         */
2970        public boolean canSnowAt(int par1, int par2, int par3)
2971        {
2972            BiomeGenBase var4 = this.getBiomeGenForCoords(par1, par3);
2973            float var5 = var4.getFloatTemperature();
2974    
2975            if (var5 > 0.15F)
2976            {
2977                return false;
2978            }
2979            else
2980            {
2981                if (par2 >= 0 && par2 < 256 && this.getSavedLightValue(EnumSkyBlock.Block, par1, par2, par3) < 10)
2982                {
2983                    int var6 = this.getBlockId(par1, par2 - 1, par3);
2984                    int var7 = this.getBlockId(par1, par2, par3);
2985    
2986                    if (var7 == 0 && Block.snow.canPlaceBlockAt(this, par1, par2, par3) && var6 != 0 && var6 != Block.ice.blockID && Block.blocksList[var6].blockMaterial.blocksMovement())
2987                    {
2988                        return true;
2989                    }
2990                }
2991    
2992                return false;
2993            }
2994        }
2995    
2996        public void updateAllLightTypes(int par1, int par2, int par3)
2997        {
2998            if (!this.provider.hasNoSky)
2999            {
3000                this.updateLightByType(EnumSkyBlock.Sky, par1, par2, par3);
3001            }
3002    
3003            this.updateLightByType(EnumSkyBlock.Block, par1, par2, par3);
3004        }
3005    
3006        private int computeSkyLightValue(int par1, int par2, int par3, int par4, int par5, int par6)
3007        {
3008            int var7 = 0;
3009    
3010            if (this.canBlockSeeTheSky(par2, par3, par4))
3011            {
3012                var7 = 15;
3013            }
3014            else
3015            {
3016                if (par6 == 0)
3017                {
3018                    par6 = 1;
3019                }
3020    
3021                int var8 = this.getSavedLightValue(EnumSkyBlock.Sky, par2 - 1, par3, par4) - par6;
3022                int var9 = this.getSavedLightValue(EnumSkyBlock.Sky, par2 + 1, par3, par4) - par6;
3023                int var10 = this.getSavedLightValue(EnumSkyBlock.Sky, par2, par3 - 1, par4) - par6;
3024                int var11 = this.getSavedLightValue(EnumSkyBlock.Sky, par2, par3 + 1, par4) - par6;
3025                int var12 = this.getSavedLightValue(EnumSkyBlock.Sky, par2, par3, par4 - 1) - par6;
3026                int var13 = this.getSavedLightValue(EnumSkyBlock.Sky, par2, par3, par4 + 1) - par6;
3027    
3028                if (var8 > var7)
3029                {
3030                    var7 = var8;
3031                }
3032    
3033                if (var9 > var7)
3034                {
3035                    var7 = var9;
3036                }
3037    
3038                if (var10 > var7)
3039                {
3040                    var7 = var10;
3041                }
3042    
3043                if (var11 > var7)
3044                {
3045                    var7 = var11;
3046                }
3047    
3048                if (var12 > var7)
3049                {
3050                    var7 = var12;
3051                }
3052    
3053                if (var13 > var7)
3054                {
3055                    var7 = var13;
3056                }
3057            }
3058    
3059            return var7;
3060        }
3061    
3062        private int computeBlockLightValue(int par1, int par2, int par3, int par4, int par5, int par6)
3063        {
3064            int var7 = (par5 == 0 || Block.blocksList[par5] == null ? 0 : Block.blocksList[par5].getLightValue(this, par2, par3, par4));
3065            int var8 = this.getSavedLightValue(EnumSkyBlock.Block, par2 - 1, par3, par4) - par6;
3066            int var9 = this.getSavedLightValue(EnumSkyBlock.Block, par2 + 1, par3, par4) - par6;
3067            int var10 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3 - 1, par4) - par6;
3068            int var11 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3 + 1, par4) - par6;
3069            int var12 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3, par4 - 1) - par6;
3070            int var13 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3, par4 + 1) - par6;
3071    
3072            if (var8 > var7)
3073            {
3074                var7 = var8;
3075            }
3076    
3077            if (var9 > var7)
3078            {
3079                var7 = var9;
3080            }
3081    
3082            if (var10 > var7)
3083            {
3084                var7 = var10;
3085            }
3086    
3087            if (var11 > var7)
3088            {
3089                var7 = var11;
3090            }
3091    
3092            if (var12 > var7)
3093            {
3094                var7 = var12;
3095            }
3096    
3097            if (var13 > var7)
3098            {
3099                var7 = var13;
3100            }
3101    
3102            return var7;
3103        }
3104    
3105        public void updateLightByType(EnumSkyBlock par1EnumSkyBlock, int par2, int par3, int par4)
3106        {
3107            if (this.doChunksNearChunkExist(par2, par3, par4, 17))
3108            {
3109                int var5 = 0;
3110                int var6 = 0;
3111                this.theProfiler.startSection("getBrightness");
3112                int var7 = this.getSavedLightValue(par1EnumSkyBlock, par2, par3, par4);
3113                boolean var8 = false;
3114                int var9 = this.getBlockId(par2, par3, par4);
3115                int var10 = this.getBlockLightOpacity(par2, par3, par4);
3116    
3117                if (var10 == 0)
3118                {
3119                    var10 = 1;
3120                }
3121    
3122                boolean var11 = false;
3123                int var24;
3124    
3125                if (par1EnumSkyBlock == EnumSkyBlock.Sky)
3126                {
3127                    var24 = this.computeSkyLightValue(var7, par2, par3, par4, var9, var10);
3128                }
3129                else
3130                {
3131                    var24 = this.computeBlockLightValue(var7, par2, par3, par4, var9, var10);
3132                }
3133    
3134                int var12;
3135                int var13;
3136                int var14;
3137                int var15;
3138                int var17;
3139                int var16;
3140                int var19;
3141                int var18;
3142    
3143                if (var24 > var7)
3144                {
3145                    this.lightUpdateBlockList[var6++] = 133152;
3146                }
3147                else if (var24 < var7)
3148                {
3149                    if (par1EnumSkyBlock != EnumSkyBlock.Block)
3150                    {
3151                        ;
3152                    }
3153    
3154                    this.lightUpdateBlockList[var6++] = 133152 + (var7 << 18);
3155    
3156                    while (var5 < var6)
3157                    {
3158                        var9 = this.lightUpdateBlockList[var5++];
3159                        var10 = (var9 & 63) - 32 + par2;
3160                        var24 = (var9 >> 6 & 63) - 32 + par3;
3161                        var12 = (var9 >> 12 & 63) - 32 + par4;
3162                        var13 = var9 >> 18 & 15;
3163                        var14 = this.getSavedLightValue(par1EnumSkyBlock, var10, var24, var12);
3164    
3165                        if (var14 == var13)
3166                        {
3167                            this.setLightValue(par1EnumSkyBlock, var10, var24, var12, 0);
3168    
3169                            if (var13 > 0)
3170                            {
3171                                var15 = var10 - par2;
3172                                var16 = var24 - par3;
3173                                var17 = var12 - par4;
3174    
3175                                if (var15 < 0)
3176                                {
3177                                    var15 = -var15;
3178                                }
3179    
3180                                if (var16 < 0)
3181                                {
3182                                    var16 = -var16;
3183                                }
3184    
3185                                if (var17 < 0)
3186                                {
3187                                    var17 = -var17;
3188                                }
3189    
3190                                if (var15 + var16 + var17 < 17)
3191                                {
3192                                    for (var18 = 0; var18 < 6; ++var18)
3193                                    {
3194                                        var19 = var18 % 2 * 2 - 1;
3195                                        int var20 = var10 + var18 / 2 % 3 / 2 * var19;
3196                                        int var21 = var24 + (var18 / 2 + 1) % 3 / 2 * var19;
3197                                        int var22 = var12 + (var18 / 2 + 2) % 3 / 2 * var19;
3198                                        var14 = this.getSavedLightValue(par1EnumSkyBlock, var20, var21, var22);
3199                                        int var23 = Block.lightOpacity[this.getBlockId(var20, var21, var22)];
3200    
3201                                        if (var23 == 0)
3202                                        {
3203                                            var23 = 1;
3204                                        }
3205    
3206                                        if (var14 == var13 - var23 && var6 < this.lightUpdateBlockList.length)
3207                                        {
3208                                            this.lightUpdateBlockList[var6++] = var20 - par2 + 32 + (var21 - par3 + 32 << 6) + (var22 - par4 + 32 << 12) + (var13 - var23 << 18);
3209                                        }
3210                                    }
3211                                }
3212                            }
3213                        }
3214                    }
3215    
3216                    var5 = 0;
3217                }
3218    
3219                this.theProfiler.endSection();
3220                this.theProfiler.startSection("tcp < tcc");
3221    
3222                while (var5 < var6)
3223                {
3224                    var9 = this.lightUpdateBlockList[var5++];
3225                    var10 = (var9 & 63) - 32 + par2;
3226                    var24 = (var9 >> 6 & 63) - 32 + par3;
3227                    var12 = (var9 >> 12 & 63) - 32 + par4;
3228                    var13 = this.getSavedLightValue(par1EnumSkyBlock, var10, var24, var12);
3229                    var14 = this.getBlockId(var10, var24, var12);
3230                    var15 = Block.lightOpacity[var14];
3231    
3232                    if (var15 == 0)
3233                    {
3234                        var15 = 1;
3235                    }
3236    
3237                    boolean var25 = false;
3238    
3239                    if (par1EnumSkyBlock == EnumSkyBlock.Sky)
3240                    {
3241                        var16 = this.computeSkyLightValue(var13, var10, var24, var12, var14, var15);
3242                    }
3243                    else
3244                    {
3245                        var16 = this.computeBlockLightValue(var13, var10, var24, var12, var14, var15);
3246                    }
3247    
3248                    if (var16 != var13)
3249                    {
3250                        this.setLightValue(par1EnumSkyBlock, var10, var24, var12, var16);
3251    
3252                        if (var16 > var13)
3253                        {
3254                            var17 = var10 - par2;
3255                            var18 = var24 - par3;
3256                            var19 = var12 - par4;
3257    
3258                            if (var17 < 0)
3259                            {
3260                                var17 = -var17;
3261                            }
3262    
3263                            if (var18 < 0)
3264                            {
3265                                var18 = -var18;
3266                            }
3267    
3268                            if (var19 < 0)
3269                            {
3270                                var19 = -var19;
3271                            }
3272    
3273                            if (var17 + var18 + var19 < 17 && var6 < this.lightUpdateBlockList.length - 6)
3274                            {
3275                                if (this.getSavedLightValue(par1EnumSkyBlock, var10 - 1, var24, var12) < var16)
3276                                {
3277                                    this.lightUpdateBlockList[var6++] = var10 - 1 - par2 + 32 + (var24 - par3 + 32 << 6) + (var12 - par4 + 32 << 12);
3278                                }
3279    
3280                                if (this.getSavedLightValue(par1EnumSkyBlock, var10 + 1, var24, var12) < var16)
3281                                {
3282                                    this.lightUpdateBlockList[var6++] = var10 + 1 - par2 + 32 + (var24 - par3 + 32 << 6) + (var12 - par4 + 32 << 12);
3283                                }
3284    
3285                                if (this.getSavedLightValue(par1EnumSkyBlock, var10, var24 - 1, var12) < var16)
3286                                {
3287                                    this.lightUpdateBlockList[var6++] = var10 - par2 + 32 + (var24 - 1 - par3 + 32 << 6) + (var12 - par4 + 32 << 12);
3288                                }
3289    
3290                                if (this.getSavedLightValue(par1EnumSkyBlock, var10, var24 + 1, var12) < var16)
3291                                {
3292                                    this.lightUpdateBlockList[var6++] = var10 - par2 + 32 + (var24 + 1 - par3 + 32 << 6) + (var12 - par4 + 32 << 12);
3293                                }
3294    
3295                                if (this.getSavedLightValue(par1EnumSkyBlock, var10, var24, var12 - 1) < var16)
3296                                {
3297                                    this.lightUpdateBlockList[var6++] = var10 - par2 + 32 + (var24 - par3 + 32 << 6) + (var12 - 1 - par4 + 32 << 12);
3298                                }
3299    
3300                                if (this.getSavedLightValue(par1EnumSkyBlock, var10, var24, var12 + 1) < var16)
3301                                {
3302                                    this.lightUpdateBlockList[var6++] = var10 - par2 + 32 + (var24 - par3 + 32 << 6) + (var12 + 1 - par4 + 32 << 12);
3303                                }
3304                            }
3305                        }
3306                    }
3307                }
3308    
3309                this.theProfiler.endSection();
3310            }
3311        }
3312    
3313        /**
3314         * Runs through the list of updates to run and ticks them
3315         */
3316        public boolean tickUpdates(boolean par1)
3317        {
3318            return false;
3319        }
3320    
3321        public List getPendingBlockUpdates(Chunk par1Chunk, boolean par2)
3322        {
3323            return null;
3324        }
3325    
3326        /**
3327         * Will get all entities within the specified AABB excluding the one passed into it. Args: entityToExclude, aabb
3328         */
3329        public List getEntitiesWithinAABBExcludingEntity(Entity par1Entity, AxisAlignedBB par2AxisAlignedBB)
3330        {
3331            this.entitiesWithinAABBExcludingEntity.clear();
3332            int var3 = MathHelper.floor_double((par2AxisAlignedBB.minX - MAX_ENTITY_RADIUS) / 16.0D);
3333            int var4 = MathHelper.floor_double((par2AxisAlignedBB.maxX + MAX_ENTITY_RADIUS) / 16.0D);
3334            int var5 = MathHelper.floor_double((par2AxisAlignedBB.minZ - MAX_ENTITY_RADIUS) / 16.0D);
3335            int var6 = MathHelper.floor_double((par2AxisAlignedBB.maxZ + MAX_ENTITY_RADIUS) / 16.0D);
3336    
3337            for (int var7 = var3; var7 <= var4; ++var7)
3338            {
3339                for (int var8 = var5; var8 <= var6; ++var8)
3340                {
3341                    if (this.chunkExists(var7, var8))
3342                    {
3343                        this.getChunkFromChunkCoords(var7, var8).getEntitiesWithinAABBForEntity(par1Entity, par2AxisAlignedBB, this.entitiesWithinAABBExcludingEntity);
3344                    }
3345                }
3346            }
3347    
3348            return this.entitiesWithinAABBExcludingEntity;
3349        }
3350    
3351        /**
3352         * Returns all entities of the specified class type which intersect with the AABB. Args: entityClass, aabb
3353         */
3354        public List getEntitiesWithinAABB(Class par1Class, AxisAlignedBB par2AxisAlignedBB)
3355        {
3356            int var3 = MathHelper.floor_double((par2AxisAlignedBB.minX - MAX_ENTITY_RADIUS) / 16.0D);
3357            int var4 = MathHelper.floor_double((par2AxisAlignedBB.maxX + MAX_ENTITY_RADIUS) / 16.0D);
3358            int var5 = MathHelper.floor_double((par2AxisAlignedBB.minZ - MAX_ENTITY_RADIUS) / 16.0D);
3359            int var6 = MathHelper.floor_double((par2AxisAlignedBB.maxZ + MAX_ENTITY_RADIUS) / 16.0D);
3360            ArrayList var7 = new ArrayList();
3361    
3362            for (int var8 = var3; var8 <= var4; ++var8)
3363            {
3364                for (int var9 = var5; var9 <= var6; ++var9)
3365                {
3366                    if (this.chunkExists(var8, var9))
3367                    {
3368                        this.getChunkFromChunkCoords(var8, var9).getEntitiesOfTypeWithinAAAB(par1Class, par2AxisAlignedBB, var7);
3369                    }
3370                }
3371            }
3372    
3373            return var7;
3374        }
3375    
3376        public Entity findNearestEntityWithinAABB(Class par1Class, AxisAlignedBB par2AxisAlignedBB, Entity par3Entity)
3377        {
3378            List var4 = this.getEntitiesWithinAABB(par1Class, par2AxisAlignedBB);
3379            Entity var5 = null;
3380            double var6 = Double.MAX_VALUE;
3381            Iterator var8 = var4.iterator();
3382    
3383            while (var8.hasNext())
3384            {
3385                Entity var9 = (Entity)var8.next();
3386    
3387                if (var9 != par3Entity)
3388                {
3389                    double var10 = par3Entity.getDistanceSqToEntity(var9);
3390    
3391                    if (var10 <= var6)
3392                    {
3393                        var5 = var9;
3394                        var6 = var10;
3395                    }
3396                }
3397            }
3398    
3399            return var5;
3400        }
3401    
3402        @SideOnly(Side.CLIENT)
3403    
3404        /**
3405         * Accessor for world Loaded Entity List
3406         */
3407        public List getLoadedEntityList()
3408        {
3409            return this.loadedEntityList;
3410        }
3411    
3412        /**
3413         * marks the chunk that contains this tilentity as modified and then calls worldAccesses.doNothingWithTileEntity
3414         */
3415        public void updateTileEntityChunkAndDoNothing(int par1, int par2, int par3, TileEntity par4TileEntity)
3416        {
3417            if (this.blockExists(par1, par2, par3))
3418            {
3419                this.getChunkFromBlockCoords(par1, par3).setChunkModified();
3420            }
3421        }
3422    
3423        /**
3424         * Counts how many entities of an entity class exist in the world. Args: entityClass
3425         */
3426        public int countEntities(Class par1Class)
3427        {
3428            int var2 = 0;
3429    
3430            for (int var3 = 0; var3 < this.loadedEntityList.size(); ++var3)
3431            {
3432                Entity var4 = (Entity)this.loadedEntityList.get(var3);
3433    
3434                if (par1Class.isAssignableFrom(var4.getClass()))
3435                {
3436                    ++var2;
3437                }
3438            }
3439    
3440            return var2;
3441        }
3442    
3443        /**
3444         * adds entities to the loaded entities list, and loads thier skins.
3445         */
3446        public void addLoadedEntities(List par1List)
3447        {
3448            for (int var2 = 0; var2 < par1List.size(); ++var2)
3449            {
3450                Entity entity = (Entity)par1List.get(var2);
3451                if (!MinecraftForge.EVENT_BUS.post(new EntityJoinWorldEvent(entity, this)))
3452                {
3453                    loadedEntityList.add(entity);
3454                    this.obtainEntitySkin(entity);
3455                }
3456            }
3457        }
3458    
3459        /**
3460         * Adds a list of entities to be unloaded on the next pass of World.updateEntities()
3461         */
3462        public void unloadEntities(List par1List)
3463        {
3464            this.unloadedEntityList.addAll(par1List);
3465        }
3466    
3467        /**
3468         * Returns true if the given Entity can be placed on the given side of the given block position.
3469         */
3470        public boolean canPlaceEntityOnSide(int par1, int par2, int par3, int par4, boolean par5, int par6, Entity par7Entity)
3471        {
3472            int var8 = this.getBlockId(par2, par3, par4);
3473            Block var9 = Block.blocksList[var8];
3474            Block var10 = Block.blocksList[par1];
3475            AxisAlignedBB var11 = var10.getCollisionBoundingBoxFromPool(this, par2, par3, par4);
3476    
3477            if (par5)
3478            {
3479                var11 = null;
3480            }
3481    
3482            if (var11 != null && !this.checkIfAABBIsClearExcludingEntity(var11, par7Entity))
3483            {
3484                return false;
3485            }
3486            else
3487            {
3488                if (var9 != null && (var9 == Block.waterMoving || var9 == Block.waterStill || var9 == Block.lavaMoving || var9 == Block.lavaStill || var9 == Block.fire || var9.blockMaterial.isGroundCover()))
3489                {
3490                    var9 = null;
3491                }
3492                if (var9 != null && var9.isBlockReplaceable(this, par2, par3, par4))
3493                {
3494                    var9 = null;
3495                }
3496                return par1 > 0 && var9 == null && var10.canPlaceBlockOnSide(this, par2, par3, par4, par6);
3497            }
3498        }
3499    
3500        public PathEntity getPathEntityToEntity(Entity par1Entity, Entity par2Entity, float par3, boolean par4, boolean par5, boolean par6, boolean par7)
3501        {
3502            this.theProfiler.startSection("pathfind");
3503            int var8 = MathHelper.floor_double(par1Entity.posX);
3504            int var9 = MathHelper.floor_double(par1Entity.posY + 1.0D);
3505            int var10 = MathHelper.floor_double(par1Entity.posZ);
3506            int var11 = (int)(par3 + 16.0F);
3507            int var12 = var8 - var11;
3508            int var13 = var9 - var11;
3509            int var14 = var10 - var11;
3510            int var15 = var8 + var11;
3511            int var16 = var9 + var11;
3512            int var17 = var10 + var11;
3513            ChunkCache var18 = new ChunkCache(this, var12, var13, var14, var15, var16, var17);
3514            PathEntity var19 = (new PathFinder(var18, par4, par5, par6, par7)).createEntityPathTo(par1Entity, par2Entity, par3);
3515            this.theProfiler.endSection();
3516            return var19;
3517        }
3518    
3519        public PathEntity getEntityPathToXYZ(Entity par1Entity, int par2, int par3, int par4, float par5, boolean par6, boolean par7, boolean par8, boolean par9)
3520        {
3521            this.theProfiler.startSection("pathfind");
3522            int var10 = MathHelper.floor_double(par1Entity.posX);
3523            int var11 = MathHelper.floor_double(par1Entity.posY);
3524            int var12 = MathHelper.floor_double(par1Entity.posZ);
3525            int var13 = (int)(par5 + 8.0F);
3526            int var14 = var10 - var13;
3527            int var15 = var11 - var13;
3528            int var16 = var12 - var13;
3529            int var17 = var10 + var13;
3530            int var18 = var11 + var13;
3531            int var19 = var12 + var13;
3532            ChunkCache var20 = new ChunkCache(this, var14, var15, var16, var17, var18, var19);
3533            PathEntity var21 = (new PathFinder(var20, par6, par7, par8, par9)).createEntityPathTo(par1Entity, par2, par3, par4, par5);
3534            this.theProfiler.endSection();
3535            return var21;
3536        }
3537    
3538        /**
3539         * Is this block powering in the specified direction Args: x, y, z, direction
3540         */
3541        public boolean isBlockProvidingPowerTo(int par1, int par2, int par3, int par4)
3542        {
3543            int var5 = this.getBlockId(par1, par2, par3);
3544            return var5 == 0 ? false : Block.blocksList[var5].isIndirectlyPoweringTo(this, par1, par2, par3, par4);
3545        }
3546    
3547        /**
3548         * Whether one of the neighboring blocks is putting power into this block. Args: x, y, z
3549         */
3550        public boolean isBlockGettingPowered(int par1, int par2, int par3)
3551        {
3552            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)))));
3553        }
3554    
3555        /**
3556         * Is a block next to you getting powered (if its an attachable block) or is it providing power directly to you.
3557         * Args: x, y, z, direction
3558         */
3559        public boolean isBlockIndirectlyProvidingPowerTo(int par1, int par2, int par3, int par4)
3560        {
3561            if (this.isBlockNormalCube(par1, par2, par3))
3562            {
3563                return this.isBlockGettingPowered(par1, par2, par3);
3564            }
3565            else
3566            {
3567                int var5 = this.getBlockId(par1, par2, par3);
3568                return var5 == 0 ? false : Block.blocksList[var5].isPoweringTo(this, par1, par2, par3, par4);
3569            }
3570        }
3571    
3572        /**
3573         * Used to see if one of the blocks next to you or your block is getting power from a neighboring block. Used by
3574         * items like TNT or Doors so they don't have redstone going straight into them.  Args: x, y, z
3575         */
3576        public boolean isBlockIndirectlyGettingPowered(int par1, int par2, int par3)
3577        {
3578            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)))));
3579        }
3580    
3581        /**
3582         * Gets the closest player to the entity within the specified distance (if distance is less than 0 then ignored).
3583         * Args: entity, dist
3584         */
3585        public EntityPlayer getClosestPlayerToEntity(Entity par1Entity, double par2)
3586        {
3587            return this.getClosestPlayer(par1Entity.posX, par1Entity.posY, par1Entity.posZ, par2);
3588        }
3589    
3590        /**
3591         * Gets the closest player to the point within the specified distance (distance can be set to less than 0 to not
3592         * limit the distance). Args: x, y, z, dist
3593         */
3594        public EntityPlayer getClosestPlayer(double par1, double par3, double par5, double par7)
3595        {
3596            double var9 = -1.0D;
3597            EntityPlayer var11 = null;
3598    
3599            for (int var12 = 0; var12 < this.playerEntities.size(); ++var12)
3600            {
3601                EntityPlayer var13 = (EntityPlayer)this.playerEntities.get(var12);
3602                double var14 = var13.getDistanceSq(par1, par3, par5);
3603    
3604                if ((par7 < 0.0D || var14 < par7 * par7) && (var9 == -1.0D || var14 < var9))
3605                {
3606                    var9 = var14;
3607                    var11 = var13;
3608                }
3609            }
3610    
3611            return var11;
3612        }
3613    
3614        /**
3615         * Returns the closest vulnerable player to this entity within the given radius, or null if none is found
3616         */
3617        public EntityPlayer getClosestVulnerablePlayerToEntity(Entity par1Entity, double par2)
3618        {
3619            return this.getClosestVulnerablePlayer(par1Entity.posX, par1Entity.posY, par1Entity.posZ, par2);
3620        }
3621    
3622        /**
3623         * Returns the closest vulnerable player within the given radius, or null if none is found.
3624         */
3625        public EntityPlayer getClosestVulnerablePlayer(double par1, double par3, double par5, double par7)
3626        {
3627            double var9 = -1.0D;
3628            EntityPlayer var11 = null;
3629    
3630            for (int var12 = 0; var12 < this.playerEntities.size(); ++var12)
3631            {
3632                EntityPlayer var13 = (EntityPlayer)this.playerEntities.get(var12);
3633    
3634                if (!var13.capabilities.disableDamage)
3635                {
3636                    double var14 = var13.getDistanceSq(par1, par3, par5);
3637    
3638                    if ((par7 < 0.0D || var14 < par7 * par7) && (var9 == -1.0D || var14 < var9))
3639                    {
3640                        var9 = var14;
3641                        var11 = var13;
3642                    }
3643                }
3644            }
3645    
3646            return var11;
3647        }
3648    
3649        /**
3650         * Find a player by name in this world.
3651         */
3652        public EntityPlayer getPlayerEntityByName(String par1Str)
3653        {
3654            for (int var2 = 0; var2 < this.playerEntities.size(); ++var2)
3655            {
3656                if (par1Str.equals(((EntityPlayer)this.playerEntities.get(var2)).username))
3657                {
3658                    return (EntityPlayer)this.playerEntities.get(var2);
3659                }
3660            }
3661    
3662            return null;
3663        }
3664    
3665        @SideOnly(Side.CLIENT)
3666    
3667        /**
3668         * If on MP, sends a quitting packet.
3669         */
3670        public void sendQuittingDisconnectingPacket() {}
3671    
3672        /**
3673         * Checks whether the session lock file was modified by another process
3674         */
3675        public void checkSessionLock() throws MinecraftException
3676        {
3677            this.saveHandler.checkSessionLock();
3678        }
3679    
3680        /**
3681         * Sets the world time.
3682         */
3683        public void setWorldTime(long par1)
3684        {
3685            this.worldInfo.setWorldTime(par1);
3686        }
3687    
3688        /**
3689         * Retrieve the world seed from level.dat
3690         */
3691        public long getSeed()
3692        {
3693            return this.worldInfo.getSeed();
3694        }
3695    
3696        public long getWorldTime()
3697        {
3698            return this.worldInfo.getWorldTime();
3699        }
3700    
3701        /**
3702         * Returns the coordinates of the spawn point
3703         */
3704        public ChunkCoordinates getSpawnPoint()
3705        {
3706            return new ChunkCoordinates(this.worldInfo.getSpawnX(), this.worldInfo.getSpawnY(), this.worldInfo.getSpawnZ());
3707        }
3708    
3709        @SideOnly(Side.CLIENT)
3710        public void setSpawnLocation(int par1, int par2, int par3)
3711        {
3712            this.worldInfo.setSpawnPosition(par1, par2, par3);
3713        }
3714    
3715        @SideOnly(Side.CLIENT)
3716    
3717        /**
3718         * spwans an entity and loads surrounding chunks
3719         */
3720        public void joinEntityInSurroundings(Entity par1Entity)
3721        {
3722            int var2 = MathHelper.floor_double(par1Entity.posX / 16.0D);
3723            int var3 = MathHelper.floor_double(par1Entity.posZ / 16.0D);
3724            byte var4 = 2;
3725    
3726            for (int var5 = var2 - var4; var5 <= var2 + var4; ++var5)
3727            {
3728                for (int var6 = var3 - var4; var6 <= var3 + var4; ++var6)
3729                {
3730                    this.getChunkFromChunkCoords(var5, var6);
3731                }
3732            }
3733    
3734            if (!this.loadedEntityList.contains(par1Entity))
3735            {
3736                if (!MinecraftForge.EVENT_BUS.post(new EntityJoinWorldEvent(par1Entity, this)))
3737                {
3738                    loadedEntityList.add(par1Entity);
3739                }
3740            }
3741        }
3742    
3743        /**
3744         * Called when checking if a certain block can be mined or not. The 'spawn safe zone' check is located here.
3745         */
3746        public boolean canMineBlock(EntityPlayer par1EntityPlayer, int par2, int par3, int par4)
3747        {
3748            return true;
3749        }
3750    
3751        /**
3752         * sends a Packet 38 (Entity Status) to all tracked players of that entity
3753         */
3754        public void setEntityState(Entity par1Entity, byte par2) {}
3755    
3756        /**
3757         * gets the IChunkProvider this world uses.
3758         */
3759        public IChunkProvider getChunkProvider()
3760        {
3761            return this.chunkProvider;
3762        }
3763    
3764        /**
3765         * Adds a block event with the given Args to the blockEventCache. During the next tick(), the block specified will
3766         * have its onBlockEvent handler called with the given parameters. Args: X,Y,Z, BlockID, EventID, EventParameter
3767         */
3768        public void addBlockEvent(int par1, int par2, int par3, int par4, int par5, int par6)
3769        {
3770            if (par4 > 0)
3771            {
3772                Block.blocksList[par4].onBlockEventReceived(this, par1, par2, par3, par5, par6);
3773            }
3774        }
3775    
3776        /**
3777         * Returns this world's current save handler
3778         */
3779        public ISaveHandler getSaveHandler()
3780        {
3781            return this.saveHandler;
3782        }
3783    
3784        /**
3785         * Gets the World's WorldInfo instance
3786         */
3787        public WorldInfo getWorldInfo()
3788        {
3789            return this.worldInfo;
3790        }
3791    
3792        /**
3793         * Updates the flag that indicates whether or not all players in the world are sleeping.
3794         */
3795        public void updateAllPlayersSleepingFlag() {}
3796    
3797        public float getWeightedThunderStrength(float par1)
3798        {
3799            return (this.prevThunderingStrength + (this.thunderingStrength - this.prevThunderingStrength) * par1) * this.getRainStrength(par1);
3800        }
3801    
3802        /**
3803         * Not sure about this actually. Reverting this one myself.
3804         */
3805        public float getRainStrength(float par1)
3806        {
3807            return this.prevRainingStrength + (this.rainingStrength - this.prevRainingStrength) * par1;
3808        }
3809    
3810        @SideOnly(Side.CLIENT)
3811        public void setRainStrength(float par1)
3812        {
3813            this.prevRainingStrength = par1;
3814            this.rainingStrength = par1;
3815        }
3816    
3817        /**
3818         * Returns true if the current thunder strength (weighted with the rain strength) is greater than 0.9
3819         */
3820        public boolean isThundering()
3821        {
3822            return (double)this.getWeightedThunderStrength(1.0F) > 0.9D;
3823        }
3824    
3825        /**
3826         * Returns true if the current rain strength is greater than 0.2
3827         */
3828        public boolean isRaining()
3829        {
3830            return (double)this.getRainStrength(1.0F) > 0.2D;
3831        }
3832    
3833        public boolean canLightningStrikeAt(int par1, int par2, int par3)
3834        {
3835            if (!this.isRaining())
3836            {
3837                return false;
3838            }
3839            else if (!this.canBlockSeeTheSky(par1, par2, par3))
3840            {
3841                return false;
3842            }
3843            else if (this.getPrecipitationHeight(par1, par3) > par2)
3844            {
3845                return false;
3846            }
3847            else
3848            {
3849                BiomeGenBase var4 = this.getBiomeGenForCoords(par1, par3);
3850                return var4.getEnableSnow() ? false : var4.canSpawnLightningBolt();
3851            }
3852        }
3853    
3854        /**
3855         * Checks to see if the biome rainfall values for a given x,y,z coordinate set are extremely high
3856         */
3857        public boolean isBlockHighHumidity(int par1, int par2, int par3)
3858        {
3859            BiomeGenBase var4 = this.getBiomeGenForCoords(par1, par3);
3860            return var4.isHighHumidity();
3861        }
3862    
3863        /**
3864         * Assigns the given String id to the given MapDataBase using the MapStorage, removing any existing ones of the same
3865         * id.
3866         */
3867        public void setItemData(String par1Str, WorldSavedData par2WorldSavedData)
3868        {
3869            this.mapStorage.setData(par1Str, par2WorldSavedData);
3870        }
3871    
3872        /**
3873         * Loads an existing MapDataBase corresponding to the given String id from disk using the MapStorage, instantiating
3874         * the given Class, or returns null if none such file exists. args: Class to instantiate, String dataid
3875         */
3876        public WorldSavedData loadItemData(Class par1Class, String par2Str)
3877        {
3878            return this.mapStorage.loadData(par1Class, par2Str);
3879        }
3880    
3881        /**
3882         * Returns an unique new data id from the MapStorage for the given prefix and saves the idCounts map to the
3883         * 'idcounts' file.
3884         */
3885        public int getUniqueDataId(String par1Str)
3886        {
3887            return this.mapStorage.getUniqueDataId(par1Str);
3888        }
3889    
3890        /**
3891         * See description for playAuxSFX.
3892         */
3893        public void playAuxSFX(int par1, int par2, int par3, int par4, int par5)
3894        {
3895            this.playAuxSFXAtEntity((EntityPlayer)null, par1, par2, par3, par4, par5);
3896        }
3897    
3898        /**
3899         * See description for playAuxSFX.
3900         */
3901        public void playAuxSFXAtEntity(EntityPlayer par1EntityPlayer, int par2, int par3, int par4, int par5, int par6)
3902        {
3903            for (int var7 = 0; var7 < this.worldAccesses.size(); ++var7)
3904            {
3905                ((IWorldAccess)this.worldAccesses.get(var7)).playAuxSFX(par1EntityPlayer, par2, par3, par4, par5, par6);
3906            }
3907        }
3908    
3909        /**
3910         * Returns current world height.
3911         */
3912        public int getHeight()
3913        {
3914            return 256;
3915        }
3916    
3917        /**
3918         * Returns current world height.
3919         */
3920        public int getActualHeight()
3921        {
3922            return this.provider.hasNoSky ? 128 : 256;
3923        }
3924    
3925        /**
3926         * puts the World Random seed to a specific state dependant on the inputs
3927         */
3928        public Random setRandomSeed(int par1, int par2, int par3)
3929        {
3930            long var4 = (long)par1 * 341873128712L + (long)par2 * 132897987541L + this.getWorldInfo().getSeed() + (long)par3;
3931            this.rand.setSeed(var4);
3932            return this.rand;
3933        }
3934    
3935        /**
3936         * Updates lighting. Returns true if there are more lighting updates to update
3937         */
3938        public boolean updatingLighting()
3939        {
3940            return false;
3941        }
3942    
3943        /**
3944         * Returns the location of the closest structure of the specified type. If not found returns null.
3945         */
3946        public ChunkPosition findClosestStructure(String par1Str, int par2, int par3, int par4)
3947        {
3948            return this.getChunkProvider().findClosestStructure(this, par1Str, par2, par3, par4);
3949        }
3950    
3951        @SideOnly(Side.CLIENT)
3952    
3953        /**
3954         * set by !chunk.getAreLevelsEmpty
3955         */
3956        public boolean extendedLevelsInChunkCache()
3957        {
3958            return false;
3959        }
3960    
3961        @SideOnly(Side.CLIENT)
3962    
3963        /**
3964         * Returns horizon height for use in rendering the sky.
3965         */
3966        public double getHorizon()
3967        {
3968            return this.worldInfo.getTerrainType().getHorizon(this);
3969        }
3970    
3971        /**
3972         * Adds some basic stats of the world to the given crash report.
3973         */
3974        public CrashReport addWorldInfoToCrashReport(CrashReport par1CrashReport)
3975        {
3976            par1CrashReport.addCrashSectionCallable("World " + this.worldInfo.getWorldName() + " Entities", new CallableLvl1(this));
3977            par1CrashReport.addCrashSectionCallable("World " + this.worldInfo.getWorldName() + " Players", new CallableLvl2(this));
3978            par1CrashReport.addCrashSectionCallable("World " + this.worldInfo.getWorldName() + " Chunk Stats", new CallableLvl3(this));
3979            return par1CrashReport;
3980        }
3981    
3982        /**
3983         * Starts (or continues) destroying a block with given ID at the given coordinates for the given partially destroyed
3984         * value
3985         */
3986        public void destroyBlockInWorldPartially(int par1, int par2, int par3, int par4, int par5)
3987        {
3988            Iterator var6 = this.worldAccesses.iterator();
3989    
3990            while (var6.hasNext())
3991            {
3992                IWorldAccess var7 = (IWorldAccess)var6.next();
3993                var7.destroyBlockPartially(par1, par2, par3, par4, par5);
3994            }
3995        }
3996    
3997        /**
3998         * Adds a single TileEntity to the world.
3999         * @param entity The TileEntity to be added.
4000         */
4001        public void addTileEntity(TileEntity entity) 
4002        {
4003            List dest = scanningTileEntities ? addedTileEntityList : loadedTileEntityList;
4004            if(entity.canUpdate())
4005            {
4006                dest.add(entity);
4007            }
4008        }
4009    
4010        /**
4011         * Determine if the given block is considered solid on the
4012         * specified side.  Used by placement logic.
4013         * 
4014         * @param X Block X Position
4015         * @param Y Block Y Position
4016         * @param Z Block Z Position
4017         * @param side The Side in question
4018         * @return True if the side is solid
4019         */
4020        public boolean isBlockSolidOnSide(int X, int Y, int Z, ForgeDirection side)
4021        {
4022            return isBlockSolidOnSide(X, Y, Z, side, false);
4023        }
4024    
4025        /**
4026         * Determine if the given block is considered solid on the
4027         * specified side.  Used by placement logic.
4028         * 
4029         * @param X Block X Position
4030         * @param Y Block Y Position
4031         * @param Z Block Z Position
4032         * @param side The Side in question
4033         * @param _default The defult to return if the block doesn't exist.
4034         * @return True if the side is solid
4035         */
4036        public boolean isBlockSolidOnSide(int X, int Y, int Z, ForgeDirection side, boolean _default)
4037        {
4038            if (X < -30000000 || Z < -30000000 || X >= 30000000 || Z >= 30000000)
4039            {
4040                return _default;
4041            }
4042    
4043            Chunk var5 = this.chunkProvider.provideChunk(X >> 4, Z >> 4);
4044            if (var5 == null || var5.isEmpty())
4045            {
4046                return _default;
4047            }
4048    
4049            Block block = Block.blocksList[getBlockId(X, Y, Z)];
4050            if(block == null)
4051            {
4052                return false;
4053            }
4054    
4055            return block.isBlockSolidOnSide(this, X, Y, Z, side);
4056        }
4057    }