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