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