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