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