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