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