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