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