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