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