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