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