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