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