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                    var3 = var2.chunkCoordX;
2133                    var13 = var2.chunkCoordZ;
2134    
2135                    if (var2.addedToChunk && this.chunkExists(var3, var13))
2136                    {
2137                        this.getChunkFromChunkCoords(var3, var13).removeEntity(var2);
2138                    }
2139    
2140                    this.loadedEntityList.remove(var1--);
2141                    this.releaseEntitySkin(var2);
2142                }
2143    
2144                this.theProfiler.endSection();
2145            }
2146    
2147            this.theProfiler.endStartSection("tileEntities");
2148            this.scanningTileEntities = true;
2149            Iterator var14 = this.loadedTileEntityList.iterator();
2150    
2151            while (var14.hasNext())
2152            {
2153                TileEntity var9 = (TileEntity)var14.next();
2154    
2155                if (!var9.isInvalid() && var9.func_70309_m() && this.blockExists(var9.xCoord, var9.yCoord, var9.zCoord))
2156                {
2157                    try
2158                    {
2159                        var9.updateEntity();
2160                    }
2161                    catch (Throwable var6)
2162                    {
2163                        var4 = CrashReport.makeCrashReport(var6, "Ticking tile entity");
2164                        var5 = var4.makeCategory("Tile entity being ticked");
2165    
2166                        if (var9 == null)
2167                        {
2168                            var5.addCrashSection("Tile entity", "~~NULL~~");
2169                        }
2170                        else
2171                        {
2172                            var9.func_85027_a(var5);
2173                        }
2174    
2175                        throw new ReportedException(var4);
2176                    }
2177                }
2178    
2179                if (var9.isInvalid())
2180                {
2181                    var14.remove();
2182    
2183                    if (this.chunkExists(var9.xCoord >> 4, var9.zCoord >> 4))
2184                    {
2185                        Chunk var11 = this.getChunkFromChunkCoords(var9.xCoord >> 4, var9.zCoord >> 4);
2186    
2187                        if (var11 != null)
2188                        {
2189                            var11.cleanChunkBlockTileEntity(var9.xCoord & 15, var9.yCoord, var9.zCoord & 15);
2190                        }
2191                    }
2192                }
2193            }
2194    
2195    
2196            if (!this.entityRemoval.isEmpty())
2197            {
2198                for (Object tile : entityRemoval)
2199                {
2200                   ((TileEntity)tile).onChunkUnload();
2201                }
2202                this.loadedTileEntityList.removeAll(this.entityRemoval);
2203                this.entityRemoval.clear();
2204            }
2205    
2206            this.scanningTileEntities = false;
2207    
2208            this.theProfiler.endStartSection("pendingTileEntities");
2209    
2210            if (!this.addedTileEntityList.isEmpty())
2211            {
2212                for (int var10 = 0; var10 < this.addedTileEntityList.size(); ++var10)
2213                {
2214                    TileEntity var12 = (TileEntity)this.addedTileEntityList.get(var10);
2215    
2216                    if (!var12.isInvalid())
2217                    {
2218                        if (!this.loadedTileEntityList.contains(var12))
2219                        {
2220                            this.loadedTileEntityList.add(var12);
2221                        }
2222                    }
2223                    else
2224                    {
2225                        if (this.chunkExists(var12.xCoord >> 4, var12.zCoord >> 4))
2226                        {
2227                            Chunk var15 = this.getChunkFromChunkCoords(var12.xCoord >> 4, var12.zCoord >> 4);
2228    
2229                            if (var15 != null)
2230                            {
2231                                var15.cleanChunkBlockTileEntity(var12.xCoord & 15, var12.yCoord, var12.zCoord & 15);
2232                            }
2233                        }
2234                    }
2235                }
2236    
2237                this.addedTileEntityList.clear();
2238            }
2239    
2240            this.theProfiler.endSection();
2241            this.theProfiler.endSection();
2242        }
2243    
2244        public void addTileEntity(Collection par1Collection)
2245        {
2246            List dest = scanningTileEntities ? addedTileEntityList : loadedTileEntityList;
2247            for(Object entity : par1Collection)
2248            {
2249                if(((TileEntity)entity).canUpdate())
2250                {
2251                    dest.add(entity);
2252                }
2253            }
2254        }
2255    
2256        /**
2257         * Will update the entity in the world if the chunk the entity is in is currently loaded. Args: entity
2258         */
2259        public void updateEntity(Entity par1Entity)
2260        {
2261            this.updateEntityWithOptionalForce(par1Entity, true);
2262        }
2263    
2264        /**
2265         * Will update the entity in the world if the chunk the entity is in is currently loaded or its forced to update.
2266         * Args: entity, forceUpdate
2267         */
2268        public void updateEntityWithOptionalForce(Entity par1Entity, boolean par2)
2269        {
2270            int var3 = MathHelper.floor_double(par1Entity.posX);
2271            int var4 = MathHelper.floor_double(par1Entity.posZ);
2272    
2273            boolean isForced = getPersistentChunks().containsKey(new ChunkCoordIntPair(var3 >> 4, var4 >> 4));
2274            byte var5 = isForced ? (byte)0 : 32;
2275            boolean canUpdate = !par2 || this.checkChunksExist(var3 - var5, 0, var4 - var5, var3 + var5, 0, var4 + var5);
2276            if (!canUpdate)
2277            {
2278                EntityEvent.CanUpdate event = new EntityEvent.CanUpdate(par1Entity);
2279                MinecraftForge.EVENT_BUS.post(event);
2280                canUpdate = event.canUpdate;
2281            }
2282            if (canUpdate)
2283            {
2284                par1Entity.lastTickPosX = par1Entity.posX;
2285                par1Entity.lastTickPosY = par1Entity.posY;
2286                par1Entity.lastTickPosZ = par1Entity.posZ;
2287                par1Entity.prevRotationYaw = par1Entity.rotationYaw;
2288                par1Entity.prevRotationPitch = par1Entity.rotationPitch;
2289    
2290                if (par2 && par1Entity.addedToChunk)
2291                {
2292                    if (par1Entity.ridingEntity != null)
2293                    {
2294                        par1Entity.updateRidden();
2295                    }
2296                    else
2297                    {
2298                        ++par1Entity.ticksExisted;
2299                        par1Entity.onUpdate();
2300                    }
2301                }
2302    
2303                this.theProfiler.startSection("chunkCheck");
2304    
2305                if (Double.isNaN(par1Entity.posX) || Double.isInfinite(par1Entity.posX))
2306                {
2307                    par1Entity.posX = par1Entity.lastTickPosX;
2308                }
2309    
2310                if (Double.isNaN(par1Entity.posY) || Double.isInfinite(par1Entity.posY))
2311                {
2312                    par1Entity.posY = par1Entity.lastTickPosY;
2313                }
2314    
2315                if (Double.isNaN(par1Entity.posZ) || Double.isInfinite(par1Entity.posZ))
2316                {
2317                    par1Entity.posZ = par1Entity.lastTickPosZ;
2318                }
2319    
2320                if (Double.isNaN((double)par1Entity.rotationPitch) || Double.isInfinite((double)par1Entity.rotationPitch))
2321                {
2322                    par1Entity.rotationPitch = par1Entity.prevRotationPitch;
2323                }
2324    
2325                if (Double.isNaN((double)par1Entity.rotationYaw) || Double.isInfinite((double)par1Entity.rotationYaw))
2326                {
2327                    par1Entity.rotationYaw = par1Entity.prevRotationYaw;
2328                }
2329    
2330                int var6 = MathHelper.floor_double(par1Entity.posX / 16.0D);
2331                int var7 = MathHelper.floor_double(par1Entity.posY / 16.0D);
2332                int var8 = MathHelper.floor_double(par1Entity.posZ / 16.0D);
2333    
2334                if (!par1Entity.addedToChunk || par1Entity.chunkCoordX != var6 || par1Entity.chunkCoordY != var7 || par1Entity.chunkCoordZ != var8)
2335                {
2336                    if (par1Entity.addedToChunk && this.chunkExists(par1Entity.chunkCoordX, par1Entity.chunkCoordZ))
2337                    {
2338                        this.getChunkFromChunkCoords(par1Entity.chunkCoordX, par1Entity.chunkCoordZ).removeEntityAtIndex(par1Entity, par1Entity.chunkCoordY);
2339                    }
2340    
2341                    if (this.chunkExists(var6, var8))
2342                    {
2343                        par1Entity.addedToChunk = true;
2344                        this.getChunkFromChunkCoords(var6, var8).addEntity(par1Entity);
2345                    }
2346                    else
2347                    {
2348                        par1Entity.addedToChunk = false;
2349                    }
2350                }
2351    
2352                this.theProfiler.endSection();
2353    
2354                if (par2 && par1Entity.addedToChunk && par1Entity.riddenByEntity != null)
2355                {
2356                    if (!par1Entity.riddenByEntity.isDead && par1Entity.riddenByEntity.ridingEntity == par1Entity)
2357                    {
2358                        this.updateEntity(par1Entity.riddenByEntity);
2359                    }
2360                    else
2361                    {
2362                        par1Entity.riddenByEntity.ridingEntity = null;
2363                        par1Entity.riddenByEntity = null;
2364                    }
2365                }
2366            }
2367        }
2368    
2369        /**
2370         * Returns true if there are no solid, live entities in the specified AxisAlignedBB
2371         */
2372        public boolean checkIfAABBIsClear(AxisAlignedBB par1AxisAlignedBB)
2373        {
2374            return this.checkIfAABBIsClearExcludingEntity(par1AxisAlignedBB, (Entity)null);
2375        }
2376    
2377        /**
2378         * Returns true if there are no solid, live entities in the specified AxisAlignedBB, excluding the given entity
2379         */
2380        public boolean checkIfAABBIsClearExcludingEntity(AxisAlignedBB par1AxisAlignedBB, Entity par2Entity)
2381        {
2382            List var3 = this.getEntitiesWithinAABBExcludingEntity((Entity)null, par1AxisAlignedBB);
2383    
2384            for (int var4 = 0; var4 < var3.size(); ++var4)
2385            {
2386                Entity var5 = (Entity)var3.get(var4);
2387    
2388                if (!var5.isDead && var5.preventEntitySpawning && var5 != par2Entity)
2389                {
2390                    return false;
2391                }
2392            }
2393    
2394            return true;
2395        }
2396    
2397        /**
2398         * Returns true if there are any blocks in the region constrained by an AxisAlignedBB
2399         */
2400        public boolean isAABBNonEmpty(AxisAlignedBB par1AxisAlignedBB)
2401        {
2402            int var2 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2403            int var3 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2404            int var4 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2405            int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2406            int var6 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2407            int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2408    
2409            if (par1AxisAlignedBB.minX < 0.0D)
2410            {
2411                --var2;
2412            }
2413    
2414            if (par1AxisAlignedBB.minY < 0.0D)
2415            {
2416                --var4;
2417            }
2418    
2419            if (par1AxisAlignedBB.minZ < 0.0D)
2420            {
2421                --var6;
2422            }
2423    
2424            for (int var8 = var2; var8 < var3; ++var8)
2425            {
2426                for (int var9 = var4; var9 < var5; ++var9)
2427                {
2428                    for (int var10 = var6; var10 < var7; ++var10)
2429                    {
2430                        Block var11 = Block.blocksList[this.getBlockId(var8, var9, var10)];
2431    
2432                        if (var11 != null)
2433                        {
2434                            return true;
2435                        }
2436                    }
2437                }
2438            }
2439    
2440            return false;
2441        }
2442    
2443        /**
2444         * Returns if any of the blocks within the aabb are liquids. Args: aabb
2445         */
2446        public boolean isAnyLiquid(AxisAlignedBB par1AxisAlignedBB)
2447        {
2448            int var2 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2449            int var3 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2450            int var4 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2451            int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2452            int var6 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2453            int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2454    
2455            if (par1AxisAlignedBB.minX < 0.0D)
2456            {
2457                --var2;
2458            }
2459    
2460            if (par1AxisAlignedBB.minY < 0.0D)
2461            {
2462                --var4;
2463            }
2464    
2465            if (par1AxisAlignedBB.minZ < 0.0D)
2466            {
2467                --var6;
2468            }
2469    
2470            for (int var8 = var2; var8 < var3; ++var8)
2471            {
2472                for (int var9 = var4; var9 < var5; ++var9)
2473                {
2474                    for (int var10 = var6; var10 < var7; ++var10)
2475                    {
2476                        Block var11 = Block.blocksList[this.getBlockId(var8, var9, var10)];
2477    
2478                        if (var11 != null && var11.blockMaterial.isLiquid())
2479                        {
2480                            return true;
2481                        }
2482                    }
2483                }
2484            }
2485    
2486            return false;
2487        }
2488    
2489        /**
2490         * Returns whether or not the given bounding box is on fire or not
2491         */
2492        public boolean isBoundingBoxBurning(AxisAlignedBB par1AxisAlignedBB)
2493        {
2494            int var2 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2495            int var3 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2496            int var4 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2497            int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2498            int var6 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2499            int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2500    
2501            if (this.checkChunksExist(var2, var4, var6, var3, var5, var7))
2502            {
2503                for (int var8 = var2; var8 < var3; ++var8)
2504                {
2505                    for (int var9 = var4; var9 < var5; ++var9)
2506                    {
2507                        for (int var10 = var6; var10 < var7; ++var10)
2508                        {
2509                            int var11 = this.getBlockId(var8, var9, var10);
2510    
2511                            if (var11 == Block.fire.blockID || var11 == Block.lavaMoving.blockID || var11 == Block.lavaStill.blockID)
2512                            {
2513                                return true;
2514                            }
2515                            else
2516                            {
2517                                Block block = Block.blocksList[var11];
2518                                if (block != null && block.isBlockBurning(this, var8, var9, var10))
2519                                {
2520                                    return true;
2521                                }
2522                            }
2523                        }
2524                    }
2525                }
2526            }
2527    
2528            return false;
2529        }
2530    
2531        /**
2532         * handles the acceleration of an object whilst in water. Not sure if it is used elsewhere.
2533         */
2534        public boolean handleMaterialAcceleration(AxisAlignedBB par1AxisAlignedBB, Material par2Material, Entity par3Entity)
2535        {
2536            int var4 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2537            int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2538            int var6 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2539            int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2540            int var8 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2541            int var9 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2542    
2543            if (!this.checkChunksExist(var4, var6, var8, var5, var7, var9))
2544            {
2545                return false;
2546            }
2547            else
2548            {
2549                boolean var10 = false;
2550                Vec3 var11 = this.getWorldVec3Pool().getVecFromPool(0.0D, 0.0D, 0.0D);
2551    
2552                for (int var12 = var4; var12 < var5; ++var12)
2553                {
2554                    for (int var13 = var6; var13 < var7; ++var13)
2555                    {
2556                        for (int var14 = var8; var14 < var9; ++var14)
2557                        {
2558                            Block var15 = Block.blocksList[this.getBlockId(var12, var13, var14)];
2559    
2560                            if (var15 != null && var15.blockMaterial == par2Material)
2561                            {
2562                                double var16 = (double)((float)(var13 + 1) - BlockFluid.getFluidHeightPercent(this.getBlockMetadata(var12, var13, var14)));
2563    
2564                                if ((double)var7 >= var16)
2565                                {
2566                                    var10 = true;
2567                                    var15.velocityToAddToEntity(this, var12, var13, var14, par3Entity, var11);
2568                                }
2569                            }
2570                        }
2571                    }
2572                }
2573    
2574                if (var11.lengthVector() > 0.0D)
2575                {
2576                    var11 = var11.normalize();
2577                    double var18 = 0.014D;
2578                    par3Entity.motionX += var11.xCoord * var18;
2579                    par3Entity.motionY += var11.yCoord * var18;
2580                    par3Entity.motionZ += var11.zCoord * var18;
2581                }
2582    
2583                return var10;
2584            }
2585        }
2586    
2587        /**
2588         * Returns true if the given bounding box contains the given material
2589         */
2590        public boolean isMaterialInBB(AxisAlignedBB par1AxisAlignedBB, Material par2Material)
2591        {
2592            int var3 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2593            int var4 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2594            int var5 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2595            int var6 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2596            int var7 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2597            int var8 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2598    
2599            for (int var9 = var3; var9 < var4; ++var9)
2600            {
2601                for (int var10 = var5; var10 < var6; ++var10)
2602                {
2603                    for (int var11 = var7; var11 < var8; ++var11)
2604                    {
2605                        Block var12 = Block.blocksList[this.getBlockId(var9, var10, var11)];
2606    
2607                        if (var12 != null && var12.blockMaterial == par2Material)
2608                        {
2609                            return true;
2610                        }
2611                    }
2612                }
2613            }
2614    
2615            return false;
2616        }
2617    
2618        /**
2619         * checks if the given AABB is in the material given. Used while swimming.
2620         */
2621        public boolean isAABBInMaterial(AxisAlignedBB par1AxisAlignedBB, Material par2Material)
2622        {
2623            int var3 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2624            int var4 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2625            int var5 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2626            int var6 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2627            int var7 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2628            int var8 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2629    
2630            for (int var9 = var3; var9 < var4; ++var9)
2631            {
2632                for (int var10 = var5; var10 < var6; ++var10)
2633                {
2634                    for (int var11 = var7; var11 < var8; ++var11)
2635                    {
2636                        Block var12 = Block.blocksList[this.getBlockId(var9, var10, var11)];
2637    
2638                        if (var12 != null && var12.blockMaterial == par2Material)
2639                        {
2640                            int var13 = this.getBlockMetadata(var9, var10, var11);
2641                            double var14 = (double)(var10 + 1);
2642    
2643                            if (var13 < 8)
2644                            {
2645                                var14 = (double)(var10 + 1) - (double)var13 / 8.0D;
2646                            }
2647    
2648                            if (var14 >= par1AxisAlignedBB.minY)
2649                            {
2650                                return true;
2651                            }
2652                        }
2653                    }
2654                }
2655            }
2656    
2657            return false;
2658        }
2659    
2660        /**
2661         * Creates an explosion. Args: entity, x, y, z, strength
2662         */
2663        public Explosion createExplosion(Entity par1Entity, double par2, double par4, double par6, float par8, boolean par9)
2664        {
2665            return this.newExplosion(par1Entity, par2, par4, par6, par8, false, par9);
2666        }
2667    
2668        /**
2669         * returns a new explosion. Does initiation (at time of writing Explosion is not finished)
2670         */
2671        public Explosion newExplosion(Entity par1Entity, double par2, double par4, double par6, float par8, boolean par9, boolean par10)
2672        {
2673            Explosion var11 = new Explosion(this, par1Entity, par2, par4, par6, par8);
2674            var11.isFlaming = par9;
2675            var11.isSmoking = par10;
2676            var11.doExplosionA();
2677            var11.doExplosionB(true);
2678            return var11;
2679        }
2680    
2681        /**
2682         * Gets the percentage of real blocks within within a bounding box, along a specified vector.
2683         */
2684        public float getBlockDensity(Vec3 par1Vec3, AxisAlignedBB par2AxisAlignedBB)
2685        {
2686            double var3 = 1.0D / ((par2AxisAlignedBB.maxX - par2AxisAlignedBB.minX) * 2.0D + 1.0D);
2687            double var5 = 1.0D / ((par2AxisAlignedBB.maxY - par2AxisAlignedBB.minY) * 2.0D + 1.0D);
2688            double var7 = 1.0D / ((par2AxisAlignedBB.maxZ - par2AxisAlignedBB.minZ) * 2.0D + 1.0D);
2689            int var9 = 0;
2690            int var10 = 0;
2691    
2692            for (float var11 = 0.0F; var11 <= 1.0F; var11 = (float)((double)var11 + var3))
2693            {
2694                for (float var12 = 0.0F; var12 <= 1.0F; var12 = (float)((double)var12 + var5))
2695                {
2696                    for (float var13 = 0.0F; var13 <= 1.0F; var13 = (float)((double)var13 + var7))
2697                    {
2698                        double var14 = par2AxisAlignedBB.minX + (par2AxisAlignedBB.maxX - par2AxisAlignedBB.minX) * (double)var11;
2699                        double var16 = par2AxisAlignedBB.minY + (par2AxisAlignedBB.maxY - par2AxisAlignedBB.minY) * (double)var12;
2700                        double var18 = par2AxisAlignedBB.minZ + (par2AxisAlignedBB.maxZ - par2AxisAlignedBB.minZ) * (double)var13;
2701    
2702                        if (this.rayTraceBlocks(this.getWorldVec3Pool().getVecFromPool(var14, var16, var18), par1Vec3) == null)
2703                        {
2704                            ++var9;
2705                        }
2706    
2707                        ++var10;
2708                    }
2709                }
2710            }
2711    
2712            return (float)var9 / (float)var10;
2713        }
2714    
2715        /**
2716         * If the block in the given direction of the given coordinate is fire, extinguish it. Args: Player, X,Y,Z,
2717         * blockDirection
2718         */
2719        public boolean extinguishFire(EntityPlayer par1EntityPlayer, int par2, int par3, int par4, int par5)
2720        {
2721            if (par5 == 0)
2722            {
2723                --par3;
2724            }
2725    
2726            if (par5 == 1)
2727            {
2728                ++par3;
2729            }
2730    
2731            if (par5 == 2)
2732            {
2733                --par4;
2734            }
2735    
2736            if (par5 == 3)
2737            {
2738                ++par4;
2739            }
2740    
2741            if (par5 == 4)
2742            {
2743                --par2;
2744            }
2745    
2746            if (par5 == 5)
2747            {
2748                ++par2;
2749            }
2750    
2751            if (this.getBlockId(par2, par3, par4) == Block.fire.blockID)
2752            {
2753                this.playAuxSFXAtEntity(par1EntityPlayer, 1004, par2, par3, par4, 0);
2754                this.setBlockWithNotify(par2, par3, par4, 0);
2755                return true;
2756            }
2757            else
2758            {
2759                return false;
2760            }
2761        }
2762    
2763        @SideOnly(Side.CLIENT)
2764    
2765        /**
2766         * This string is 'All: (number of loaded entities)' Viewable by press ing F3
2767         */
2768        public String getDebugLoadedEntities()
2769        {
2770            return "All: " + this.loadedEntityList.size();
2771        }
2772    
2773        @SideOnly(Side.CLIENT)
2774    
2775        /**
2776         * Returns the name of the current chunk provider, by calling chunkprovider.makeString()
2777         */
2778        public String getProviderName()
2779        {
2780            return this.chunkProvider.makeString();
2781        }
2782    
2783        /**
2784         * Returns the TileEntity associated with a given block in X,Y,Z coordinates, or null if no TileEntity exists
2785         */
2786        public TileEntity getBlockTileEntity(int par1, int par2, int par3)
2787        {
2788            if (par2 >= 256)
2789            {
2790                return null;
2791            }
2792            else
2793            {
2794                Chunk var4 = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
2795    
2796                if (var4 == null)
2797                {
2798                    return null;
2799                }
2800                else
2801                {
2802                    TileEntity var5 = var4.getChunkBlockTileEntity(par1 & 15, par2, par3 & 15);
2803    
2804                    if (var5 == null)
2805                    {
2806                        for (int var6 = 0; var6 < this.addedTileEntityList.size(); ++var6)
2807                        {
2808                            TileEntity var7 = (TileEntity)this.addedTileEntityList.get(var6);
2809    
2810                            if (!var7.isInvalid() && var7.xCoord == par1 && var7.yCoord == par2 && var7.zCoord == par3)
2811                            {
2812                                var5 = var7;
2813                                break;
2814                            }
2815                        }
2816                    }
2817    
2818                    return var5;
2819                }
2820            }
2821        }
2822    
2823        /**
2824         * Sets the TileEntity for a given block in X, Y, Z coordinates
2825         */
2826        public void setBlockTileEntity(int par1, int par2, int par3, TileEntity par4TileEntity)
2827        {
2828            if (par4TileEntity == null || par4TileEntity.isInvalid())
2829            {
2830                return;
2831            }
2832    
2833            if (par4TileEntity.canUpdate())
2834            {
2835                List dest = scanningTileEntities ? addedTileEntityList : loadedTileEntityList;
2836                dest.add(par4TileEntity);
2837            }
2838    
2839            Chunk chunk = getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
2840            if (chunk != null)
2841            {
2842                chunk.setChunkBlockTileEntity(par1 & 15, par2, par3 & 15, par4TileEntity);
2843            }
2844        }
2845    
2846        /**
2847         * Removes the TileEntity for a given block in X,Y,Z coordinates
2848         */
2849        public void removeBlockTileEntity(int par1, int par2, int par3)
2850        {
2851            Chunk chunk = getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
2852            if (chunk != null)
2853            {
2854                chunk.removeChunkBlockTileEntity(par1 & 15, par2, par3 & 15);
2855            }
2856        }
2857    
2858        /**
2859         * adds tile entity to despawn list (renamed from markEntityForDespawn)
2860         */
2861        public void markTileEntityForDespawn(TileEntity par1TileEntity)
2862        {
2863            this.entityRemoval.add(par1TileEntity);
2864        }
2865    
2866        /**
2867         * Returns true if the block at the specified coordinates is an opaque cube. Args: x, y, z
2868         */
2869        public boolean isBlockOpaqueCube(int par1, int par2, int par3)
2870        {
2871            Block var4 = Block.blocksList[this.getBlockId(par1, par2, par3)];
2872            return var4 == null ? false : var4.isOpaqueCube();
2873        }
2874    
2875        /**
2876         * Indicate if a material is a normal solid opaque cube.
2877         */
2878        public boolean isBlockNormalCube(int par1, int par2, int par3)
2879        {
2880            Block block = Block.blocksList[getBlockId(par1, par2, par3)];
2881            return block != null && block.isBlockNormalCube(this, par1, par2, par3);
2882        }
2883    
2884        public boolean func_85174_u(int par1, int par2, int par3)
2885        {
2886            int var4 = this.getBlockId(par1, par2, par3);
2887    
2888            if (var4 != 0 && Block.blocksList[var4] != null)
2889            {
2890                AxisAlignedBB var5 = Block.blocksList[var4].getCollisionBoundingBoxFromPool(this, par1, par2, par3);
2891                return var5 != null && var5.getAverageEdgeLength() >= 1.0D;
2892            }
2893            else
2894            {
2895                return false;
2896            }
2897        }
2898    
2899        /**
2900         * Returns true if the block at the given coordinate has a solid (buildable) top surface.
2901         */
2902        public boolean doesBlockHaveSolidTopSurface(int par1, int par2, int par3)
2903        {
2904            return isBlockSolidOnSide(par1, par2, par3, ForgeDirection.UP);
2905        }
2906    
2907        /**
2908         * Checks if the block is a solid, normal cube. If the chunk does not exist, or is not loaded, it returns the
2909         * boolean parameter.
2910         */
2911        public boolean isBlockNormalCubeDefault(int par1, int par2, int par3, boolean par4)
2912        {
2913            if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000)
2914            {
2915                Chunk var5 = this.chunkProvider.provideChunk(par1 >> 4, par3 >> 4);
2916    
2917                if (var5 != null && !var5.isEmpty())
2918                {
2919                    Block var6 = Block.blocksList[this.getBlockId(par1, par2, par3)];
2920                    return var6 == null ? false : isBlockNormalCube(par1, par2, par3);
2921                }
2922                else
2923                {
2924                    return par4;
2925                }
2926            }
2927            else
2928            {
2929                return par4;
2930            }
2931        }
2932    
2933        /**
2934         * Called on construction of the World class to setup the initial skylight values
2935         */
2936        public void calculateInitialSkylight()
2937        {
2938            int var1 = this.calculateSkylightSubtracted(1.0F);
2939    
2940            if (var1 != this.skylightSubtracted)
2941            {
2942                this.skylightSubtracted = var1;
2943            }
2944        }
2945    
2946        /**
2947         * Set which types of mobs are allowed to spawn (peaceful vs hostile).
2948         */
2949        public void setAllowedSpawnTypes(boolean par1, boolean par2)
2950        {
2951            provider.setAllowedSpawnTypes(par1, par2);
2952        }
2953    
2954        /**
2955         * Runs a single tick for the world
2956         */
2957        public void tick()
2958        {
2959            this.updateWeather();
2960        }
2961    
2962        /**
2963         * Called from World constructor to set rainingStrength and thunderingStrength
2964         */
2965        private void calculateInitialWeather()
2966        {
2967            provider.calculateInitialWeather();
2968        }
2969    
2970        public void calculateInitialWeatherBody()
2971        {
2972            if (this.worldInfo.isRaining())
2973            {
2974                this.rainingStrength = 1.0F;
2975    
2976                if (this.worldInfo.isThundering())
2977                {
2978                    this.thunderingStrength = 1.0F;
2979                }
2980            }
2981        }
2982    
2983        /**
2984         * Updates all weather states.
2985         */
2986        protected void updateWeather()
2987        {
2988            provider.updateWeather();
2989        }
2990    
2991        public void updateWeatherBody()
2992        {
2993            if (!this.provider.hasNoSky)
2994            {
2995                int var1 = this.worldInfo.getThunderTime();
2996    
2997                if (var1 <= 0)
2998                {
2999                    if (this.worldInfo.isThundering())
3000                    {
3001                        this.worldInfo.setThunderTime(this.rand.nextInt(12000) + 3600);
3002                    }
3003                    else
3004                    {
3005                        this.worldInfo.setThunderTime(this.rand.nextInt(168000) + 12000);
3006                    }
3007                }
3008                else
3009                {
3010                    --var1;
3011                    this.worldInfo.setThunderTime(var1);
3012    
3013                    if (var1 <= 0)
3014                    {
3015                        this.worldInfo.setThundering(!this.worldInfo.isThundering());
3016                    }
3017                }
3018    
3019                int var2 = this.worldInfo.getRainTime();
3020    
3021                if (var2 <= 0)
3022                {
3023                    if (this.worldInfo.isRaining())
3024                    {
3025                        this.worldInfo.setRainTime(this.rand.nextInt(12000) + 12000);
3026                    }
3027                    else
3028                    {
3029                        this.worldInfo.setRainTime(this.rand.nextInt(168000) + 12000);
3030                    }
3031                }
3032                else
3033                {
3034                    --var2;
3035                    this.worldInfo.setRainTime(var2);
3036    
3037                    if (var2 <= 0)
3038                    {
3039                        this.worldInfo.setRaining(!this.worldInfo.isRaining());
3040                    }
3041                }
3042    
3043                this.prevRainingStrength = this.rainingStrength;
3044    
3045                if (this.worldInfo.isRaining())
3046                {
3047                    this.rainingStrength = (float)((double)this.rainingStrength + 0.01D);
3048                }
3049                else
3050                {
3051                    this.rainingStrength = (float)((double)this.rainingStrength - 0.01D);
3052                }
3053    
3054                if (this.rainingStrength < 0.0F)
3055                {
3056                    this.rainingStrength = 0.0F;
3057                }
3058    
3059                if (this.rainingStrength > 1.0F)
3060                {
3061                    this.rainingStrength = 1.0F;
3062                }
3063    
3064                this.prevThunderingStrength = this.thunderingStrength;
3065    
3066                if (this.worldInfo.isThundering())
3067                {
3068                    this.thunderingStrength = (float)((double)this.thunderingStrength + 0.01D);
3069                }
3070                else
3071                {
3072                    this.thunderingStrength = (float)((double)this.thunderingStrength - 0.01D);
3073                }
3074    
3075                if (this.thunderingStrength < 0.0F)
3076                {
3077                    this.thunderingStrength = 0.0F;
3078                }
3079    
3080                if (this.thunderingStrength > 1.0F)
3081                {
3082                    this.thunderingStrength = 1.0F;
3083                }
3084            }
3085        }
3086    
3087        public void toggleRain()
3088        {
3089            provider.toggleRain();
3090        }
3091    
3092        protected void setActivePlayerChunksAndCheckLight()
3093        {
3094            this.activeChunkSet.clear();
3095            this.activeChunkSet.addAll(getPersistentChunks().keySet());
3096    
3097            this.theProfiler.startSection("buildList");
3098            int var1;
3099            EntityPlayer var2;
3100            int var3;
3101            int var4;
3102    
3103            for (var1 = 0; var1 < this.playerEntities.size(); ++var1)
3104            {
3105                var2 = (EntityPlayer)this.playerEntities.get(var1);
3106                var3 = MathHelper.floor_double(var2.posX / 16.0D);
3107                var4 = MathHelper.floor_double(var2.posZ / 16.0D);
3108                byte var5 = 7;
3109    
3110                for (int var6 = -var5; var6 <= var5; ++var6)
3111                {
3112                    for (int var7 = -var5; var7 <= var5; ++var7)
3113                    {
3114                        this.activeChunkSet.add(new ChunkCoordIntPair(var6 + var3, var7 + var4));
3115                    }
3116                }
3117            }
3118    
3119            this.theProfiler.endSection();
3120    
3121            if (this.ambientTickCountdown > 0)
3122            {
3123                --this.ambientTickCountdown;
3124            }
3125    
3126            this.theProfiler.startSection("playerCheckLight");
3127    
3128            if (!this.playerEntities.isEmpty())
3129            {
3130                var1 = this.rand.nextInt(this.playerEntities.size());
3131                var2 = (EntityPlayer)this.playerEntities.get(var1);
3132                var3 = MathHelper.floor_double(var2.posX) + this.rand.nextInt(11) - 5;
3133                var4 = MathHelper.floor_double(var2.posY) + this.rand.nextInt(11) - 5;
3134                int var8 = MathHelper.floor_double(var2.posZ) + this.rand.nextInt(11) - 5;
3135                this.updateAllLightTypes(var3, var4, var8);
3136            }
3137    
3138            this.theProfiler.endSection();
3139        }
3140    
3141        protected void moodSoundAndLightCheck(int par1, int par2, Chunk par3Chunk)
3142        {
3143            this.theProfiler.endStartSection("moodSound");
3144    
3145            if (this.ambientTickCountdown == 0 && !this.isRemote)
3146            {
3147                this.updateLCG = this.updateLCG * 3 + 1013904223;
3148                int var4 = this.updateLCG >> 2;
3149                int var5 = var4 & 15;
3150                int var6 = var4 >> 8 & 15;
3151                int var7 = var4 >> 16 & 127;
3152                int var8 = par3Chunk.getBlockID(var5, var7, var6);
3153                var5 += par1;
3154                var6 += par2;
3155    
3156                if (var8 == 0 && this.getFullBlockLightValue(var5, var7, var6) <= this.rand.nextInt(8) && this.getSavedLightValue(EnumSkyBlock.Sky, var5, var7, var6) <= 0)
3157                {
3158                    EntityPlayer var9 = this.getClosestPlayer((double)var5 + 0.5D, (double)var7 + 0.5D, (double)var6 + 0.5D, 8.0D);
3159    
3160                    if (var9 != null && var9.getDistanceSq((double)var5 + 0.5D, (double)var7 + 0.5D, (double)var6 + 0.5D) > 4.0D)
3161                    {
3162                        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);
3163                        this.ambientTickCountdown = this.rand.nextInt(12000) + 6000;
3164                    }
3165                }
3166            }
3167    
3168            this.theProfiler.endStartSection("checkLight");
3169            par3Chunk.enqueueRelightChecks();
3170        }
3171    
3172        /**
3173         * plays random cave ambient sounds and runs updateTick on random blocks within each chunk in the vacinity of a
3174         * player
3175         */
3176        protected void tickBlocksAndAmbiance()
3177        {
3178            this.setActivePlayerChunksAndCheckLight();
3179        }
3180    
3181        /**
3182         * checks to see if a given block is both water and is cold enough to freeze
3183         */
3184        public boolean isBlockFreezable(int par1, int par2, int par3)
3185        {
3186            return this.canBlockFreeze(par1, par2, par3, false);
3187        }
3188    
3189        /**
3190         * checks to see if a given block is both water and has at least one immediately adjacent non-water block
3191         */
3192        public boolean isBlockFreezableNaturally(int par1, int par2, int par3)
3193        {
3194            return this.canBlockFreeze(par1, par2, par3, true);
3195        }
3196    
3197        /**
3198         * checks to see if a given block is both water, and cold enough to freeze - if the par4 boolean is set, this will
3199         * only return true if there is a non-water block immediately adjacent to the specified block
3200         */
3201        public boolean canBlockFreeze(int par1, int par2, int par3, boolean par4)
3202        {
3203            return provider.canBlockFreeze(par1, par2, par3, par4);
3204        }
3205    
3206        public boolean canBlockFreezeBody(int par1, int par2, int par3, boolean par4)
3207        {
3208            BiomeGenBase var5 = this.getBiomeGenForCoords(par1, par3);
3209            float var6 = var5.getFloatTemperature();
3210    
3211            if (var6 > 0.15F)
3212            {
3213                return false;
3214            }
3215            else
3216            {
3217                if (par2 >= 0 && par2 < 256 && this.getSavedLightValue(EnumSkyBlock.Block, par1, par2, par3) < 10)
3218                {
3219                    int var7 = this.getBlockId(par1, par2, par3);
3220    
3221                    if ((var7 == Block.waterStill.blockID || var7 == Block.waterMoving.blockID) && this.getBlockMetadata(par1, par2, par3) == 0)
3222                    {
3223                        if (!par4)
3224                        {
3225                            return true;
3226                        }
3227    
3228                        boolean var8 = true;
3229    
3230                        if (var8 && this.getBlockMaterial(par1 - 1, par2, par3) != Material.water)
3231                        {
3232                            var8 = false;
3233                        }
3234    
3235                        if (var8 && this.getBlockMaterial(par1 + 1, par2, par3) != Material.water)
3236                        {
3237                            var8 = false;
3238                        }
3239    
3240                        if (var8 && this.getBlockMaterial(par1, par2, par3 - 1) != Material.water)
3241                        {
3242                            var8 = false;
3243                        }
3244    
3245                        if (var8 && this.getBlockMaterial(par1, par2, par3 + 1) != Material.water)
3246                        {
3247                            var8 = false;
3248                        }
3249    
3250                        if (!var8)
3251                        {
3252                            return true;
3253                        }
3254                    }
3255                }
3256    
3257                return false;
3258            }
3259        }
3260    
3261        /**
3262         * Tests whether or not snow can be placed at a given location
3263         */
3264        public boolean canSnowAt(int par1, int par2, int par3)
3265        {
3266            return provider.canSnowAt(par1, par2, par3);
3267        }
3268    
3269        public boolean canSnowAtBody(int par1, int par2, int par3)
3270        {
3271            BiomeGenBase var4 = this.getBiomeGenForCoords(par1, par3);
3272            float var5 = var4.getFloatTemperature();
3273    
3274            if (var5 > 0.15F)
3275            {
3276                return false;
3277            }
3278            else
3279            {
3280                if (par2 >= 0 && par2 < 256 && this.getSavedLightValue(EnumSkyBlock.Block, par1, par2, par3) < 10)
3281                {
3282                    int var6 = this.getBlockId(par1, par2 - 1, par3);
3283                    int var7 = this.getBlockId(par1, par2, par3);
3284    
3285                    if (var7 == 0 && Block.snow.canPlaceBlockAt(this, par1, par2, par3) && var6 != 0 && var6 != Block.ice.blockID && Block.blocksList[var6].blockMaterial.blocksMovement())
3286                    {
3287                        return true;
3288                    }
3289                }
3290    
3291                return false;
3292            }
3293        }
3294    
3295        public void updateAllLightTypes(int par1, int par2, int par3)
3296        {
3297            if (!this.provider.hasNoSky)
3298            {
3299                this.updateLightByType(EnumSkyBlock.Sky, par1, par2, par3);
3300            }
3301    
3302            this.updateLightByType(EnumSkyBlock.Block, par1, par2, par3);
3303        }
3304    
3305        private int computeSkyLightValue(int par1, int par2, int par3, int par4, int par5, int par6)
3306        {
3307            int var7 = 0;
3308    
3309            if (this.canBlockSeeTheSky(par2, par3, par4))
3310            {
3311                var7 = 15;
3312            }
3313            else
3314            {
3315                if (par6 == 0)
3316                {
3317                    par6 = 1;
3318                }
3319    
3320                int var8 = this.getSavedLightValue(EnumSkyBlock.Sky, par2 - 1, par3, par4) - par6;
3321                int var9 = this.getSavedLightValue(EnumSkyBlock.Sky, par2 + 1, par3, par4) - par6;
3322                int var10 = this.getSavedLightValue(EnumSkyBlock.Sky, par2, par3 - 1, par4) - par6;
3323                int var11 = this.getSavedLightValue(EnumSkyBlock.Sky, par2, par3 + 1, par4) - par6;
3324                int var12 = this.getSavedLightValue(EnumSkyBlock.Sky, par2, par3, par4 - 1) - par6;
3325                int var13 = this.getSavedLightValue(EnumSkyBlock.Sky, par2, par3, par4 + 1) - par6;
3326    
3327                if (var8 > var7)
3328                {
3329                    var7 = var8;
3330                }
3331    
3332                if (var9 > var7)
3333                {
3334                    var7 = var9;
3335                }
3336    
3337                if (var10 > var7)
3338                {
3339                    var7 = var10;
3340                }
3341    
3342                if (var11 > var7)
3343                {
3344                    var7 = var11;
3345                }
3346    
3347                if (var12 > var7)
3348                {
3349                    var7 = var12;
3350                }
3351    
3352                if (var13 > var7)
3353                {
3354                    var7 = var13;
3355                }
3356            }
3357    
3358            return var7;
3359        }
3360    
3361        private int computeBlockLightValue(int par1, int par2, int par3, int par4, int par5, int par6)
3362        {
3363            int var7 = (par5 == 0 || Block.blocksList[par5] == null ? 0 : Block.blocksList[par5].getLightValue(this, par2, par3, par4));
3364            int var8 = this.getSavedLightValue(EnumSkyBlock.Block, par2 - 1, par3, par4) - par6;
3365            int var9 = this.getSavedLightValue(EnumSkyBlock.Block, par2 + 1, par3, par4) - par6;
3366            int var10 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3 - 1, par4) - par6;
3367            int var11 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3 + 1, par4) - par6;
3368            int var12 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3, par4 - 1) - par6;
3369            int var13 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3, par4 + 1) - par6;
3370    
3371            if (var8 > var7)
3372            {
3373                var7 = var8;
3374            }
3375    
3376            if (var9 > var7)
3377            {
3378                var7 = var9;
3379            }
3380    
3381            if (var10 > var7)
3382            {
3383                var7 = var10;
3384            }
3385    
3386            if (var11 > var7)
3387            {
3388                var7 = var11;
3389            }
3390    
3391            if (var12 > var7)
3392            {
3393                var7 = var12;
3394            }
3395    
3396            if (var13 > var7)
3397            {
3398                var7 = var13;
3399            }
3400    
3401            return var7;
3402        }
3403    
3404        public void updateLightByType(EnumSkyBlock par1EnumSkyBlock, int par2, int par3, int par4)
3405        {
3406            if (this.doChunksNearChunkExist(par2, par3, par4, 17))
3407            {
3408                int var5 = 0;
3409                int var6 = 0;
3410                this.theProfiler.startSection("getBrightness");
3411                int var7 = this.getSavedLightValue(par1EnumSkyBlock, par2, par3, par4);
3412                boolean var8 = false;
3413                int var9 = this.getBlockId(par2, par3, par4);
3414                int var10 = this.getBlockLightOpacity(par2, par3, par4);
3415    
3416                if (var10 == 0)
3417                {
3418                    var10 = 1;
3419                }
3420    
3421                boolean var11 = false;
3422                int var24;
3423    
3424                if (par1EnumSkyBlock == EnumSkyBlock.Sky)
3425                {
3426                    var24 = this.computeSkyLightValue(var7, par2, par3, par4, var9, var10);
3427                }
3428                else
3429                {
3430                    var24 = this.computeBlockLightValue(var7, par2, par3, par4, var9, var10);
3431                }
3432    
3433                int var12;
3434                int var13;
3435                int var14;
3436                int var15;
3437                int var17;
3438                int var16;
3439                int var19;
3440                int var18;
3441    
3442                if (var24 > var7)
3443                {
3444                    this.lightUpdateBlockList[var6++] = 133152;
3445                }
3446                else if (var24 < var7)
3447                {
3448                    if (par1EnumSkyBlock != EnumSkyBlock.Block)
3449                    {
3450                        ;
3451                    }
3452    
3453                    this.lightUpdateBlockList[var6++] = 133152 + (var7 << 18);
3454    
3455                    while (var5 < var6)
3456                    {
3457                        var9 = this.lightUpdateBlockList[var5++];
3458                        var10 = (var9 & 63) - 32 + par2;
3459                        var24 = (var9 >> 6 & 63) - 32 + par3;
3460                        var12 = (var9 >> 12 & 63) - 32 + par4;
3461                        var13 = var9 >> 18 & 15;
3462                        var14 = this.getSavedLightValue(par1EnumSkyBlock, var10, var24, var12);
3463    
3464                        if (var14 == var13)
3465                        {
3466                            this.setLightValue(par1EnumSkyBlock, var10, var24, var12, 0);
3467    
3468                            if (var13 > 0)
3469                            {
3470                                var15 = var10 - par2;
3471                                var16 = var24 - par3;
3472                                var17 = var12 - par4;
3473    
3474                                if (var15 < 0)
3475                                {
3476                                    var15 = -var15;
3477                                }
3478    
3479                                if (var16 < 0)
3480                                {
3481                                    var16 = -var16;
3482                                }
3483    
3484                                if (var17 < 0)
3485                                {
3486                                    var17 = -var17;
3487                                }
3488    
3489                                if (var15 + var16 + var17 < 17)
3490                                {
3491                                    for (var18 = 0; var18 < 6; ++var18)
3492                                    {
3493                                        var19 = var18 % 2 * 2 - 1;
3494                                        int var20 = var10 + var18 / 2 % 3 / 2 * var19;
3495                                        int var21 = var24 + (var18 / 2 + 1) % 3 / 2 * var19;
3496                                        int var22 = var12 + (var18 / 2 + 2) % 3 / 2 * var19;
3497                                        var14 = this.getSavedLightValue(par1EnumSkyBlock, var20, var21, var22);
3498                                        int var23 = this.getBlockLightOpacity(var20, var21, var22);
3499    
3500                                        if (var23 == 0)
3501                                        {
3502                                            var23 = 1;
3503                                        }
3504    
3505                                        if (var14 == var13 - var23 && var6 < this.lightUpdateBlockList.length)
3506                                        {
3507                                            this.lightUpdateBlockList[var6++] = var20 - par2 + 32 + (var21 - par3 + 32 << 6) + (var22 - par4 + 32 << 12) + (var13 - var23 << 18);
3508                                        }
3509                                    }
3510                                }
3511                            }
3512                        }
3513                    }
3514    
3515                    var5 = 0;
3516                }
3517    
3518                this.theProfiler.endSection();
3519                this.theProfiler.startSection("checkedPosition < toCheckCount");
3520    
3521                while (var5 < var6)
3522                {
3523                    var9 = this.lightUpdateBlockList[var5++];
3524                    var10 = (var9 & 63) - 32 + par2;
3525                    var24 = (var9 >> 6 & 63) - 32 + par3;
3526                    var12 = (var9 >> 12 & 63) - 32 + par4;
3527                    var13 = this.getSavedLightValue(par1EnumSkyBlock, var10, var24, var12);
3528                    var14 = this.getBlockId(var10, var24, var12);
3529                    var15 = this.getBlockLightOpacity(var10, var24, var12);
3530    
3531                    if (var15 == 0)
3532                    {
3533                        var15 = 1;
3534                    }
3535    
3536                    boolean var25 = false;
3537    
3538                    if (par1EnumSkyBlock == EnumSkyBlock.Sky)
3539                    {
3540                        var16 = this.computeSkyLightValue(var13, var10, var24, var12, var14, var15);
3541                    }
3542                    else
3543                    {
3544                        var16 = this.computeBlockLightValue(var13, var10, var24, var12, var14, var15);
3545                    }
3546    
3547                    if (var16 != var13)
3548                    {
3549                        this.setLightValue(par1EnumSkyBlock, var10, var24, var12, var16);
3550    
3551                        if (var16 > var13)
3552                        {
3553                            var17 = var10 - par2;
3554                            var18 = var24 - par3;
3555                            var19 = var12 - par4;
3556    
3557                            if (var17 < 0)
3558                            {
3559                                var17 = -var17;
3560                            }
3561    
3562                            if (var18 < 0)
3563                            {
3564                                var18 = -var18;
3565                            }
3566    
3567                            if (var19 < 0)
3568                            {
3569                                var19 = -var19;
3570                            }
3571    
3572                            if (var17 + var18 + var19 < 17 && var6 < this.lightUpdateBlockList.length - 6)
3573                            {
3574                                if (this.getSavedLightValue(par1EnumSkyBlock, var10 - 1, var24, var12) < var16)
3575                                {
3576                                    this.lightUpdateBlockList[var6++] = var10 - 1 - par2 + 32 + (var24 - par3 + 32 << 6) + (var12 - par4 + 32 << 12);
3577                                }
3578    
3579                                if (this.getSavedLightValue(par1EnumSkyBlock, var10 + 1, var24, var12) < var16)
3580                                {
3581                                    this.lightUpdateBlockList[var6++] = var10 + 1 - par2 + 32 + (var24 - par3 + 32 << 6) + (var12 - par4 + 32 << 12);
3582                                }
3583    
3584                                if (this.getSavedLightValue(par1EnumSkyBlock, var10, var24 - 1, var12) < var16)
3585                                {
3586                                    this.lightUpdateBlockList[var6++] = var10 - par2 + 32 + (var24 - 1 - par3 + 32 << 6) + (var12 - par4 + 32 << 12);
3587                                }
3588    
3589                                if (this.getSavedLightValue(par1EnumSkyBlock, var10, var24 + 1, var12) < var16)
3590                                {
3591                                    this.lightUpdateBlockList[var6++] = var10 - par2 + 32 + (var24 + 1 - par3 + 32 << 6) + (var12 - par4 + 32 << 12);
3592                                }
3593    
3594                                if (this.getSavedLightValue(par1EnumSkyBlock, var10, var24, var12 - 1) < var16)
3595                                {
3596                                    this.lightUpdateBlockList[var6++] = var10 - par2 + 32 + (var24 - par3 + 32 << 6) + (var12 - 1 - par4 + 32 << 12);
3597                                }
3598    
3599                                if (this.getSavedLightValue(par1EnumSkyBlock, var10, var24, var12 + 1) < var16)
3600                                {
3601                                    this.lightUpdateBlockList[var6++] = var10 - par2 + 32 + (var24 - par3 + 32 << 6) + (var12 + 1 - par4 + 32 << 12);
3602                                }
3603                            }
3604                        }
3605                    }
3606                }
3607    
3608                this.theProfiler.endSection();
3609            }
3610        }
3611    
3612        /**
3613         * Runs through the list of updates to run and ticks them
3614         */
3615        public boolean tickUpdates(boolean par1)
3616        {
3617            return false;
3618        }
3619    
3620        public List getPendingBlockUpdates(Chunk par1Chunk, boolean par2)
3621        {
3622            return null;
3623        }
3624    
3625        /**
3626         * Will get all entities within the specified AABB excluding the one passed into it. Args: entityToExclude, aabb
3627         */
3628        public List getEntitiesWithinAABBExcludingEntity(Entity par1Entity, AxisAlignedBB par2AxisAlignedBB)
3629        {
3630            this.entitiesWithinAABBExcludingEntity.clear();
3631            int var3 = MathHelper.floor_double((par2AxisAlignedBB.minX - MAX_ENTITY_RADIUS) / 16.0D);
3632            int var4 = MathHelper.floor_double((par2AxisAlignedBB.maxX + MAX_ENTITY_RADIUS) / 16.0D);
3633            int var5 = MathHelper.floor_double((par2AxisAlignedBB.minZ - MAX_ENTITY_RADIUS) / 16.0D);
3634            int var6 = MathHelper.floor_double((par2AxisAlignedBB.maxZ + MAX_ENTITY_RADIUS) / 16.0D);
3635    
3636            for (int var7 = var3; var7 <= var4; ++var7)
3637            {
3638                for (int var8 = var5; var8 <= var6; ++var8)
3639                {
3640                    if (this.chunkExists(var7, var8))
3641                    {
3642                        this.getChunkFromChunkCoords(var7, var8).getEntitiesWithinAABBForEntity(par1Entity, par2AxisAlignedBB, this.entitiesWithinAABBExcludingEntity);
3643                    }
3644                }
3645            }
3646    
3647            return this.entitiesWithinAABBExcludingEntity;
3648        }
3649    
3650        /**
3651         * Returns all entities of the specified class type which intersect with the AABB. Args: entityClass, aabb
3652         */
3653        public List getEntitiesWithinAABB(Class par1Class, AxisAlignedBB par2AxisAlignedBB)
3654        {
3655            return this.selectEntitiesWithinAABB(par1Class, par2AxisAlignedBB, (IEntitySelector)null);
3656        }
3657    
3658        public List selectEntitiesWithinAABB(Class par1Class, AxisAlignedBB par2AxisAlignedBB, IEntitySelector par3IEntitySelector)
3659        {
3660            int var4 = MathHelper.floor_double((par2AxisAlignedBB.minX - MAX_ENTITY_RADIUS) / 16.0D);
3661            int var5 = MathHelper.floor_double((par2AxisAlignedBB.maxX + MAX_ENTITY_RADIUS) / 16.0D);
3662            int var6 = MathHelper.floor_double((par2AxisAlignedBB.minZ - MAX_ENTITY_RADIUS) / 16.0D);
3663            int var7 = MathHelper.floor_double((par2AxisAlignedBB.maxZ + MAX_ENTITY_RADIUS) / 16.0D);
3664            ArrayList var8 = new ArrayList();
3665    
3666            for (int var9 = var4; var9 <= var5; ++var9)
3667            {
3668                for (int var10 = var6; var10 <= var7; ++var10)
3669                {
3670                    if (this.chunkExists(var9, var10))
3671                    {
3672                        this.getChunkFromChunkCoords(var9, var10).getEntitiesOfTypeWithinAAAB(par1Class, par2AxisAlignedBB, var8, par3IEntitySelector);
3673                    }
3674                }
3675            }
3676    
3677            return var8;
3678        }
3679    
3680        public Entity findNearestEntityWithinAABB(Class par1Class, AxisAlignedBB par2AxisAlignedBB, Entity par3Entity)
3681        {
3682            List var4 = this.getEntitiesWithinAABB(par1Class, par2AxisAlignedBB);
3683            Entity var5 = null;
3684            double var6 = Double.MAX_VALUE;
3685    
3686            for (int var8 = 0; var8 < var4.size(); ++var8)
3687            {
3688                Entity var9 = (Entity)var4.get(var8);
3689    
3690                if (var9 != par3Entity)
3691                {
3692                    double var10 = par3Entity.getDistanceSqToEntity(var9);
3693    
3694                    if (var10 <= var6)
3695                    {
3696                        var5 = var9;
3697                        var6 = var10;
3698                    }
3699                }
3700            }
3701    
3702            return var5;
3703        }
3704    
3705        /**
3706         * Returns the Entity with the given ID, or null if it doesn't exist in this World.
3707         */
3708        public abstract Entity getEntityByID(int var1);
3709    
3710        @SideOnly(Side.CLIENT)
3711    
3712        /**
3713         * Accessor for world Loaded Entity List
3714         */
3715        public List getLoadedEntityList()
3716        {
3717            return this.loadedEntityList;
3718        }
3719    
3720        /**
3721         * marks the chunk that contains this tilentity as modified and then calls worldAccesses.doNothingWithTileEntity
3722         */
3723        public void updateTileEntityChunkAndDoNothing(int par1, int par2, int par3, TileEntity par4TileEntity)
3724        {
3725            if (this.blockExists(par1, par2, par3))
3726            {
3727                this.getChunkFromBlockCoords(par1, par3).setChunkModified();
3728            }
3729        }
3730    
3731        /**
3732         * Counts how many entities of an entity class exist in the world. Args: entityClass
3733         */
3734        public int countEntities(Class par1Class)
3735        {
3736            int var2 = 0;
3737    
3738            for (int var3 = 0; var3 < this.loadedEntityList.size(); ++var3)
3739            {
3740                Entity var4 = (Entity)this.loadedEntityList.get(var3);
3741    
3742                if (par1Class.isAssignableFrom(var4.getClass()))
3743                {
3744                    ++var2;
3745                }
3746            }
3747    
3748            return var2;
3749        }
3750    
3751        /**
3752         * adds entities to the loaded entities list, and loads thier skins.
3753         */
3754        public void addLoadedEntities(List par1List)
3755        {
3756            for (int var2 = 0; var2 < par1List.size(); ++var2)
3757            {
3758                Entity entity = (Entity)par1List.get(var2);
3759                if (!MinecraftForge.EVENT_BUS.post(new EntityJoinWorldEvent(entity, this)))
3760                {
3761                    loadedEntityList.add(entity);
3762                    this.obtainEntitySkin(entity);
3763                }
3764            }
3765        }
3766    
3767        /**
3768         * Adds a list of entities to be unloaded on the next pass of World.updateEntities()
3769         */
3770        public void unloadEntities(List par1List)
3771        {
3772            this.unloadedEntityList.addAll(par1List);
3773        }
3774    
3775        /**
3776         * Returns true if the given Entity can be placed on the given side of the given block position.
3777         */
3778        public boolean canPlaceEntityOnSide(int par1, int par2, int par3, int par4, boolean par5, int par6, Entity par7Entity)
3779        {
3780            int var8 = this.getBlockId(par2, par3, par4);
3781            Block var9 = Block.blocksList[var8];
3782            Block var10 = Block.blocksList[par1];
3783            AxisAlignedBB var11 = var10.getCollisionBoundingBoxFromPool(this, par2, par3, par4);
3784    
3785            if (par5)
3786            {
3787                var11 = null;
3788            }
3789    
3790            if (var11 != null && !this.checkIfAABBIsClearExcludingEntity(var11, par7Entity))
3791            {
3792                return false;
3793            }
3794            else
3795            {
3796                if (var9 != null && (var9 == Block.waterMoving || var9 == Block.waterStill || var9 == Block.lavaMoving || var9 == Block.lavaStill || var9 == Block.fire || var9.blockMaterial.isReplaceable()))
3797                {
3798                    var9 = null;
3799                }
3800    
3801                if (var9 != null && var9.isBlockReplaceable(this, par2, par3, par4))
3802                {
3803                    var9 = null;
3804                }
3805    
3806                return var9 != null && var9.blockMaterial == Material.circuits && var10 == Block.anvil ? true : par1 > 0 && var9 == null && var10.canPlaceBlockOnSide(this, par2, par3, par4, par6);
3807            }
3808        }
3809    
3810        public PathEntity getPathEntityToEntity(Entity par1Entity, Entity par2Entity, float par3, boolean par4, boolean par5, boolean par6, boolean par7)
3811        {
3812            this.theProfiler.startSection("pathfind");
3813            int var8 = MathHelper.floor_double(par1Entity.posX);
3814            int var9 = MathHelper.floor_double(par1Entity.posY + 1.0D);
3815            int var10 = MathHelper.floor_double(par1Entity.posZ);
3816            int var11 = (int)(par3 + 16.0F);
3817            int var12 = var8 - var11;
3818            int var13 = var9 - var11;
3819            int var14 = var10 - var11;
3820            int var15 = var8 + var11;
3821            int var16 = var9 + var11;
3822            int var17 = var10 + var11;
3823            ChunkCache var18 = new ChunkCache(this, var12, var13, var14, var15, var16, var17);
3824            PathEntity var19 = (new PathFinder(var18, par4, par5, par6, par7)).createEntityPathTo(par1Entity, par2Entity, par3);
3825            this.theProfiler.endSection();
3826            return var19;
3827        }
3828    
3829        public PathEntity getEntityPathToXYZ(Entity par1Entity, int par2, int par3, int par4, float par5, boolean par6, boolean par7, boolean par8, boolean par9)
3830        {
3831            this.theProfiler.startSection("pathfind");
3832            int var10 = MathHelper.floor_double(par1Entity.posX);
3833            int var11 = MathHelper.floor_double(par1Entity.posY);
3834            int var12 = MathHelper.floor_double(par1Entity.posZ);
3835            int var13 = (int)(par5 + 8.0F);
3836            int var14 = var10 - var13;
3837            int var15 = var11 - var13;
3838            int var16 = var12 - var13;
3839            int var17 = var10 + var13;
3840            int var18 = var11 + var13;
3841            int var19 = var12 + var13;
3842            ChunkCache var20 = new ChunkCache(this, var14, var15, var16, var17, var18, var19);
3843            PathEntity var21 = (new PathFinder(var20, par6, par7, par8, par9)).createEntityPathTo(par1Entity, par2, par3, par4, par5);
3844            this.theProfiler.endSection();
3845            return var21;
3846        }
3847    
3848        /**
3849         * Is this block powering in the specified direction Args: x, y, z, direction
3850         */
3851        public boolean isBlockProvidingPowerTo(int par1, int par2, int par3, int par4)
3852        {
3853            int var5 = this.getBlockId(par1, par2, par3);
3854            return var5 == 0 ? false : Block.blocksList[var5].isProvidingStrongPower(this, par1, par2, par3, par4);
3855        }
3856    
3857        /**
3858         * Whether one of the neighboring blocks is putting power into this block. Args: x, y, z
3859         */
3860        public boolean isBlockGettingPowered(int par1, int par2, int par3)
3861        {
3862            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)))));
3863        }
3864    
3865        /**
3866         * Is a block next to you getting powered (if its an attachable block) or is it providing power directly to you.
3867         * Args: x, y, z, direction
3868         */
3869        public boolean isBlockIndirectlyProvidingPowerTo(int par1, int par2, int par3, int par4)
3870        {
3871            if (this.isBlockNormalCube(par1, par2, par3))
3872            {
3873                return this.isBlockGettingPowered(par1, par2, par3);
3874            }
3875            else
3876            {
3877                int var5 = this.getBlockId(par1, par2, par3);
3878                return var5 == 0 ? false : Block.blocksList[var5].isProvidingWeakPower(this, par1, par2, par3, par4);
3879            }
3880        }
3881    
3882        /**
3883         * Used to see if one of the blocks next to you or your block is getting power from a neighboring block. Used by
3884         * items like TNT or Doors so they don't have redstone going straight into them.  Args: x, y, z
3885         */
3886        public boolean isBlockIndirectlyGettingPowered(int par1, int par2, int par3)
3887        {
3888            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)))));
3889        }
3890    
3891        /**
3892         * Gets the closest player to the entity within the specified distance (if distance is less than 0 then ignored).
3893         * Args: entity, dist
3894         */
3895        public EntityPlayer getClosestPlayerToEntity(Entity par1Entity, double par2)
3896        {
3897            return this.getClosestPlayer(par1Entity.posX, par1Entity.posY, par1Entity.posZ, par2);
3898        }
3899    
3900        /**
3901         * Gets the closest player to the point within the specified distance (distance can be set to less than 0 to not
3902         * limit the distance). Args: x, y, z, dist
3903         */
3904        public EntityPlayer getClosestPlayer(double par1, double par3, double par5, double par7)
3905        {
3906            double var9 = -1.0D;
3907            EntityPlayer var11 = null;
3908    
3909            for (int var12 = 0; var12 < this.playerEntities.size(); ++var12)
3910            {
3911                EntityPlayer var13 = (EntityPlayer)this.playerEntities.get(var12);
3912                double var14 = var13.getDistanceSq(par1, par3, par5);
3913    
3914                if ((par7 < 0.0D || var14 < par7 * par7) && (var9 == -1.0D || var14 < var9))
3915                {
3916                    var9 = var14;
3917                    var11 = var13;
3918                }
3919            }
3920    
3921            return var11;
3922        }
3923    
3924        /**
3925         * Returns the closest vulnerable player to this entity within the given radius, or null if none is found
3926         */
3927        public EntityPlayer getClosestVulnerablePlayerToEntity(Entity par1Entity, double par2)
3928        {
3929            return this.getClosestVulnerablePlayer(par1Entity.posX, par1Entity.posY, par1Entity.posZ, par2);
3930        }
3931    
3932        /**
3933         * Returns the closest vulnerable player within the given radius, or null if none is found.
3934         */
3935        public EntityPlayer getClosestVulnerablePlayer(double par1, double par3, double par5, double par7)
3936        {
3937            double var9 = -1.0D;
3938            EntityPlayer var11 = null;
3939    
3940            for (int var12 = 0; var12 < this.playerEntities.size(); ++var12)
3941            {
3942                EntityPlayer var13 = (EntityPlayer)this.playerEntities.get(var12);
3943    
3944                if (!var13.capabilities.disableDamage && var13.isEntityAlive())
3945                {
3946                    double var14 = var13.getDistanceSq(par1, par3, par5);
3947                    double var16 = par7;
3948    
3949                    if (var13.isSneaking())
3950                    {
3951                        var16 = par7 * 0.800000011920929D;
3952                    }
3953    
3954                    if (var13.getHasActivePotion())
3955                    {
3956                        float var18 = var13.func_82243_bO();
3957    
3958                        if (var18 < 0.1F)
3959                        {
3960                            var18 = 0.1F;
3961                        }
3962    
3963                        var16 *= (double)(0.7F * var18);
3964                    }
3965    
3966                    if ((par7 < 0.0D || var14 < var16 * var16) && (var9 == -1.0D || var14 < var9))
3967                    {
3968                        var9 = var14;
3969                        var11 = var13;
3970                    }
3971                }
3972            }
3973    
3974            return var11;
3975        }
3976    
3977        /**
3978         * Find a player by name in this world.
3979         */
3980        public EntityPlayer getPlayerEntityByName(String par1Str)
3981        {
3982            for (int var2 = 0; var2 < this.playerEntities.size(); ++var2)
3983            {
3984                if (par1Str.equals(((EntityPlayer)this.playerEntities.get(var2)).username))
3985                {
3986                    return (EntityPlayer)this.playerEntities.get(var2);
3987                }
3988            }
3989    
3990            return null;
3991        }
3992    
3993        @SideOnly(Side.CLIENT)
3994    
3995        /**
3996         * If on MP, sends a quitting packet.
3997         */
3998        public void sendQuittingDisconnectingPacket() {}
3999    
4000        /**
4001         * Checks whether the session lock file was modified by another process
4002         */
4003        public void checkSessionLock() throws MinecraftException
4004        {
4005            this.saveHandler.checkSessionLock();
4006        }
4007    
4008        @SideOnly(Side.CLIENT)
4009        public void func_82738_a(long par1)
4010        {
4011            this.worldInfo.incrementTotalWorldTime(par1);
4012        }
4013    
4014        /**
4015         * Retrieve the world seed from level.dat
4016         */
4017        public long getSeed()
4018        {
4019            return provider.getSeed();
4020        }
4021    
4022        public long getTotalWorldTime()
4023        {
4024            return this.worldInfo.getWorldTotalTime();
4025        }
4026    
4027        public long getWorldTime()
4028        {
4029            return provider.getWorldTime();
4030        }
4031    
4032        /**
4033         * Sets the world time.
4034         */
4035        public void setWorldTime(long par1)
4036        {
4037            provider.setWorldTime(par1);
4038        }
4039    
4040        /**
4041         * Returns the coordinates of the spawn point
4042         */
4043        public ChunkCoordinates getSpawnPoint()
4044        {
4045            return provider.getSpawnPoint();
4046        }
4047    
4048        @SideOnly(Side.CLIENT)
4049        public void setSpawnLocation(int par1, int par2, int par3)
4050        {
4051            provider.setSpawnPoint(par1, par2, par3);
4052        }
4053    
4054        @SideOnly(Side.CLIENT)
4055    
4056        /**
4057         * spwans an entity and loads surrounding chunks
4058         */
4059        public void joinEntityInSurroundings(Entity par1Entity)
4060        {
4061            int var2 = MathHelper.floor_double(par1Entity.posX / 16.0D);
4062            int var3 = MathHelper.floor_double(par1Entity.posZ / 16.0D);
4063            byte var4 = 2;
4064    
4065            for (int var5 = var2 - var4; var5 <= var2 + var4; ++var5)
4066            {
4067                for (int var6 = var3 - var4; var6 <= var3 + var4; ++var6)
4068                {
4069                    this.getChunkFromChunkCoords(var5, var6);
4070                }
4071            }
4072    
4073            if (!this.loadedEntityList.contains(par1Entity))
4074            {
4075                if (!MinecraftForge.EVENT_BUS.post(new EntityJoinWorldEvent(par1Entity, this)))
4076                {
4077                    loadedEntityList.add(par1Entity);
4078                }
4079            }
4080        }
4081    
4082        /**
4083         * Called when checking if a certain block can be mined or not. The 'spawn safe zone' check is located here.
4084         */
4085        public boolean canMineBlock(EntityPlayer par1EntityPlayer, int par2, int par3, int par4)
4086        {
4087            return provider.canMineBlock(par1EntityPlayer, par2, par3, par4);
4088        }
4089    
4090        public boolean canMineBlockBody(EntityPlayer par1EntityPlayer, int par2, int par3, int par4)
4091        {
4092            return true;
4093        }
4094    
4095        /**
4096         * sends a Packet 38 (Entity Status) to all tracked players of that entity
4097         */
4098        public void setEntityState(Entity par1Entity, byte par2) {}
4099    
4100        /**
4101         * gets the IChunkProvider this world uses.
4102         */
4103        public IChunkProvider getChunkProvider()
4104        {
4105            return this.chunkProvider;
4106        }
4107    
4108        /**
4109         * Adds a block event with the given Args to the blockEventCache. During the next tick(), the block specified will
4110         * have its onBlockEvent handler called with the given parameters. Args: X,Y,Z, BlockID, EventID, EventParameter
4111         */
4112        public void addBlockEvent(int par1, int par2, int par3, int par4, int par5, int par6)
4113        {
4114            if (par4 > 0)
4115            {
4116                Block.blocksList[par4].onBlockEventReceived(this, par1, par2, par3, par5, par6);
4117            }
4118        }
4119    
4120        /**
4121         * Returns this world's current save handler
4122         */
4123        public ISaveHandler getSaveHandler()
4124        {
4125            return this.saveHandler;
4126        }
4127    
4128        /**
4129         * Gets the World's WorldInfo instance
4130         */
4131        public WorldInfo getWorldInfo()
4132        {
4133            return this.worldInfo;
4134        }
4135    
4136        /**
4137         * Gets the GameRules instance.
4138         */
4139        public GameRules getGameRules()
4140        {
4141            return this.worldInfo.getGameRulesInstance();
4142        }
4143    
4144        /**
4145         * Updates the flag that indicates whether or not all players in the world are sleeping.
4146         */
4147        public void updateAllPlayersSleepingFlag() {}
4148    
4149        public float getWeightedThunderStrength(float par1)
4150        {
4151            return (this.prevThunderingStrength + (this.thunderingStrength - this.prevThunderingStrength) * par1) * this.getRainStrength(par1);
4152        }
4153    
4154        /**
4155         * Not sure about this actually. Reverting this one myself.
4156         */
4157        public float getRainStrength(float par1)
4158        {
4159            return this.prevRainingStrength + (this.rainingStrength - this.prevRainingStrength) * par1;
4160        }
4161    
4162        @SideOnly(Side.CLIENT)
4163        public void setRainStrength(float par1)
4164        {
4165            this.prevRainingStrength = par1;
4166            this.rainingStrength = par1;
4167        }
4168    
4169        /**
4170         * Returns true if the current thunder strength (weighted with the rain strength) is greater than 0.9
4171         */
4172        public boolean isThundering()
4173        {
4174            return (double)this.getWeightedThunderStrength(1.0F) > 0.9D;
4175        }
4176    
4177        /**
4178         * Returns true if the current rain strength is greater than 0.2
4179         */
4180        public boolean isRaining()
4181        {
4182            return (double)this.getRainStrength(1.0F) > 0.2D;
4183        }
4184    
4185        public boolean canLightningStrikeAt(int par1, int par2, int par3)
4186        {
4187            if (!this.isRaining())
4188            {
4189                return false;
4190            }
4191            else if (!this.canBlockSeeTheSky(par1, par2, par3))
4192            {
4193                return false;
4194            }
4195            else if (this.getPrecipitationHeight(par1, par3) > par2)
4196            {
4197                return false;
4198            }
4199            else
4200            {
4201                BiomeGenBase var4 = this.getBiomeGenForCoords(par1, par3);
4202                return var4.getEnableSnow() ? false : var4.canSpawnLightningBolt();
4203            }
4204        }
4205    
4206        /**
4207         * Checks to see if the biome rainfall values for a given x,y,z coordinate set are extremely high
4208         */
4209        public boolean isBlockHighHumidity(int par1, int par2, int par3)
4210        {
4211            return provider.isBlockHighHumidity(par1, par2, par3);
4212        }
4213    
4214        /**
4215         * Assigns the given String id to the given MapDataBase using the MapStorage, removing any existing ones of the same
4216         * id.
4217         */
4218        public void setItemData(String par1Str, WorldSavedData par2WorldSavedData)
4219        {
4220            this.mapStorage.setData(par1Str, par2WorldSavedData);
4221        }
4222    
4223        /**
4224         * Loads an existing MapDataBase corresponding to the given String id from disk using the MapStorage, instantiating
4225         * the given Class, or returns null if none such file exists. args: Class to instantiate, String dataid
4226         */
4227        public WorldSavedData loadItemData(Class par1Class, String par2Str)
4228        {
4229            return this.mapStorage.loadData(par1Class, par2Str);
4230        }
4231    
4232        /**
4233         * Returns an unique new data id from the MapStorage for the given prefix and saves the idCounts map to the
4234         * 'idcounts' file.
4235         */
4236        public int getUniqueDataId(String par1Str)
4237        {
4238            return this.mapStorage.getUniqueDataId(par1Str);
4239        }
4240    
4241        public void func_82739_e(int par1, int par2, int par3, int par4, int par5)
4242        {
4243            for (int var6 = 0; var6 < this.worldAccesses.size(); ++var6)
4244            {
4245                ((IWorldAccess)this.worldAccesses.get(var6)).broadcastSound(par1, par2, par3, par4, par5);
4246            }
4247        }
4248    
4249        /**
4250         * See description for playAuxSFX.
4251         */
4252        public void playAuxSFX(int par1, int par2, int par3, int par4, int par5)
4253        {
4254            this.playAuxSFXAtEntity((EntityPlayer)null, par1, par2, par3, par4, par5);
4255        }
4256    
4257        /**
4258         * See description for playAuxSFX.
4259         */
4260        public void playAuxSFXAtEntity(EntityPlayer par1EntityPlayer, int par2, int par3, int par4, int par5, int par6)
4261        {
4262            try
4263            {
4264                for (int var7 = 0; var7 < this.worldAccesses.size(); ++var7)
4265                {
4266                    ((IWorldAccess)this.worldAccesses.get(var7)).playAuxSFX(par1EntityPlayer, par2, par3, par4, par5, par6);
4267                }
4268            }
4269            catch (Throwable var10)
4270            {
4271                CrashReport var8 = CrashReport.makeCrashReport(var10, "Playing level event");
4272                CrashReportCategory var9 = var8.makeCategory("Level event being played");
4273                var9.addCrashSection("Block coordinates", CrashReportCategory.func_85071_a(par3, par4, par5));
4274                var9.addCrashSection("Event source", par1EntityPlayer);
4275                var9.addCrashSection("Event type", Integer.valueOf(par2));
4276                var9.addCrashSection("Event data", Integer.valueOf(par6));
4277                throw new ReportedException(var8);
4278            }
4279        }
4280    
4281        /**
4282         * Returns current world height.
4283         */
4284        public int getHeight()
4285        {
4286            return provider.getHeight();
4287        }
4288    
4289        /**
4290         * Returns current world height.
4291         */
4292        public int getActualHeight()
4293        {
4294            return provider.getActualHeight();
4295        }
4296    
4297        public IUpdatePlayerListBox func_82735_a(EntityMinecart par1EntityMinecart)
4298        {
4299            return null;
4300        }
4301    
4302        /**
4303         * puts the World Random seed to a specific state dependant on the inputs
4304         */
4305        public Random setRandomSeed(int par1, int par2, int par3)
4306        {
4307            long var4 = (long)par1 * 341873128712L + (long)par2 * 132897987541L + this.getWorldInfo().getSeed() + (long)par3;
4308            this.rand.setSeed(var4);
4309            return this.rand;
4310        }
4311    
4312        /**
4313         * Returns the location of the closest structure of the specified type. If not found returns null.
4314         */
4315        public ChunkPosition findClosestStructure(String par1Str, int par2, int par3, int par4)
4316        {
4317            return this.getChunkProvider().findClosestStructure(this, par1Str, par2, par3, par4);
4318        }
4319    
4320        @SideOnly(Side.CLIENT)
4321    
4322        /**
4323         * set by !chunk.getAreLevelsEmpty
4324         */
4325        public boolean extendedLevelsInChunkCache()
4326        {
4327            return false;
4328        }
4329    
4330        @SideOnly(Side.CLIENT)
4331    
4332        /**
4333         * Returns horizon height for use in rendering the sky.
4334         */
4335        public double getHorizon()
4336        {
4337            return provider.getHorizon();
4338        }
4339    
4340        /**
4341         * Adds some basic stats of the world to the given crash report.
4342         */
4343        public CrashReportCategory addWorldInfoToCrashReport(CrashReport par1CrashReport)
4344        {
4345            CrashReportCategory var2 = par1CrashReport.makeCategoryDepth("Affected level", 1);
4346            var2.addCrashSection("Level name", this.worldInfo == null ? "????" : this.worldInfo.getWorldName());
4347            var2.addCrashSectionCallable("All players", new CallableLvl2(this));
4348            var2.addCrashSectionCallable("Chunk stats", new CallableLvl3(this));
4349    
4350            try
4351            {
4352                this.worldInfo.func_85118_a(var2);
4353            }
4354            catch (Throwable var4)
4355            {
4356                var2.addCrashSectionThrowable("Level Data Unobtainable", var4);
4357            }
4358    
4359            return var2;
4360        }
4361    
4362        /**
4363         * Starts (or continues) destroying a block with given ID at the given coordinates for the given partially destroyed
4364         * value
4365         */
4366        public void destroyBlockInWorldPartially(int par1, int par2, int par3, int par4, int par5)
4367        {
4368            for (int var6 = 0; var6 < this.worldAccesses.size(); ++var6)
4369            {
4370                IWorldAccess var7 = (IWorldAccess)this.worldAccesses.get(var6);
4371                var7.destroyBlockPartially(par1, par2, par3, par4, par5);
4372            }
4373        }
4374    
4375        /**
4376         * Return the Vec3Pool object for this world.
4377         */
4378        public Vec3Pool getWorldVec3Pool()
4379        {
4380            return this.vecPool;
4381        }
4382    
4383        /**
4384         * returns a calendar object containing the current date
4385         */
4386        public Calendar getCurrentDate()
4387        {
4388            if (this.getTotalWorldTime() % 600L == 0L)
4389            {
4390                this.theCalendar.setTimeInMillis(System.currentTimeMillis());
4391            }
4392    
4393            return this.theCalendar;
4394        }
4395    
4396        @SideOnly(Side.CLIENT)
4397        public void func_92088_a(double par1, double par3, double par5, double par7, double par9, double par11, NBTTagCompound par13NBTTagCompound) {}
4398    
4399        /**
4400         * Adds a single TileEntity to the world.
4401         * @param entity The TileEntity to be added.
4402         */
4403        public void addTileEntity(TileEntity entity)
4404        {
4405            List dest = scanningTileEntities ? addedTileEntityList : loadedTileEntityList;
4406            if(entity.canUpdate())
4407            {
4408                dest.add(entity);
4409            }
4410        }
4411    
4412        /**
4413         * Determine if the given block is considered solid on the
4414         * specified side.  Used by placement logic.
4415         *
4416         * @param x Block X Position
4417         * @param y Block Y Position
4418         * @param z Block Z Position
4419         * @param side The Side in question
4420         * @return True if the side is solid
4421         */
4422        public boolean isBlockSolidOnSide(int x, int y, int z, ForgeDirection side)
4423        {
4424            return isBlockSolidOnSide(x, y, z, side, false);
4425        }
4426    
4427        /**
4428         * Determine if the given block is considered solid on the
4429         * specified side.  Used by placement logic.
4430         *
4431         * @param x Block X Position
4432         * @param y Block Y Position
4433         * @param z Block Z Position
4434         * @param side The Side in question
4435         * @param _default The defult to return if the block doesn't exist.
4436         * @return True if the side is solid
4437         */
4438        public boolean isBlockSolidOnSide(int x, int y, int z, ForgeDirection side, boolean _default)
4439        {
4440            if (x < -30000000 || z < -30000000 || x >= 30000000 || z >= 30000000)
4441            {
4442                return _default;
4443            }
4444    
4445            Chunk var5 = this.chunkProvider.provideChunk(x >> 4, z >> 4);
4446            if (var5 == null || var5.isEmpty())
4447            {
4448                return _default;
4449            }
4450    
4451            Block block = Block.blocksList[getBlockId(x, y, z)];
4452            if(block == null)
4453            {
4454                return false;
4455            }
4456    
4457            return block.isBlockSolidOnSide(this, x, y, z, side);
4458        }
4459    
4460        /**
4461         * Get the persistent chunks for this world
4462         *
4463         * @return
4464         */
4465        public ImmutableSetMultimap<ChunkCoordIntPair, Ticket> getPersistentChunks()
4466        {
4467            return ForgeChunkManager.getPersistentChunksFor(this);
4468        }
4469    }