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