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